Repository: SpoonLabs/gumtree-spoon-ast-diff
Pull request #109 (2019-08-02 13:38:49)

Root Operations lose order

martinezmatias: Travis fails:
```
Expected feature release number in range of 9 to 14, but got: 8
167The command "~/bin/install-jdk.sh --target "/home/travis/oraclejdk8" --workspace "/home/travis/.cache/install-jdk" --feature "8" --license "BCL"" failed and exited with 3 during .
```

In coming I "solved" it by  adding in the travis conf "dist: trusty"

Patch:
diff --git a/.travis.yml b/.travis.yml
index 4e5319b..bfc566b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,3 +17,4 @@ cache:
 after_success:
   - .buildscript/deploy_to_maven.sh
 
+dist: trusty
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 11f6835..c95fdf4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,7 +37,7 @@
     <dependency>
       <groupId>fr.inria.gforge.spoon</groupId>
       <artifactId>spoon-core</artifactId>
-      <version>7.4.0</version>
+      <version>7.5.0</version>
     </dependency>
     <dependency>
       <groupId>com.github.gumtreediff</groupId>
diff --git a/src/main/java/gumtree/spoon/diff/ActionClassifier.java b/src/main/java/gumtree/spoon/diff/ActionClassifier.java
index 63484b7..87b6f85 100644
--- a/src/main/java/gumtree/spoon/diff/ActionClassifier.java
+++ b/src/main/java/gumtree/spoon/diff/ActionClassifier.java
@@ -1,8 +1,8 @@
 package gumtree.spoon.diff;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -28,12 +28,12 @@ public class ActionClassifier {
 	// /
 	// ROOT CLASSIFIER
 	// /
-	private Set<ITree> srcUpdTrees = new HashSet<>();
-	private Set<ITree> dstUpdTrees = new HashSet<>();
-	private Set<ITree> srcMvTrees = new HashSet<>();
-	private Set<ITree> dstMvTrees = new HashSet<>();
-	private Set<ITree> srcDelTrees = new HashSet<>();
-	private Set<ITree> dstAddTrees = new HashSet<>();
+	private List<ITree> srcUpdTrees = new ArrayList<>();
+	private List<ITree> dstUpdTrees = new ArrayList<>();
+	private List<ITree> srcMvTrees = new ArrayList<>();
+	private List<ITree> dstMvTrees = new ArrayList<>();
+	private List<ITree> srcDelTrees = new ArrayList<>();
+	private List<ITree> dstAddTrees = new ArrayList<>();
 	private Map<ITree, Action> originalActionsSrc = new HashMap<>();
 	private Map<ITree, Action> originalActionsDst = new HashMap<>();
 


Test patch:
diff --git a/src/test/java/gumtree/spoon/diff/DiffTest.java b/src/test/java/gumtree/spoon/diff/DiffTest.java
index c2ec2ca..af79b30 100644
--- a/src/test/java/gumtree/spoon/diff/DiffTest.java
+++ b/src/test/java/gumtree/spoon/diff/DiffTest.java
@@ -1,19 +1,23 @@
 package gumtree.spoon.diff;
 
-import gumtree.spoon.AstComparator;
-import gumtree.spoon.diff.operations.Operation;
-import gumtree.spoon.diff.operations.OperationKind;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import java.io.File;
 import java.util.List;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+import gumtree.spoon.AstComparator;
+import gumtree.spoon.diff.operations.Operation;
+import gumtree.spoon.diff.operations.OperationKind;
+import spoon.Launcher;
+import spoon.reflect.declaration.CtClass;
 
 /**
  * Test Spoon Diff
- * @author  Matias Martinez, matias.martinez@inria.fr
+ * 
+ * @author Matias Martinez, matias.martinez@inria.fr
  *
  */
 public class DiffTest {
@@ -25,45 +29,45 @@ public class DiffTest {
 		File fr = new File("src/test/resources/examples/test1/TypeHandler2.java");
 
 		AstComparator diff = new AstComparator();
-		Diff result = diff.compare(fl,fr);
-		assertEquals("Update FieldRead at org.apache.commons.cli.TypeHandler:80" +newline
-				+ "\torg.apache.commons.cli.PatternOptionBuilder.DATE_VALUE to org.apache.commons.cli.PatternOptionBuilder.CLASS_VALUE" + newline
-				+ "Insert Invocation at org.apache.commons.cli.TypeHandler:118" + newline
+		Diff result = diff.compare(fl, fr);
+		assertEquals("Update FieldRead at org.apache.commons.cli.TypeHandler:80" + newline
+				+ "\torg.apache.commons.cli.PatternOptionBuilder.DATE_VALUE to org.apache.commons.cli.PatternOptionBuilder.CLASS_VALUE"
+				+ newline + "Insert Invocation at org.apache.commons.cli.TypeHandler:118" + newline
 				+ "\tjava.lang.System.out.println(\"Hola\")" + newline, result.toString());
 		fl = new File("src/test/resources/examples/test2/CommandLine1.java");
 		fr = new File("src/test/resources/examples/test2/CommandLine2.java");
 
-		result = diff.compare(fl,fr);
-		assertEquals("Update Literal at org.apache.commons.cli.CommandLine:275" + newline
-				+ "\t1 to 1000000" + newline, result.toString());
+		result = diff.compare(fl, fr);
+		assertEquals("Update Literal at org.apache.commons.cli.CommandLine:275" + newline + "\t1 to 1000000" + newline,
+				result.toString());
 
 		fl = new File("src/test/resources/examples/test3/CommandLine1.java");
 		fr = new File("src/test/resources/examples/test3/CommandLine2.java");
 
-		result = diff.compare(fl,fr);
+		result = diff.compare(fl, fr);
 		String deleteStr = "Delete Method at org.apache.commons.cli.CommandLine:161" + newline
 				+ "\tpublic java.lang.String[] getOptionValues(java.lang.String opt) {" + newline
-				+ "\t    java.util.List<java.lang.String> values = new java.util.ArrayList<java.lang.String>();" + newline
-				+ "\t    for (org.apache.commons.cli.Option option : options) {" + newline
+				+ "\t    java.util.List<java.lang.String> values = new java.util.ArrayList<java.lang.String>();"
+				+ newline + "\t    for (org.apache.commons.cli.Option option : options) {" + newline
 				+ "\t        if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) {" + newline
-				+ "\t            values.addAll(option.getValuesList());" + newline
-				+ "\t        }" + newline
-				+ "\t    }" + newline
-				+ "\t    return values.isEmpty() ? null : values.toArray(new java.lang.String[values.size()]);" + newline
-				+ "\t}" + newline;
+				+ "\t            values.addAll(option.getValuesList());" + newline + "\t        }" + newline + "\t    }"
+				+ newline
+				+ "\t    return values.isEmpty() ? null : values.toArray(new java.lang.String[values.size()]);"
+				+ newline + "\t}" + newline;
 		assertTrue(result.toString(), result.toString().endsWith(deleteStr));
 	}
 
 	/**
 	 * Add new element + child
+	 * 
 	 * @throws Exception
 	 */
 	@Test
-	public void test_actionClassifier_1() throws Exception{
+	public void test_actionClassifier_1() throws Exception {
 		AstComparator diff = new AstComparator();
 		File fl = new File("src/test/resources/examples/roots/test8/left_QuickNotepad_1.13.java");
 		File fr = new File("src/test/resources/examples/roots/test8/right_QuickNotepad_1.14.java");
-		Diff result = diff.compare(fl,fr);
+		Diff result = diff.compare(fl, fr);
 
 		List<Operation> actionsRoot = result.getRootOperations();
 		assertEquals(1, actionsRoot.size());
@@ -72,15 +76,17 @@ public class DiffTest {
 
 	/**
 	 * changes an element and adds a new child to it
+	 * 
 	 * @throws Exception
 	 */
 	@Test
-	public void test_actionClassifier_2() throws Exception{
+	public void test_actionClassifier_2() throws Exception {
 		AstComparator diff = new AstComparator();
-		// meld src/test/resources/examples/roots/test9/left_QuickNotepad_1.13.java src/test/resources/examples/roots/test9/right_QuickNotepad_1.14.java
+		// meld src/test/resources/examples/roots/test9/left_QuickNotepad_1.13.java
+		// src/test/resources/examples/roots/test9/right_QuickNotepad_1.14.java
 		File fl = new File("src/test/resources/examples/roots/test9/left_QuickNotepad_1.13.java");
 		File fr = new File("src/test/resources/examples/roots/test9/right_QuickNotepad_1.14.java");
-		Diff result = diff.compare(fl,fr);
+		Diff result = diff.compare(fl, fr);
 
 		List<Operation> actionsRoot = result.getRootOperations();
 		assertEquals(2, actionsRoot.size());
@@ -93,14 +99,15 @@ public class DiffTest {
 
 	/**
 	 * Remove element, keep its only child
+	 * 
 	 * @throws Exception
 	 */
 	@Test
-	public void test_actionClassifier_3() throws Exception{
+	public void test_actionClassifier_3() throws Exception {
 		AstComparator diff = new AstComparator();
 		File fl = new File("src/test/resources/examples/roots/test10/left_QuickNotepad_1.13.java");
 		File fr = new File("src/test/resources/examples/roots/test10/right_QuickNotepad_1.14.java");
-		Diff result = diff.compare(fl,fr);
+		Diff result = diff.compare(fl, fr);
 
 		List<Operation> actionsRoot = result.getRootOperations();
 		assertEquals(2, actionsRoot.size());
@@ -111,14 +118,15 @@ public class DiffTest {
 
 	/**
 	 * Removes element with 2 children, keep one child, remove the other
+	 * 
 	 * @throws Exception
 	 */
 	@Test
-	public void test_actionClassifier_4() throws Exception{
+	public void test_actionClassifier_4() throws Exception {
 		AstComparator diff = new AstComparator();
 		File fl = new File("src/test/resources/examples/roots/test11/left_QuickNotepad_1.13.java");
 		File fr = new File("src/test/resources/examples/roots/test11/right_QuickNotepad_1.14.java");
-		Diff result = diff.compare(fl,fr);
+		Diff result = diff.compare(fl, fr);
 
 		List<Operation> actionsRoot = result.getRootOperations();
 		assertEquals(2, actionsRoot.size());
@@ -129,14 +137,15 @@ public class DiffTest {
 
 	/**
 	 * Add element with 2 children, one new, other from a move
+	 * 
 	 * @throws Exception
 	 */
 	@Test
-	public void test_actionClassifier_5() throws Exception{
+	public void test_actionClassifier_5() throws Exception {
 		AstComparator diff = new AstComparator();
 		File fl = new File("src/test/resources/examples/roots/test12/left_QuickNotepad_1.13.java");
 		File fr = new File("src/test/resources/examples/roots/test12/right_QuickNotepad_1.14.java");
-		Diff result = diff.compare(fl,fr);
+		Diff result = diff.compare(fl, fr);
 
 		List<Operation> actionsRoot = result.getRootOperations();
 		assertEquals(2, actionsRoot.size());
@@ -144,4 +153,46 @@ public class DiffTest {
 		assertTrue(result.containsOperation(OperationKind.Insert, "If"));
 		assertTrue(result.containsOperation(OperationKind.Move, "Invocation"));
 	}
+
+	@SuppressWarnings("rawtypes")
+	@Test
+	public void test_action_RootOrder() throws Exception {
+		AstComparator diff = new AstComparator();
+
+		CtClass c1b = Launcher.parseClass(" class BehaviorCall implements Call{\n"
+				+ "final AtomicReference failureRef = new AtomicReference<>();\n"
+				+ "final CountDownLatch latch = new CountDownLatch(1);\n" + "\n" + " enqueue(new Callback<T>() {\n"
+				+ "  @Override public void onResponse(Response<T> response) {\n" + "     responseRef.set(response);\n"
+				+ "     latch.countDown();\n" + "   }\n" + "}\n" + ")\n" + "\n" + "}");
+
+		CtClass c2b = Launcher.parseClass("class BehaviorCall implements Call {\n"
+				+ "final AtomicReference failureRef = new AtomicReference<>();\n"
+				+ "final CountDownLatch latch = new CountDownLatch(1);\n" + "\n" + " enqueue(new Callback<T>() {\n"
+				+ "@override public void onResponse(Response response) {\n"
+
+				// Added
+				+ "System.out.println();"
+				//
+				+ "responseRef.set(response);\n"
+				// Diff
+				+ "if(response != null){return response;}" + "latch.countDown();\n" + "}\n" + "}\n" + ")\n" + "}");
+
+		Diff result = diff.compare(c1b, c2b);
+
+		List<Operation> actionsRoot = result.getRootOperations();
+		// Buggy
+		actionsRoot = result.getRootOperations();
+		assertEquals(2, actionsRoot.size());
+
+		Operation oproot0 = result.getRootOperations().get(0);
+		Operation oproot1 = result.getRootOperations().get(1);
+
+		int indexInAll0 = result.getAllOperations().indexOf(oproot0);
+		int indexInAll1 = result.getAllOperations().indexOf(oproot1);
+
+		// Preserve the position
+		assertTrue(indexInAll0 < indexInAll1);
+
+	}
+
 }