package nginx.clojure.wave; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.Serializable; import nginx.clojure.asm.Type; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * The some testing code is copied from * https://github.com/Grundlefleck/ASM-NonClassloadingSimpleVerifier/blob/master/src/test/java/org/objectweb/asm/tree/analysis/TypeHierarchyUnitTest.java * But the testing target is quite different about their implementation. */ public class TypeInterpreterTest { MethodDatabase db; TypeInterpreter ti; public Type JAVA_LANG_OBJECT = Type.getType(Object.class); @Before public void setUp() throws Exception { db = new MethodDatabase(Thread.currentThread().getContextClassLoader()); ti = new TypeInterpreter(db); } @After public void tearDown() throws Exception { } public Type getType(Class c) { return Type.getType(c); } @Test public void testSuperClassOfConcreteClassExtendingObjectImplicitlyIsTypeRepresentingJavaLangObject() { assertEquals(JAVA_LANG_OBJECT, ti.fetchSuperClass(getType(UnrelatedType.class))); } @Test public void testSuperClassOfSubclass() { assertEquals(getType(Superclass.class), ti.fetchSuperClass(getType(Subclass.class))); } @Test public void testSuperClassOfInterfaceWithNoSuperInterfaceIsObject() { assertEquals(JAVA_LANG_OBJECT, ti.fetchSuperClass(getType(Interface.class))); } @Test public void testSuperClassOfSubInterfaceIsJavaLangObject() { assertEquals(JAVA_LANG_OBJECT, ti.fetchSuperClass(getType(SubInterface.class))); } @Test public void testSuperclassOfArrayClassHasSameSemanticsAsJavaLangClass_fetchSuperClass() throws Exception { assertEquals(getType(Object[].class.getSuperclass()), ti.fetchSuperClass(getType(Object[].class))); assertEquals(getType(Interface[].class.getSuperclass()), ti.fetchSuperClass(getType(Interface[].class))); assertEquals(getType(Superclass[].class.getSuperclass()), ti.fetchSuperClass(getType(Superclass[].class))); } @Test public void testClassIsAssignableFromItself() { assertIsAssignableFrom(AssignableFromItself.class, AssignableFromItself.class); } @Test public void testClassIsNotAssignableToUnrelatedType() { assertIsNotAssignableFrom(AssignableFromItself.class, UnrelatedType.class); assertIsNotAssignableFrom(UnrelatedType.class, AssignableFromItself.class); } @Test public void testSuperclassIsAssignableFromSubclass() throws Exception { assertIsAssignableFrom(Superclass.class, Subclass.class); } @Test public void testIndirectSubclassIsAssignableToSuperclass() throws Exception { assertIsAssignableFrom(Superclass.class, SubSubclass.class); } @Test public void testSubclassIsNotAssignableToOtherClassWithSameSuperclass() throws Exception { assertIsNotAssignableFrom(Subclass.class, OtherSubclass.class); } @Test public void testSubclassIsNotAssignableFromSuperclass() throws Exception { assertIsNotAssignableFrom(Subclass.class, Superclass.class); } @Test public void testInterfaceIsAssignableFromImplementingClass() throws Exception { assertIsAssignableFrom(Interface.class, ImplementsInterface.class); } @Test public void testInterfaceIsAssignableFromSubclassOfImplementingClass() throws Exception { assertIsAssignableFrom(Interface.class, ExtendsImplementsInterface.class); assertIsNotAssignableFrom(ExtendsImplementsInterface.class, Interface.class); } @Test public void testSuperInterfaceIsAssignableFromSubInterface() throws Exception { assertIsAssignableFrom(SuperInterface.class, SubInterface.class); assertIsNotAssignableFrom(SubInterface.class, SuperInterface.class); } @Test public void testImplementingClassIsNotAssignableFromInterface() throws Exception { assertIsNotAssignableFrom(ImplementsInterface.class, Interface.class); } @Test public void testObjectIsAssignableFromAnything() throws Exception { assertIsAssignableFrom(Object.class, Superclass.class); assertIsAssignableFrom(Object.class, Subclass.class); assertIsAssignableFrom(Object.class, Interface.class); assertIsAssignableFrom(Object.class, SubInterface.class); } @Test public void testAllImplementedInterfacesAreAssignableFromImplementingClass() throws Exception { assertIsAssignableFrom(Interface.class, ImplementsSeveralInterfaces.class); assertIsAssignableFrom(SubInterface.class, ImplementsSeveralInterfaces.class); assertIsAssignableFrom(SuperInterface.class, ImplementsSeveralInterfaces.class); assertIsNotAssignableFrom(OtherImplementsInterface.class, ImplementsSeveralInterfaces.class); } @Test public void testInterfaceIsAssignableFromClassWithSuperclassOutwithInterfaceHierarchy() throws Exception { assertIsAssignableFrom(SuperInterface.class, ExtendsClassOutwithInterfaceHierarchy.class); } @Test public void testArrayTypeAssignment() throws Exception { assertIsAssignableFrom(Object.class, Interface[].class); assertIsAssignableFrom(Cloneable.class, Interface[].class); assertIsAssignableFrom(Serializable.class, Interface[].class); assertIsAssignableFrom(Object[].class, Interface[].class); assertIsAssignableFrom(Object[].class, Interface[].class); assertIsAssignableFrom(Interface[].class, Interface[].class); assertIsAssignableFrom(Interface[].class, ImplementsInterface[].class); assertIsNotAssignableFrom(ImplementsInterface[].class, Interface[].class); assertIsAssignableFrom(Interface[].class, ExtendsImplementsInterface[].class); assertIsAssignableFrom(Object[].class, Superclass[].class); assertIsAssignableFrom(Object[].class, Subclass[].class); assertIsAssignableFrom(Superclass[].class, Subclass[].class); assertIsNotAssignableFrom(Subclass[].class, Superclass[].class); } @Test public void testArrayDimensionAssignment() throws Exception { assertIsAssignableFrom(Object.class, Object[].class); assertIsNotAssignableFrom(Object[].class, Object.class); assertIsAssignableFrom(Object.class, Interface[].class); assertIsAssignableFrom(Object[].class, Interface[][].class); assertIsAssignableFrom(Object[][].class, Interface[][].class); assertIsNotAssignableFrom(Interface.class, Interface[].class); assertIsNotAssignableFrom(Interface[].class, Interface.class); assertIsNotAssignableFrom(Interface[].class, Interface[][].class); assertIsNotAssignableFrom(Interface[][].class, Interface[].class); } @Test public void testAnonymousInnerClasses() throws Exception { assertIsAssignableFrom(Interface.class, new Interface() { }.getClass()); assertIsNotAssignableFrom(new Interface() { }.getClass(), Interface.class); } @Test public void testAssignmentOfPrimitiveArrayTypes() throws Exception { assertIsAssignableFrom(boolean[].class, boolean[].class); assertIsAssignableFrom(byte[].class, byte[].class); assertIsAssignableFrom(char[].class, char[].class); assertIsAssignableFrom(short[].class, short[].class); assertIsAssignableFrom(int[].class, int[].class); assertIsAssignableFrom(long[].class, long[].class); assertIsAssignableFrom(float[].class, float[].class); assertIsAssignableFrom(double[].class, double[].class); assertIsNotAssignableFrom(Object[].class, float[].class); } @Test public void testGetCommonSuperClass_shouldBeObjectForUnrelatedClasses() throws Exception { assertCommonSuperclass(Object.class, Superclass.class, UnrelatedType.class); } @Test public void testGetCommonSuperClass_shouldBeClosestSharedSuperclass() throws Exception { assertCommonSuperclass(Superclass.class, Subclass.class, OtherSubclass.class); } @Test public void testGetCommonSuperClass_shouldBeSameTypeWhenBothAreEqual() throws Exception { assertCommonSuperclass(UnrelatedType.class, UnrelatedType.class, UnrelatedType.class); } @Test public void testGetCommonSuperClass_shouldBeSuperclassOfTwoGivenTypes() throws Exception { assertCommonSuperclass(Superclass.class, Superclass.class, Subclass.class); } @Test public void testGetCommonSuperClass_shouldBeObjectForUnrelatedInterfaces() throws Exception { assertCommonSuperclass(Object.class, Interface.class, OtherInterface.class); } // @Test // public void fails_returnsObject_testGetCommonSuperClass_shouldBeClosestSharedInterface() throws Exception { // assertCommonSuperclass(SubInterface.class, ImplementsSeveralInterfaces.class, AlsoImplementsSubInterface.class); // } @Test public void testGetCommonSuperClass_shouldBeObjectForTwoInterfacesWhoShareCommonSuperInterface() throws Exception { assertCommonSuperclass(Object.class, SubInterface.class, OtherSubInterface.class); } private void assertIsAssignableFrom(Class<?> to, Class<?> from) { assertTrue("Assertion is not consistent with Class.isAssignableFrom", to.isAssignableFrom(from)); Type toType = Type.getType(to); Type fromType = Type.getType(from); assertTrue("Type Hierarchy visitor is not consistent with Class.isAssignableFrom", ti.checkAssignableFrom(toType, fromType)); } private void assertIsNotAssignableFrom(Class<?> to, Class<?> from) { assertFalse("Assertion is not consistent with Class.isAssignableFrom", to.isAssignableFrom(from)); Type toType = Type.getType(to); Type fromType = Type.getType(from); assertFalse("Type Hierarchy visitor is not consistent with Class.isAssignableFrom", ti.checkAssignableFrom(toType, fromType)); } private void assertCommonSuperclass(Class<?> expected, Class<?> first, Class<?> second) { assertEquals(slashedName(expected), db.getCommonSuperClass(slashedName(first), slashedName(second))); assertEquals(slashedName(expected), db.getCommonSuperClass(slashedName(second), slashedName(first))); } private String slashedName(Class<?> cls) { return cls.getName().replace(".", "/"); } public static class AssignableFromItself { } public static class UnrelatedType { } public static class Superclass { } public static class Subclass extends Superclass { } public static class OtherSubclass extends Superclass { } public static class SubSubclass extends Subclass { } public static interface Interface { } public static interface OtherInterface { } public static class ImplementsInterface implements Interface { } public static class ExtendsImplementsInterface extends ImplementsInterface { } public static interface SuperInterface { } public static interface SubInterface extends SuperInterface { } public static interface OtherSubInterface { } public static class ImplementsSeveralInterfaces implements Interface, SubInterface { } public static class OtherImplementsInterface implements Interface { } public static class AlsoImplementsSubInterface implements SubInterface { } public static class ExtendsClassOutwithInterfaceHierarchy extends UnrelatedType implements SubInterface { } }