| /* |
| * Copyright 2010 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.place.rebind; |
| |
| import com.google.gwt.core.ext.TreeLogger; |
| import com.google.gwt.core.ext.UnableToCompleteException; |
| import com.google.gwt.core.ext.typeinfo.JClassType; |
| import com.google.gwt.core.ext.typeinfo.JType; |
| import com.google.gwt.core.ext.typeinfo.NotFoundException; |
| import com.google.gwt.core.ext.typeinfo.TypeOracle; |
| import com.google.gwt.dev.CompilerContext; |
| import com.google.gwt.dev.javac.CompilationStateBuilder; |
| import com.google.gwt.dev.javac.testing.impl.JavaResourceBase; |
| import com.google.gwt.dev.javac.testing.impl.MockJavaResource; |
| import com.google.gwt.dev.resource.Resource; |
| import com.google.gwt.dev.util.UnitTestTreeLogger; |
| import com.google.gwt.dev.util.log.PrintWriterTreeLogger; |
| import com.google.gwt.place.shared.Place; |
| import com.google.gwt.place.shared.PlaceHistoryMapper; |
| import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory; |
| import com.google.gwt.place.shared.PlaceTokenizer; |
| import com.google.gwt.place.shared.Prefix; |
| import com.google.gwt.place.shared.WithTokenizers; |
| import com.google.gwt.place.testplacemappers.NoFactory; |
| import com.google.gwt.place.testplacemappers.WithFactory; |
| import com.google.gwt.place.testplaces.AbstractTokenizer; |
| import com.google.gwt.place.testplaces.Place1; |
| import com.google.gwt.place.testplaces.Place2; |
| import com.google.gwt.place.testplaces.Place3; |
| import com.google.gwt.place.testplaces.Place4; |
| import com.google.gwt.place.testplaces.Place6; |
| import com.google.gwt.place.testplaces.Tokenizer2; |
| import com.google.gwt.place.testplaces.Tokenizer3; |
| import com.google.gwt.place.testplaces.Tokenizer4; |
| import com.google.gwt.place.testplaces.TokenizerFactory; |
| |
| import junit.framework.TestCase; |
| |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| /** |
| * Test case for {@link PlaceHistoryGeneratorContext} that uses mock |
| * CompilationStates. |
| */ |
| public class PlaceHistoryGeneratorContextTest extends TestCase { |
| |
| private static final JType[] EMPTY_JTYPE_ARRAY = new JType[0]; |
| |
| private static TreeLogger createCompileLogger() { |
| PrintWriterTreeLogger logger = new PrintWriterTreeLogger(new PrintWriter( |
| System.err, true)); |
| logger.setMaxDetail(TreeLogger.ERROR); |
| return logger; |
| } |
| |
| private static TypeOracle createTypeOracle(Resource... extraResources) { |
| Set<Resource> resources = new HashSet<Resource>( |
| Arrays.asList(JavaResourceBase.getStandardResources())); |
| resources.add(new RealJavaResource(Place.class)); |
| resources.add(new RealJavaResource(PlaceTokenizer.class)); |
| resources.add(new RealJavaResource(PlaceHistoryMapper.class)); |
| resources.add(new RealJavaResource(PlaceHistoryMapperWithFactory.class)); |
| resources.add(new RealJavaResource(WithTokenizers.class)); |
| resources.add(new RealJavaResource(Prefix.class)); |
| resources.add(new RealJavaResource(NoFactory.class)); |
| resources.add(new RealJavaResource(WithFactory.class)); |
| resources.add(new RealJavaResource(TokenizerFactory.class)); |
| resources.add(new RealJavaResource(Place1.class)); |
| resources.add(new RealJavaResource(Place2.class)); |
| resources.add(new RealJavaResource(Place3.class)); |
| resources.add(new RealJavaResource(Place4.class)); |
| resources.add(new RealJavaResource(Place6.class)); |
| resources.add(new RealJavaResource(AbstractTokenizer.class)); |
| resources.add(new RealJavaResource(Tokenizer2.class)); |
| resources.add(new RealJavaResource(Tokenizer3.class)); |
| resources.add(new RealJavaResource(Tokenizer4.class)); |
| resources.addAll(Arrays.asList(extraResources)); |
| try { |
| return CompilationStateBuilder.buildFrom( |
| createCompileLogger(), new CompilerContext(), resources).getTypeOracle(); |
| } catch (UnableToCompleteException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public void testCreateNotAnInterface() throws UnableToCompleteException { |
| MockJavaResource intf = new MockJavaResource("my.MyPlaceHistoryMapper") { |
| |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package my;\n"); |
| code.append("import com.google.gwt.place.shared.PlaceHistoryMapper;\n"); |
| |
| code.append("public abstract class MyPlaceHistoryMapper implements PlaceHistoryMapper {\n"); |
| code.append("}\n"); |
| return code; |
| } |
| }; |
| |
| TypeOracle typeOracle = createTypeOracle(intf); |
| |
| UnitTestTreeLogger logger = new UnitTestTreeLogger.Builder().createLogger(); |
| |
| PlaceHistoryGeneratorContext context = PlaceHistoryGeneratorContext.create( |
| logger, typeOracle, intf.getTypeName()); |
| |
| assertNull(context); |
| } |
| |
| public void testCreateNoFactory() throws UnableToCompleteException, |
| NotFoundException { |
| doTestCreate(NoFactory.class, null); |
| } |
| |
| public void testCreateWithFactory() throws UnableToCompleteException, |
| NotFoundException { |
| doTestCreate(WithFactory.class, TokenizerFactory.class); |
| } |
| |
| public void testNoFactory() throws UnableToCompleteException, |
| NotFoundException { |
| |
| TypeOracle typeOracle = createTypeOracle(); |
| JClassType place1 = typeOracle.getType(Place1.class.getName()); |
| JClassType place2 = typeOracle.getType(Place2.class.getName()); |
| JClassType place3 = typeOracle.getType(Place3.class.getName()); |
| JClassType place4 = typeOracle.getType(Place4.class.getName()); |
| JClassType place6 = typeOracle.getType(Place6.class.getName()); |
| |
| PlaceHistoryGeneratorContext context = createContext(TreeLogger.NULL, |
| typeOracle, NoFactory.class.getName(), null); |
| |
| // Found all place prefixes? |
| assertEquals(new HashSet<String>(Arrays.asList("", Place1.Tokenizer.PREFIX, |
| "Place2", "Place3", "Place4")), context.getPrefixes()); |
| |
| // Found all place types and correctly sorted them? |
| assertEquals(Arrays.asList(place3, place4, place1, place2, place6), |
| new ArrayList<JClassType>(context.getPlaceTypes())); |
| |
| // correctly maps place types to their prefixes? |
| assertEquals(Place1.Tokenizer.PREFIX, context.getPrefix(place1)); |
| assertEquals("Place2", context.getPrefix(place2)); |
| assertEquals("Place3", context.getPrefix(place3)); |
| assertEquals("Place4", context.getPrefix(place4)); |
| assertEquals("", context.getPrefix(place6)); |
| |
| // there obviously shouldn't be factory methods |
| assertNull(context.getTokenizerGetter(Place1.Tokenizer.PREFIX)); |
| assertNull(context.getTokenizerGetter("Place2")); |
| assertNull(context.getTokenizerGetter("Place3")); |
| assertNull(context.getTokenizerGetter("Place4")); |
| assertNull(context.getTokenizerGetter("")); |
| |
| // correctly maps prefixes to their tokenizer type? |
| assertEquals(typeOracle.getType(Place1.Tokenizer.class.getCanonicalName()), |
| context.getTokenizerType(Place1.Tokenizer.PREFIX)); |
| assertEquals(typeOracle.getType(Tokenizer2.class.getName()), |
| context.getTokenizerType("Place2")); |
| assertEquals(typeOracle.getType(Tokenizer3.class.getName()), |
| context.getTokenizerType("Place3")); |
| assertEquals(typeOracle.getType(Tokenizer4.class.getName()), |
| context.getTokenizerType("Place4")); |
| assertEquals(typeOracle.getType(Place6.Tokenizer.class.getCanonicalName()), |
| context.getTokenizerType("")); |
| } |
| |
| public void testWithFactory() throws UnableToCompleteException, |
| NotFoundException { |
| |
| TypeOracle typeOracle = createTypeOracle(); |
| |
| JClassType place1 = typeOracle.getType(Place1.class.getName()); |
| JClassType place2 = typeOracle.getType(Place2.class.getName()); |
| JClassType place3 = typeOracle.getType(Place3.class.getName()); |
| JClassType place4 = typeOracle.getType(Place4.class.getName()); |
| JClassType place6 = typeOracle.getType(Place6.class.getName()); |
| JClassType factory = typeOracle.getType(TokenizerFactory.class.getName()); |
| |
| PlaceHistoryGeneratorContext context = createContext(TreeLogger.NULL, |
| typeOracle, WithFactory.class.getName(), |
| TokenizerFactory.class.getName()); |
| |
| // Found all place prefixes? |
| assertEquals(new HashSet<String>(Arrays.asList("", Place1.Tokenizer.PREFIX, |
| TokenizerFactory.PLACE2_PREFIX, "Place3", "Place4")), |
| context.getPrefixes()); |
| |
| // Found all place types and correctly sorted them? |
| assertEquals(Arrays.asList(place3, place4, place1, place2, place6), |
| new ArrayList<JClassType>(context.getPlaceTypes())); |
| |
| // correctly maps place types to their prefixes? |
| assertEquals(Place1.Tokenizer.PREFIX, context.getPrefix(place1)); |
| assertEquals(TokenizerFactory.PLACE2_PREFIX, context.getPrefix(place2)); |
| assertEquals("Place3", context.getPrefix(place3)); |
| assertEquals("Place4", context.getPrefix(place4)); |
| assertEquals("", context.getPrefix(place6)); |
| |
| // correctly map prefixes to their factory method (or null)? |
| assertEquals(factory.getMethod("getTokenizer1", EMPTY_JTYPE_ARRAY), |
| context.getTokenizerGetter(Place1.Tokenizer.PREFIX)); |
| assertEquals(factory.getMethod("getTokenizer2", EMPTY_JTYPE_ARRAY), |
| context.getTokenizerGetter(TokenizerFactory.PLACE2_PREFIX)); |
| assertEquals(factory.getMethod("getTokenizer3", EMPTY_JTYPE_ARRAY), |
| context.getTokenizerGetter("Place3")); |
| assertNull(context.getTokenizerGetter("Place4")); |
| assertNull(context.getTokenizerGetter("")); |
| |
| // correctly maps prefixes to their tokenizer type (or null)? |
| assertNull(context.getTokenizerType(Place1.Tokenizer.PREFIX)); |
| assertNull(context.getTokenizerType(TokenizerFactory.PLACE2_PREFIX)); |
| assertNull(context.getTokenizerType("Place3")); |
| assertEquals(typeOracle.getType(Tokenizer4.class.getName()), |
| context.getTokenizerType("Place4")); |
| assertEquals(typeOracle.getType(Place6.Tokenizer.class.getCanonicalName()), |
| context.getTokenizerType("")); |
| } |
| |
| public void testDuplicatePrefix() { |
| MockJavaResource intf = new MockJavaResource("my.MyPlaceHistoryMapper") { |
| |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package my;\n"); |
| code.append("import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;\n"); |
| code.append("import com.google.gwt.place.shared.WithTokenizers;\n"); |
| code.append("import com.google.gwt.place.shared.Prefix;\n"); |
| code.append("import com.google.gwt.place.testplaces.Place1;\n"); |
| code.append("import com.google.gwt.place.testplaces.Tokenizer2;\n"); |
| |
| code.append("@WithTokenizers(Place1.Tokenizer.class)\n"); |
| code.append("public interface MyPlaceHistoryMapper extends PlaceHistoryMapperWithFactory<MyPlaceHistoryMapper.Factory> {\n"); |
| code.append(" interface Factory {\n"); |
| code.append(" @Prefix(Place1.Tokenizer.PREFIX) Tokenizer2 tokenizer2();\n"); |
| code.append(" }\n"); |
| code.append("}\n"); |
| return code; |
| } |
| }; |
| |
| TypeOracle typeOracle = createTypeOracle(intf); |
| |
| UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder(); |
| loggerBuilder.expectError(String.format( |
| "Found duplicate place prefix \"%s\" on %s, already seen on %s", |
| Place1.Tokenizer.PREFIX, Place1.Tokenizer.class.getCanonicalName(), |
| intf.getTypeName() + ".Factory#tokenizer2()"), null); |
| UnitTestTreeLogger logger = loggerBuilder.createLogger(); |
| |
| PlaceHistoryGeneratorContext context = createContext(logger, typeOracle, |
| intf.getTypeName(), intf.getTypeName() + ".Factory"); |
| |
| try { |
| context.ensureInitialized(); |
| fail(); |
| } catch (UnableToCompleteException e) { |
| // expected exception |
| } |
| |
| logger.assertCorrectLogEntries(); |
| } |
| |
| public void testDuplicatePlaceType() { |
| MockJavaResource intf = new MockJavaResource("my.MyPlaceHistoryMapper") { |
| |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package my;\n"); |
| code.append("import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;\n"); |
| code.append("import com.google.gwt.place.shared.PlaceTokenizer;\n"); |
| code.append("import com.google.gwt.place.shared.WithTokenizers;\n"); |
| code.append("import com.google.gwt.place.shared.Prefix;\n"); |
| code.append("import com.google.gwt.place.testplaces.Place1;\n"); |
| |
| code.append("@WithTokenizers(Place1.Tokenizer.class)\n"); |
| code.append("public interface MyPlaceHistoryMapper extends PlaceHistoryMapperWithFactory<MyPlaceHistoryMapper.Factory> {\n"); |
| code.append(" interface Factory {\n"); |
| code.append(" @Prefix(\"anotherPrefix\") PlaceTokenizer<Place1> bar();\n"); |
| code.append(" }\n"); |
| code.append("}\n"); |
| return code; |
| } |
| }; |
| |
| TypeOracle typeOracle = createTypeOracle(intf); |
| |
| UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder(); |
| loggerBuilder.expectError( |
| String.format( |
| "Found duplicate tokenizer's place type \"%s\" on %s, already seen on %s", |
| Place1.class.getName(), Place1.Tokenizer.class.getCanonicalName(), |
| intf.getTypeName() + ".Factory#bar()"), null); |
| UnitTestTreeLogger logger = loggerBuilder.createLogger(); |
| |
| PlaceHistoryGeneratorContext context = createContext(logger, typeOracle, |
| intf.getTypeName(), intf.getTypeName() + ".Factory"); |
| |
| try { |
| context.ensureInitialized(); |
| fail(); |
| } catch (UnableToCompleteException e) { |
| // expected exception |
| } |
| |
| logger.assertCorrectLogEntries(); |
| } |
| |
| public void testPrefixContainingColon() { |
| MockJavaResource intf = new MockJavaResource("my.MyPlaceHistoryMapper") { |
| |
| @Override |
| public CharSequence getContent() { |
| StringBuilder code = new StringBuilder(); |
| code.append("package my;\n"); |
| code.append("import com.google.gwt.place.shared.Place;\n"); |
| code.append("import com.google.gwt.place.shared.PlaceHistoryMapperWithFactory;\n"); |
| code.append("import com.google.gwt.place.shared.PlaceTokenizer;\n"); |
| code.append("import com.google.gwt.place.shared.Prefix;\n"); |
| |
| code.append("public interface MyPlaceHistoryMapper extends PlaceHistoryMapperWithFactory<MyPlaceHistoryMapper.Factory> {\n"); |
| code.append(" interface Factory {\n"); |
| code.append(" @Prefix(\"foo:bar\") PlaceTokenizer<Place> foo_bar();\n"); |
| code.append(" }\n"); |
| code.append("}\n"); |
| return code; |
| } |
| }; |
| |
| TypeOracle typeOracle = createTypeOracle(intf); |
| |
| UnitTestTreeLogger.Builder loggerBuilder = new UnitTestTreeLogger.Builder(); |
| loggerBuilder.expectError( |
| "Found place prefix \"foo:bar\" containing separator char \":\", on " |
| + intf.getTypeName() + ".Factory#foo_bar()", null); |
| UnitTestTreeLogger logger = loggerBuilder.createLogger(); |
| |
| PlaceHistoryGeneratorContext context = createContext(logger, typeOracle, |
| intf.getTypeName(), intf.getTypeName() + ".Factory"); |
| |
| try { |
| context.ensureInitialized(); |
| fail(); |
| } catch (UnableToCompleteException e) { |
| // expected exception |
| } |
| |
| logger.assertCorrectLogEntries(); |
| } |
| |
| private void doTestCreate(Class<? extends PlaceHistoryMapper> intf, |
| Class<?> factory) throws UnableToCompleteException, NotFoundException { |
| UnitTestTreeLogger logger = new UnitTestTreeLogger.Builder().createLogger(); |
| |
| TypeOracle typeOracle = createTypeOracle(); |
| |
| PlaceHistoryGeneratorContext context = PlaceHistoryGeneratorContext.create( |
| logger, typeOracle, intf.getName()); |
| |
| assertEquals(typeOracle.getType(String.class.getName()), context.stringType); |
| assertEquals(typeOracle.getType(PlaceTokenizer.class.getName()), |
| context.placeTokenizerType); |
| assertSame(logger, context.logger); |
| assertSame(typeOracle, context.typeOracle); |
| |
| assertEquals(typeOracle.getType(intf.getName()), context.interfaceType); |
| |
| if (factory == null) { |
| assertNull(context.factoryType); |
| } else { |
| assertEquals(typeOracle.getType(factory.getName()), context.factoryType); |
| } |
| |
| assertEquals(intf.getSimpleName() + "Impl", context.implName); |
| assertEquals(intf.getPackage().getName(), context.packageName); |
| |
| logger.assertCorrectLogEntries(); |
| } |
| |
| private PlaceHistoryGeneratorContext createContext(TreeLogger logger, |
| TypeOracle typeOracle, String interfaceName, String factoryName) { |
| return new PlaceHistoryGeneratorContext(logger, typeOracle, |
| typeOracle.findType(interfaceName), // |
| typeOracle.findType(factoryName), // |
| typeOracle.findType(String.class.getName()), // |
| typeOracle.findType(PlaceTokenizer.class.getName()), // |
| null, null); |
| } |
| } |