package japicmp.compat;
import japicmp.cmp.ClassesHelper;
import japicmp.cmp.JarArchiveComparatorOptions;
import japicmp.model.*;
import japicmp.util.*;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import org.hamcrest.core.Is;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static japicmp.util.Helper.*;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class CompatibilityChangesTest {
@Test
public void testClassRemoved() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
return Collections.emptyList();
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.REMOVED));
assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CLASS_REMOVED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testClassNowAbstract() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().abstractModifier().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CLASS_NOW_ABSTRACT));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testClassNowFinal() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().finalModifier().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CLASS_NOW_FINAL));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testClassNoLongerPublic() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().privateModifier().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CLASS_NO_LONGER_PUBLIC));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testClassTypeChanged() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtInterfaceBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CLASS_TYPE_CHANGED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testSuperclassRemoved() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(ctClass, superclass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtInterfaceBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.getSuperclass().getCompatibilityChanges(), hasItem(JApiCompatibilityChange.SUPERCLASS_REMOVED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testSuperclassChanged() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(ctClass, superclass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass2").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(ctClass, superclass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.getSuperclass().getCompatibilityChanges(), hasItem(JApiCompatibilityChange.SUPERCLASS_REMOVED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testSuperclassAdded() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(ctClass, superclass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.getSuperclass().getCompatibilityChanges(), hasItem(JApiCompatibilityChange.SUPERCLASS_ADDED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
JApiSuperclass superclass = jApiClass.getSuperclass();
assertThat(superclass.isBinaryCompatible(), is(true));
assertThat(superclass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.SUPERCLASS_ADDED));
}
@Test
public void testSuperclassUnchangedObject() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED));
assertThat(jApiClass.getCompatibilityChanges().size(), is(0));
assertThat(jApiClass.isBinaryCompatible(), is(true));
JApiSuperclass superclass = jApiClass.getSuperclass();
assertThat(superclass.isBinaryCompatible(), is(true));
assertThat(superclass.getCompatibilityChanges().size(), is(0));
}
@Test
public void testMethodRemovedInSuperclass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(superclass).name("getInstance").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(ctClass, superclass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(ctClass, superclass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED));
assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_REMOVED_IN_SUPERCLASS));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testMethodRemovedInSuperclassButOverriddenInSubclass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(superclass).name("getInstance").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(superclass).name("getInstance").addToClass(ctClass);
return Arrays.asList(ctClass, superclass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(superclass).name("getInstance").addToClass(ctClass);
return Arrays.asList(ctClass, superclass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
}
@Test
public void testFieldRemovedInSuperclass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(ctClass, superclass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(ctClass, superclass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED));
assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_REMOVED_IN_SUPERCLASS));
assertThat(jApiClass.isBinaryCompatible(), is(false));
}
@Test
public void testFieldRemovedInSuperclassButOverriddenInSubclass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(ctClass);
return Arrays.asList(ctClass, superclass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(ctClass);
return Arrays.asList(ctClass, superclass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
}
@Test
public void testMethodRemoved() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("isRemoved").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "isRemoved");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_REMOVED));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
JApiSuperclass superclass = jApiClass.getSuperclass();
assertThat(superclass.isBinaryCompatible(), is(true));
assertThat(superclass.getCompatibilityChanges().size(), is(0));
}
@Test
public void testMethodLessAccessiblePublicToPrivate() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("isRemoved").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().privateAccess().returnType(CtClass.booleanType).name("isRemoved").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "isRemoved");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_LESS_ACCESSIBLE));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
}
@Test
public void testMethodLessAccessibleThanInSuperclass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("isRemoved").body("return true;").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(superclass, ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("isRemoved").body("return true;").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
CtMethodBuilder.create().protectedAccess().returnType(CtClass.booleanType).name("isRemoved").body("return true;").addToClass(ctClass);
return Arrays.asList(superclass, ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "isRemoved");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_LESS_ACCESSIBLE_THAN_IN_SUPERCLASS));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
}
@Test
public void testMethodStaticOverridesNonStatic() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("isOverridden").body("return true;").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Arrays.asList(superclass, ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("isOverridden").body("return true;").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().staticAccess().returnType(CtClass.booleanType).name("isOverridden").body("return true;").addToClass(ctClass);
return Arrays.asList(superclass, ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "isOverridden");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_IS_STATIC_AND_OVERRIDES_NOT_STATIC));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
}
@Test
public void testMethodReturnTypeChanges() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.intType).name("returnTypeChanges").body("return 42;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("returnTypeChanges").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "returnTypeChanges");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_RETURN_TYPE_CHANGED));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
}
@Test
public void testMethodNowAbstract() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("methodBecomesAbstract").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().abstractMethod().returnType(CtClass.booleanType).name("methodBecomesAbstract").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "methodBecomesAbstract");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_NOW_ABSTRACT));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
}
@Test
public void testMethodNowFinal() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("methodBecomesFinal").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().finalMethod().returnType(CtClass.booleanType).name("methodBecomesFinal").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "methodBecomesFinal");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_NOW_FINAL));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
}
@Test
public void testMethodNowStatic() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("methodBecomesStatic").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().staticAccess().returnType(CtClass.booleanType).name("methodBecomesStatic").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "methodBecomesStatic");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_NOW_STATIC));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
}
@Test
public void testMethodNoLongerStatic() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().staticAccess().returnType(CtClass.booleanType).name("methodNoLongerStatic").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().returnType(CtClass.booleanType).name("methodNoLongerStatic").body("return true;").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "methodNoLongerStatic");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_NO_LONGER_STATIC));
assertThat(jApiMethod.isBinaryCompatible(), is(false));
}
@Test
public void testFieldStaticOverridesStatic() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtFieldBuilder.create().staticAccess().type(CtClass.intType).name("field").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtFieldBuilder.create().staticAccess().type(CtClass.intType).name("field").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
CtFieldBuilder.create().staticAccess().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
assertThat(jApiField.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_STATIC_AND_OVERRIDES_STATIC));
assertThat(jApiField.isBinaryCompatible(), is(false));
}
@Test
public void testFieldLessAccessibleThanInSuperclass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superclass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(superclass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superclass).addToClassPool(classPool);
CtFieldBuilder.create().packageProtectedAccess().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
assertThat(jApiField.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_LESS_ACCESSIBLE_THAN_IN_SUPERCLASS));
assertThat(jApiField.isBinaryCompatible(), is(false));
}
@Test
public void testFieldNowFinal() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().finalAccess().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
assertThat(jApiField.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_NOW_FINAL));
assertThat(jApiField.isBinaryCompatible(), is(false));
}
@Test
public void testFieldNowStatic() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().staticAccess().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
assertThat(jApiField.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_NOW_STATIC));
assertThat(jApiField.isBinaryCompatible(), is(false));
}
@Test
public void testFieldNoLongerStatic() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().staticAccess().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
assertThat(jApiField.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_NO_LONGER_STATIC));
assertThat(jApiField.isBinaryCompatible(), is(false));
}
@Test
public void testFieldTypeChanged() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.floatType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
assertThat(jApiField.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_TYPE_CHANGED));
assertThat(jApiField.isBinaryCompatible(), is(false));
}
@Test
public void testFieldRemoved() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
assertThat(jApiField.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_REMOVED));
assertThat(jApiField.isBinaryCompatible(), is(false));
}
@Test
public void testFieldLessAccessible() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtFieldBuilder.create().packageProtectedAccess().type(CtClass.intType).name("field").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
assertThat(jApiField.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.FIELD_LESS_ACCESSIBLE));
assertThat(jApiField.isBinaryCompatible(), is(false));
}
@Test
public void testConstructorRemoved() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtConstructorBuilder.create().publicAccess().parameter(CtClass.intType).addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiConstructor jApiConstructor = getJApiConstructor(jApiClass.getConstructors(), Collections.singletonList("int"));
assertThat(jApiConstructor.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CONSTRUCTOR_REMOVED));
assertThat(jApiConstructor.isBinaryCompatible(), is(false));
}
@Test
public void testConstructorLessAccessible() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtConstructorBuilder.create().publicAccess().parameter(CtClass.intType).addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtConstructorBuilder.create().protectedAccess().parameter(CtClass.intType).addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(false));
JApiConstructor jApiConstructor = getJApiConstructor(jApiClass.getConstructors(), Collections.singletonList("int"));
assertThat(jApiConstructor.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CONSTRUCTOR_LESS_ACCESSIBLE));
assertThat(jApiConstructor.isBinaryCompatible(), is(false));
}
@Test
public void testMethodAddedToInterface() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtInterfaceBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtInterfaceBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().abstractMethod().name("method").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(false));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_ADDED_TO_INTERFACE));
assertThat(jApiMethod.isBinaryCompatible(), is(true));
assertThat(jApiMethod.isSourceCompatible(), is(false));
}
@Test
public void testAbstractClassNowExtendsAnotherAbstractClass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superClass = CtClassBuilder.create().abstractModifier().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().abstractModifier().name("japicmp.Test").addToClassPool(classPool);
return Arrays.asList(ctClass, superClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superClass = CtClassBuilder.create().abstractModifier().name("japicmp.Superclass").addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).abstractMethod().name("newAbstractMethod").addToClass(superClass);
CtClass ctClass = CtClassBuilder.create().abstractModifier().name("japicmp.Test").withSuperclass(superClass).addToClassPool(classPool);
return Arrays.asList(ctClass, superClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(false));
jApiClass = getJApiClass(jApiClasses, "japicmp.Superclass");
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "newAbstractMethod");
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_ABSTRACT_ADDED_TO_CLASS));
assertThat(jApiMethod.isBinaryCompatible(), is(true));
assertThat(jApiMethod.isSourceCompatible(), is(false));
}
@Test
public void testMethodAddedToNewInterface() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
return Collections.emptyList();
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtInterfaceBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().abstractMethod().name("method").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.NEW));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method");
assertThat(jApiMethod.getCompatibilityChanges().size(), is(0));
assertThat(jApiMethod.isBinaryCompatible(), is(true));
assertThat(jApiMethod.isSourceCompatible(), is(true));
}
@Test
public void testInterfaceMovedToAbstractClass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool);
CtMethodBuilder.create().abstractMethod().returnType(CtClass.voidType).name("method").addToClass(ctInterface);
CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctInterface).addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.voidType).name("method").body("int a = 42;").addToClass(ctClass);
return Arrays.asList(ctInterface, ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool);
CtMethodBuilder.create().abstractMethod().returnType(CtClass.voidType).name("method").addToClass(ctInterface);
CtClass ctAbstractClass = CtClassBuilder.create().name("AbstractTest").implementsInterface(ctInterface).addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("Test").withSuperclass(ctAbstractClass).addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.voidType).name("method").body("int a = 42;").addToClass(ctClass);
return Arrays.asList(ctInterface, ctClass, ctAbstractClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
assertThat(jApiClass.getInterfaces().size(), is(1));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method");
assertThat(jApiMethod.getCompatibilityChanges().size(), is(0));
assertThat(jApiMethod.isBinaryCompatible(), is(true));
assertThat(jApiMethod.isSourceCompatible(), is(true));
}
@Test
public void testAbstractMethodMovedToInterface() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctInterface).addToClassPool(classPool);
CtMethodBuilder.create().abstractMethod().returnType(CtClass.voidType).name("method").addToClass(ctClass);
return Arrays.asList(ctInterface, ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctInterface = CtInterfaceBuilder.create().name("Interface").addToClassPool(classPool);
CtMethodBuilder.create().abstractMethod().returnType(CtClass.voidType).name("method").addToClass(ctInterface);
CtClass ctClass = CtClassBuilder.create().name("Test").implementsInterface(ctInterface).addToClassPool(classPool);
return Arrays.asList(ctInterface, ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
assertThat(jApiClass.getInterfaces().size(), is(1));
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method");
assertThat(jApiMethod.getChangeStatus(), is(JApiChangeStatus.REMOVED));
assertThat(jApiMethod.isBinaryCompatible(), is(true));
assertThat(jApiMethod.isSourceCompatible(), is(true));
}
@Test
public void testMethodMovedFromOneInterfaceToAnother() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctInterface1 = CtInterfaceBuilder.create().name("Interface1").addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).abstractMethod().name("method").addToClass(ctInterface1);
CtClass ctInterface2 = CtInterfaceBuilder.create().name("Interface2").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().abstractModifier().name("japicmp.Test").implementsInterface(ctInterface1).implementsInterface(ctInterface2).addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).name("method").body("return 42;").addToClass(ctClass);
return Arrays.asList(ctClass, ctInterface1, ctInterface2);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctInterface1 = CtInterfaceBuilder.create().name("Interface1").addToClassPool(classPool);
CtClass ctInterface2 = CtInterfaceBuilder.create().name("Interface2").addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).abstractMethod().name("method").addToClass(ctInterface2);
CtClass ctClass = CtClassBuilder.create().abstractModifier().name("japicmp.Test").implementsInterface(ctInterface1).implementsInterface(ctInterface2).addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).name("method").body("return 42;").addToClass(ctClass);
return Arrays.asList(ctClass, ctInterface1, ctInterface2);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
}
@Test
public void testMethodMovedFromOneAbstractClassToAnother() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setIncludeSynthetic(true);
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass abstractClass1 = CtClassBuilder.create().abstractModifier().name("AbstractClass1").addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).abstractMethod().name("method").addToClass(abstractClass1);
CtClass abstractClass2 = CtClassBuilder.create().abstractModifier().name("AbstractClass2").withSuperclass(abstractClass1).addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().abstractModifier().name("japicmp.Test").withSuperclass(abstractClass2).addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).name("method").body("return 42;").addToClass(ctClass);
return Arrays.asList(ctClass, abstractClass1, abstractClass2);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass abstractClass1 = CtClassBuilder.create().abstractModifier().name("AbstractClass1").addToClassPool(classPool);
CtClass abstractClass2 = CtClassBuilder.create().abstractModifier().name("AbstractClass2").withSuperclass(abstractClass1).addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).abstractMethod().name("method").addToClass(abstractClass2);
CtClass ctClass = CtClassBuilder.create().abstractModifier().name("japicmp.Test").withSuperclass(abstractClass2).addToClassPool(classPool);
CtMethodBuilder.create().returnType(CtClass.intType).name("method").body("return 42;").addToClass(ctClass);
return Arrays.asList(ctClass, abstractClass1, abstractClass2);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.UNCHANGED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
}
@Test
public void testClassNowCheckedException() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
options.setAccessModifier(AccessModifier.PRIVATE);
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(classPool.get("java.lang.Exception")).addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.getChangeStatus(), is(JApiChangeStatus.MODIFIED));
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(false));
assertThat(jApiClass.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.CLASS_NOW_CHECKED_EXCEPTION));
}
@Test
public void testMethodThrowsNewCheckedException() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().name("method").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().name("method").exceptions(new CtClass[] {classPool.get("java.lang.Exception")}).addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
JApiMethod method = getJApiMethod(jApiClass.getMethods(), "method");
assertThat(method.getExceptions().size(), Is.is(1));
assertThat(method.getExceptions().get(0).getChangeStatus(), Is.is(JApiChangeStatus.NEW));
assertThat(method.getExceptions().get(0).isCheckedException(), Is.is(true));
assertThat(method.isBinaryCompatible(), is(true));
assertThat(method.isSourceCompatible(), is(false));
assertThat(method.getCompatibilityChanges(), hasItem(JApiCompatibilityChange.METHOD_NOW_THROWS_CHECKED_EXCEPTION));
}
@Test
public void testMethodThrowsNewRuntimeException() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().name("method").addToClass(ctClass);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().name("method").exceptions(new CtClass[] {classPool.get("java.lang.RuntimeException")}).addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
JApiMethod method = getJApiMethod(jApiClass.getMethods(), "method");
assertThat(method.getExceptions().size(), Is.is(1));
assertThat(method.getExceptions().get(0).getChangeStatus(), Is.is(JApiChangeStatus.NEW));
assertThat(method.getExceptions().get(0).isCheckedException(), Is.is(false));
assertThat(method.isBinaryCompatible(), is(true));
assertThat(method.isSourceCompatible(), is(true));
assertThat(method.getCompatibilityChanges().size(), is(0));
}
@Test
public void testNewMethodThrowsCheckedException() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
return Collections.singletonList(ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
CtMethodBuilder.create().publicAccess().name("method").exceptions(new CtClass[] {classPool.get("java.lang.Exception")}).addToClass(ctClass);
return Collections.singletonList(ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
JApiMethod method = getJApiMethod(jApiClass.getMethods(), "method");
assertThat(method.getExceptions().size(), Is.is(1));
assertThat(method.getExceptions().get(0).getChangeStatus(), Is.is(JApiChangeStatus.NEW));
assertThat(method.getExceptions().get(0).isCheckedException(), Is.is(true));
assertThat(method.isBinaryCompatible(), is(true));
assertThat(method.isSourceCompatible(), is(true));
}
@Test
public void testMemberVariableMovedToSuperclass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass superClass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superClass).addToClassPool(classPool);
CtFieldBuilder.create().protectedAccess().type(CtClass.intType).name("test").addToClass(ctClass);
return Arrays.asList(superClass, ctClass);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass superClass = CtClassBuilder.create().name("japicmp.Superclass").addToClassPool(classPool);
CtFieldBuilder.create().protectedAccess().type(CtClass.intType).name("test").addToClass(superClass);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superClass).addToClassPool(classPool);
return Arrays.asList(superClass, ctClass);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
}
@Test
public void testInterfaceImplementedBySuperclass() throws Exception {
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
@Override
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
CtClass ctInterface = CtInterfaceBuilder.create().name("japicmp.Interface").addToClassPool(classPool);
CtClass superClass = CtClassBuilder.create().name("japicmp.Superclass").implementsInterface(ctInterface).addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superClass).implementsInterface(ctInterface).addToClassPool(classPool);
return Arrays.asList(superClass, ctClass, ctInterface);
}
@Override
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
CtClass ctInterface = CtInterfaceBuilder.create().name("japicmp.Interface").addToClassPool(classPool);
CtClass superClass = CtClassBuilder.create().name("japicmp.Superclass").implementsInterface(ctInterface).addToClassPool(classPool);
CtClass ctClass = CtClassBuilder.create().name("japicmp.Test").withSuperclass(superClass).addToClassPool(classPool);
return Arrays.asList(superClass, ctClass, ctInterface);
}
});
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
assertThat(jApiClass.isBinaryCompatible(), is(true));
assertThat(jApiClass.isSourceCompatible(), is(true));
}
}