package test.diff; import java.io.File; import java.io.IOException; import java.io.Serializable; import aQute.bnd.differ.Baseline; import aQute.bnd.differ.Baseline.Info; import aQute.bnd.differ.DiffPluginImpl; import aQute.bnd.osgi.Builder; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Jar; import aQute.bnd.osgi.Processor; import aQute.bnd.service.diff.Delta; import aQute.bnd.service.diff.Diff; import aQute.bnd.service.diff.Tree; import aQute.lib.io.IO; import junit.framework.TestCase; public class DiffTest extends TestCase { static DiffPluginImpl differ = new DiffPluginImpl(); public void testBaselineDiffs() throws Exception { Tree newerTree = make(IO.getFile("testresources/baseline/test1.jar")); Tree olderTree = make(IO.getFile("testresources/baseline/test2.jar")); Diff diff = newerTree.diff(olderTree); show(diff, 2); assertEquals(Delta.UNCHANGED, diff.getDelta()); assertEquals(Delta.UNCHANGED, diff.get("<init>()").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("putAll(java.util.List)").getDelta()); } private Tree make(File file) throws Exception { Builder b = new Builder(); b.addClasspath(file); b.setProperty("Export-Package", "*"); b.build(); assertTrue(b.check()); return differ.tree(b).get("<api>").get("a").get("a.clazzA"); } /** * Test API differences. We have a package in the /demo workspace project * and we have the same package in our test.api package. */ public void testAPI() throws Exception { Jar older = new Jar(IO.getFile("../demo/generated/demo.jar")); Builder b = new Builder(); b.addClasspath(IO.getFile("bin")); b.setExportPackage("test.api"); b.build(); assertTrue(b.check()); Jar newer = b.getJar(); Tree newerTree = differ.tree(newer).get("<api>").get("test.api"); Tree olderTree = differ.tree(older).get("<api>").get("test.api"); Diff treeDiff = newerTree.diff(olderTree); show(treeDiff, 2); assertEquals(Delta.MAJOR, treeDiff.getDelta()); Diff diff = treeDiff.get("test.api.Interf"); assertEquals(Delta.MAJOR, diff.getDelta()); assertEquals(Delta.UNCHANGED, diff.get("abstract").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("foo()").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("foo()").get("abstract").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("foo()").get("java.util.Collection").getDelta()); assertEquals(Delta.MAJOR, diff.get("foo(java.lang.Object)").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("foo(java.lang.Object)").get("abstract").getDelta()); assertEquals(Delta.REMOVED, diff.get("foo(java.lang.Object)").get("java.lang.Object").getDelta()); assertEquals(Delta.ADDED, diff.get("foo(java.lang.Object)").get("java.util.List").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("fooInt()").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("fooInt()").get("int").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("fooString()").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("fooString()").get("java.lang.String").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("foo(java.util.List)").getDelta()); assertEquals(Delta.UNCHANGED, diff.get("foo(java.util.List)").get("void").getDelta()); diff = treeDiff.get("test.api.A"); assertEquals(Delta.MINOR, diff.getDelta()); assertEquals(Delta.ADDED, diff.get("n").getDelta()); assertEquals(Delta.ADDED, diff.get("n").get("static").getDelta()); assertEquals(Delta.ADDED, diff.get("n").get("int").getDelta()); diff = treeDiff.get("test.api.C"); assertEquals(Delta.MAJOR, diff.getDelta()); assertEquals(Delta.MAJOR, diff.get("s").getDelta()); assertEquals(Delta.ADDED, diff.get("s").get("int").getDelta()); assertEquals(Delta.REMOVED, diff.get("s").get("java.lang.String").getDelta()); b.close(); } public void testAPIStaticSuperClassChange() throws Exception { Jar older = new Jar(IO.getFile("../demo/generated/demo.jar")); Builder b = new Builder(); b.addClasspath(IO.getFile("bin")); b.setExportPackage("test.api"); b.build(); assertTrue(b.check()); Jar newer = b.getJar(); Processor processor = new Processor(); DiffPluginImpl differ = new DiffPluginImpl(); Baseline baseline = new Baseline(processor, differ); Info info = baseline.baseline(newer, older, null).iterator().next(); Diff field = info.packageDiff.get("test.api.B"); show(field, 2); assertEquals(Delta.UNCHANGED, field.getDelta()); b.close(); } public void testInheritanceII() throws Exception { Builder b = new Builder(); b.addClasspath(IO.getFile("bin")); b.setProperty(Constants.EXPORT_PACKAGE, "test.diff.inherit"); b.build(); Tree newer = differ.tree(b); System.out.println(newer.get("<api>")); Tree older = differ.tree(b); assertTrue(newer.diff(older).getDelta() == Delta.UNCHANGED); } /** * The diff command reports changes on (at least) the guava bundles when * they have not changed, even when I feed it the same file at both ends. * Even stranger is the fact that, though always about the same class, the * actual diff is not consistent. Tested with several versions of bnd * (including master HEAD) as well as several versions of the guava bundles * from maven central. Reproduced by @bnd . * * <pre> * $ java -jar * biz.aQute.bnd.jar diff guava-14.0.1.jar guava-14.0.1.jar MINOR PACKAGE * com.google.common.collect MINOR CLASS * com.google.common.collect.ContiguousSet MINOR METHOD * tailSet(java.lang.Object,boolean) ADDED RETURN * com.google.common.collect.ImmutableCollection ADDED RETURN * com.google.common.collect.ImmutableSet ADDED RETURN * com.google.common.collect.ImmutableSortedSet ADDED RETURN * com.google.common.collect.ImmutableSortedSetFauxverideShim ADDED RETURN * com.google.common.collect.SortedIterable ADDED RETURN * java.io.Serializable ADDED RETURN java.lang.Iterable ADDED RETURN * java.lang.Iterable ADDED RETURN java.lang.Iterable ADDED RETURN * java.util.Collection ADDED RETURN java.util.Collection ADDED RETURN * java.util.Set * </pre> * * @throws Exception */ public void testGuavaDiff() throws Exception { File guava = IO.getFile("testresources/guava-14.0.1.jar"); Tree one = differ.tree(guava); System.out.println(one.get("<api>")); Tree two = differ.tree(guava); Diff diff = one.diff(two); assertTrue(diff.getDelta() == Delta.UNCHANGED); } /** * Test the scenario where nested annotations can generate false positive in * diffs * <p> * The trigger is a class-level annotations of the form * * <pre> * {@literal @}Properties(value = { {@literal @}Property(name = "some.key", * value = "some.value") }) * </pre> * * @throws Exception */ public void testNestedExportedAnnotations() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin/")); b.setExportPackage("test.annotations.diff.payload"); Jar build = b.build(); Tree one = differ.tree(build); System.out.println(one); Tree two = differ.tree(build); Diff diff = one.diff(two); assertTrue(diff.getDelta() == Delta.UNCHANGED); b.close(); } /** * Test the scenario where nested annotations can generate false positive in * diffs * <p> * The trigger is a class-level annotations of the form * * <pre> * {@literal @}Properties(value = { {@literal @}Property(name = "some.key", * value = "some.value") }) * </pre> * * @throws Exception */ public void testNestedExportedAnnotations2() throws Exception { File input = IO.getFile("testresources/exported-annotations.jar"); Tree one = differ.tree(input); Tree two = differ.tree(input); Diff diff = one.diff(two); assertTrue(diff.getDelta() == Delta.UNCHANGED); } public void testAwtGeom() throws Exception { Tree newer = differ.tree(IO.getFile("../cnf/repo/ee.j2se/ee.j2se-1.6.0.jar")); Tree gp = newer.get("<api>").get("java.awt.geom").get("java.awt.geom.GeneralPath"); assertNotNull(gp); show(gp, 0); } public static final class Final { public Final foo() { return null; } } public static class II { final int x = 3; public II foo() { return null; } } public static class I extends II { public static I bar() { return null; } @Override public I foo() { return null; } } public static void testInheritance() throws Exception { Builder b = new Builder(); b.addClasspath(IO.getFile("bin")); b.setProperty(Constants.EXPORT_PACKAGE, "test.diff"); b.build(); Tree newer = differ.tree(b); Tree older = differ.tree(b); System.out.println(newer); System.out.println(older); Diff diff = newer.diff(older); Diff p = diff.get("<api>").get("test.diff"); assertTrue(p.getDelta() == Delta.UNCHANGED); show(p, 0); Diff c = p.get("test.diff.DiffTest$I"); assertNotNull(c.get("hashCode()")); assertNotNull(c.get("finalize()")); assertNotNull(c.get("foo()")); Diff cc = p.get("test.diff.DiffTest$Final"); assertNotNull(cc.get("foo()")); b.close(); } public static interface Intf { void foo(); } public static abstract class X implements Intf { @Override public void foo() {} } static interface A extends Comparable<Object>, Serializable { } public static void testSimple() throws Exception { DiffPluginImpl differ = new DiffPluginImpl(); differ.setIgnore( "Bundle-Copyright,Bundle-Description,Bundle-License,Bundle-Name,bundle-manifestversion,Export-Package,Import-Package,Bundle-Vendor,Bundle-Version"); Tree newer = differ.tree(new Jar(IO.getFile("jar/osgi.core-4.3.0.jar"))); Tree older = differ.tree(new Jar(IO.getFile("jar/osgi.core.jar"))); // 4.2 Diff diff = newer.get("<manifest>").diff(older.get("<manifest>")); show(diff, 0); assertEquals(Delta.UNCHANGED, diff.getDelta()); } static abstract class SBB {} public static class CMP implements Comparable<Number> { @Override public int compareTo(Number var0) { // TODO Auto-generated method stub return 0; } } static class SB extends SBB implements Appendable { @Override public SB append(char var0) throws IOException { // TODO Auto-generated method stub return null; } @Override public SB append(CharSequence var0) throws IOException { // TODO Auto-generated method stub return null; } @Override public SB append(CharSequence var0, int var1, int var2) throws IOException { // TODO Auto-generated method stub return null; } } static void show(Diff diff, int indent) { // if (diff.getDelta() == Delta.UNCHANGED || diff.getDelta() == // Delta.IGNORED) // return; for (int i = 0; i < indent; i++) System.err.print(" "); System.err.println(diff.toString()); // if (diff.getDelta().isStructural()) // return; for (Diff c : diff.getChildren()) { show(c, indent + 1); } } static void show(Tree tree, int indent) { for (int i = 0; i < indent; i++) System.err.print(" "); System.err.println(tree.toString()); for (Tree c : tree.getChildren()) { show(c, indent + 1); } } }