summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test
diff options
context:
space:
mode:
authorAlex Spradlin <alexaspradlin@google.com>2020-02-26 15:31:37 -0800
committerAlex Spradlin <alexaspradlin@google.com>2020-03-11 15:39:38 -0700
commite498d43186264f4592d5c9b9303037734cc38b0d (patch)
tree5a617d8231e5e652a13e8cf529d563e3ff50ab50 /org.eclipse.jgit.test
parent04e16afb05912f3a163d8cda3560a5b2f1ea997f (diff)
downloadjgit-e498d43186264f4592d5c9b9303037734cc38b0d.tar.gz
jgit-e498d43186264f4592d5c9b9303037734cc38b0d.zip
RevWalk: new topo sort to not mix lines of history
The topological sort algorithm in TopoSortGenerator for RevWalk may mix multiple lines of history, producing results that differ from C git's git-log whose man page states: "Show no parents before all of its children are shown, and avoid showing commits on multiple lines of history intermixed." Lines of history are mixed because TopoSortGenerator merely delays producing a commit until all of its children have been produced; it does not immediately produce a commit after its last child has been produced. Therefore, add a new RevSort option called TOPO_KEEP_BRANCH_TOGETHER with a new topo sort algorithm in TopoNonIntermixGenerator. In the Generator, when the last child of a commit has been produced, unpop that commit so that it will be returned upon the subsequent call to next(). To avoid producing duplicates, mark commits that have not yet been produced as TOPO_QUEUED so that when a commit is popped, it is produced if and only if TOPO_QUEUED is set. To support nesting with other generators that may produce the same commit multiple times like DepthGenerator (for example, StartGenerator does this), do not increment parent inDegree for the same child commit more than once. Commit b5e764abd21bd4593287361a625ecc49bc0efd77 modified the existing TopoSortGenerator to avoid mixing lines of history, but it was reverted in e40c38ab08837473375c571c2f07ab680fc1985d because the new behavior caused problems for EGit users. This motivated adding a new Generator for the new behavior. Signed-off-by: Alex Spradlin <alexaspradlin@google.com> Change-Id: Icbb24eac98c00e45c175b01e1c8122554f617933
Diffstat (limited to 'org.eclipse.jgit.test')
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java52
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java170
2 files changed, 222 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java
index 4a3b04d4e2..c8256b89c0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java
@@ -164,6 +164,23 @@ public class FirstParentRevWalkTest extends RevWalkTestCase {
}
@Test
+ public void testTopoNonIntermixSort() throws Exception {
+ RevCommit a = commit();
+ RevCommit b1 = commit(a);
+ RevCommit b2 = commit(a);
+ RevCommit c = commit(b1, b2);
+
+ rw.reset();
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ rw.setFirstParent(true);
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
public void testCommitTimeSort() throws Exception {
RevCommit a = commit();
RevCommit b1 = commit(a);
@@ -428,4 +445,39 @@ public class FirstParentRevWalkTest extends RevWalkTestCase {
assertCommit(c, rw.next());
assertNull(rw.next());
}
+
+ @Test
+ public void testWithTopoNonIntermixSortAndTreeFilter() throws Exception {
+ RevCommit a = commit();
+ RevCommit b = commit(tree(file("0", blob("b"))), a);
+ RevCommit c = commit(tree(file("0", blob("c"))), b, a);
+ RevCommit d = commit(tree(file("0", blob("d"))), c);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER, true);
+ rw.setTreeFilter(PathFilterGroup.createFromStrings("0"));
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testWithTopoNonIntermixSortAndTreeFilter2() throws Exception {
+ RevCommit a = commit();
+ RevCommit b = commit(tree(file("0", blob("b"))), a);
+ RevCommit c = commit(tree(file("0", blob("c"))), a, b);
+ RevCommit d = commit(tree(file("0", blob("d"))), c);
+
+ rw.reset();
+ rw.setFirstParent(true);
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER, true);
+ rw.setTreeFilter(PathFilterGroup.createFromStrings("0"));
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c, rw.next());
+ assertNull(rw.next());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java
index 6f110fa317..18ea2c83ce 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java
@@ -10,9 +10,12 @@
package org.eclipse.jgit.revwalk;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.eclipse.jgit.internal.JGitText;
import org.junit.Test;
public class RevWalkSortTest extends RevWalkTestCase {
@@ -144,4 +147,171 @@ public class RevWalkSortTest extends RevWalkTestCase {
assertCommit(d, rw.next());
assertNull(rw.next());
}
+
+ @Test
+ public void testSort_TOPO_NON_INTERMIX() throws Exception {
+ // c1 is back dated before its parent.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(-5, b);
+ final RevCommit c2 = commit(10, b);
+ final RevCommit d = commit(c1, c2);
+
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c2, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSort_TOPO_NON_INTERMIX_OutOfOrderCommitTimes()
+ throws Exception {
+ // b is committed before c2 in a different line of history.
+ //
+ final RevCommit a = commit();
+ final RevCommit c1 = commit(a);
+ final RevCommit b = commit(a);
+ final RevCommit c2 = commit(c1);
+ final RevCommit d = commit(b, c2);
+
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c2, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSort_TOPO_NON_INTERMIX_MultipleLinesOfHistory()
+ throws Exception {
+ final RevCommit a1 = commit();
+ final RevCommit b1 = commit(a1);
+ final RevCommit a2 = commit(a1, b1);
+ final RevCommit b2 = commit(b1);
+ final RevCommit b3 = commit(b1);
+ final RevCommit a3 = commit(a2, b2);
+ final RevCommit a4 = commit(a3, b3);
+
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ markStart(a4);
+ assertCommit(a4, rw.next());
+ assertCommit(b3, rw.next());
+ assertCommit(a3, rw.next());
+ assertCommit(b2, rw.next());
+ assertCommit(a2, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a1, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSort_TOPO_NON_INTERMIX_REVERSE() throws Exception {
+ // c1 is back dated before its parent.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(-5, b);
+ final RevCommit c2 = commit(10, b);
+ final RevCommit d = commit(c1, c2);
+
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ rw.sort(RevSort.REVERSE, true);
+ markStart(d);
+ assertCommit(a, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(c2, rw.next());
+ assertCommit(d, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSort_TOPO_NON_INTERMIX_REVERSE_MultipleLinesOfHistory()
+ throws Exception {
+ final RevCommit a1 = commit();
+ final RevCommit b1 = commit(a1);
+ final RevCommit a2 = commit(a1, b1);
+ final RevCommit b2 = commit(b1);
+ final RevCommit b3 = commit(b1);
+ final RevCommit a3 = commit(a2, b2);
+ final RevCommit a4 = commit(a3, b3);
+
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ rw.sort(RevSort.REVERSE, true);
+ markStart(a4);
+ assertCommit(a1, rw.next());
+ assertCommit(b1, rw.next());
+ assertCommit(a2, rw.next());
+ assertCommit(b2, rw.next());
+ assertCommit(a3, rw.next());
+ assertCommit(b3, rw.next());
+ assertCommit(a4, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSort_TOPO_NON_INTERMIX_ParentOfMultipleStartChildren()
+ throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(a);
+ final RevCommit d1 = commit(a);
+ final RevCommit d2 = commit(d1);
+ final RevCommit e = commit(a);
+
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ markStart(b);
+ markStart(c);
+ markStart(d2);
+ markStart(e);
+ assertCommit(e, rw.next());
+ assertCommit(d2, rw.next());
+ assertCommit(d1, rw.next());
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSort_TOPO_NON_INTERMIX_Uninteresting() throws Exception {
+ final RevCommit a1 = commit();
+ final RevCommit a2 = commit(a1);
+ final RevCommit a3 = commit(a2);
+ final RevCommit b = commit(a1);
+ final RevCommit a4 = commit(a3, b);
+
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ markStart(a4);
+ markUninteresting(a2);
+ assertCommit(a4, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a3, rw.next());
+ assertNull(rw.next());
+ }
+
+ @Test
+ public void testSort_TOPO_NON_INTERMIX_and_TOPO_throws() throws Exception {
+ final RevCommit a = commit();
+
+ rw.sort(RevSort.TOPO_KEEP_BRANCH_TOGETHER);
+ rw.sort(RevSort.TOPO, true);
+ markStart(a);
+ try {
+ rw.next();
+ fail("did not throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ assertEquals(
+ JGitText.get().cannotCombineTopoSortWithTopoNonIntermixSort,
+ e.getMessage());
+ }
+ }
}