/* * 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.dev.javac; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JArrayType; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JConstructor; import com.google.gwt.core.ext.typeinfo.JField; import com.google.gwt.core.ext.typeinfo.JGenericType; import com.google.gwt.core.ext.typeinfo.JMethod; import com.google.gwt.core.ext.typeinfo.JParameterizedType; import com.google.gwt.core.ext.typeinfo.JPrimitiveType; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.JTypeParameter; import com.google.gwt.core.ext.typeinfo.JWildcardType; import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.core.ext.typeinfo.TypeOracleException; import com.google.gwt.dev.javac.TypeOracleMediator.TypeData; import com.google.gwt.dev.javac.mediatortest.AfterAssimilate; import com.google.gwt.dev.javac.mediatortest.BaseInterface; import com.google.gwt.dev.javac.mediatortest.BeforeAssimilate; import com.google.gwt.dev.javac.mediatortest.BindToTypeScope; import com.google.gwt.dev.javac.mediatortest.ConstrainedList; import com.google.gwt.dev.javac.mediatortest.ConstrainedListAsField; import com.google.gwt.dev.javac.mediatortest.DeclaresGenericInnerInterface; import com.google.gwt.dev.javac.mediatortest.DeclaresGenericInnerType; import com.google.gwt.dev.javac.mediatortest.DefaultClass; import com.google.gwt.dev.javac.mediatortest.Derived; import com.google.gwt.dev.javac.mediatortest.DerivedInterface; import com.google.gwt.dev.javac.mediatortest.EnclosingLocal; import com.google.gwt.dev.javac.mediatortest.EnclosingLocalWithMember; import com.google.gwt.dev.javac.mediatortest.ExtendsGenericList; import com.google.gwt.dev.javac.mediatortest.ExtendsGenericOuter; import com.google.gwt.dev.javac.mediatortest.ExtendsParameterizedInterface; import com.google.gwt.dev.javac.mediatortest.Fields; import com.google.gwt.dev.javac.mediatortest.GenericList; import com.google.gwt.dev.javac.mediatortest.GenericOuter; import com.google.gwt.dev.javac.mediatortest.Implementations; import com.google.gwt.dev.javac.mediatortest.ListAsField; import com.google.gwt.dev.javac.mediatortest.Methods; import com.google.gwt.dev.javac.mediatortest.Outer; import com.google.gwt.dev.javac.mediatortest.OuterInt; import com.google.gwt.dev.javac.mediatortest.ReferencesGenericListConstant; import com.google.gwt.dev.javac.mediatortest.ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed; import com.google.gwt.dev.javac.testing.impl.MockJavaResource; import com.google.gwt.dev.javac.testing.impl.StaticJavaResource; import com.google.gwt.dev.resource.Resource; import com.google.gwt.dev.util.Util; import com.google.gwt.dev.util.log.AbstractTreeLogger; import com.google.gwt.dev.util.log.PrintWriterTreeLogger; import junit.framework.TestCase; import org.apache.commons.collections.map.AbstractReferenceMap; import org.apache.commons.collections.map.ReferenceMap; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * Test TypeOracleMediator. * * NOTE: These tests require the test source code to be on the classpath. In * Eclipse, make sure your launch configuration includes the 'core/test' * directory on the classpath tab. */ public abstract class TypeOracleMediatorTestBase extends TestCase { protected static abstract class CheckedJavaResource extends MutableJavaResource { private final String[] shortTypeNames; public CheckedJavaResource(Class<?> clazz, String... shortTypeNames) { super(clazz); this.shortTypeNames = shortTypeNames; } public CheckedJavaResource(String packageName, String shortMainTypeName, String... shortTypeNames) { super(packageName, Shared.makeTypeName(packageName, shortMainTypeName)); this.shortTypeNames = shortTypeNames; } public abstract void check(JClassType type) throws NotFoundException; public List<String> getTypeNames() { List<String> typeNames = new ArrayList<String>(); typeNames.add(getTypeName()); for (String shortTypeName : shortTypeNames) { String typeName = Shared.makeTypeName(getPackageName(), shortTypeName); typeNames.add(typeName); } return typeNames; } } protected static abstract class MutableJavaResource extends MockJavaResource { private static byte[] getByteCode(Class<?> aClass) throws IOException { String resourcePath = aClass.getName().replace(".", "/") + ".class"; ClassLoader loader = aClass.getClassLoader(); if (loader == null && aClass.getName().startsWith("java.")) { loader = Thread.currentThread().getContextClassLoader(); } InputStream istream = loader.getResourceAsStream(resourcePath); assertNotNull(istream); return Util.readStreamAsBytes(istream); } // For building the type oracle from bytecode private final Class<?> clazz; private String extraSource = ""; private final String packageName; public MutableJavaResource(Class<?> clazz) { super(clazz.getName()); this.clazz = clazz; this.packageName = clazz.getPackage().getName(); } public MutableJavaResource(String packageName, String qualifiedTypeName) { super(qualifiedTypeName); this.clazz = null; this.packageName = packageName; } public String getPackageName() { return packageName; } /** * This method is used to pull sample source from inside the test case. By * default, return <code>null</code> to indicate that source should be on * the classpath. * * @return */ public String getSource() { return null; } /** * Pulls Java source from files in the mediatortest package. If source files * are on the classpath, prefer this data. */ public String getSourceFromClasspath() throws IOException { if (clazz == null) { return null; } assertFalse(clazz.getName().startsWith("java.")); ClassLoader loader = clazz.getClassLoader(); String resourcePath = clazz.getName().replace(".", "/") + ".java"; InputStream istream = loader.getResourceAsStream(resourcePath); if (istream == null) { fail("Could not read " + resourcePath + " from classloader."); } return Util.readStreamAsString(istream); } public TypeData[] getTypeData() throws IOException { return getTypeData(clazz); } @Override public void touch() { super.touch(); extraSource += '\n'; } /** * Looks for the source data on the classpath. */ @Override public CharSequence getContent() { String source = getSource(); if (source == null) { try { source = getSourceFromClasspath(); } catch (IOException ex) { return null; } assertNotNull("Make sure your runtime environment includes the source " + "for the testcases on the classpath if this assertion fails", source); } return source + extraSource; } private TypeData[] getTypeData(Class<?> aClass) throws IOException { List<TypeData> results = new ArrayList<TypeData>(); String packageName = Shared.getPackageName(aClass.getName()); TypeData newData = new TypeData(packageName, aClass.getSimpleName(), aClass.getName().replace(".", "/"), null, getByteCode(aClass), System.currentTimeMillis()); results.add(newData); Class<?>[] subclasses = aClass.getDeclaredClasses(); for (Class<?> subclass : subclasses) { for (TypeData result : getTypeData(subclass)) { results.add(result); } } return results.toArray(new TypeData[results.size()]); } } protected static final CheckedJavaResource CU_AfterAssimilate = new CheckedJavaResource( AfterAssimilate.class) { @Override public void check(JClassType type) { assertNotNull(type); assertEquals("AfterAssimilate", type.getSimpleSourceName()); assertNotNull(type.getSuperclass()); assertEquals(getPackageName() + ".BeforeAssimilate", type.getSuperclass() .getQualifiedSourceName()); } }; protected static final CheckedJavaResource CU_BaseInterface = new CheckedJavaResource( BaseInterface.class) { @Override public void check(JClassType type) { assertEquals(getTypeName(), type.getQualifiedSourceName()); assertNotNull(type.isInterface()); } }; protected static final CheckedJavaResource CU_BeforeAssimilate = new CheckedJavaResource( BeforeAssimilate.class) { @Override public void check(JClassType type) { assertEquals(getTypeName(), type.getQualifiedSourceName()); } }; protected static final CheckedJavaResource CU_BindToTypeScope = new CheckedJavaResource( BindToTypeScope.class, "BindToTypeScope.Object", "BindToTypeScope.DerivedObject") { @Override public void check(JClassType type) throws NotFoundException { if ("BindToTypeScope".equals(type.getSimpleSourceName())) { checkBindToTypeScope(type); } else if ("Object".equals(type.getSimpleSourceName())) { checkObject(type); } else { checkDerivedObject(type); } } public void checkBindToTypeScope(JClassType type) throws NotFoundException { assertEquals("BindToTypeScope", type.getSimpleSourceName()); assertEquals(getTypeName(), type.getQualifiedSourceName()); JClassType object = type.getNestedType("Object"); assertNotNull(object); JClassType derivedObject = type.getNestedType("DerivedObject"); assertNotNull(derivedObject); } public void checkObject(JClassType type) { assertEquals("Object", type.getSimpleSourceName()); assertEquals(getTypeName() + ".Object", type.getQualifiedSourceName()); } private void checkDerivedObject(JClassType type) throws NotFoundException { JClassType bindToTypeScope = type.getEnclosingType(); assertNotNull(bindToTypeScope); JClassType object = bindToTypeScope.getNestedType("Object"); assertNotNull(object); assertEquals(object.getSimpleSourceName(), "Object"); JClassType derivedObject = bindToTypeScope.getNestedType("DerivedObject"); assertNotNull(derivedObject); assertEquals(derivedObject.getSimpleSourceName(), "DerivedObject"); assertEquals(object, derivedObject.getSuperclass()); } }; protected static final CheckedJavaResource CU_ConstrainedList = new CheckedJavaResource( ConstrainedList.class) { @Override public void check(JClassType type) throws NotFoundException { assertNotNull(type.isGenericType()); } }; protected static final CheckedJavaResource CU_ConstrainedListAsField = new CheckedJavaResource( ConstrainedListAsField.class) { @Override public void check(JClassType type) throws NotFoundException { assertNull(type.isGenericType()); assertNull(type.getEnclosingType()); } }; protected static final CheckedJavaResource CU_DeclaresInnerGenericInterface = new CheckedJavaResource(DeclaresGenericInnerInterface.class, "DeclaresGenericInnerInterface.Inner") { @Override public void check(JClassType type) throws NotFoundException { assertNotNull(type.isGenericType()); } }; protected static final CheckedJavaResource CU_DeclaresInnerGenericType = new CheckedJavaResource( DeclaresGenericInnerType.class, "DeclaresGenericInnerType.Inner") { @Override public void check(JClassType type) throws NotFoundException { assertNotNull(type.isGenericType()); } }; protected static final CheckedJavaResource CU_DefaultClass = new CheckedJavaResource( DefaultClass.class) { @Override public void check(JClassType type) { assertEquals("DefaultClass", type.getSimpleSourceName()); assertEquals(getTypeName(), type.getQualifiedSourceName()); JClassType object = type.getOracle().findType("java.lang", "Object"); assertNotNull(object); assertEquals(object, type.getSuperclass()); assertNull(type.isInterface()); assertEquals(0, type.getMethods().length); assertEquals(0, type.getFields().length); } }; protected static final CheckedJavaResource CU_Derived = new CheckedJavaResource(Derived.class, "Derived.Nested") { @Override public void check(JClassType type) { if ("Derived".equals(type.getSimpleSourceName())) { checkDerived(type); } else if ("Nested".equals(type.getSimpleSourceName())) { checkNested(type); } else { assert (false); } } private void checkDerived(JClassType type) { assertEquals(getTypeName(), type.getQualifiedSourceName()); } private void checkNested(JClassType type) { assertEquals(getTypeName() + ".Nested", type.getQualifiedSourceName()); } }; protected static final CheckedJavaResource CU_DerivedInterface = new CheckedJavaResource( DerivedInterface.class) { @Override public void check(JClassType type) { assertEquals(getTypeName(), type.getQualifiedSourceName()); assertNotNull(type.isInterface()); } }; protected static final CheckedJavaResource CU_EnclosingLocalClass = new CheckedJavaResource( EnclosingLocal.class) { @Override public void check(JClassType type) { final String name = type.getSimpleSourceName(); assertEquals("EnclosingLocal", name); checkEnclosing(type); } public void checkEnclosing(JClassType type) { assertEquals("EnclosingLocal", type.getSimpleSourceName()); assertEquals(getTypeName(), type.getQualifiedSourceName()); // verify the local class doesn't show up JClassType[] nested = type.getNestedTypes(); assertEquals(0, nested.length); } }; protected static final CheckedJavaResource CU_EnclosingLocalWithMember = new CheckedJavaResource( EnclosingLocalWithMember.class) { @Override public void check(JClassType type) { final String name = type.getSimpleSourceName(); assertEquals("EnclosingLocalWithMember", name); checkEnclosing(type); } public void checkEnclosing(JClassType type) { assertEquals(getTypeName(), type.getQualifiedSourceName()); // verify the local class doesn't show up JClassType[] nested = type.getNestedTypes(); assertEquals(0, nested.length); } }; protected static final CheckedJavaResource CU_ExtendsGenericList = new CheckedJavaResource( ExtendsGenericList.class) { @Override public void check(JClassType type) throws NotFoundException { assertNotNull(type.getSuperclass().isParameterized()); } }; protected static final CheckedJavaResource CU_ExtendsGenericOuterInner = new CheckedJavaResource( ExtendsGenericOuter.class, "ExtendsGenericOuter.ExtendsInner") { @Override public void check(JClassType type) { final String name = type.getSimpleSourceName(); if ("ExtendsGenericOuter".equals(name)) { checkOuter(type); } else { checkInner(type); } } public void checkInner(JClassType type) { assertEquals("ExtendsInner", type.getSimpleSourceName()); assertEquals(getTypeName() + ".ExtendsInner", type.getQualifiedSourceName()); assertEquals(getTypeName(), type.getEnclosingType().getQualifiedSourceName()); } public void checkOuter(JClassType type) { assertEquals("ExtendsGenericOuter", type.getSimpleSourceName()); assertEquals(getTypeName(), type.getQualifiedSourceName()); JClassType[] nested = type.getNestedTypes(); assertEquals(1, nested.length); JClassType inner = nested[0]; assertEquals(getTypeName() + ".ExtendsInner", inner.getQualifiedSourceName()); } }; protected static final CheckedJavaResource CU_ExtendsParameterizedInterface = new CheckedJavaResource(ExtendsParameterizedInterface.class) { @Override public void check(JClassType type) throws NotFoundException { assertNotNull(type.getSuperclass().isParameterized()); } }; protected static final CheckedJavaResource CU_FieldsAndTypes = new CheckedJavaResource( Fields.class) { @Override public void check(JClassType type) throws NotFoundException { if ("Fields".equals(type.getSimpleSourceName())) { assertEquals(getTypeName(), type.getQualifiedSourceName()); TypeOracle tio = type.getOracle(); JField[] fields = type.getFields(); assertEquals(12, fields.length); JField field; JType fieldType; JArrayType arrayType; JType componentType; final JClassType someType = tio.getType(getPackageName(), "DefaultClass"); final JArrayType intArrayType = tio.getArrayType(JPrimitiveType.INT); final JArrayType someTypeArrayType = tio.getArrayType(someType); final JArrayType intArrayArrayType = tio.getArrayType(intArrayType); field = type.getField("privateInt"); assertTrue(field.isPrivate()); assertEquals(JPrimitiveType.INT, field.getType()); field = type.getField("privateSomeType"); assertTrue(field.isPrivate()); assertEquals(someType, field.getType()); field = type.getField("protectedInt"); assertTrue(field.isProtected()); field = type.getField("publicInt"); assertTrue(field.isPublic()); field = type.getField("packageInt"); assertTrue(field.isDefaultAccess()); field = type.getField("staticInt"); assertTrue(field.isStatic()); field = type.getField("transientInt"); assertTrue(field.isTransient()); field = type.getField("volatileInt"); assertTrue(field.isVolatile()); field = type.getField("multiInt"); assertTrue(field.isPublic()); assertTrue(field.isStatic()); assertTrue(field.isFinal()); assertTrue(field.isTransient()); field = type.getField("intArray"); fieldType = field.getType(); arrayType = fieldType.isArray(); assertNotNull(arrayType); assertSame(intArrayType, arrayType); componentType = arrayType.getComponentType(); assertNotNull(componentType); assertSame(JPrimitiveType.INT, componentType); assertEquals("int[]", fieldType.getQualifiedSourceName()); field = type.getField("someTypeArray"); fieldType = field.getType(); arrayType = fieldType.isArray(); assertNotNull(arrayType); assertSame(someTypeArrayType, arrayType); componentType = arrayType.getComponentType(); assertNotNull(componentType); assertSame(someType, componentType); assertEquals(getPackageName() + ".DefaultClass[]", fieldType.getQualifiedSourceName()); field = type.getField("intArrayArray"); fieldType = field.getType(); arrayType = fieldType.isArray(); assertNotNull(arrayType); assertSame(intArrayArrayType, arrayType); componentType = arrayType.getComponentType(); assertNotNull(componentType); assertSame(intArrayType, arrayType.getComponentType()); arrayType = (JArrayType) arrayType.getComponentType(); assertSame(JPrimitiveType.INT, arrayType.getComponentType()); assertEquals("int[][]", fieldType.getQualifiedSourceName()); } else { // No need to check SomeType since there's already a DefaultClass // test. } } }; protected static final CheckedJavaResource CU_GenericList = new CheckedJavaResource( GenericList.class) { @Override public void check(JClassType type) throws NotFoundException { assertNotNull(type.isGenericType()); } }; protected static final CheckedJavaResource CU_GenericOuterInner = new CheckedJavaResource( GenericOuter.class, "GenericOuter.Inner") { @Override public void check(JClassType type) { final String name = type.getSimpleSourceName(); if ("GenericOuter".equals(name)) { checkOuter(type); } else { checkInner(type); } } public void checkInner(JClassType type) { assertEquals("Inner", type.getSimpleSourceName()); assertEquals(getTypeName() + ".Inner", type.getQualifiedSourceName()); assertEquals(getTypeName(), type.getEnclosingType().getQualifiedSourceName()); } public void checkOuter(JClassType type) { assertEquals("GenericOuter", type.getSimpleSourceName()); assertEquals(getTypeName(), type.getQualifiedSourceName()); JClassType[] nested = type.getNestedTypes(); assertEquals(1, nested.length); JClassType inner = nested[0]; assertEquals(getTypeName() + ".Inner", inner.getQualifiedSourceName()); } }; protected static final CheckedJavaResource CU_List = new CheckedJavaResource(List.class) { @Override public void check(JClassType type) throws NotFoundException { assertNotNull(type.isGenericType()); assertNotNull(type.isInterface()); // TODO(zundel): This is a bug when building from source: interfaces // should not be default instantiable // assertNull(type.isDefaultInstantiable()); } @Override public String getSource() { StringBuilder sb = new StringBuilder(); sb.append("package java.util;\n"); sb.append("public interface List<E> {\n"); sb.append("}"); return sb.toString(); } }; protected static final CheckedJavaResource CU_Object = new CheckedJavaResource(Object.class) { @Override public void check(JClassType type) { assertEquals("Object", type.getSimpleSourceName()); assertEquals("java.lang.Object", type.getQualifiedSourceName()); } @Override public String getSource() { StringBuffer sb = new StringBuffer(); sb.append("package java.lang;"); sb.append("public class Object { }"); return sb.toString(); } }; protected static final CheckedJavaResource CU_OuterInner = new CheckedJavaResource(Outer.class, "Outer.Inner") { @Override public void check(JClassType type) { final String name = type.getSimpleSourceName(); if ("Outer".equals(name)) { checkOuter(type); } else { checkInner(type); } } public void checkInner(JClassType type) { assertEquals("Inner", type.getSimpleSourceName()); assertEquals(CU_OuterInner.getTypeName() + ".Inner", type.getQualifiedSourceName()); assertEquals(CU_OuterInner.getTypeName(), type.getEnclosingType().getQualifiedSourceName()); } public void checkOuter(JClassType type) { assertEquals("Outer", type.getSimpleSourceName()); assertEquals(CU_OuterInner.getTypeName(), type.getQualifiedSourceName()); JClassType[] nested = type.getNestedTypes(); assertEquals(1, nested.length); JClassType inner = nested[0]; assertEquals(CU_OuterInner.getTypeName() + ".Inner", inner.getQualifiedSourceName()); } }; protected static final CheckedJavaResource CU_ReferencesGenericListConstant = new CheckedJavaResource(ReferencesGenericListConstant.class) { @Override public void check(JClassType type) throws NotFoundException { assertEquals(getTypeName(), type.getQualifiedSourceName()); } }; protected static final CheckedJavaResource CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed = new CheckedJavaResource(ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed.class) { @Override public void check(JClassType type) throws NotFoundException { JClassType[] intfs = type.getImplementedInterfaces(); assertEquals(1, intfs.length); assertNotNull(intfs[0].isParameterized()); } }; protected static final CheckedJavaResource CU_String = new CheckedJavaResource(String.class) { @Override public void check(JClassType type) { assertEquals("String", type.getSimpleSourceName()); assertEquals("java.lang.String", type.getQualifiedSourceName()); } @Override public String getSource() { StringBuffer sb = new StringBuffer(); sb.append("package java.lang;"); sb.append("public class String { }"); return sb.toString(); } }; protected static final CheckedJavaResource CU_Throwable = new CheckedJavaResource(Throwable.class) { @Override public void check(JClassType type) { assertEquals("Throwable", type.getSimpleSourceName()); assertEquals("java.lang.Throwable", type.getQualifiedSourceName()); } @Override public String getSource() { StringBuffer sb = new StringBuffer(); sb.append("package java.lang;"); sb.append("public class Throwable { }"); return sb.toString(); } }; protected static final CheckedJavaResource CU_UnnestedImplementations = new CheckedJavaResource( Implementations.class, "Implementations.OuterImpl", "Implementations.InnerImpl") { @Override public void check(JClassType type) { if (type.getSimpleSourceName().equals("Implementations")) { assertEquals(getTypeName(), type.getQualifiedSourceName()); } } }; protected static void assertIsAssignable(JClassType from, JClassType to) { assertTrue("'" + from + "' should be assignable to '" + to + "'", from.isAssignableTo(to)); assertTrue("'" + to + "' should be assignable from '" + from + "'", to.isAssignableFrom(from)); } protected static void assertIsNotAssignable(JClassType from, JClassType to) { assertFalse(from + " should not be assignable to " + to, from.isAssignableTo(to)); assertFalse(to + " should not be assignable to " + from, to.isAssignableFrom(from)); } protected static void recordAssignability(Map<JClassType, Set<JClassType>> assignabilityMap, JClassType from, JClassType to) { Set<JClassType> set = assignabilityMap.get(from); if (set == null) { set = new HashSet<JClassType>(); assignabilityMap.put(from, set); } set.add(to); } /** * Public so that this will be initialized before the CUs. */ public final Map<String, CheckedJavaResource> publicTypeNameToTestCupMap = new HashMap<String, CheckedJavaResource>(); protected CheckedJavaResource CU_ListAsField = new CheckedJavaResource(ListAsField.class) { @Override public void check(JClassType type) throws NotFoundException { assertNull(type.isGenericType()); assertNull(type.getEnclosingType()); } }; protected CheckedJavaResource CU_MethodsAndParams = new CheckedJavaResource(Methods.class) { @Override public void check(JClassType type) throws NotFoundException { TypeOracle tio = type.getOracle(); JMethod[] methods = type.getMethods(); assertEquals(6, methods.length); JMethod method; JType[] thrownTypes; final JClassType javaLangObject = tio.findType("java.lang", "Object"); final JClassType javaLangThrowable = tio.findType("java.lang", "Throwable"); final JType[] noParamTypes = new JType[0]; method = type.getMethod("returnsInt", noParamTypes); assertSame(JPrimitiveType.INT, method.getReturnType()); assertEquals(0, method.getParameters().length); method = type.getMethod("returnsSomeType", noParamTypes); assertSame(javaLangObject, method.getReturnType()); assertEquals(0, method.getParameters().length); method = type.getMethod("staticMethod", noParamTypes); assertSame(JPrimitiveType.VOID, method.getReturnType()); assertEquals(0, method.getParameters().length); assertTrue(method.isStatic()); method = type.getMethod("finalMethod", noParamTypes); assertSame(JPrimitiveType.VOID, method.getReturnType()); assertEquals(0, method.getParameters().length); assertTrue(method.isFinal()); try { method = type.getMethod("overloaded", noParamTypes); fail("expected throw"); } catch (NotFoundException e) { } methods = type.getOverloads("overloaded"); assertEquals(2, methods.length); for (JMethod element : methods) { assertEquals("overloaded", element.getName()); } method = type.getMethod("overloaded", new JType[]{JPrimitiveType.INT, javaLangObject}); assertSame(JPrimitiveType.VOID, method.getReturnType()); thrownTypes = method.getThrows(); assertEquals(1, thrownTypes.length); assertSame(javaLangThrowable, thrownTypes[0]); method = type.getMethod("overloaded", new JType[]{JPrimitiveType.INT, JPrimitiveType.CHAR}); assertSame(javaLangObject, method.getReturnType()); thrownTypes = method.getThrows(); assertEquals(0, thrownTypes.length); } }; protected CheckedJavaResource CU_NestedGenericInterfaces = new CheckedJavaResource( OuterInt.class, "OuterInt.InnerInt") { @Override public void check(JClassType type) { final String name = type.getSimpleSourceName(); if ("OuterInt".equals(name)) { checkOuter(type); } else { checkInner(type); } } public void checkInner(JClassType type) { assertEquals("InnerInt", type.getSimpleSourceName()); assertEquals(getTypeName() + ".InnerInt", type.getQualifiedSourceName()); assertEquals(getTypeName(), type.getEnclosingType().getQualifiedSourceName()); } public void checkOuter(JClassType type) { assertEquals("OuterInt", type.getSimpleSourceName()); assertEquals(getTypeName(), type.getQualifiedSourceName()); JClassType[] nested = type.getNestedTypes(); assertEquals(1, nested.length); JClassType inner = nested[0]; assertEquals(getTypeName() + ".InnerInt", inner.getQualifiedSourceName()); } }; protected final Set<Resource> resources = new LinkedHashSet<Resource>(); protected TypeOracle typeOracle; public void checkTypes(JClassType[] types) throws NotFoundException { for (JClassType type : types) { check(type); JClassType[] nestedTypes = type.getNestedTypes(); checkTypes(nestedTypes); } } /** * Tests which variant of AbstractRefrenceMap we want to store the map for * parameterizedTypes, arrayTypes, and wildCardTypes in TypeOracle. Note: this * test is manual because gc can be unreliable. */ @SuppressWarnings("unchecked") public void manualTestAbstractRefrenceMap() { /* * with a HARD -> WEAK map, verify that the entry remains if there is no * reference to key, but is deleted when the reference to value is gone */ Map<Integer, Integer> simpleMap = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK, true); Integer bar = new Integer(42); simpleMap.put(new Integer(32), bar); Runtime.getRuntime().gc(); assertEquals(1, simpleMap.size()); bar = null; Runtime.getRuntime().gc(); assertEquals(0, simpleMap.size()); /* * with a WEAK -> WEAK map, verify that the entry is gone if there are no * references to either the key or the value. */ simpleMap = new ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true); Map<Integer, Integer> reverseMap = new ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true); Integer foo = new Integer(32); bar = new Integer(42); simpleMap.put(foo, bar); reverseMap.put(bar, foo); Runtime.getRuntime().gc(); assertEquals(1, simpleMap.size()); assertEquals(1, reverseMap.size()); bar = null; Runtime.getRuntime().gc(); assertEquals(0, simpleMap.size()); assertEquals(0, reverseMap.size()); } @Override public void setUp() { resources.clear(); } public void testAssignable() throws TypeOracleException, IOException { // Note: The order of adding resources is important for testing from byte // code addTestResource(CU_Object); addTestResource(CU_BaseInterface); addTestResource(CU_DerivedInterface); addTestResource(CU_OuterInner); addTestResource(CU_Derived); buildTypeOracle(); Map<JClassType, Set<JClassType>> assignabilityMap = new HashMap<JClassType, Set<JClassType>>(); JClassType obj = typeOracle.findType(CU_Object.getTypeName()); assertNotNull(obj); JClassType inner = typeOracle.findType(CU_OuterInner.getTypeName() + ".Inner"); assertNotNull(inner); JClassType derived = typeOracle.findType(CU_Derived.getTypeName()); assertNotNull(derived); JClassType nested = typeOracle.findType(CU_Derived.getTypeName() + ".Nested"); assertNotNull(nested); JClassType baseIntf = typeOracle.findType(CU_Derived.getPackageName() + ".BaseInterface"); assertNotNull(baseIntf); JClassType derivedIntf = typeOracle.findType(CU_Derived.getPackageName() + ".DerivedInterface"); assertNotNull(derivedIntf); recordAssignability(assignabilityMap, derivedIntf, baseIntf); recordAssignability(assignabilityMap, derived, inner); recordAssignability(assignabilityMap, nested, inner); recordAssignability(assignabilityMap, nested, derivedIntf); recordAssignability(assignabilityMap, nested, baseIntf); JClassType[] allTypes = typeOracle.getTypes(); assertEquals(7, allTypes.length); for (JClassType fromType : allTypes) { for (JClassType toType : allTypes) { if (fromType == toType || toType == typeOracle.getJavaLangObject()) { assertIsAssignable(fromType, toType); } else { Set<JClassType> set = assignabilityMap.get(fromType); if (set != null && set.contains(toType)) { assertIsAssignable(fromType, toType); } else { assertIsNotAssignable(fromType, toType); } } } } } public void testAssimilation() throws TypeOracleException, IOException { addTestResource(CU_Object); addTestResource(CU_BeforeAssimilate); buildTypeOracle(); assertEquals(2, typeOracle.getTypes().length); // Build onto an existing type oracle. addTestResource(CU_AfterAssimilate); buildTypeOracle(); assertEquals(3, typeOracle.getTypes().length); } public void testBindToTypeScope() throws TypeOracleException, IOException { addTestResource(CU_Object); addTestResource(CU_BindToTypeScope); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(4, types.length); } public void testConstrainedField() throws TypeOracleException, IOException { addTestResource(CU_Object); addTestResource(CU_Throwable); addTestResource(CU_ConstrainedList); addTestResource(CU_ConstrainedListAsField); buildTypeOracle(); // Get the types produced by the TypeOracle JClassType type = typeOracle.getType(CU_ConstrainedListAsField.getTypeName()); assertNull(type.isParameterized()); JField[] fields = type.getFields(); assert (fields.length == 1); JField field = type.getField("field"); assertNotNull(field); JType fieldType = field.getType(); JParameterizedType fieldParamType = fieldType.isParameterized(); assertNotNull(fieldParamType); assertNull(fieldParamType.getEnclosingType()); JGenericType baseType = fieldParamType.getBaseType(); assertNotNull(baseType); assertEquals(CU_ConstrainedList.getTypeName(), baseType.getQualifiedSourceName()); JClassType[] typeArgs = fieldParamType.getTypeArgs(); assertEquals(1, typeArgs.length); JWildcardType wildcard = typeArgs[0].isWildcard(); assertNotNull(wildcard); JClassType upperBound = wildcard.getUpperBound(); assertEquals("Throwable", upperBound.getSimpleSourceName()); } public void testConstrainedList() throws TypeOracleException, IOException, InterruptedException { addTestResource(CU_Object); addTestResource(CU_Throwable); addTestResource(CU_ConstrainedList); buildTypeOracle(); JClassType type = typeOracle.getType(CU_ConstrainedList.getPackageName() + ".ConstrainedList"); JClassType throwable = typeOracle.getType("java.lang.Throwable"); assertNotNull(throwable); assertEquals("Throwable", throwable.getSimpleSourceName()); assertNull(type.isParameterized()); JGenericType genericType = type.isGenericType(); assertNotNull(genericType); JTypeParameter[] typeParams = genericType.getTypeParameters(); assertEquals(1, typeParams.length); assertEquals(throwable, typeParams[0].getBaseType()); assertEquals(type, typeParams[0].getDeclaringClass()); JClassType[] bounds = typeParams[0].getBounds(); assertEquals(1, bounds.length); assertEquals(throwable, bounds[0]); } public void testConstructors() throws TypeOracleException, IOException { addTestResource(CU_Object); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(1, types.length); JClassType objectType = types[0]; assertEquals("Object", objectType.getSimpleSourceName()); JConstructor[] ctors = objectType.getConstructors(); assertEquals(1, ctors.length); JConstructor defaultCtor = ctors[0]; assertEquals("Object", defaultCtor.getName()); assertEquals(0, defaultCtor.getParameters().length); } public void testDefaultClass() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_DefaultClass); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(2, types.length); } public void testEnclosingGenericType() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_String); addTestResource(CU_List); addTestResource(CU_GenericOuterInner); addTestResource(CU_ExtendsGenericOuterInner); buildTypeOracle(); // Get the types produced by the TypeOracle JClassType outer = typeOracle.getType(CU_GenericOuterInner.getPackageName() + ".GenericOuter"); JClassType inner = typeOracle.getType(CU_GenericOuterInner.getPackageName() + ".GenericOuter.Inner"); assertNull(outer.getEnclosingType()); assertEquals(outer, inner.getEnclosingType()); assertNull(inner.isParameterized()); assertNotNull(outer.isGenericType()); assertNotNull(inner.isGenericType()); JField[] fields = inner.getFields(); assertEquals(fields.length, 2); JField field = inner.getField("field"); assertNotNull(field); JType fieldType = field.getType(); JTypeParameter typeParam = fieldType.isTypeParameter(); assertNotNull(typeParam); assertEquals("V", typeParam.getName()); JClassType[] bounds = typeParam.getBounds(); assertEquals(1, bounds.length); assertEquals(typeOracle.getJavaLangObject(), bounds[0]); JClassType extendsOuter = typeOracle.getType(CU_GenericOuterInner.getPackageName() + ".ExtendsGenericOuter"); JClassType extendsInner = typeOracle.getType(CU_GenericOuterInner.getPackageName() + ".ExtendsGenericOuter.ExtendsInner"); assertNull(extendsOuter.getEnclosingType()); assertEquals(extendsOuter, extendsInner.getEnclosingType()); JClassType outerSuper = extendsOuter.getSuperclass(); JParameterizedType outerSuperParam = outerSuper.isParameterized(); assertNotNull(outerSuperParam); assertEquals(outer, outerSuperParam.getBaseType()); JClassType innerSuper = extendsInner.getSuperclass(); assertEquals("GenericOuter.Inner", innerSuper.getName()); field = inner.getField("field"); assertNotNull(field); /* * This test fails for OpenJDK compiled classes compared to JDT classes. The * reason is that the superclass of this type doesn't contain a type * signature for OpenJDK byte code. * * Commenting out this code for the tests: I'm not sure any generators * depend on this subtle difference. */ // assertEquals("java.lang.String", // field.getType().getQualifiedSourceName()); // JParameterizedType innerSuperParam = innerSuper.isParameterized(); // assertNotNull(innerSuperParam); // assertEquals(inner, innerSuperParam.getBaseType()); } public void testEnclosingType() throws TypeOracleException, IOException { addTestResource(CU_Object); addTestResource(CU_List); addTestResource(CU_ListAsField); buildTypeOracle(); JClassType listAsField = typeOracle.getType(CU_ListAsField.getTypeName()); assertNotNull(listAsField); assertNull(listAsField.isParameterized()); JField field = listAsField.getField("field"); assertNotNull(field); JType fieldType = field.getType(); JParameterizedType fieldParamType = fieldType.isParameterized(); assertNotNull(fieldParamType); assertNull(fieldParamType.getEnclosingType()); JGenericType baseType = fieldParamType.getBaseType(); assertNotNull(baseType); assertEquals("java.util.List", baseType.getQualifiedSourceName()); } public void testFieldsAndTypes() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_DefaultClass); addTestResource(CU_FieldsAndTypes); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(3, types.length); } // Check that anonymous classes are not reflected in TypeOracle public void testLocal() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_EnclosingLocalClass); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(2, types.length); } public void testLocalWithSynthetic() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_EnclosingLocalWithMember); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(2, types.length); } public void testMethodsAndParams() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_Throwable); addTestResource(CU_MethodsAndParams); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(3, types.length); } public void testOuterInner() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_OuterInner); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(3, types.length); JClassType outer = null; for (JClassType type : types) { if ("Outer".equals(type.getSimpleSourceName())) { outer = type; break; } } assertNotNull(outer); assertEquals("Outer", outer.getSimpleSourceName()); JClassType superclass = outer.getSuperclass(); JType objectRef = typeOracle.getJavaLangObject(); assertNotNull(objectRef); assertEquals(objectRef, superclass); } /** * Tests that we can build nested parameterized types even if that happens * while the type oracle is being built. This test assumes that * CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed will * cause a parameterized form of CU_DeclaresInnerGenericInterface to be * created before the type oracle has had a chance to resolve * CU_DeclaresInnerGenericInterface. */ public void testParameterizedTypeBuildDependencies() throws TypeOracleException { addTestResource(CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed); // Intentionally omitting the ExtendsParameterizedInterface resource // addResource(CU_ExtendsParameterizedInterface); addTestResource(CU_DeclaresInnerGenericInterface); addTestResource(CU_Object); buildTypeOracle(); assertNull(typeOracle.findType(CU_ExtendsParameterizedInterface.getTypeName())); } /** * Test that modifying a type will cause any types that depend on it to be * rebuilt by the TypeOracleBuilder during a refresh. * * @throws UnableToCompleteException * @throws NotFoundException * @throws IOException */ public void testRefresh() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_ExtendsGenericList); addTestResource(CU_GenericList); addTestResource(CU_ReferencesGenericListConstant); buildTypeOracle(); // Get the types produced by the TypeOracle JClassType extendsGenericListType = typeOracle.getType(CU_ExtendsGenericList.getTypeName()); JClassType genericListType = typeOracle.getType(CU_GenericList.getTypeName()); JClassType referencesGenericListConstantType = typeOracle.getType(CU_ReferencesGenericListConstant.getTypeName()); /* * Invalidate CU_GenericList and simulate a refresh. This should cause * anything that depends on GenericList to be rebuilt by the type oracle. */ CU_GenericList.touch(); buildTypeOracle(); assertNotSame(genericListType.getQualifiedSourceName() + "; ", typeOracle .getType(CU_GenericList.getTypeName()), genericListType); assertNotSame(extendsGenericListType.getQualifiedSourceName() + "; ", typeOracle .getType(CU_ExtendsGenericList.getTypeName()), extendsGenericListType); /* * Make sure that referencing a constant field will cause a type to be * rebuilt if the constant changes. */ assertNotSame(referencesGenericListConstantType.getQualifiedSourceName(), typeOracle .getType(CU_ReferencesGenericListConstant.getTypeName()), referencesGenericListConstantType); } public void testTypeParams() throws TypeOracleException { addTestResource(CU_Object); addTestResource(CU_NestedGenericInterfaces); addTestResource(CU_UnnestedImplementations); buildTypeOracle(); JClassType[] types = typeOracle.getTypes(); assertEquals(6, types.length); JClassType type = typeOracle.findType(CU_UnnestedImplementations.getTypeName() + ".InnerImpl"); assertNotNull(type); JClassType[] interfaces = type.getImplementedInterfaces(); assertEquals(1, interfaces.length); JClassType intf = interfaces[0]; JParameterizedType intfParam = intf.isParameterized(); assertNotNull(intfParam); JClassType intfEnclosing = intf.getEnclosingType(); assertNotNull(intfEnclosing.isRawType()); } /** * Creates a {@link Resource} and adds it the set of resources. * * @throws UnableToCompleteException */ protected void addResource(String qualifiedTypeName, CharSequence source) { resources.add(new StaticJavaResource(qualifiedTypeName, source)); } protected abstract void buildTypeOracle() throws TypeOracleException; /** * Tweak this if you want to see the log output. */ protected TreeLogger createTreeLogger() { boolean reallyLog = false; if (reallyLog) { AbstractTreeLogger logger = new PrintWriterTreeLogger(); logger.setMaxDetail(TreeLogger.ALL); return logger; } else { return TreeLogger.NULL; } } private void addTestResource(CheckedJavaResource checkedResource) { resources.add(checkedResource); for (String typeName : checkedResource.getTypeNames()) { register(typeName, checkedResource); } } private void check(JClassType classInfo) throws NotFoundException { final String qName = classInfo.getQualifiedSourceName(); CheckedJavaResource cup = publicTypeNameToTestCupMap.get(qName); if (cup != null) { cup.check(classInfo); } } private void register(String qualifiedTypeName, CheckedJavaResource cup) { assertFalse(publicTypeNameToTestCupMap.containsKey(qualifiedTypeName)); publicTypeNameToTestCupMap.put(qualifiedTypeName, cup); } }