summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test')
-rw-r--r--org.eclipse.jgit.test/META-INF/MANIFEST.MF112
-rw-r--r--org.eclipse.jgit.test/pom.xml2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java47
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java16
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java68
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java96
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java371
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java433
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java54
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java79
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java48
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java229
12 files changed, 1460 insertions, 95 deletions
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 581395d90c..381a71957f 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Automatic-Module-Name: org.eclipse.jgit.test
Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 6.1.1.qualifier
+Bundle-Version: 6.2.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %Bundle-Vendor
Bundle-RequiredExecutionEnvironment: JavaSE-11
@@ -16,61 +16,61 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
org.apache.commons.compress.compressors.gzip;version="[1.15.0,2.0)",
org.apache.commons.compress.compressors.xz;version="[1.15.0,2.0)",
org.assertj.core.api;version="[3.14.0,4.0.0)",
- org.eclipse.jgit.annotations;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.api;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.api.errors;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.archive;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.attributes;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.awtui;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.blame;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.diff;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.dircache;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.errors;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.events;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.fnmatch;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.gitrepo;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.hooks;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.ignore;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.ignore.internal;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.diffmergetool;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.fsck;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.revwalk;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.storage.file;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.storage.io;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.storage.pack;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.storage.reftable;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.transport.connectivity;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.transport.http;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.transport.parser;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.internal.transport.ssh;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.junit;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.junit.time;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.lfs;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.lib;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.lib.internal;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.logging;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.merge;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.nls;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.notes;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.patch;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.pgm;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.pgm.internal;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.revplot;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.revwalk;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.revwalk.filter;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.storage.file;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.storage.pack;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.submodule;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.transport;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.transport.http;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.transport.resolver;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.treewalk;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.treewalk.filter;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.util;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.util.io;version="[6.1.1,6.2.0)",
- org.eclipse.jgit.util.sha1;version="[6.1.1,6.2.0)",
+ org.eclipse.jgit.annotations;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.api;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.api.errors;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.archive;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.attributes;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.awtui;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.blame;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.diff;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.dircache;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.errors;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.events;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.fnmatch;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.gitrepo;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.hooks;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.ignore;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.ignore.internal;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.diffmergetool;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.fsck;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.revwalk;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.storage.io;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.storage.reftable;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.transport.connectivity;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.transport.http;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.transport.parser;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.internal.transport.ssh;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.junit;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.junit.time;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.lfs;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.lib;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.lib.internal;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.logging;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.merge;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.nls;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.notes;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.patch;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.pgm;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.pgm.internal;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.revplot;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.revwalk;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.revwalk.filter;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.storage.file;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.storage.pack;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.submodule;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.transport;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.transport.http;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.treewalk;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.util;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.util.io;version="[6.2.1,6.3.0)",
+ org.eclipse.jgit.util.sha1;version="[6.2.1,6.3.0)",
org.hamcrest;version="[1.1.0,3.0.0)",
org.hamcrest.collection;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index 6b66919894..efba3e0ed9 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -19,7 +19,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>6.1.1-SNAPSHOT</version>
+ <version>6.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.test</artifactId>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
index b608afa5c7..3ec454cfc3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
@@ -116,6 +116,53 @@ public class FetchCommandTest extends RepositoryTestCase {
}
@Test
+ public void testFetchSimpleNegativeRefSpec() throws Exception {
+ remoteGit.commit().setMessage("commit").call();
+
+ FetchResult res = git.fetch().setRemote("test")
+ .setRefSpecs("refs/heads/master:refs/heads/test",
+ "^:refs/heads/test")
+ .call();
+ assertNull(res.getTrackingRefUpdate("refs/heads/test"));
+
+ res = git.fetch().setRemote("test")
+ .setRefSpecs("refs/heads/master:refs/heads/test",
+ "^refs/heads/master")
+ .call();
+ assertNull(res.getTrackingRefUpdate("refs/heads/test"));
+ }
+
+ @Test
+ public void negativeRefSpecFilterBySource() throws Exception {
+ remoteGit.commit().setMessage("commit").call();
+ remoteGit.branchCreate().setName("test").call();
+ remoteGit.commit().setMessage("commit1").call();
+ remoteGit.branchCreate().setName("dev").call();
+
+ FetchResult res = git.fetch().setRemote("test")
+ .setRefSpecs("refs/*:refs/origins/*", "^refs/*/test")
+ .call();
+ assertNotNull(res.getTrackingRefUpdate("refs/origins/heads/master"));
+ assertNull(res.getTrackingRefUpdate("refs/origins/heads/test"));
+ assertNotNull(res.getTrackingRefUpdate("refs/origins/heads/dev"));
+ }
+
+ @Test
+ public void negativeRefSpecFilterByDestination() throws Exception {
+ remoteGit.commit().setMessage("commit").call();
+ remoteGit.branchCreate().setName("meta").call();
+ remoteGit.commit().setMessage("commit1").call();
+ remoteGit.branchCreate().setName("data").call();
+
+ FetchResult res = git.fetch().setRemote("test")
+ .setRefSpecs("refs/*:refs/secret/*", "^:refs/secret/*/meta")
+ .call();
+ assertNotNull(res.getTrackingRefUpdate("refs/secret/heads/master"));
+ assertNull(res.getTrackingRefUpdate("refs/secret/heads/meta"));
+ assertNotNull(res.getTrackingRefUpdate("refs/secret/heads/data"));
+ }
+
+ @Test
public void fetchAddsBranches() throws Exception {
final String branch1 = "b1";
final String branch2 = "b2";
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java
index 12ec2aae57..05af175cfa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LsRemoteCommandTest.java
@@ -21,6 +21,8 @@ import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.util.SystemReader;
import org.junit.Test;
public class LsRemoteCommandTest extends RepositoryTestCase {
@@ -107,6 +109,20 @@ public class LsRemoteCommandTest extends RepositoryTestCase {
}
@Test
+ public void testLsRemoteWithoutLocalRepositoryUrlInsteadOf()
+ throws Exception {
+ String uri = fileUri();
+ StoredConfig userConfig = SystemReader.getInstance().getUserConfig();
+ userConfig.load();
+ userConfig.setString("url", uri, "insteadOf", "file:///foo");
+ userConfig.save();
+ Collection<Ref> refs = Git.lsRemoteRepository().setRemote("file:///foo")
+ .setHeads(true).call();
+ assertNotNull(refs);
+ assertEquals(2, refs.size());
+ }
+
+ @Test
public void testLsRemoteWithSymRefs() throws Exception {
File directory = createTempDirectory("testRepository");
CloneCommand command = Git.cloneRepository();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
index 64475f5d50..917b6c3297 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -36,6 +36,7 @@ import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.lib.Sets;
+import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.merge.ContentMergeStrategy;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
@@ -2018,6 +2019,73 @@ public class MergeCommandTest extends RepositoryTestCase {
}
}
+ @Test
+ public void testMergeConflictWithMessageAndCommentChar() throws Exception {
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ writeTrashFile("a", "1\na(side)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("side").call();
+
+ checkoutBranch("refs/heads/master");
+
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
+
+ StoredConfig config = db.getConfig();
+ config.setString("core", null, "commentChar", "^");
+
+ Ref sideBranch = db.exactRef("refs/heads/side");
+
+ git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
+ .setMessage("user message").call();
+
+ assertEquals("user message\n\n^ Conflicts:\n^\ta\n",
+ db.readMergeCommitMsg());
+ }
+ }
+
+ @Test
+ public void testMergeConflictWithMessageAndCommentCharAuto()
+ throws Exception {
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ writeTrashFile("a", "1\na(side)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("side").call();
+
+ checkoutBranch("refs/heads/master");
+
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
+
+ StoredConfig config = db.getConfig();
+ config.setString("core", null, "commentChar", "auto");
+
+ Ref sideBranch = db.exactRef("refs/heads/side");
+
+ git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
+ .setMessage("#user message").call();
+
+ assertEquals("#user message\n\n; Conflicts:\n;\ta\n",
+ db.readMergeCommitMsg());
+ }
+ }
+
private static void setExecutable(Git git, String path, boolean executable) {
FS.DETECTED.setExecute(
new File(git.getRepository().getWorkTree(), path), executable);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
index c64ff0b1c3..d574e45f6f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
@@ -30,6 +30,7 @@ import java.util.List;
import org.eclipse.jgit.api.MergeResult.MergeStatus;
import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler;
+import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler2;
import org.eclipse.jgit.api.RebaseCommand.Operation;
import org.eclipse.jgit.api.RebaseResult.Status;
import org.eclipse.jgit.api.errors.InvalidRebaseStepException;
@@ -46,6 +47,7 @@ import org.eclipse.jgit.events.ChangeRecorder;
import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -56,6 +58,7 @@ import org.eclipse.jgit.lib.RebaseTodoLine.Action;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.RepositoryState;
+import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;
@@ -3410,6 +3413,99 @@ public class RebaseCommandTest extends RepositoryTestCase {
}
+ @Test
+ public void testInteractiveRebaseSquashFixupSequence() throws Exception {
+ // create file1, add and commit
+ writeTrashFile(FILE1, "file1");
+ git.add().addFilepattern(FILE1).call();
+ git.commit().setMessage("commit1").call();
+
+ // modify file1, add and commit
+ writeTrashFile(FILE1, "modified file1");
+ git.add().addFilepattern(FILE1).call();
+ git.commit().setMessage("commit2").call();
+
+ // modify file1, add and commit
+ writeTrashFile(FILE1, "modified file1 a second time");
+ git.add().addFilepattern(FILE1).call();
+ // Make it difficult; use git standard comment characters in the commit
+ // messages
+ git.commit().setMessage("#commit3").call();
+
+ // modify file1, add and commit
+ writeTrashFile(FILE1, "modified file1 a third time");
+ git.add().addFilepattern(FILE1).call();
+ git.commit().setMessage("@commit4").call();
+
+ // modify file1, add and commit
+ writeTrashFile(FILE1, "modified file1 a fourth time");
+ git.add().addFilepattern(FILE1).call();
+ git.commit().setMessage(";commit5").call();
+
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("core", null, "commentChar", "auto");
+ // With "auto", we should end up with '@' being used as comment
+ // character (commit4 is skipped, so it should not advance the
+ // character).
+ RebaseResult result = git.rebase().setUpstream("HEAD~4")
+ .runInteractively(new InteractiveHandler2() {
+
+ @Override
+ public void prepareSteps(List<RebaseTodoLine> steps) {
+ try {
+ steps.get(0).setAction(Action.PICK);
+ steps.get(1).setAction(Action.SQUASH);
+ steps.get(2).setAction(Action.FIXUP);
+ steps.get(3).setAction(Action.SQUASH);
+ } catch (IllegalTodoFileModification e) {
+ fail("unexpected exception: " + e);
+ }
+ }
+
+ @Override
+ public String modifyCommitMessage(String commit) {
+ fail("should not be called");
+ return commit;
+ }
+
+ @Override
+ public ModifyResult editCommitMessage(String message,
+ CleanupMode mode, char commentChar) {
+ assertEquals('@', commentChar);
+ assertEquals("@ This is a combination of 4 commits.\n"
+ + "@ The first commit's message is:\n"
+ + "commit2\n"
+ + "@ This is the 2nd commit message:\n"
+ + "#commit3\n"
+ + "@ The 3rd commit message will be skipped:\n"
+ + "@ @commit4\n"
+ + "@ This is the 4th commit message:\n"
+ + ";commit5", message);
+ return new ModifyResult() {
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public CleanupMode getCleanupMode() {
+ return mode;
+ }
+
+ @Override
+ public boolean shouldAddChangeId() {
+ return false;
+ }
+ };
+ }
+ }).call();
+ assertEquals(Status.OK, result.getStatus());
+ Iterator<RevCommit> logIterator = git.log().all().call().iterator();
+ String actualCommitMsg = logIterator.next().getFullMessage();
+ assertEquals("commit2\n#commit3\n;commit5", actualCommitMsg);
+ }
+
private File getTodoFile() {
File todoFile = new File(db.getDirectory(), GIT_REBASE_TODO);
return todoFile;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java
index c9ebec7638..f69a1794ef 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java
@@ -10,21 +10,36 @@
package org.eclipse.jgit.internal.diffmergetool;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.internal.BooleanTriState;
import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS.ExecutionResult;
import org.junit.Test;
/**
@@ -32,20 +47,119 @@ import org.junit.Test;
*/
public class ExternalDiffToolTest extends ExternalToolTestCase {
+ @Test(expected = ToolException.class)
+ public void testUserToolWithError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 1;
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ invokeCompare(toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUserToolWithCommandNotFoundError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 127; // command not found
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ invokeCompare(toolName);
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test
+ public void testUserDefinedTool() throws Exception {
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ DiffTools manager = new DiffTools(db);
+
+ Map<String, ExternalDiffTool> tools = manager.getUserDefinedTools();
+ ExternalDiffTool externalTool = tools.get(customToolName);
+ boolean trustExitCode = true;
+ manager.compare(local, remote, externalTool, trustExitCode);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testUserDefinedToolWithPrompt() throws Exception {
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ DiffTools manager = new DiffTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.compare(local, remote, Optional.of(customToolName),
+ BooleanTriState.TRUE, false, BooleanTriState.TRUE,
+ promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+
+ List<String> actualToolPrompts = promptHandler.toolPrompts;
+ List<String> expectedToolPrompts = Arrays.asList("customTool");
+ assertEquals("Expected a user prompt for custom tool call",
+ expectedToolPrompts, actualToolPrompts);
+
+ assertEquals("Expected to no informing about missing tools",
+ Collections.EMPTY_LIST, noToolHandler.missingTools);
+ }
+
@Test
- public void testToolNames() {
+ public void testUserDefinedToolWithCancelledPrompt() throws Exception {
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
DiffTools manager = new DiffTools(db);
- Set<String> actualToolNames = manager.getToolNames();
- Set<String> expectedToolNames = Collections.emptySet();
- assertEquals("Incorrect set of external diff tool names",
- expectedToolNames, actualToolNames);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.compare(local, remote,
+ Optional.of(customToolName), BooleanTriState.TRUE, false,
+ BooleanTriState.TRUE, promptHandler, noToolHandler);
+ assertFalse("Expected no result if user cancels the operation",
+ result.isPresent());
}
@Test
public void testAllTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_DIFFTOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, "echo");
+
DiffTools manager = new DiffTools(db);
- Set<String> actualToolNames = manager.getAvailableTools().keySet();
+ Set<String> actualToolNames = manager.getAllToolNames();
Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolName);
CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values();
for (CommandLineDiffTool defaultTool : defaultTools) {
String toolName = defaultTool.name();
@@ -86,11 +200,11 @@ public class ExternalDiffToolTest extends ExternalToolTestCase {
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
CONFIG_KEY_PATH, "/usr/bin/echo");
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
- CONFIG_KEY_PROMPT, "--no-prompt");
+ CONFIG_KEY_PROMPT, String.valueOf(false));
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
- CONFIG_KEY_GUITOOL, "--no-gui");
+ CONFIG_KEY_GUITOOL, String.valueOf(false));
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
- CONFIG_KEY_TRUST_EXIT_CODE, "--no-trust-exit-code");
+ CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(false));
DiffTools manager = new DiffTools(db);
Set<String> actualToolNames = manager.getUserDefinedTools().keySet();
Set<String> expectedToolNames = new LinkedHashSet<>();
@@ -100,59 +214,240 @@ public class ExternalDiffToolTest extends ExternalToolTestCase {
}
@Test
- public void testNotAvailableTools() {
- DiffTools manager = new DiffTools(db);
- Set<String> actualToolNames = manager.getNotAvailableTools().keySet();
- Set<String> expectedToolNames = Collections.emptySet();
- assertEquals("Incorrect set of not available external diff tools",
- expectedToolNames, actualToolNames);
- }
+ public void testCompare() throws ToolException {
+ String toolName = "customTool";
- @Test
- public void testCompare() {
- DiffTools manager = new DiffTools(db);
+ FileBasedConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
- String newPath = "";
- String oldPath = "";
- String newId = "";
- String oldId = "";
- String toolName = "";
- BooleanTriState prompt = BooleanTriState.UNSET;
- BooleanTriState gui = BooleanTriState.UNSET;
- BooleanTriState trustExitCode = BooleanTriState.UNSET;
+ String command = getEchoCommand();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+ Optional<ExecutionResult> result = invokeCompare(toolName);
+ assertTrue("Expected external diff tool result to be available",
+ result.isPresent());
int expectedCompareResult = 0;
- int compareResult = manager.compare(newPath, oldPath, newId, oldId,
- toolName, prompt, gui, trustExitCode);
assertEquals("Incorrect compare result for external diff tool",
- expectedCompareResult, compareResult);
+ expectedCompareResult, result.get().getRc());
}
@Test
public void testDefaultTool() throws Exception {
+ String toolName = "customTool";
+ String guiToolName = "customGuiTool";
+
FileBasedConfig config = db.getConfig();
// the default diff tool is configured without a subsection
String subsection = null;
- config.setString("diff", subsection, "tool", "customTool");
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
DiffTools manager = new DiffTools(db);
- BooleanTriState gui = BooleanTriState.UNSET;
+ boolean gui = false;
String defaultToolName = manager.getDefaultToolName(gui);
assertEquals(
"Expected configured difftool to be the default external diff tool",
- "my_default_toolname", defaultToolName);
+ toolName, defaultToolName);
- gui = BooleanTriState.TRUE;
+ gui = true;
String defaultGuiToolName = manager.getDefaultToolName(gui);
assertEquals(
- "Expected configured difftool to be the default external diff tool",
- "my_gui_tool", defaultGuiToolName);
+ "Expected default gui difftool to be the default tool if no gui tool is set",
+ toolName, defaultGuiToolName);
- config.setString("diff", subsection, "guitool", "customGuiTool");
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_GUITOOL,
+ guiToolName);
manager = new DiffTools(db);
defaultGuiToolName = manager.getDefaultToolName(gui);
assertEquals(
"Expected configured difftool to be the default external diff guitool",
- "my_gui_tool", defaultGuiToolName);
+ guiToolName, defaultGuiToolName);
+ }
+
+ @Test
+ public void testOverridePreDefinedToolPath() {
+ String newToolPath = "/tmp/path/";
+
+ CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values();
+ assertTrue("Expected to find pre-defined external diff tools",
+ defaultTools.length > 0);
+
+ CommandLineDiffTool overridenTool = defaultTools[0];
+ String overridenToolName = overridenTool.name();
+ String overridenToolPath = newToolPath + overridenToolName;
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, overridenToolName,
+ CONFIG_KEY_PATH, overridenToolPath);
+
+ DiffTools manager = new DiffTools(db);
+ Map<String, ExternalDiffTool> availableTools = manager
+ .getPredefinedTools(true);
+ ExternalDiffTool externalDiffTool = availableTools
+ .get(overridenToolName);
+ String actualDiffToolPath = externalDiffTool.getPath();
+ assertEquals(
+ "Expected pre-defined external diff tool to have overriden path",
+ overridenToolPath, actualDiffToolPath);
+ String expectedDiffToolCommand = overridenToolPath + " "
+ + overridenTool.getParameters();
+ String actualDiffToolCommand = externalDiffTool.getCommand();
+ assertEquals(
+ "Expected pre-defined external diff tool to have overriden command",
+ expectedDiffToolCommand, actualDiffToolCommand);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUndefinedTool() throws Exception {
+ String toolName = "undefined";
+ invokeCompare(toolName);
+ fail("Expected exception to be thrown due to not defined external diff tool");
+ }
+
+ @Test
+ public void testDefaultToolExecutionWithPrompt() throws Exception {
+ FileBasedConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString("diff", subsection, "tool", "customTool");
+
+ String command = getEchoCommand();
+
+ config.setString("difftool", "customTool", "cmd", command);
+
+ DiffTools manager = new DiffTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.compare(local, remote, Optional.empty(), BooleanTriState.TRUE,
+ false, BooleanTriState.TRUE, promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testNoDefaultToolName() {
+ DiffTools manager = new DiffTools(db);
+ boolean gui = false;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+
+ gui = true;
+ defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+ }
+
+ @Test
+ public void testExternalToolInGitAttributes() throws Exception {
+ String content = "attributes:\n*.txt difftool=customTool";
+ File gitattributes = writeTrashFile(".gitattributes", content);
+ gitattributes.deleteOnExit();
+ try (TestRepository<Repository> testRepository = new TestRepository<>(
+ db)) {
+ FileBasedConfig config = db.getConfig();
+ config.setString("difftool", "customTool", "cmd", "echo");
+ testRepository.git().add().addFilepattern(localFile.getName())
+ .call();
+
+ testRepository.git().add().addFilepattern(".gitattributes").call();
+
+ testRepository.branch("master").commit().message("first commit")
+ .create();
+
+ DiffTools manager = new DiffTools(db);
+ Optional<String> tool = manager
+ .getExternalToolFromAttributes(localFile.getName());
+ assertTrue("Failed to find user defined tool", tool.isPresent());
+ assertEquals("Failed to find user defined tool", "customTool",
+ tool.get());
+ } finally {
+ Files.delete(gitattributes.toPath());
+ }
+ }
+
+ @Test
+ public void testNotExternalToolInGitAttributes() throws Exception {
+ String content = "";
+ File gitattributes = writeTrashFile(".gitattributes", content);
+ gitattributes.deleteOnExit();
+ try (TestRepository<Repository> testRepository = new TestRepository<>(
+ db)) {
+ FileBasedConfig config = db.getConfig();
+ config.setString("difftool", "customTool", "cmd", "echo");
+ testRepository.git().add().addFilepattern(localFile.getName())
+ .call();
+
+ testRepository.git().add().addFilepattern(".gitattributes").call();
+
+ testRepository.branch("master").commit().message("first commit")
+ .create();
+
+ DiffTools manager = new DiffTools(db);
+ Optional<String> tool = manager
+ .getExternalToolFromAttributes(localFile.getName());
+ assertFalse(
+ "Expected no external tool if no default tool is specified in .gitattributes",
+ tool.isPresent());
+ } finally {
+ Files.delete(gitattributes.toPath());
+ }
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullTool() throws Exception {
+ DiffTools manager = new DiffTools(db);
+
+ boolean trustExitCode = true;
+ ExternalDiffTool tool = null;
+ manager.compare(local, remote, tool, trustExitCode);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullToolWithPrompt() throws Exception {
+ DiffTools manager = new DiffTools(db);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<String> tool = null;
+ manager.compare(local, remote, tool, BooleanTriState.TRUE, false,
+ BooleanTriState.TRUE, promptHandler, noToolHandler);
+ }
+
+ private Optional<ExecutionResult> invokeCompare(String toolName)
+ throws ToolException {
+ DiffTools manager = new DiffTools(db);
+
+ BooleanTriState prompt = BooleanTriState.UNSET;
+ boolean gui = false;
+ BooleanTriState trustExitCode = BooleanTriState.TRUE;
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.compare(local, remote,
+ Optional.of(toolName), prompt, gui, trustExitCode,
+ promptHandler, noToolHandler);
+ return result;
+ }
+
+ private String getEchoCommand() {
+ return "(echo \"$LOCAL\" \"$REMOTE\") > "
+ + commandResult.getAbsolutePath();
+ }
+
+ private void assertEchoCommandHasCorrectOutput() throws IOException {
+ List<String> actualLines = Files.readAllLines(commandResult.toPath());
+ String actualContent = String.join(System.lineSeparator(), actualLines);
+ actualLines = Arrays.asList(actualContent.split(" "));
+ List<String> expectedLines = Arrays.asList(localFile.getAbsolutePath(),
+ remoteFile.getAbsolutePath());
+ assertEquals("Dummy test tool called with unexpected arguments",
+ expectedLines, actualLines);
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java
new file mode 100644
index 0000000000..94b67b374b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2020-2022, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.diffmergetool;
+
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGETOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.junit.Test;
+
+/**
+ * Testing external merge tools.
+ */
+public class ExternalMergeToolTest extends ExternalToolTestCase {
+
+ @Test(expected = ToolException.class)
+ public void testUserToolWithError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 1;
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName,
+ CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(Boolean.TRUE));
+
+ invokeMerge(toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUserToolWithCommandNotFoundError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 127; // command not found
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ invokeMerge(toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test
+ public void testKdiff3() throws Exception {
+ assumePosixPlatform();
+
+ CommandLineMergeTool autoMergingTool = CommandLineMergeTool.kdiff3;
+ assumeMergeToolIsAvailable(autoMergingTool);
+
+ CommandLineMergeTool tool = autoMergingTool;
+ PreDefinedMergeTool externalTool = new PreDefinedMergeTool(tool.name(),
+ tool.getPath(), tool.getParameters(true),
+ tool.getParameters(false),
+ tool.isExitCodeTrustable() ? BooleanTriState.TRUE
+ : BooleanTriState.FALSE);
+
+ MergeTools manager = new MergeTools(db);
+ ExecutionResult result = manager.merge(local, remote, merged, null,
+ null, externalTool);
+ assertEquals("Expected merge tool to succeed", 0, result.getRc());
+
+ List<String> actualLines = Files.readAllLines(mergedFile.toPath());
+ String actualMergeResult = String.join(System.lineSeparator(),
+ actualLines);
+ String expectedMergeResult = DEFAULT_CONTENT;
+ assertEquals(
+ "Failed to merge equal local and remote versions with pre-defined tool: "
+ + tool.getPath(),
+ expectedMergeResult, actualMergeResult);
+ }
+
+ @Test
+ public void testUserDefinedTool() throws Exception {
+ String customToolName = "customTool";
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> tools = manager.getUserDefinedTools();
+ ExternalMergeTool externalTool = tools.get(customToolName);
+ manager.merge(local, remote, merged, base, null, externalTool);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testUserDefinedToolWithPrompt() throws Exception {
+ String customToolName = "customTool";
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.merge(local, remote, merged, base, null,
+ Optional.of(customToolName), BooleanTriState.TRUE, false,
+ promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+
+ List<String> actualToolPrompts = promptHandler.toolPrompts;
+ List<String> expectedToolPrompts = Arrays.asList("customTool");
+ assertEquals("Expected a user prompt for custom tool call",
+ expectedToolPrompts, actualToolPrompts);
+
+ assertEquals("Expected to no informing about missing tools",
+ Collections.EMPTY_LIST, noToolHandler.missingTools);
+ }
+
+ @Test
+ public void testUserDefinedToolWithCancelledPrompt() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.merge(local, remote, merged,
+ base, null, Optional.empty(), BooleanTriState.TRUE, false,
+ promptHandler, noToolHandler);
+ assertFalse("Expected no result if user cancels the operation",
+ result.isPresent());
+ }
+
+ @Test
+ public void testAllTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, "echo");
+
+ MergeTools manager = new MergeTools(db);
+ Set<String> actualToolNames = manager.getAllToolNames();
+ Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolName);
+ CommandLineMergeTool[] defaultTools = CommandLineMergeTool.values();
+ for (CommandLineMergeTool defaultTool : defaultTools) {
+ String toolName = defaultTool.name();
+ expectedToolNames.add(toolName);
+ }
+ assertEquals("Incorrect set of external merge tools", expectedToolNames,
+ actualToolNames);
+ }
+
+ @Test
+ public void testOverridePredefinedToolPath() {
+ String toolName = CommandLineMergeTool.guiffy.name();
+ String customToolPath = "/usr/bin/echo";
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ "echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_PATH,
+ customToolPath);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> tools = manager.getUserDefinedTools();
+ ExternalMergeTool mergeTool = tools.get(toolName);
+ assertNotNull("Expected tool \"" + toolName + "\" to be user defined",
+ mergeTool);
+
+ String toolPath = mergeTool.getPath();
+ assertEquals("Expected external merge tool to have an overriden path",
+ customToolPath, toolPath);
+ }
+
+ @Test
+ public void testUserDefinedTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolname = "customTool";
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_CMD, "echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_PATH, "/usr/bin/echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_PROMPT, String.valueOf(false));
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_GUITOOL, String.valueOf(false));
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(false));
+ MergeTools manager = new MergeTools(db);
+ Set<String> actualToolNames = manager.getUserDefinedTools().keySet();
+ Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolname);
+ assertEquals("Incorrect set of external merge tools", expectedToolNames,
+ actualToolNames);
+ }
+
+ @Test
+ public void testCompare() throws ToolException {
+ String toolName = "customTool";
+
+ FileBasedConfig config = db.getConfig();
+ // the default merge tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ String command = getEchoCommand();
+
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ Optional<ExecutionResult> result = invokeMerge(toolName);
+ assertTrue("Expected external merge tool result to be available",
+ result.isPresent());
+ int expectedCompareResult = 0;
+ assertEquals("Incorrect compare result for external merge tool",
+ expectedCompareResult, result.get().getRc());
+ }
+
+ @Test
+ public void testDefaultTool() throws Exception {
+ String toolName = "customTool";
+ String guiToolName = "customGuiTool";
+
+ FileBasedConfig config = db.getConfig();
+ // the default merge tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ MergeTools manager = new MergeTools(db);
+ boolean gui = false;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured mergetool to be the default external merge tool",
+ toolName, defaultToolName);
+
+ gui = true;
+ String defaultGuiToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected default mergetool to not be set",
+ defaultGuiToolName);
+
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_GUITOOL,
+ guiToolName);
+ manager = new MergeTools(db);
+ defaultGuiToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured mergetool to be the default external merge guitool",
+ guiToolName, defaultGuiToolName);
+ }
+
+ @Test
+ public void testOverridePreDefinedToolPath() {
+ String newToolPath = "/tmp/path/";
+
+ CommandLineMergeTool[] defaultTools = CommandLineMergeTool.values();
+ assertTrue("Expected to find pre-defined external merge tools",
+ defaultTools.length > 0);
+
+ CommandLineMergeTool overridenTool = defaultTools[0];
+ String overridenToolName = overridenTool.name();
+ String overridenToolPath = newToolPath + overridenToolName;
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, overridenToolName,
+ CONFIG_KEY_PATH, overridenToolPath);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> availableTools = manager
+ .getPredefinedTools(true);
+ ExternalMergeTool externalMergeTool = availableTools
+ .get(overridenToolName);
+ String actualMergeToolPath = externalMergeTool.getPath();
+ assertEquals(
+ "Expected pre-defined external merge tool to have overriden path",
+ overridenToolPath, actualMergeToolPath);
+ boolean withBase = true;
+ String expectedMergeToolCommand = overridenToolPath + " "
+ + overridenTool.getParameters(withBase);
+ String actualMergeToolCommand = externalMergeTool.getCommand();
+ assertEquals(
+ "Expected pre-defined external merge tool to have overriden command",
+ expectedMergeToolCommand, actualMergeToolCommand);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUndefinedTool() throws Exception {
+ String toolName = "undefined";
+ invokeMerge(toolName);
+ fail("Expected exception to be thrown due to not defined external merge tool");
+ }
+
+ @Test
+ public void testDefaultToolExecutionWithPrompt() throws Exception {
+ FileBasedConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString("merge", subsection, "tool", "customTool");
+
+ String command = getEchoCommand();
+
+ config.setString("mergetool", "customTool", "cmd", command);
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.merge(local, remote, merged, base, null, Optional.empty(),
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testNoDefaultToolName() {
+ MergeTools manager = new MergeTools(db);
+ boolean gui = false;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+
+ gui = true;
+ defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullTool() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = null;
+ MissingToolHandler noToolHandler = null;
+
+ Optional<String> tool = null;
+
+ manager.merge(local, remote, merged, base, null, tool,
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullToolWithPrompt() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<String> tool = null;
+
+ manager.merge(local, remote, merged, base, null, tool,
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+ }
+
+ private Optional<ExecutionResult> invokeMerge(String toolName)
+ throws ToolException {
+ BooleanTriState prompt = BooleanTriState.UNSET;
+ boolean gui = false;
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.merge(local, remote, merged,
+ base, null, Optional.of(toolName), prompt, gui, promptHandler,
+ noToolHandler);
+ return result;
+ }
+
+ private void assumeMergeToolIsAvailable(
+ CommandLineMergeTool autoMergingTool) {
+ boolean isAvailable = ExternalToolUtils.isToolAvailable(db.getFS(),
+ db.getDirectory(), db.getWorkTree(), autoMergingTool.getPath());
+ assumeTrue("Assuming external tool is available: "
+ + autoMergingTool.name(), isAvailable);
+ }
+
+ private String getEchoCommand() {
+ return "(echo $LOCAL $REMOTE $MERGED $BASE) > "
+ + commandResult.getAbsolutePath();
+ }
+
+ private void assertEchoCommandHasCorrectOutput() throws IOException {
+ List<String> actualLines = Files.readAllLines(commandResult.toPath());
+ String actualContent = String.join(System.lineSeparator(), actualLines);
+ actualLines = Arrays.asList(actualContent.split(" "));
+ List<String> expectedLines = Arrays.asList(localFile.getAbsolutePath(),
+ remoteFile.getAbsolutePath(), mergedFile.getAbsolutePath(),
+ baseFile.getAbsolutePath());
+ assertEquals("Dummy test tool called with unexpected arguments",
+ expectedLines, actualLines);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java
index 0cc12978a8..7a6ff46578 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java
@@ -11,6 +11,8 @@ package org.eclipse.jgit.internal.diffmergetool;
import java.io.File;
import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.util.FS;
@@ -36,6 +38,14 @@ public abstract class ExternalToolTestCase extends RepositoryTestCase {
protected File commandResult;
+ protected FileElement local;
+
+ protected FileElement remote;
+
+ protected FileElement merged;
+
+ protected FileElement base;
+
@Before
@Override
public void setUp() throws Exception {
@@ -51,6 +61,15 @@ public abstract class ExternalToolTestCase extends RepositoryTestCase {
baseFile.deleteOnExit();
commandResult = writeTrashFile("commandResult.txt", "");
commandResult.deleteOnExit();
+
+ local = new FileElement(localFile.getAbsolutePath(),
+ FileElement.Type.LOCAL);
+ remote = new FileElement(remoteFile.getAbsolutePath(),
+ FileElement.Type.REMOTE);
+ merged = new FileElement(mergedFile.getAbsolutePath(),
+ FileElement.Type.MERGED);
+ base = new FileElement(baseFile.getAbsolutePath(),
+ FileElement.Type.BASE);
}
@After
@@ -71,4 +90,39 @@ public abstract class ExternalToolTestCase extends RepositoryTestCase {
"This test can run only in Linux tests",
FS.DETECTED instanceof FS_POSIX);
}
+
+ protected static class PromptHandler implements PromptContinueHandler {
+
+ private final boolean promptResult;
+
+ final List<String> toolPrompts = new ArrayList<>();
+
+ private PromptHandler(boolean promptResult) {
+ this.promptResult = promptResult;
+ }
+
+ static PromptHandler acceptPrompt() {
+ return new PromptHandler(true);
+ }
+
+ static PromptHandler cancelPrompt() {
+ return new PromptHandler(false);
+ }
+
+ @Override
+ public boolean prompt(String toolName) {
+ toolPrompts.add(toolName);
+ return promptResult;
+ }
+ }
+
+ protected static class MissingToolHandler implements InformNoToolHandler {
+
+ final List<String> missingTools = new ArrayList<>();
+
+ @Override
+ public void inform(List<String> toolNames) {
+ missingTools.addAll(toolNames);
+ }
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java
index d95d7814e4..7066f9d422 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitConfigTest.java
@@ -11,7 +11,10 @@
package org.eclipse.jgit.lib;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
@@ -169,6 +172,82 @@ public class CommitConfigTest {
CommitConfig.cleanText(message, CleanupMode.SCISSORS, '#'));
}
+ @Test
+ public void testCommentCharDefault() throws Exception {
+ CommitConfig cfg = parse("");
+ assertEquals('#', cfg.getCommentChar());
+ assertFalse(cfg.isAutoCommentChar());
+ }
+
+ @Test
+ public void testCommentCharAuto() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar = auto\n");
+ assertEquals('#', cfg.getCommentChar());
+ assertTrue(cfg.isAutoCommentChar());
+ }
+
+ @Test
+ public void testCommentCharEmpty() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar =\n");
+ assertEquals('#', cfg.getCommentChar());
+ }
+
+ @Test
+ public void testCommentCharInvalid() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar = \" \"\n");
+ assertEquals('#', cfg.getCommentChar());
+ }
+
+ @Test
+ public void testCommentCharNonAscii() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar = รถ\n");
+ assertEquals('#', cfg.getCommentChar());
+ }
+
+ @Test
+ public void testCommentChar() throws Exception {
+ CommitConfig cfg = parse("[core]\n\tcommentChar = _\n");
+ assertEquals('_', cfg.getCommentChar());
+ }
+
+ @Test
+ public void testDetermineCommentChar() throws Exception {
+ String text = "A commit message\n\nBody\n";
+ assertEquals('#', CommitConfig.determineCommentChar(text));
+ }
+
+ @Test
+ public void testDetermineCommentChar2() throws Exception {
+ String text = "A commit message\n\nBody\n\n# Conflicts:\n#\tfoo.txt\n";
+ char ch = CommitConfig.determineCommentChar(text);
+ assertNotEquals('#', ch);
+ assertTrue(ch > ' ' && ch < 127);
+ }
+
+ @Test
+ public void testDetermineCommentChar3() throws Exception {
+ String text = "A commit message\n\n;Body\n\n# Conflicts:\n#\tfoo.txt\n";
+ char ch = CommitConfig.determineCommentChar(text);
+ assertNotEquals('#', ch);
+ assertNotEquals(';', ch);
+ assertTrue(ch > ' ' && ch < 127);
+ }
+
+ @Test
+ public void testDetermineCommentChar4() throws Exception {
+ String text = "A commit message\n\nBody\n\n # Conflicts:\n\t #\tfoo.txt\n";
+ char ch = CommitConfig.determineCommentChar(text);
+ assertNotEquals('#', ch);
+ assertTrue(ch > ' ' && ch < 127);
+ }
+
+ @Test
+ public void testDetermineCommentChar5() throws Exception {
+ String text = "A commit message\n\nBody\n\n#a\n;b\n@c\n!d\n$\n%\n^\n&\n|\n:";
+ char ch = CommitConfig.determineCommentChar(text);
+ assertEquals(0, ch);
+ }
+
private static CommitConfig parse(String content)
throws ConfigInvalidException {
Config c = new Config();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
index b56308cb72..ef0817adb8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
@@ -443,6 +443,26 @@ public class RefSpecTest {
a.setDestination("refs/remotes/origin/*/*");
}
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidNegativeAndForce() {
+ assertNotNull(new RefSpec("^+refs/heads/master"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidForceAndNegative() {
+ assertNotNull(new RefSpec("+^refs/heads/master"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidNegativeNoSrcDest() {
+ assertNotNull(new RefSpec("^"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidNegativeBothSrcDest() {
+ assertNotNull(new RefSpec("^refs/heads/*:refs/heads/*"));
+ }
+
@Test
public void sourceOnlywithWildcard() {
RefSpec a = new RefSpec("refs/heads/*",
@@ -480,4 +500,32 @@ public class RefSpecTest {
assertTrue(a.isMatching());
assertTrue(a.isForceUpdate());
}
+
+ @Test
+ public void negativeRefSpecWithDest() {
+ RefSpec a = new RefSpec("^:refs/readonly/*");
+ assertTrue(a.isNegative());
+ assertNull(a.getSource());
+ assertEquals(a.getDestination(), "refs/readonly/*");
+ }
+
+ // Because of some of the API's existing behavior, without a colon at the
+ // end of the refspec, dest will be null.
+ @Test
+ public void negativeRefSpecWithSrcAndNullDest() {
+ RefSpec a = new RefSpec("^refs/testdata/*");
+ assertTrue(a.isNegative());
+ assertNull(a.getDestination());
+ assertEquals(a.getSource(), "refs/testdata/*");
+ }
+
+ // Because of some of the API's existing behavior, with a colon at the end
+ // of the refspec, dest will be empty.
+ @Test
+ public void negativeRefSpecWithSrcAndEmptyDest() {
+ RefSpec a = new RefSpec("^refs/testdata/*:");
+ assertTrue(a.isNegative());
+ assertTrue(a.getDestination().isEmpty());
+ assertEquals(a.getSource(), "refs/testdata/*");
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java
new file mode 100644
index 0000000000..7ac83195fb
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class SideBandInputStreamTest {
+
+ private StringWriter messages;
+
+ private SideBandInputStream sideband;
+
+ @Before
+ public void setup() {
+ messages = new StringWriter();
+ }
+
+ @Test
+ public void progressSingleCR() throws IOException {
+ init(packet("message\r"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message\r", messages.toString());
+ }
+
+ @Test
+ public void progressSingleLF() throws IOException {
+ init(packet("message\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message\n", messages.toString());
+ }
+
+ @Test
+ public void progressSingleCRLF() throws IOException {
+ init(packet("message\r\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message\r\n", messages.toString());
+ }
+
+ @Test
+ public void progressMultiCR() throws IOException {
+ init(packet("message 0%\rmessage 100%\r"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\rmessage 100%\r", messages.toString());
+ }
+
+ @Test
+ public void progressMultiLF() throws IOException {
+ init(packet("message 0%\nmessage 100%\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressMultiCRLF() throws IOException {
+ init(packet("message 0%\r\nmessage 100%\r\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r\nmessage 100%\r\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartial() throws IOException {
+ init(packet("message"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialTwoCR() throws IOException {
+ init(packet("message") + packet("message\r"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessage\r", messages.toString());
+ }
+
+ @Test
+ public void progressPartialTwoLF() throws IOException {
+ init(packet("message") + packet("message\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessage\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialTwoCRLF() throws IOException {
+ init(packet("message") + packet("message\r\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessage\r\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialThreeCR() throws IOException {
+ init(packet("message") + packet("message") + packet("message\r"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessagemessage\r", messages.toString());
+ }
+
+ @Test
+ public void progressPartialThreeLF() throws IOException {
+ init(packet("message") + packet("message") + packet("message\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessagemessage\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialThreeCRLF() throws IOException {
+ init(packet("message") + packet("message") + packet("message\r\n"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("messagemessagemessage\r\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialCR() throws IOException {
+ init(packet("message 0%\rmessage 100%"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\rmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialLF() throws IOException {
+ init(packet("message 0%\nmessage 100%"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\n", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialCRLF() throws IOException {
+ init(packet("message 0%\r\nmessage 100%"));
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r\n", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\r\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialSplitCR() throws IOException {
+ init(packet("message") + "0006\001a" + packet(" 0%\rmessa")
+ + packet("ge 100%"));
+ assertEquals('a', sideband.read());
+ assertEquals("", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\rmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialSplitLF() throws IOException {
+ init(packet("message") + "0006\001a" + packet(" 0%\nmessa")
+ + packet("ge 100%"));
+ assertEquals('a', sideband.read());
+ assertEquals("", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\n", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressPartialSplitCRLF() throws IOException {
+ init(packet("message") + "0006\001a" + packet(" 0%\r\nmessa")
+ + packet("ge 100%"));
+ assertEquals('a', sideband.read());
+ assertEquals("", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\r\n", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\r\nmessage 100%\n", messages.toString());
+ }
+
+ @Test
+ public void progressInterleaved() throws IOException {
+ init(packet("message 0%\r") + "0006\001a" + packet("message 10%")
+ + "0006\001b" + packet("\rmessage 100%\n"));
+ assertEquals('a', sideband.read());
+ assertEquals("message 0%\r", messages.toString());
+ assertEquals('b', sideband.read());
+ assertEquals("message 0%\r", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\rmessage 10%\rmessage 100%\n",
+ messages.toString());
+ }
+
+ @Test
+ public void progressInterleavedPartial() throws IOException {
+ init(packet("message 0%\r") + "0006\001a" + packet("message 10%")
+ + "0006\001b" + packet("\rmessage 100%"));
+ assertEquals('a', sideband.read());
+ assertEquals("message 0%\r", messages.toString());
+ assertEquals('b', sideband.read());
+ assertEquals("message 0%\r", messages.toString());
+ assertTrue(sideband.read() < 0);
+ assertEquals("message 0%\rmessage 10%\r", messages.toString());
+ sideband.drainMessages();
+ assertEquals("message 0%\rmessage 10%\rmessage 100%\n",
+ messages.toString());
+ }
+
+ private String packet(String data) {
+ return String.format("%04x\002%s", Integer.valueOf(data.length() + 5),
+ data);
+ }
+
+ private void init(String packets) {
+ InputStream rawIn = new ByteArrayInputStream(
+ (packets + "0000").getBytes(StandardCharsets.UTF_8));
+ sideband = new SideBandInputStream(rawIn, null, messages, null);
+ }
+}