package japicmp.cmp; import japicmp.compat.CompatibilityChanges; import japicmp.model.*; import japicmp.util.CtClassBuilder; import japicmp.util.CtInterfaceBuilder; import japicmp.util.CtMethodBuilder; import javassist.ClassPool; import javassist.CtClass; import org.junit.Test; import java.util.Arrays; import java.util.List; import static japicmp.util.Helper.getJApiClass; import static japicmp.util.Helper.getJApiImplementedInterface; import static japicmp.util.Helper.getJApiMethod; import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertThat; public class InterfacesTest { @Test public void testMethodAddedToInterfaceDefinedInSuperInterface() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("SuperInterface").addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(superInterface); CtClass subInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(superInterface).addToClassPool(classPool); return Arrays.asList(superInterface, subInterface); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("SuperInterface").addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(superInterface); CtClass subInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(superInterface).addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(subInterface); return Arrays.asList(superInterface, subInterface); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "SubInterface"); JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method"); assertThat(jApiMethod.getChangeStatus(), is(JApiChangeStatus.NEW)); assertThat(jApiMethod.isBinaryCompatible(), is(true)); assertThat(jApiMethod.isSourceCompatible(), is(true)); } @Test public void testMethodAddedToInterfaceAndInSuperInterface() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("SuperInterface").addToClassPool(classPool); CtClass subInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(superInterface).addToClassPool(classPool); return Arrays.asList(superInterface, subInterface); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("SuperInterface").addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(superInterface); CtClass subInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(superInterface).addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(subInterface); return Arrays.asList(superInterface, subInterface); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "SubInterface"); JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method"); assertThat(jApiMethod.getChangeStatus(), is(JApiChangeStatus.NEW)); assertThat(jApiMethod.isBinaryCompatible(), is(true)); assertThat(jApiMethod.isSourceCompatible(), is(false)); } @Test public void testInterfaceMarkerAdded() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").addToClassPool(classPool); return Arrays.asList(superInterface, ctClass); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(superInterface).addToClassPool(classPool); return Arrays.asList(superInterface, ctClass); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "Test"); assertThat(jApiClass.isBinaryCompatible(), is(true)); assertThat(jApiClass.isSourceCompatible(), is(true)); } @Test public void testInterfaceAdded() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtMethodBuilder.create().publicAccess().abstractMethod().name("method").addToClass(superInterface); CtClass ctClass = CtClassBuilder.create().name("Test").addToClassPool(classPool); return Arrays.asList(superInterface, ctClass); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtMethodBuilder.create().publicAccess().abstractMethod().name("method").addToClass(superInterface); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(superInterface).addToClassPool(classPool); return Arrays.asList(superInterface, ctClass); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "Test"); assertThat(jApiClass.isBinaryCompatible(), is(true)); assertThat(jApiClass.isSourceCompatible(), is(true)); assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.INTERFACE_ADDED)); } @Test public void testMethodPulledUp() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("SuperInterface").addToClassPool(classPool); CtClass subInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(superInterface).addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(subInterface); return Arrays.asList(superInterface, subInterface); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass superInterface = CtInterfaceBuilder.create().name("SuperInterface").addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(superInterface); CtClass subInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(superInterface).addToClassPool(classPool); return Arrays.asList(superInterface, subInterface); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "SuperInterface"); assertThat(jApiClass.isBinaryCompatible(), is(true)); assertThat(jApiClass.isSourceCompatible(), is(false)); jApiClass = getJApiClass(jApiClasses, "SubInterface"); assertThat(jApiClass.isBinaryCompatible(), is(true)); assertThat(jApiClass.isSourceCompatible(), is(true)); } @Test public void testClassImplementsInterface() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(ctClassInterface); CtClass ctClass = CtClassBuilder.create().name("Test").addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClass); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(ctClassInterface); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassInterface).addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().name("method").addToClass(ctClass); return Arrays.asList(ctClassInterface, ctClass); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "Test"); assertThat(jApiClass.isBinaryCompatible(), is(true)); assertThat(jApiClass.isSourceCompatible(), is(true)); } @Test public void testClassNoLongerImplementsInterface() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(ctClassInterface); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassInterface).addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().name("method").addToClass(ctClass); return Arrays.asList(ctClassInterface, ctClass); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtMethodBuilder.create().returnType(CtClass.voidType).publicAccess().abstractMethod().name("method").addToClass(ctClassInterface); CtClass ctClass = CtClassBuilder.create().name("Test").addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClass); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "Test"); assertThat(jApiClass.isBinaryCompatible(), is(false)); assertThat(jApiClass.isSourceCompatible(), is(false)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getChangeStatus(), is(JApiChangeStatus.REMOVED)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getCompatibilityChanges(), hasItem(JApiCompatibilityChange.INTERFACE_REMOVED)); } @Test public void testInterfaceHierarchyHasOneMoreLevel() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassInterface).addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClass); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClassSubInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(ctClassInterface).addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassSubInterface).addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClassSubInterface, ctClass); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "Test"); assertThat(jApiClass.isBinaryCompatible(), is(true)); assertThat(jApiClass.isSourceCompatible(), is(true)); assertThat(jApiClass.getInterfaces().size(), is(2)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getChangeStatus(), is(JApiChangeStatus.UNCHANGED)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "SubInterface").getChangeStatus(), is(JApiChangeStatus.NEW)); } @Test public void testInterfaceHierarchyHasOneLessLevel() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClassSubInterface = CtInterfaceBuilder.create().name("SubInterface").withSuperInterface(ctClassInterface).addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassSubInterface).addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClassSubInterface, ctClass); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassInterface).addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClass); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "Test"); assertThat(jApiClass.isBinaryCompatible(), is(false)); assertThat(jApiClass.isSourceCompatible(), is(false)); assertThat(jApiClass.getInterfaces().size(), is(2)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getChangeStatus(), is(JApiChangeStatus.UNCHANGED)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "SubInterface").getChangeStatus(), is(JApiChangeStatus.REMOVED)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "SubInterface").getCompatibilityChanges(), hasItem(JApiCompatibilityChange.INTERFACE_REMOVED)); } @Test public void testInterfaceMovedToSuperclass() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClassSuperClass = CtClassBuilder.create().name("SuperClass").addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassInterface).withSuperclass(ctClassSuperClass).addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClassSuperClass, ctClass); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClassSuperClass = CtClassBuilder.create().name("SuperClass").implementsInterface(ctClassInterface).addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").withSuperclass(ctClassSuperClass).addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClassSuperClass, ctClass); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "Test"); assertThat(jApiClass.isBinaryCompatible(), is(true)); assertThat(jApiClass.isSourceCompatible(), is(true)); assertThat(jApiClass.getInterfaces().size(), is(1)); JApiSuperclass jApiSuperclass = jApiClass.getSuperclass(); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getChangeStatus(), is(JApiChangeStatus.UNCHANGED)); assertThat(jApiSuperclass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED)); } @Test public void testInterfaceMovedToSubclass() throws Exception { JarArchiveComparatorOptions jarArchiveComparatorOptions = new JarArchiveComparatorOptions(); jarArchiveComparatorOptions.setAccessModifier(AccessModifier.PRIVATE); List<JApiClass> jApiClasses = ClassesHelper.compareClasses(jarArchiveComparatorOptions, new ClassesHelper.ClassesGenerator() { @Override public List<CtClass> createOldClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClassSuperClass = CtClassBuilder.create().name("SuperClass").implementsInterface(ctClassInterface).addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").withSuperclass(ctClassSuperClass).addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClassSuperClass, ctClass); } @Override public List<CtClass> createNewClasses(ClassPool classPool) throws Exception { CtClass ctClassInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool); CtClass ctClassSuperClass = CtClassBuilder.create().name("SuperClass").addToClassPool(classPool); CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctClassInterface).withSuperclass(ctClassSuperClass).addToClassPool(classPool); return Arrays.asList(ctClassInterface, ctClassSuperClass, ctClass); } }); JApiClass jApiClass = getJApiClass(jApiClasses, "Test"); assertThat(jApiClass.isBinaryCompatible(), is(true)); assertThat(jApiClass.isSourceCompatible(), is(true)); assertThat(jApiClass.getInterfaces().size(), is(1)); JApiSuperclass jApiSuperclass = jApiClass.getSuperclass(); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getChangeStatus(), is(JApiChangeStatus.NEW)); // not has INTERFACE_ADDED because it is only moved not added/removed assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getCompatibilityChanges(), not(hasItem(JApiCompatibilityChange.INTERFACE_ADDED))); assertThat(jApiSuperclass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED)); jApiClass = getJApiClass(jApiClasses, "SuperClass"); assertThat(jApiClass.isBinaryCompatible(), is(false)); assertThat(jApiClass.isSourceCompatible(), is(false)); assertThat(jApiClass.getInterfaces().size(), is(1)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getChangeStatus(), is(JApiChangeStatus.REMOVED)); assertThat(getJApiImplementedInterface(jApiClass.getInterfaces(), "Interface").getCompatibilityChanges(), hasItem(JApiCompatibilityChange.INTERFACE_REMOVED)); } }