diff options
Diffstat (limited to 'org.eclipse.jgit.test/tst/org')
61 files changed, 2689 insertions, 374 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java index c67c86a937..687926bd8d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java @@ -43,6 +43,7 @@ */ package org.eclipse.jgit.api; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.util.FileUtils.RECURSIVE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -118,7 +119,7 @@ public class AddCommandTest extends RepositoryTestCase { public void testAddExistingSingleFile() throws IOException, GitAPIException { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } @@ -489,7 +490,7 @@ public class AddCommandTest extends RepositoryTestCase { GitAPIException { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("row1\r\nrow2"); } @@ -519,7 +520,7 @@ public class AddCommandTest extends RepositoryTestCase { data.append("row1\r\nrow2"); } String crData = data.toString(); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print(crData); } String lfData = data.toString().replaceAll("\r", ""); @@ -544,7 +545,7 @@ public class AddCommandTest extends RepositoryTestCase { GitAPIException { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("row1\r\nrow2\u0000"); } @@ -570,7 +571,7 @@ public class AddCommandTest extends RepositoryTestCase { FileUtils.mkdir(new File(db.getWorkTree(), "sub")); File file = new File(db.getWorkTree(), "sub/a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } @@ -588,7 +589,7 @@ public class AddCommandTest extends RepositoryTestCase { GitAPIException { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } @@ -597,7 +598,7 @@ public class AddCommandTest extends RepositoryTestCase { dc.getEntry(0).getObjectId(); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("other content"); } @@ -613,7 +614,7 @@ public class AddCommandTest extends RepositoryTestCase { public void testAddExistingSingleFileTwiceWithCommit() throws Exception { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } @@ -624,7 +625,7 @@ public class AddCommandTest extends RepositoryTestCase { git.commit().setMessage("commit a.txt").call(); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("other content"); } @@ -640,7 +641,7 @@ public class AddCommandTest extends RepositoryTestCase { public void testAddRemovedFile() throws Exception { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } @@ -663,7 +664,7 @@ public class AddCommandTest extends RepositoryTestCase { public void testAddRemovedCommittedFile() throws Exception { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } @@ -690,13 +691,13 @@ public class AddCommandTest extends RepositoryTestCase { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } File file2 = new File(db.getWorkTree(), "b.txt"); FileUtils.createNewFile(file2); - try (PrintWriter writer = new PrintWriter(file2)) { + try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) { writer.print("content b"); } @@ -707,12 +708,12 @@ public class AddCommandTest extends RepositoryTestCase { addEntryToBuilder("b.txt", file2, newObjectInserter, builder, 0); addEntryToBuilder("a.txt", file, newObjectInserter, builder, 1); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("other content"); } addEntryToBuilder("a.txt", file, newObjectInserter, builder, 3); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("our content"); } addEntryToBuilder("a.txt", file, newObjectInserter, builder, 2) @@ -743,13 +744,13 @@ public class AddCommandTest extends RepositoryTestCase { public void testAddTwoFiles() throws Exception { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } File file2 = new File(db.getWorkTree(), "b.txt"); FileUtils.createNewFile(file2); - try (PrintWriter writer = new PrintWriter(file2)) { + try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) { writer.print("content b"); } @@ -767,13 +768,13 @@ public class AddCommandTest extends RepositoryTestCase { FileUtils.mkdir(new File(db.getWorkTree(), "sub")); File file = new File(db.getWorkTree(), "sub/a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } File file2 = new File(db.getWorkTree(), "sub/b.txt"); FileUtils.createNewFile(file2); - try (PrintWriter writer = new PrintWriter(file2)) { + try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) { writer.print("content b"); } @@ -791,19 +792,19 @@ public class AddCommandTest extends RepositoryTestCase { FileUtils.mkdir(new File(db.getWorkTree(), "sub")); File file = new File(db.getWorkTree(), "sub/a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } File ignoreFile = new File(db.getWorkTree(), ".gitignore"); FileUtils.createNewFile(ignoreFile); - try (PrintWriter writer = new PrintWriter(ignoreFile)) { + try (PrintWriter writer = new PrintWriter(ignoreFile, UTF_8.name())) { writer.print("sub/b.txt"); } File file2 = new File(db.getWorkTree(), "sub/b.txt"); FileUtils.createNewFile(file2); - try (PrintWriter writer = new PrintWriter(file2)) { + try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) { writer.print("content b"); } @@ -821,13 +822,13 @@ public class AddCommandTest extends RepositoryTestCase { FileUtils.mkdir(new File(db.getWorkTree(), "sub")); File file = new File(db.getWorkTree(), "sub/a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } File file2 = new File(db.getWorkTree(), "sub/b.txt"); FileUtils.createNewFile(file2); - try (PrintWriter writer = new PrintWriter(file2)) { + try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) { writer.print("content b"); } @@ -849,13 +850,13 @@ public class AddCommandTest extends RepositoryTestCase { FileUtils.mkdir(new File(db.getWorkTree(), "sub")); File file = new File(db.getWorkTree(), "sub/a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } File file2 = new File(db.getWorkTree(), "sub/b.txt"); FileUtils.createNewFile(file2); - try (PrintWriter writer = new PrintWriter(file2)) { + try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) { writer.print("content b"); } @@ -872,12 +873,12 @@ public class AddCommandTest extends RepositoryTestCase { // new unstaged file sub/c.txt File file3 = new File(db.getWorkTree(), "sub/c.txt"); FileUtils.createNewFile(file3); - try (PrintWriter writer = new PrintWriter(file3)) { + try (PrintWriter writer = new PrintWriter(file3, UTF_8.name())) { writer.print("content c"); } // file sub/a.txt is modified - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("modified content"); } @@ -904,13 +905,13 @@ public class AddCommandTest extends RepositoryTestCase { FileUtils.mkdir(new File(db.getWorkTree(), "sub")); File file = new File(db.getWorkTree(), "sub/a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } File file2 = new File(db.getWorkTree(), "sub/b.txt"); FileUtils.createNewFile(file2); - try (PrintWriter writer = new PrintWriter(file2)) { + try (PrintWriter writer = new PrintWriter(file2, UTF_8.name())) { writer.print("content b"); } @@ -927,12 +928,12 @@ public class AddCommandTest extends RepositoryTestCase { // new unstaged file sub/c.txt File file3 = new File(db.getWorkTree(), "sub/c.txt"); FileUtils.createNewFile(file3); - try (PrintWriter writer = new PrintWriter(file3)) { + try (PrintWriter writer = new PrintWriter(file3, UTF_8.name())) { writer.print("content c"); } // file sub/a.txt is modified - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("modified content"); } @@ -1244,7 +1245,8 @@ public class AddCommandTest extends RepositoryTestCase { ConfigConstants.CONFIG_KEY_DIRNOGITLINKS, true); config.save(); - assert (db.getConfig().get(WorkingTreeOptions.KEY).isDirNoGitLinks()); + assertTrue( + db.getConfig().get(WorkingTreeOptions.KEY).isDirNoGitLinks()); try (Git git = new Git(db)) { git.add().addFilepattern("nested-repo").call(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java index fbec024a86..0f2e6b8ac6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java @@ -42,6 +42,7 @@ */ package org.eclipse.jgit.api; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -406,7 +407,9 @@ public class ArchiveCommandTest extends RepositoryTestCase { @Override public void putEntry(MockOutputStream out, ObjectId tree, String path, FileMode mode, ObjectLoader loader) { - String content = mode != FileMode.TREE ? new String(loader.getBytes()) : null; + String content = mode != FileMode.TREE + ? new String(loader.getBytes(), UTF_8) + : null; entries.put(path, content); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java index 7a1d222ca0..7e73084e8e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java @@ -44,6 +44,7 @@ package org.eclipse.jgit.api; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.io.File; @@ -489,4 +490,73 @@ public class BlameCommandTest extends RepositoryTestCase { assertEquals(side, lines.getSourceCommit(2)); } } + + @Test + public void testBlameWithNulByteInHistory() throws Exception { + try (Git git = new Git(db)) { + String[] content1 = { "First line", "Another line" }; + writeTrashFile("file.txt", join(content1)); + git.add().addFilepattern("file.txt").call(); + RevCommit c1 = git.commit().setMessage("create file").call(); + + String[] content2 = { "First line", "Second line with NUL >\000<", + "Another line" }; + assertTrue("Content should contain a NUL byte", + content2[1].indexOf(0) > 0); + writeTrashFile("file.txt", join(content2)); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("add line with NUL").call(); + + String[] content3 = { "First line", "Second line with NUL >\000<", + "Third line" }; + writeTrashFile("file.txt", join(content3)); + git.add().addFilepattern("file.txt").call(); + RevCommit c3 = git.commit().setMessage("change third line").call(); + + String[] content4 = { "First line", "Second line with NUL >\\000<", + "Third line" }; + assertTrue("Content should not contain a NUL byte", + content4[1].indexOf(0) < 0); + writeTrashFile("file.txt", join(content4)); + git.add().addFilepattern("file.txt").call(); + RevCommit c4 = git.commit().setMessage("fix NUL line").call(); + + BlameResult lines = git.blame().setFilePath("file.txt").call(); + assertEquals(3, lines.getResultContents().size()); + assertEquals(c1, lines.getSourceCommit(0)); + assertEquals(c4, lines.getSourceCommit(1)); + assertEquals(c3, lines.getSourceCommit(2)); + } + } + + @Test + public void testBlameWithNulByteInTopRevision() throws Exception { + try (Git git = new Git(db)) { + String[] content1 = { "First line", "Another line" }; + writeTrashFile("file.txt", join(content1)); + git.add().addFilepattern("file.txt").call(); + RevCommit c1 = git.commit().setMessage("create file").call(); + + String[] content2 = { "First line", "Second line with NUL >\000<", + "Another line" }; + assertTrue("Content should contain a NUL byte", + content2[1].indexOf(0) > 0); + writeTrashFile("file.txt", join(content2)); + git.add().addFilepattern("file.txt").call(); + RevCommit c2 = git.commit().setMessage("add line with NUL").call(); + + String[] content3 = { "First line", "Second line with NUL >\000<", + "Third line" }; + writeTrashFile("file.txt", join(content3)); + git.add().addFilepattern("file.txt").call(); + RevCommit c3 = git.commit().setMessage("change third line").call(); + + BlameResult lines = git.blame().setFilePath("file.txt").call(); + assertEquals(3, lines.getResultContents().size()); + assertEquals(c1, lines.getSourceCommit(0)); + assertEquals(c2, lines.getSourceCommit(1)); + assertEquals(c3, lines.getSourceCommit(2)); + } + } + } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java index 08ad7b8bcc..65c20aa9ab 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java @@ -160,7 +160,7 @@ public class CheckoutCommandTest extends RepositoryTestCase { } @Test - public void testCheckoutWithConflict() { + public void testCheckoutWithConflict() throws Exception { CheckoutCommand co = git.checkout(); try { writeTrashFile("Test.txt", "Another change"); @@ -171,6 +171,8 @@ public class CheckoutCommandTest extends RepositoryTestCase { assertEquals(Status.CONFLICTS, co.getResult().getStatus()); assertTrue(co.getResult().getConflictList().contains("Test.txt")); } + git.checkout().setName("master").setForce(true).call(); + assertThat(read("Test.txt"), is("Hello world")); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java index 065b5b4c3e..139f199f7a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java @@ -234,6 +234,27 @@ public class CleanCommandTest extends RepositoryTestCase { } @Test + public void testCleanDirsWithPrefixFolder() throws Exception { + String path = "sub/foo.txt"; + writeTrashFile(path, "sub is a prefix of sub-noclean"); + git.add().addFilepattern(path).call(); + Status beforeCleanStatus = git.status().call(); + assertTrue(beforeCleanStatus.getAdded().contains(path)); + + Set<String> cleanedFiles = git.clean().setCleanDirectories(true).call(); + + // The "sub" directory should not be cleaned. + assertTrue(!cleanedFiles.contains(path + "/")); + + assertTrue(cleanedFiles.contains("File2.txt")); + assertTrue(cleanedFiles.contains("File3.txt")); + assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt")); + assertTrue(cleanedFiles.contains("sub-noclean/File2.txt")); + assertTrue(cleanedFiles.contains("sub-clean/")); + assertTrue(cleanedFiles.size() == 4); + } + + @Test public void testCleanDirsWithSubmodule() throws Exception { SubmoduleAddCommand command = new SubmoduleAddCommand(db); String path = "sub"; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java index 613ca5ce95..f5f65298bc 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java @@ -370,8 +370,7 @@ public class CloneCommandTest extends RepositoryTestCase { } @Test - public void testCloneRepositoryOnlyOneBranch() throws IOException, - JGitInternalException, GitAPIException { + public void testCloneRepositoryOnlyOneBranch() throws Exception { File directory = createTempDirectory("testCloneRepositoryWithBranch"); CloneCommand command = Git.cloneRepository(); command.setBranch("refs/heads/master"); @@ -382,25 +381,47 @@ public class CloneCommandTest extends RepositoryTestCase { Git git2 = command.call(); addRepoToClose(git2.getRepository()); assertNotNull(git2); + assertNull(git2.getRepository().resolve("tag-for-blob")); + assertNotNull(git2.getRepository().resolve("tag-initial")); assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); assertEquals("refs/remotes/origin/master", allRefNames(git2 .branchList().setListMode(ListMode.REMOTE).call())); + RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), + Constants.DEFAULT_REMOTE_NAME); + List<RefSpec> specs = cfg.getFetchRefSpecs(); + assertEquals(1, specs.size()); + assertEquals( + new RefSpec("+refs/heads/master:refs/remotes/origin/master"), + specs.get(0)); + } + @Test + public void testBareCloneRepositoryOnlyOneBranch() throws Exception { // Same thing, but now test with bare repo - directory = createTempDirectory("testCloneRepositoryWithBranch_bare"); - command = Git.cloneRepository(); + File directory = createTempDirectory( + "testCloneRepositoryWithBranch_bare"); + CloneCommand command = Git.cloneRepository(); command.setBranch("refs/heads/master"); command.setBranchesToClone(Collections .singletonList("refs/heads/master")); command.setDirectory(directory); command.setURI(fileUri()); command.setBare(true); - git2 = command.call(); + Git git2 = command.call(); addRepoToClose(git2.getRepository()); assertNotNull(git2); + assertNull(git2.getRepository().resolve("tag-for-blob")); + assertNotNull(git2.getRepository().resolve("tag-initial")); assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); assertEquals("refs/heads/master", allRefNames(git2.branchList() .setListMode(ListMode.ALL).call())); + RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), + Constants.DEFAULT_REMOTE_NAME); + List<RefSpec> specs = cfg.getFetchRefSpecs(); + assertEquals(1, specs.size()); + assertEquals( + new RefSpec("+refs/heads/master:refs/heads/master"), + specs.get(0)); } public static String allRefNames(List<Ref> refs) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java index ca0630ea35..c028ca300c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java @@ -42,6 +42,7 @@ */ package org.eclipse.jgit.api; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -120,7 +121,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { // create first file File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content1"); } @@ -131,7 +132,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { // create second file file = new File(db.getWorkTree(), "b.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content2"); } @@ -231,7 +232,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { JGitInternalException, GitAPIException { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content"); } @@ -242,7 +243,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea", tw.getObjectId(0).getName()); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content2"); } commit = git.commit().setMessage("second commit").call(); @@ -265,7 +266,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { // create file File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file)) { + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { writer.print("content1"); } @@ -358,7 +359,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { messageHeader + messageFooter) .setInsertChangeId(true).call(); // we should find a real change id (at the end of the file) - byte[] chars = commit.getFullMessage().getBytes(); + byte[] chars = commit.getFullMessage().getBytes(UTF_8); int lastLineBegin = RawParseUtils.prevLF(chars, chars.length - 2); String lastLine = RawParseUtils.decode(chars, lastLineBegin + 1, chars.length); @@ -371,7 +372,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { .setInsertChangeId(true).call(); // we should find a real change id (in the line as dictated by the // template) - chars = commit.getFullMessage().getBytes(); + chars = commit.getFullMessage().getBytes(UTF_8); int lineStart = 0; int lineEnd = 0; for (int i = 0; i < 4; i++) { @@ -389,7 +390,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { messageHeader + changeIdTemplate + messageFooter) .setInsertChangeId(false).call(); // we should find the untouched template - chars = commit.getFullMessage().getBytes(); + chars = commit.getFullMessage().getBytes(UTF_8); lineStart = 0; lineEnd = 0; for (int i = 0; i < 4; i++) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java index 43c00518a6..2a2a6ba1bc 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java @@ -43,6 +43,7 @@ */ package org.eclipse.jgit.api; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -1304,7 +1305,7 @@ public class CommitOnlyTest extends RepositoryTestCase { return ""; } return new String(tw.getObjectReader().open(tw.getObjectId(0)) - .getBytes()); + .getBytes(), UTF_8); } } catch (Exception e) { return ""; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CrLfNativeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CrLfNativeTest.java new file mode 100644 index 0000000000..c72612850a --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CrLfNativeTest.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.api; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.junit.MockSystemReader; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.CoreConfig.EolStreamType; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.TreeWalk.OperationType; +import org.eclipse.jgit.util.SystemReader; +import org.junit.Test; + +public class CrLfNativeTest extends RepositoryTestCase { + + @Test + public void checkoutWithCrLfNativeUnix() throws Exception { + verifyNativeCheckout(new MockSystemReader() { + { + setUnix(); + } + }); + } + + @Test + public void checkoutWithCrLfNativeWindows() throws Exception { + verifyNativeCheckout(new MockSystemReader() { + { + setWindows(); + } + }); + } + + private void verifyNativeCheckout(SystemReader systemReader) + throws Exception { + SystemReader.setInstance(systemReader); + Git git = Git.wrap(db); + FileBasedConfig config = db.getConfig(); + config.setString("core", null, "autocrlf", "false"); + config.setString("core", null, "eol", "native"); + config.save(); + // core.eol is active only if text is set, or if text=auto + writeTrashFile(".gitattributes", "*.txt text\n"); + File file = writeTrashFile("file.txt", "line 1\nline 2\n"); + git.add().addFilepattern("file.txt").addFilepattern(".gitattributes") + .call(); + git.commit().setMessage("Initial").call(); + // Check-in with core.eol=native normalization + assertEquals( + "[.gitattributes, mode:100644, content:*.txt text\n]" + + "[file.txt, mode:100644, content:line 1\nline 2\n]", + indexState(CONTENT)); + writeTrashFile("file.txt", "something else"); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("New commit").call(); + git.reset().setMode(ResetType.HARD).setRef("HEAD~").call(); + // Check-out should convert to the native line separator + checkFile(file, systemReader.isWindows() ? "line 1\r\nline 2\r\n" + : "line 1\nline 2\n"); + Status status = git.status().call(); + assertTrue("git status should be clean", status.isClean()); + } + + /** + * Verifies the handling of the crlf attribute: crlf == text, -crlf == + * -text, crlf=input == eol=lf + * + * @throws Exception + */ + @Test + public void testCrLfAttribute() throws Exception { + FileBasedConfig config = db.getConfig(); + config.setString("core", null, "autocrlf", "false"); + config.setString("core", null, "eol", "crlf"); + config.save(); + writeTrashFile(".gitattributes", + "*.txt text\n*.crlf crlf\n*.bin -text\n*.nocrlf -crlf\n*.input crlf=input\n*.eol eol=lf"); + writeTrashFile("foo.txt", ""); + writeTrashFile("foo.crlf", ""); + writeTrashFile("foo.bin", ""); + writeTrashFile("foo.nocrlf", ""); + writeTrashFile("foo.input", ""); + writeTrashFile("foo.eol", ""); + Map<String, EolStreamType> inTypes = new HashMap<>(); + Map<String, EolStreamType> outTypes = new HashMap<>(); + try (TreeWalk walk = new TreeWalk(db)) { + walk.addTree(new FileTreeIterator(db)); + while (walk.next()) { + String path = walk.getPathString(); + if (".gitattributes".equals(path)) { + continue; + } + EolStreamType in = walk + .getEolStreamType(OperationType.CHECKIN_OP); + EolStreamType out = walk + .getEolStreamType(OperationType.CHECKOUT_OP); + inTypes.put(path, in); + outTypes.put(path, out); + } + } + assertEquals("", checkTypes("check-in", inTypes)); + assertEquals("", checkTypes("check-out", outTypes)); + } + + private String checkTypes(String prefix, Map<String, EolStreamType> types) { + StringBuilder result = new StringBuilder(); + EolStreamType a = types.get("foo.crlf"); + EolStreamType b = types.get("foo.txt"); + report(result, prefix, "crlf != text", a, b); + a = types.get("foo.nocrlf"); + b = types.get("foo.bin"); + report(result, prefix, "-crlf != -text", a, b); + a = types.get("foo.input"); + b = types.get("foo.eol"); + report(result, prefix, "crlf=input != eol=lf", a, b); + return result.toString(); + } + + private void report(StringBuilder result, String prefix, String label, + EolStreamType a, + EolStreamType b) { + if (a == null || b == null || !a.equals(b)) { + result.append(prefix).append(' ').append(label).append(": ") + .append(toString(a)).append(" != ").append(toString(b)) + .append('\n'); + } + } + + private String toString(EolStreamType type) { + return type == null ? "null" : type.name(); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java index f2093e3940..807079eb23 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java @@ -42,14 +42,16 @@ */ package org.eclipse.jgit.api; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; import java.util.Arrays; import java.util.Collection; @@ -427,7 +429,7 @@ public class DescribeCommandTest extends RepositoryTestCase { } private static void touch(File f, String contents) throws Exception { - try (FileWriter w = new FileWriter(f)) { + try (BufferedWriter w = Files.newBufferedWriter(f.toPath(), UTF_8)) { w.write(contents); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java index 48d373344e..47806cb99d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java @@ -38,6 +38,7 @@ */ package org.eclipse.jgit.api; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -722,10 +723,10 @@ public class EolRepositoryTest extends RepositoryTestCase { } e.attrs = e.attrs.trim(); e.file = new String( - IO.readFully(new File(db.getWorkTree(), pathName))); + IO.readFully(new File(db.getWorkTree(), pathName)), UTF_8); DirCacheEntry dce = dirCache.getEntry(pathName); ObjectLoader open = walk.getObjectReader().open(dce.getObjectId()); - e.index = new String(open.getBytes()); + e.index = new String(open.getBytes(), UTF_8); e.indexContentLength = dce.getLength(); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java index ca86d81301..98dfcc083e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java @@ -148,7 +148,7 @@ public class PushCommandTest extends RepositoryTestCase { git1.push().setRemote("test").setRefSpecs(spec).call(); assertEquals("1:test, 2:" + uri + ", 3:\n" + "refs/heads/master " + commit.getName() + " refs/heads/x " - + ObjectId.zeroId().name(), read(hookOutput)); + + ObjectId.zeroId().name() + "\n", read(hookOutput)); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java index 588387d3e6..dd7230bdbf 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java @@ -86,6 +86,8 @@ public class ResetCommandTest extends RepositoryTestCase { private File indexFile; + private File indexNestedFile; + private File untrackedFile; private DirCacheEntry prestage; @@ -101,7 +103,7 @@ public class ResetCommandTest extends RepositoryTestCase { indexFile = writeTrashFile("a.txt", "content"); // create nested file - writeTrashFile("dir/b.txt", "content"); + indexNestedFile = writeTrashFile("dir/b.txt", "content"); // add files and commit them git.add().addFilepattern("a.txt").addFilepattern("dir/b.txt").call(); @@ -123,13 +125,16 @@ public class ResetCommandTest extends RepositoryTestCase { AmbiguousObjectException, IOException, GitAPIException { setupRepository(); ObjectId prevHead = db.resolve(Constants.HEAD); - assertSameAsHead(git.reset().setMode(ResetType.HARD) + ResetCommand reset = git.reset(); + assertSameAsHead(reset.setMode(ResetType.HARD) .setRef(initialCommit.getName()).call()); + assertFalse("reflog should be enabled", reset.isReflogDisabled()); // check if HEAD points to initial commit now ObjectId head = db.resolve(Constants.HEAD); assertEquals(initialCommit, head); // check if files were removed assertFalse(indexFile.exists()); + assertFalse(indexNestedFile.exists()); assertTrue(untrackedFile.exists()); // fileInIndex must no longer be in HEAD and in the index String fileInIndexPath = indexFile.getAbsolutePath(); @@ -152,6 +157,7 @@ public class ResetCommandTest extends RepositoryTestCase { assertEquals(initialCommit, head); // check if files were removed assertFalse(indexFile.exists()); + assertFalse(indexNestedFile.exists()); assertTrue(untrackedFile.exists()); // fileInIndex must no longer be in HEAD and in the index String fileInIndexPath = indexFile.getAbsolutePath(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java index 196c4f7d9c..08553e1ae4 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesMatcherTest.java @@ -415,6 +415,14 @@ public class AttributesMatcherTest { } } + @Test + public void testFileNameWithLineTerminator() { + assertMatched("a?", "a\r"); + assertMatched("a?", "dir/a\r"); + assertMatched("*a", "\ra"); + assertMatched("dir/*a*", "dir/\ra\r"); + } + /** * Check for a match. If target ends with "/", match will assume that the * target is meant to be a directory. diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java index f0d3c3690f..f4ccf0506b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java @@ -42,6 +42,7 @@ */ package org.eclipse.jgit.attributes; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.attributes.Attribute.State.SET; import static org.eclipse.jgit.attributes.Attribute.State.UNSET; import static org.junit.Assert.assertEquals; @@ -88,7 +89,7 @@ public class AttributesNodeTest { String attributeFileContent = "*.type1 A -B C=value\n" + "*.type2 -A B C=value2"; - is = new ByteArrayInputStream(attributeFileContent.getBytes()); + is = new ByteArrayInputStream(attributeFileContent.getBytes(UTF_8)); AttributesNode node = new AttributesNode(); node.parse(is); assertAttribute("file.type1", node, @@ -102,7 +103,7 @@ public class AttributesNodeTest { String attributeFileContent = "!*.type1 A -B C=value\n" + "!*.type2 -A B C=value2"; - is = new ByteArrayInputStream(attributeFileContent.getBytes()); + is = new ByteArrayInputStream(attributeFileContent.getBytes(UTF_8)); AttributesNode node = new AttributesNode(); node.parse(is); assertAttribute("file.type1", node, new Attributes()); @@ -113,7 +114,7 @@ public class AttributesNodeTest { public void testEmptyNegativeAttributeKey() throws IOException { String attributeFileContent = "*.type1 - \n" // + "*.type2 - -A"; - is = new ByteArrayInputStream(attributeFileContent.getBytes()); + is = new ByteArrayInputStream(attributeFileContent.getBytes(UTF_8)); AttributesNode node = new AttributesNode(); node.parse(is); assertAttribute("file.type1", node, new Attributes()); @@ -125,7 +126,7 @@ public class AttributesNodeTest { String attributeFileContent = "*.type1 = \n" // + "*.type2 =value\n"// + "*.type3 attr=\n"; - is = new ByteArrayInputStream(attributeFileContent.getBytes()); + is = new ByteArrayInputStream(attributeFileContent.getBytes(UTF_8)); AttributesNode node = new AttributesNode(); node.parse(is); assertAttribute("file.type1", node, new Attributes()); @@ -140,7 +141,7 @@ public class AttributesNodeTest { + " \n" // + "*.type2 -A B C=value2"; - is = new ByteArrayInputStream(attributeFileContent.getBytes()); + is = new ByteArrayInputStream(attributeFileContent.getBytes(UTF_8)); AttributesNode node = new AttributesNode(); node.parse(is); assertAttribute("file.type1", node, @@ -156,7 +157,7 @@ public class AttributesNodeTest { + "*.type3 \t\t B\n" // + "*.type3\t-A";// - is = new ByteArrayInputStream(attributeFileContent.getBytes()); + is = new ByteArrayInputStream(attributeFileContent.getBytes(UTF_8)); AttributesNode node = new AttributesNode(); node.parse(is); assertAttribute("file.type1", node, @@ -170,7 +171,7 @@ public class AttributesNodeTest { public void testDoubleAsteriskAtEnd() throws IOException { String attributeFileContent = "dir/** \tA -B\tC=value"; - is = new ByteArrayInputStream(attributeFileContent.getBytes()); + is = new ByteArrayInputStream(attributeFileContent.getBytes(UTF_8)); AttributesNode node = new AttributesNode(); node.parse(is); assertAttribute("dir", node, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java index 73c230ac68..de768118bf 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java @@ -59,9 +59,12 @@ import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheEditor; import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; +import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.treewalk.EmptyTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator; @@ -417,4 +420,64 @@ public class DiffEntryTest extends RepositoryTestCase { assertEquals(FileMode.REGULAR_FILE, diff.getOldMode()); } } + + @Test + public void shouldReportSubmoduleReplacedByFileMove() throws Exception { + // Create a submodule + FileRepository submoduleStandalone = createWorkRepository(); + JGitTestUtil.writeTrashFile(submoduleStandalone, "fileInSubmodule", + "submodule"); + Git submoduleStandaloneGit = Git.wrap(submoduleStandalone); + submoduleStandaloneGit.add().addFilepattern("fileInSubmodule").call(); + submoduleStandaloneGit.commit().setMessage("add file to submodule") + .call(); + + Repository submodule_db = Git.wrap(db).submoduleAdd() + .setPath("modules/submodule") + .setURI(submoduleStandalone.getDirectory().toURI().toString()) + .call(); + File submodule_trash = submodule_db.getWorkTree(); + addRepoToClose(submodule_db); + writeTrashFile("fileInRoot", "root"); + Git rootGit = Git.wrap(db); + rootGit.add().addFilepattern("fileInRoot").call(); + rootGit.commit().setMessage("add submodule and root file").call(); + // Dummy change on fileInRoot + writeTrashFile("fileInRoot", "changed"); + rootGit.add().addFilepattern("fileInRoot").call(); + RevCommit firstCommit = rootGit.commit().setMessage("change root file") + .call(); + // Remove the submodule again and move fileInRoot into that subfolder + rootGit.rm().setCached(true).addFilepattern("modules/submodule").call(); + recursiveDelete(submodule_trash); + JGitTestUtil.deleteTrashFile(db, "fileInRoot"); + // Move the fileInRoot file + writeTrashFile("modules/submodule/fileInRoot", "changed"); + rootGit.rm().addFilepattern("fileInRoot").addFilepattern("modules/") + .call(); + rootGit.add().addFilepattern("modules/").call(); + RevCommit secondCommit = rootGit.commit() + .setMessage("remove submodule and move root file") + .call(); + // Diff should report submodule having been deleted and file moved + // (deleted and added) + try (TreeWalk walk = new TreeWalk(db)) { + walk.addTree(firstCommit.getTree()); + walk.addTree(secondCommit.getTree()); + walk.setRecursive(true); + List<DiffEntry> diffs = DiffEntry.scan(walk); + assertEquals(3, diffs.size()); + DiffEntry e = diffs.get(0); + assertEquals(DiffEntry.ChangeType.DELETE, e.getChangeType()); + assertEquals("fileInRoot", e.getOldPath()); + e = diffs.get(1); + assertEquals(DiffEntry.ChangeType.DELETE, e.getChangeType()); + assertEquals("modules/submodule", e.getOldPath()); + assertEquals(FileMode.GITLINK, e.getOldMode()); + e = diffs.get(2); + assertEquals(DiffEntry.ChangeType.ADD, e.getChangeType()); + assertEquals("modules/submodule/fileInRoot", e.getNewPath()); + } + + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java index 5885d9b7e6..178d62072d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java @@ -66,13 +66,16 @@ public class RawTextTest { } @Test - public void testBinary() { + public void testNul() { String input = "foo-a\nf\0o-b\n"; byte[] data = Constants.encodeASCII(input); final RawText a = new RawText(data); assertArrayEquals(a.content, data); - assertEquals(a.size(), 1); - assertEquals(a.getString(0, 1, false), input); + assertEquals(2, a.size()); + assertEquals("foo-a\n", a.getString(0, 1, false)); + assertEquals("f\0o-b\n", a.getString(1, 2, false)); + assertEquals("foo-a", a.getString(0, 1, true)); + assertEquals("f\0o-b", a.getString(1, 2, true)); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java index d9a4203779..50753ae1bd 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java @@ -90,6 +90,7 @@ public class DirCacheBuilderTest extends RepositoryTestCase { assertEquals(0, e.getRawMode()); try { b.add(e); + fail("did not reject unset file mode"); } catch (IllegalArgumentException err) { assertEquals("FileMode not set for path a", err.getMessage()); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java index f23e4be0ac..1f6861b356 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java @@ -52,16 +52,20 @@ import static org.junit.Assert.fail; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.InvalidRemoteException; -import org.eclipse.jgit.api.errors.RefNotFoundException; +import org.eclipse.jgit.gitrepo.RepoCommand.RemoteFile; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.BlobBasedConfig; @@ -73,6 +77,7 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.FS; import org.junit.Test; @@ -141,6 +146,7 @@ public class RepoCommandTest extends RepositoryTestCase { static class IndexedRepos implements RepoCommand.RemoteReader { Map<String, Repository> uriRepoMap; + IndexedRepos() { uriRepoMap = new HashMap<>(); } @@ -169,19 +175,21 @@ public class RepoCommandTest extends RepositoryTestCase { } @Override - public byte[] readFile(String uri, String refName, String path) - throws GitAPIException, IOException { + public RemoteFile readFileWithMode(String uri, String ref, String path) + throws GitAPIException, IOException { Repository repo = uriRepoMap.get(uri); - - String idStr = refName + ":" + path; - ObjectId id = repo.resolve(idStr); - if (id == null) { - throw new RefNotFoundException( - String.format("repo %s does not have %s", repo.toString(), idStr)); - } - try (ObjectReader reader = repo.newObjectReader()) { - return reader.open(id).getCachedBytes(Integer.MAX_VALUE); + ObjectId refCommitId = sha1(uri, ref); + if (refCommitId == null) { + throw new InvalidRefNameException(MessageFormat + .format(JGitText.get().refNotResolved, ref)); } + RevCommit commit = repo.parseCommit(refCommitId); + TreeWalk tw = TreeWalk.forPath(repo, path, commit.getTree()); + + // TODO(ifrade): Cope better with big files (e.g. using InputStream + // instead of byte[]) + return new RemoteFile(tw.getObjectReader().open(tw.getObjectId(0)) + .getCachedBytes(Integer.MAX_VALUE), tw.getFileMode(0)); } } @@ -199,6 +207,15 @@ public class RepoCommandTest extends RepositoryTestCase { return r; } + private static void assertContents(Path path, String expected) + throws IOException { + try (BufferedReader reader = Files.newBufferedReader(path, UTF_8)) { + String content = reader.readLine(); + assertEquals("Unexpected content in " + path.getFileName(), + expected, content); + } + } + @Test public void runTwiceIsNOP() throws Exception { try (Repository child = cloneRepository(groupADb, true); @@ -474,12 +491,7 @@ public class RepoCommandTest extends RepositoryTestCase { .call(); File hello = new File(db.getWorkTree(), "foo/hello.txt"); assertTrue("submodule should be checked out", hello.exists()); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { - String content = reader.readLine(); - assertEquals("submodule content should be as expected", - "master world", content); - } + assertContents(hello.toPath(), "master world"); } @Test @@ -565,20 +577,66 @@ public class RepoCommandTest extends RepositoryTestCase { // The original file should exist File hello = new File(localDb.getWorkTree(), "foo/hello.txt"); assertTrue("The original file should exist", hello.exists()); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { + assertFalse("The original file should not be executable", + hello.canExecute()); + assertContents(hello.toPath(), "master world"); + // The dest file should also exist + hello = new File(localDb.getWorkTree(), "Hello"); + assertTrue("The destination file should exist", hello.exists()); + assertFalse("The destination file should not be executable", + hello.canExecute()); + assertContents(hello.toPath(), "master world"); + } + + @Test + public void testRepoManifestCopyFile_executable() throws Exception { + try (Git git = new Git(defaultDb)) { + git.checkout().setName("master").call(); + File f = JGitTestUtil.writeTrashFile(defaultDb, "hello.sh", + "content of the executable file"); + f.setExecutable(true); + git.add().addFilepattern("hello.sh").call(); + git.commit().setMessage("Add binary file").call(); + } + + Repository localDb = createWorkRepository(); + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"").append(defaultUri) + .append("\">") + .append("<copyfile src=\"hello.sh\" dest=\"copy-hello.sh\" />") + .append("</project>").append("</manifest>"); + JGitTestUtil.writeTrashFile(localDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(localDb); + command.setPath( + localDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + + // The original file should exist and be an executable + File hello = new File(localDb.getWorkTree(), "foo/hello.sh"); + assertTrue("The original file should exist", hello.exists()); + assertTrue("The original file must be executable", hello.canExecute()); + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { String content = reader.readLine(); assertEquals("The original file should have expected content", - "master world", content); + "content of the executable file", content); } - // The dest file should also exist - hello = new File(localDb.getWorkTree(), "Hello"); + + // The destination file should also exist and be an executable + hello = new File(localDb.getWorkTree(), "copy-hello.sh"); assertTrue("The destination file should exist", hello.exists()); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { + assertTrue("The destination file must be executable", + hello.canExecute()); + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { String content = reader.readLine(); assertEquals("The destination file should have expected content", - "master world", content); + "content of the executable file", content); } } @@ -610,8 +668,8 @@ public class RepoCommandTest extends RepositoryTestCase { assertTrue("The .gitmodules file should exist", gitmodules.exists()); // The first line of .gitmodules file should be expected - try (BufferedReader reader = new BufferedReader( - new FileReader(gitmodules))) { + try (BufferedReader reader = Files + .newBufferedReader(gitmodules.toPath(), UTF_8)) { String content = reader.readLine(); assertEquals( "The first line of .gitmodules file should be as expected", @@ -644,8 +702,8 @@ public class RepoCommandTest extends RepositoryTestCase { .setURI(rootUri) .call(); File hello = new File(db.getWorkTree(), "foo/hello.txt"); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { String content = reader.readLine(); assertEquals("submodule content should be as expected", "branch world", content); @@ -671,12 +729,7 @@ public class RepoCommandTest extends RepositoryTestCase { .setURI(rootUri) .call(); File hello = new File(db.getWorkTree(), "foo/hello.txt"); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { - String content = reader.readLine(); - assertEquals("submodule content should be as expected", - "branch world", content); - } + assertContents(hello.toPath(), "branch world"); } @Test @@ -698,12 +751,7 @@ public class RepoCommandTest extends RepositoryTestCase { .setURI(rootUri) .call(); File hello = new File(db.getWorkTree(), "foo/hello.txt"); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { - String content = reader.readLine(); - assertEquals("submodule content should be as expected", - "branch world", content); - } + assertContents(hello.toPath(), "branch world"); } @Test @@ -771,12 +819,69 @@ public class RepoCommandTest extends RepositoryTestCase { assertFalse("The foo/Hello file should be skipped", foohello.exists()); // The content of Hello file should be expected - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { + assertContents(hello.toPath(), "branch world"); + } + } + + @Test + public void testCopyFileBare_executable() throws Exception { + try (Git git = new Git(defaultDb)) { + git.checkout().setName(BRANCH).call(); + File f = JGitTestUtil.writeTrashFile(defaultDb, "hello.sh", + "content of the executable file"); + f.setExecutable(true); + git.add().addFilepattern("hello.sh").call(); + git.commit().setMessage("Add binary file").call(); + } + + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"master\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"").append(defaultUri) + .append("\" revision=\"").append(BRANCH) + .append("\" >") + .append("<copyfile src=\"hello.txt\" dest=\"Hello\" />") + .append("<copyfile src=\"hello.txt\" dest=\"foo/Hello\" />") + .append("<copyfile src=\"hello.sh\" dest=\"copy-hello.sh\" />") + .append("</project>").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + // Clone it + File directory = createTempDirectory("testCopyFileBare"); + try (Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository()) { + // The Hello file should exist + File hello = new File(localDb.getWorkTree(), "Hello"); + assertTrue("The Hello file should exist", hello.exists()); + // The foo/Hello file should be skipped. + File foohello = new File(localDb.getWorkTree(), "foo/Hello"); + assertFalse("The foo/Hello file should be skipped", + foohello.exists()); + // The content of Hello file should be expected + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { String content = reader.readLine(); assertEquals("The Hello file should have expected content", "branch world", content); } + + // The executable file must be there and preserve the executable bit + File helloSh = new File(localDb.getWorkTree(), "copy-hello.sh"); + assertTrue("Destination file should exist", helloSh.exists()); + assertContents(helloSh.toPath(), "content of the executable file"); + assertTrue("Destination file should be executable", + helloSh.canExecute()); + } } @@ -829,8 +934,8 @@ public class RepoCommandTest extends RepositoryTestCase { // The .gitmodules file should have 'submodule "bar"' and shouldn't // have // 'submodule "foo"' lines. - try (BufferedReader reader = new BufferedReader( - new FileReader(dotmodules))) { + try (BufferedReader reader = Files + .newBufferedReader(dotmodules.toPath(), UTF_8)) { boolean foo = false; boolean bar = false; while (true) { @@ -879,8 +984,8 @@ public class RepoCommandTest extends RepositoryTestCase { } // Check .gitmodules file - try (BufferedReader reader = new BufferedReader( - new FileReader(dotmodules))) { + try (BufferedReader reader = Files + .newBufferedReader(dotmodules.toPath(), UTF_8)) { boolean foo = false; boolean foobar = false; boolean a = false; @@ -935,8 +1040,8 @@ public class RepoCommandTest extends RepositoryTestCase { .call(); File hello = new File(localDb.getWorkTree(), "foo/hello.txt"); assertTrue("submodule should be checked out", hello.exists()); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { String content = reader.readLine(); assertEquals("submodule content should be as expected", "master world", content); @@ -1074,8 +1179,9 @@ public class RepoCommandTest extends RepositoryTestCase { ".gitattributes"); assertTrue("The .gitattributes file should exist", gitattributes.exists()); - try (BufferedReader reader = new BufferedReader( - new FileReader(gitattributes));) { + try (BufferedReader reader = Files + .newBufferedReader(gitattributes.toPath(), + UTF_8)) { String content = reader.readLine(); assertEquals(".gitattributes content should be as expected", "/test a1 a2", content); @@ -1142,12 +1248,7 @@ public class RepoCommandTest extends RepositoryTestCase { .setURI(rootUri) .call(); File hello = new File(db.getWorkTree(), "foo/hello.txt"); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { - String content = reader.readLine(); - assertEquals("submodule content should be as expected", - "branch world", content); - } + assertContents(hello.toPath(), "branch world"); } @Test @@ -1169,8 +1270,8 @@ public class RepoCommandTest extends RepositoryTestCase { .setURI(rootUri) .call(); File hello = new File(db.getWorkTree(), "foo/hello.txt"); - try (BufferedReader reader = new BufferedReader( - new FileReader(hello))) { + try (BufferedReader reader = Files.newBufferedReader(hello.toPath(), + UTF_8)) { String content = reader.readLine(); assertEquals("submodule content should be as expected", "branch world", content); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java index 2a1721e66c..4bd1dab3e8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java @@ -512,6 +512,15 @@ public class FastIgnoreRuleTest { assertMatched("x/**/", "x/y/a/"); } + @Test + public void testFileNameWithLineTerminator() { + assertMatched("a?", "a\r"); + assertMatched("a?", "dir/a\r"); + assertMatched("a?", "a\r/file"); + assertMatched("*a", "\ra"); + assertMatched("dir/*a*", "dir/\ra\r"); + } + private void assertMatched(String pattern, String path) { boolean match = match(pattern, path); String result = path + " is " + (match ? "ignored" : "not ignored") diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java index 804d744ae2..c1811251c6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsFsckTest.java @@ -266,4 +266,59 @@ public class DfsFsckTest { "refs/heads/master"); } + private ObjectId insertGitModules(String contents) throws IOException { + ObjectId blobId = ins.insert(Constants.OBJ_BLOB, + Constants.encode(contents)); + + byte[] blobIdBytes = new byte[OBJECT_ID_LENGTH]; + blobId.copyRawTo(blobIdBytes, 0); + byte[] data = concat(encodeASCII("100644 .gitmodules\0"), blobIdBytes); + ins.insert(Constants.OBJ_TREE, data); + ins.flush(); + + return blobId; + } + + @Test + public void testInvalidGitModules() throws Exception { + String fakeGitmodules = new StringBuilder() + .append("[submodule \"test\"]\n") + .append(" path = xlib\n") + .append(" url = https://example.com/repo/xlib.git\n\n") + .append("[submodule \"test2\"]\n") + .append(" path = zlib\n") + .append(" url = -upayload.sh\n") + .toString(); + + ObjectId blobId = insertGitModules(fakeGitmodules); + + DfsFsck fsck = new DfsFsck(repo); + FsckError errors = fsck.check(null); + assertEquals(errors.getCorruptObjects().size(), 1); + + CorruptObject error = errors.getCorruptObjects().iterator().next(); + assertEquals(error.getId(), blobId); + assertEquals(error.getType(), Constants.OBJ_BLOB); + assertEquals(error.getErrorType(), ErrorType.GITMODULES_URL); + } + + + @Test + public void testValidGitModules() throws Exception { + String fakeGitmodules = new StringBuilder() + .append("[submodule \"test\"]\n") + .append(" path = xlib\n") + .append(" url = https://example.com/repo/xlib.git\n\n") + .append("[submodule \"test2\"]\n") + .append(" path = zlib\n") + .append(" url = ok/path\n") + .toString(); + + insertGitModules(fakeGitmodules); + + DfsFsck fsck = new DfsFsck(repo); + FsckError errors = fsck.check(null); + assertEquals(errors.getCorruptObjects().size(), 0); + } + } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java index deffa04b54..f6cb55870b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java @@ -43,14 +43,16 @@ package org.eclipse.jgit.internal.storage.file; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; import org.eclipse.jgit.lib.ConfigConstants; @@ -120,18 +122,19 @@ public class FileRepositoryBuilderTest extends LocalDiskRepositoryTestCase { Repository repo1 = createWorkRepository(); File dir = createTempDirectory("dir"); File dotGit = new File(dir, Constants.DOT_GIT); - try (FileWriter writer = new FileWriter(dotGit)) { - writer.append("gitdir: " + repo1.getDirectory().getAbsolutePath()).close(); - FileRepositoryBuilder builder = new FileRepositoryBuilder(); + try (BufferedWriter writer = Files.newBufferedWriter(dotGit.toPath(), + UTF_8)) { + writer.append("gitdir: " + repo1.getDirectory().getAbsolutePath()); + } + FileRepositoryBuilder builder = new FileRepositoryBuilder(); - builder.setWorkTree(dir); - builder.setMustExist(true); - Repository repo2 = builder.build(); + builder.setWorkTree(dir); + builder.setMustExist(true); + Repository repo2 = builder.build(); - assertEquals(repo1.getDirectory().getAbsolutePath(), repo2 - .getDirectory().getAbsolutePath()); - assertEquals(dir, repo2.getWorkTree()); - } + assertEquals(repo1.getDirectory().getAbsolutePath(), + repo2.getDirectory().getAbsolutePath()); + assertEquals(dir, repo2.getWorkTree()); } @Test @@ -140,20 +143,20 @@ public class FileRepositoryBuilderTest extends LocalDiskRepositoryTestCase { File dir = new File(repo1.getWorkTree(), "dir"); assertTrue(dir.mkdir()); File dotGit = new File(dir, Constants.DOT_GIT); - try (FileWriter writer = new FileWriter(dotGit)) { - writer.append("gitdir: ../" + Constants.DOT_GIT).close(); - - FileRepositoryBuilder builder = new FileRepositoryBuilder(); - builder.setWorkTree(dir); - builder.setMustExist(true); - Repository repo2 = builder.build(); - - // The tmp directory may be a symlink so the actual path - // may not - assertEquals(repo1.getDirectory().getCanonicalPath(), repo2 - .getDirectory().getCanonicalPath()); - assertEquals(dir, repo2.getWorkTree()); + try (BufferedWriter writer = Files.newBufferedWriter(dotGit.toPath(), + UTF_8)) { + writer.append("gitdir: ../" + Constants.DOT_GIT); } + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + builder.setWorkTree(dir); + builder.setMustExist(true); + Repository repo2 = builder.build(); + + // The tmp directory may be a symlink so the actual path + // may not + assertEquals(repo1.getDirectory().getCanonicalPath(), + repo2.getDirectory().getCanonicalPath()); + assertEquals(dir, repo2.getWorkTree()); } @Test @@ -161,22 +164,23 @@ public class FileRepositoryBuilderTest extends LocalDiskRepositoryTestCase { Repository repo1 = createWorkRepository(); File dir = createTempDirectory("dir"); File dotGit = new File(dir, Constants.DOT_GIT); - try (FileWriter writer = new FileWriter(dotGit)) { + try (BufferedWriter writer = Files.newBufferedWriter(dotGit.toPath(), + UTF_8)) { writer.append( - "gitdir: " + repo1.getDirectory().getAbsolutePath()).close(); - FileRepositoryBuilder builder = new FileRepositoryBuilder(); - - builder.setWorkTree(dir); - builder.findGitDir(dir); - assertEquals(repo1.getDirectory().getAbsolutePath(), builder - .getGitDir().getAbsolutePath()); - builder.setMustExist(true); - Repository repo2 = builder.build(); - - // The tmp directory may be a symlink - assertEquals(repo1.getDirectory().getCanonicalPath(), repo2 - .getDirectory().getCanonicalPath()); - assertEquals(dir, repo2.getWorkTree()); + "gitdir: " + repo1.getDirectory().getAbsolutePath()); } + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + + builder.setWorkTree(dir); + builder.findGitDir(dir); + assertEquals(repo1.getDirectory().getAbsolutePath(), + builder.getGitDir().getAbsolutePath()); + builder.setMustExist(true); + Repository repo2 = builder.build(); + + // The tmp directory may be a symlink + assertEquals(repo1.getDirectory().getCanonicalPath(), + repo2.getDirectory().getCanonicalPath()); + assertEquals(dir, repo2.getWorkTree()); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java index 8cc06d93f2..1d3ca03178 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java @@ -42,6 +42,7 @@ package org.eclipse.jgit.internal.storage.file; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -193,7 +194,8 @@ public class ObjectDirectoryTest extends RepositoryTestCase { String commit = "d3148f9410b071edd4a4c85d2a43d1fa2574b0d2"; try (PrintWriter writer = new PrintWriter( - new File(repository.getDirectory(), Constants.SHALLOW))) { + new File(repository.getDirectory(), Constants.SHALLOW), + UTF_8.name())) { writer.println(commit); } Set<ObjectId> shallowCommits = dir.getShallowCommits(); @@ -209,7 +211,8 @@ public class ObjectDirectoryTest extends RepositoryTestCase { String commit = "X3148f9410b071edd4a4c85d2a43d1fa2574b0d2"; try (PrintWriter writer = new PrintWriter( - new File(repository.getDirectory(), Constants.SHALLOW))) { + new File(repository.getDirectory(), Constants.SHALLOW), + UTF_8.name())) { writer.println(commit); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java index dc05eeabe1..acdaf3aa3c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java @@ -44,6 +44,7 @@ package org.eclipse.jgit.internal.storage.file; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -67,31 +68,31 @@ import org.junit.Test; public class ReflogReaderTest extends SampleDataRepositoryTestCase { static byte[] oneLine = "da85355dfc525c9f6f3927b876f379f46ccf826e 3e7549db262d1e836d9bf0af7e22355468f1717c A O Thor Too <authortoo@wri.tr> 1243028200 +0200\tcommit: Add a toString for debugging to RemoteRefUpdate\n" - .getBytes(); + .getBytes(UTF_8); static byte[] twoLine = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n" + "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n") - .getBytes(); + .getBytes(UTF_8); static byte[] twoLineWithAppendInProgress = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n" + "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n" + "54794942a18a237c57a80719afed44bb78172b10 ") - .getBytes(); + .getBytes(UTF_8); static byte[] aLine = "1111111111111111111111111111111111111111 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to a\n" - .getBytes(); + .getBytes(UTF_8); static byte[] masterLine = "2222222222222222222222222222222222222222 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to master\n" - .getBytes(); + .getBytes(UTF_8); static byte[] headLine = "3333333333333333333333333333333333333333 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to HEAD\n" - .getBytes(); + .getBytes(UTF_8); static byte[] oneLineWithoutComment = "da85355dfc525c9f6f3927b876f379f46ccf826e 3e7549db262d1e836d9bf0af7e22355468f1717c A O Thor Too <authortoo@wri.tr> 1243028200 +0200\n" - .getBytes(); + .getBytes(UTF_8); static byte[] switchBranch = "0d43a6890a19fd657faad1c4cfbe3cb1b47851c3 4809df9c0d8bce5b00955563f77c5a9f25aa0d12 A O Thor Too <authortoo@wri.tr> 1315088009 +0200\tcheckout: moving from new/work to master\n" - .getBytes(); + .getBytes(UTF_8); @Test public void testReadOneLine() throws Exception { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java index 1d188c3148..a84be7e9f0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java @@ -42,6 +42,7 @@ *******************************************************************************/ package org.eclipse.jgit.internal.storage.file; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import java.io.File; @@ -73,9 +74,9 @@ public class ReflogWriterTest extends SampleDataRepositoryTestCase { writer.log("refs/heads/master", oldId, newId, ident, "stash: Add\nmessage\r\nwith line feeds"); - byte[] buffer = new byte[oneLine.getBytes().length]; + byte[] buffer = new byte[oneLine.getBytes(UTF_8).length]; readReflog(buffer); - assertEquals(oneLine, new String(buffer)); + assertEquals(oneLine, new String(buffer, UTF_8)); } private void readReflog(byte[] buffer) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java index a4509695d9..9eb181635f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java @@ -335,9 +335,9 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { public void test002_CreateBadTree() throws Exception { // We won't create a tree entry with an empty filename // + final TreeFormatter formatter = new TreeFormatter(); expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage(JGitText.get().invalidTreeZeroLengthName); - final TreeFormatter formatter = new TreeFormatter(); formatter.append("", FileMode.TREE, ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904")); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/parser/FirstWantTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/parser/FirstWantTest.java new file mode 100644 index 0000000000..b877c598ef --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/parser/FirstWantTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2018, Google LLC. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.internal.transport.parser; + +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 java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.jgit.errors.PackProtocolException; +import org.junit.Test; + +public class FirstWantTest { + + @Test + public void testFirstWantWithOptions() throws PackProtocolException { + String line = "want b9d4d1eb2f93058814480eae9e1b67550f46ee38 " + + "no-progress include-tag ofs-delta agent=JGit/unknown"; + + FirstWant r = FirstWant.fromLine(line); + assertEquals("want b9d4d1eb2f93058814480eae9e1b67550f46ee38", + r.getLine()); + Set<String> capabilities = r.getCapabilities(); + Set<String> expectedCapabilities = new HashSet<>( + Arrays.asList("no-progress", "include-tag", "ofs-delta")); + assertEquals(expectedCapabilities, capabilities); + assertEquals("JGit/unknown", r.getAgent()); + } + + @Test + public void testFirstWantWithoutOptions() throws PackProtocolException { + String line = "want b9d4d1eb2f93058814480eae9e1b67550f46ee38"; + + FirstWant r = FirstWant.fromLine(line); + assertEquals("want b9d4d1eb2f93058814480eae9e1b67550f46ee38", + r.getLine()); + assertTrue(r.getCapabilities().isEmpty()); + assertNull(r.getAgent()); + } + + private String makeFirstWantLine(String capability) { + return String.format("want b9d4d1eb2f93058814480eae9e1b67550f46ee38 %s", capability); + } + + @Test + public void testFirstWantNoWhitespace() { + try { + FirstWant.fromLine( + "want b9d4d1eb2f93058814480eae9e1b67550f400000capability"); + fail("Accepting first want line without SP between oid and first capability"); + } catch (PackProtocolException e) { + // pass + } + } + + @Test + public void testFirstWantOnlyWhitespace() throws PackProtocolException { + FirstWant r = FirstWant + .fromLine("want b9d4d1eb2f93058814480eae9e1b67550f46ee38 "); + assertEquals("want b9d4d1eb2f93058814480eae9e1b67550f46ee38", + r.getLine()); + } + + @Test + public void testFirstWantValidCapabilityNames() + throws PackProtocolException { + List<String> validNames = Arrays.asList( + "c", "cap", "C", "CAP", "1", "1cap", "cap-64k_test", + "-", "-cap", + "_", "_cap"); + + for (String capability: validNames) { + FirstWant r = FirstWant.fromLine(makeFirstWantLine(capability)); + assertEquals(r.getCapabilities().size(), 1); + assertTrue(r.getCapabilities().contains(capability)); + } + } + + @Test + public void testFirstWantValidAgentName() throws PackProtocolException { + FirstWant r = FirstWant.fromLine(makeFirstWantLine("agent=pack.age/Version")); + assertEquals(r.getCapabilities().size(), 0); + assertEquals("pack.age/Version", r.getAgent()); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java index 2d0fe86f93..22dc471552 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java @@ -48,12 +48,13 @@ package org.eclipse.jgit.lib; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MICROSECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.NANOSECONDS; -import static java.util.concurrent.TimeUnit.MICROSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.eclipse.jgit.util.FileUtils.pathToString; import static org.junit.Assert.assertArrayEquals; @@ -68,11 +69,15 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import org.eclipse.jgit.api.MergeCommand.FastForwardMode; import org.eclipse.jgit.errors.ConfigInvalidException; @@ -80,6 +85,7 @@ import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.merge.MergeConfig; import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.SystemReader; import org.junit.After; @@ -96,6 +102,12 @@ public class ConfigTest { // A non-ASCII whitespace character: U+2002 EN QUAD. private static final char WS = '\u2002'; + private static final String REFS_ORIGIN = "+refs/heads/*:refs/remotes/origin/*"; + + private static final String REFS_UPSTREAM = "+refs/heads/*:refs/remotes/upstream/*"; + + private static final String REFS_BACKUP = "+refs/heads/*:refs/remotes/backup/*"; + @Rule public ExpectedException expectedEx = ExpectedException.none(); @@ -692,11 +704,7 @@ public class ConfigTest { assertEquals("", c.getString("a", null, "y")); assertArrayEquals(new String[]{""}, c.getStringList("a", null, "y")); - try { - c.getInt("a", null, "y", 1); - } catch (IllegalArgumentException e) { - assertEquals("Invalid integer value: a.y=", e.getMessage()); - } + assertEquals(1, c.getInt("a", null, "y", 1)); assertNull(c.getString("a", null, "z")); assertArrayEquals(new String[]{}, c.getStringList("a", null, "z")); @@ -713,11 +721,7 @@ public class ConfigTest { assertNull(c.getString("a", null, "y")); assertArrayEquals(new String[]{null}, c.getStringList("a", null, "y")); - try { - c.getInt("a", null, "y", 1); - } catch (IllegalArgumentException e) { - assertEquals("Invalid integer value: a.y=", e.getMessage()); - } + assertEquals(1, c.getInt("a", null, "y", 1)); assertNull(c.getString("a", null, "z")); assertArrayEquals(new String[]{}, c.getStringList("a", null, "z")); @@ -803,11 +807,9 @@ public class ConfigTest { public void testIncludeTooManyRecursions() throws IOException { File config = tmp.newFile("config"); String include = "[include]\npath=" + pathToString(config) + "\n"; - Files.write(config.toPath(), include.getBytes()); - FileBasedConfig fbConfig = new FileBasedConfig(null, config, - FS.DETECTED); + Files.write(config.toPath(), include.getBytes(UTF_8)); try { - fbConfig.load(); + loadConfig(config); fail(); } catch (ConfigInvalidException cie) { for (Throwable t = cie; t != null; t = t.getCause()) { @@ -826,7 +828,7 @@ public class ConfigTest { File config = tmp.newFile("config"); String fooBar = "[foo]\nbar=true\n"; - Files.write(config.toPath(), fooBar.getBytes()); + Files.write(config.toPath(), fooBar.getBytes(UTF_8)); Config parsed = parse("[include]\npath=" + pathToString(config) + "\n"); assertFalse(parsed.getBoolean("foo", "bar", false)); @@ -837,15 +839,13 @@ public class ConfigTest { throws IOException, ConfigInvalidException { File included = tmp.newFile("included"); String content = "[foo]\nbar=true\n"; - Files.write(included.toPath(), content.getBytes()); + Files.write(included.toPath(), content.getBytes(UTF_8)); File config = tmp.newFile("config"); content = "[Include]\npath=" + pathToString(included) + "\n"; - Files.write(config.toPath(), content.getBytes()); + Files.write(config.toPath(), content.getBytes(UTF_8)); - FileBasedConfig fbConfig = new FileBasedConfig(null, config, - FS.DETECTED); - fbConfig.load(); + FileBasedConfig fbConfig = loadConfig(config); assertTrue(fbConfig.getBoolean("foo", "bar", false)); } @@ -854,15 +854,13 @@ public class ConfigTest { throws IOException, ConfigInvalidException { File included = tmp.newFile("included"); String content = "[foo]\nbar=true\n"; - Files.write(included.toPath(), content.getBytes()); + Files.write(included.toPath(), content.getBytes(UTF_8)); File config = tmp.newFile("config"); content = "[include]\nPath=" + pathToString(included) + "\n"; - Files.write(config.toPath(), content.getBytes()); + Files.write(config.toPath(), content.getBytes(UTF_8)); - FileBasedConfig fbConfig = new FileBasedConfig(null, config, - FS.DETECTED); - fbConfig.load(); + FileBasedConfig fbConfig = loadConfig(config); assertTrue(fbConfig.getBoolean("foo", "bar", false)); } @@ -883,15 +881,13 @@ public class ConfigTest { File included = tmp.newFile("included"); String includedPath = pathToString(included); String content = "[include]\npath=\n"; - Files.write(included.toPath(), content.getBytes()); + Files.write(included.toPath(), content.getBytes(UTF_8)); File config = tmp.newFile("config"); String include = "[include]\npath=" + includedPath + "\n"; - Files.write(config.toPath(), include.getBytes()); - FileBasedConfig fbConfig = new FileBasedConfig(null, config, - FS.DETECTED); + Files.write(config.toPath(), include.getBytes(UTF_8)); try { - fbConfig.load(); + loadConfig(config); fail("Expected ConfigInvalidException"); } catch (ConfigInvalidException e) { // Check that there is some exception in the chain that contains @@ -906,6 +902,306 @@ public class ConfigTest { } } + @Test + public void testIncludeSetValueMustNotTouchIncludedLines1() + throws IOException, ConfigInvalidException { + File includedFile = createAllTypesIncludedContent(); + + File configFile = tmp.newFile("config"); + String content = createAllTypesSampleContent("Alice Parker", false, 11, + 21, 31, CoreConfig.AutoCRLF.FALSE, + "+refs/heads/*:refs/remotes/origin/*") + "\n[include]\npath=" + + pathToString(includedFile); + Files.write(configFile.toPath(), content.getBytes(UTF_8)); + + FileBasedConfig fbConfig = loadConfig(configFile); + assertValuesAsIncluded(fbConfig, REFS_ORIGIN, REFS_UPSTREAM); + assertSections(fbConfig, "user", "core", "remote", "include"); + + setAllValuesNew(fbConfig); + assertValuesAsIsSaveLoad(fbConfig, config -> { + assertValuesAsIncluded(config, REFS_BACKUP, REFS_UPSTREAM); + assertSections(fbConfig, "user", "core", "remote", "include"); + }); + } + + @Test + public void testIncludeSetValueMustNotTouchIncludedLines2() + throws IOException, ConfigInvalidException { + File includedFile = createAllTypesIncludedContent(); + + File configFile = tmp.newFile("config"); + String content = "[include]\npath=" + pathToString(includedFile) + "\n" + + createAllTypesSampleContent("Alice Parker", false, 11, 21, 31, + CoreConfig.AutoCRLF.FALSE, + "+refs/heads/*:refs/remotes/origin/*"); + Files.write(configFile.toPath(), content.getBytes(UTF_8)); + + FileBasedConfig fbConfig = loadConfig(configFile); + assertValuesAsConfig(fbConfig, REFS_UPSTREAM, REFS_ORIGIN); + assertSections(fbConfig, "include", "user", "core", "remote"); + + setAllValuesNew(fbConfig); + assertValuesAsIsSaveLoad(fbConfig, config -> { + assertValuesAsNew(config, REFS_UPSTREAM, REFS_BACKUP); + assertSections(fbConfig, "include", "user", "core", "remote"); + }); + } + + @Test + public void testIncludeSetValueOnFileWithJustContainsInclude() + throws IOException, ConfigInvalidException { + File includedFile = createAllTypesIncludedContent(); + + File configFile = tmp.newFile("config"); + String content = "[include]\npath=" + pathToString(includedFile); + Files.write(configFile.toPath(), content.getBytes(UTF_8)); + + FileBasedConfig fbConfig = loadConfig(configFile); + assertValuesAsIncluded(fbConfig, REFS_UPSTREAM); + assertSections(fbConfig, "include", "user", "core", "remote"); + + setAllValuesNew(fbConfig); + assertValuesAsIsSaveLoad(fbConfig, config -> { + assertValuesAsNew(config, REFS_UPSTREAM, REFS_BACKUP); + assertSections(fbConfig, "include", "user", "core", "remote"); + }); + } + + @Test + public void testIncludeSetValueOnFileWithJustEmptySection1() + throws IOException, ConfigInvalidException { + File includedFile = createAllTypesIncludedContent(); + + File configFile = tmp.newFile("config"); + String content = "[user]\n[include]\npath=" + + pathToString(includedFile); + Files.write(configFile.toPath(), content.getBytes(UTF_8)); + + FileBasedConfig fbConfig = loadConfig(configFile); + assertValuesAsIncluded(fbConfig, REFS_UPSTREAM); + assertSections(fbConfig, "user", "include", "core", "remote"); + + setAllValuesNew(fbConfig); + assertValuesAsIsSaveLoad(fbConfig, config -> { + assertValuesAsNewWithName(config, "Alice Muller", REFS_UPSTREAM, + REFS_BACKUP); + assertSections(fbConfig, "user", "include", "core", "remote"); + }); + } + + @Test + public void testIncludeSetValueOnFileWithJustEmptySection2() + throws IOException, ConfigInvalidException { + File includedFile = createAllTypesIncludedContent(); + + File configFile = tmp.newFile("config"); + String content = "[include]\npath=" + pathToString(includedFile) + + "\n[user]"; + Files.write(configFile.toPath(), content.getBytes(UTF_8)); + + FileBasedConfig fbConfig = loadConfig(configFile); + assertValuesAsIncluded(fbConfig, REFS_UPSTREAM); + assertSections(fbConfig, "include", "user", "core", "remote"); + + setAllValuesNew(fbConfig); + assertValuesAsIsSaveLoad(fbConfig, config -> { + assertValuesAsNew(config, REFS_UPSTREAM, REFS_BACKUP); + assertSections(fbConfig, "include", "user", "core", "remote"); + }); + } + + @Test + public void testIncludeSetValueOnFileWithJustExistingSection1() + throws IOException, ConfigInvalidException { + File includedFile = createAllTypesIncludedContent(); + + File configFile = tmp.newFile("config"); + String content = "[user]\nemail=alice@home\n[include]\npath=" + + pathToString(includedFile); + Files.write(configFile.toPath(), content.getBytes(UTF_8)); + + FileBasedConfig fbConfig = loadConfig(configFile); + assertValuesAsIncluded(fbConfig, REFS_UPSTREAM); + assertSections(fbConfig, "user", "include", "core", "remote"); + + setAllValuesNew(fbConfig); + assertValuesAsIsSaveLoad(fbConfig, config -> { + assertValuesAsNewWithName(config, "Alice Muller", REFS_UPSTREAM, + REFS_BACKUP); + assertSections(fbConfig, "user", "include", "core", "remote"); + }); + } + + @Test + public void testIncludeSetValueOnFileWithJustExistingSection2() + throws IOException, ConfigInvalidException { + File includedFile = createAllTypesIncludedContent(); + + File configFile = tmp.newFile("config"); + String content = "[include]\npath=" + pathToString(includedFile) + + "\n[user]\nemail=alice@home\n"; + Files.write(configFile.toPath(), content.getBytes(UTF_8)); + + FileBasedConfig fbConfig = loadConfig(configFile); + assertValuesAsIncluded(fbConfig, REFS_UPSTREAM); + assertSections(fbConfig, "include", "user", "core", "remote"); + + setAllValuesNew(fbConfig); + assertValuesAsIsSaveLoad(fbConfig, config -> { + assertValuesAsNew(config, REFS_UPSTREAM, REFS_BACKUP); + assertSections(fbConfig, "include", "user", "core", "remote"); + }); + } + + @Test + public void testIncludeUnsetSectionMustNotTouchIncludedLines() + throws IOException, ConfigInvalidException { + File includedFile = tmp.newFile("included"); + RefSpec includedRefSpec = new RefSpec(REFS_UPSTREAM); + String includedContent = "[remote \"origin\"]\n" + "fetch=" + + includedRefSpec; + Files.write(includedFile.toPath(), includedContent.getBytes(UTF_8)); + + File configFile = tmp.newFile("config"); + RefSpec refSpec = new RefSpec(REFS_ORIGIN); + String content = "[include]\npath=" + pathToString(includedFile) + "\n" + + "[remote \"origin\"]\n" + "fetch=" + refSpec; + Files.write(configFile.toPath(), content.getBytes(UTF_8)); + + FileBasedConfig fbConfig = loadConfig(configFile); + + Consumer<FileBasedConfig> assertion = config -> { + assertEquals(Arrays.asList(includedRefSpec, refSpec), + config.getRefSpecs("remote", "origin", "fetch")); + }; + assertion.accept(fbConfig); + + fbConfig.unsetSection("remote", "origin"); + assertValuesAsIsSaveLoad(fbConfig, config -> { + assertEquals(Collections.singletonList(includedRefSpec), + config.getRefSpecs("remote", "origin", "fetch")); + }); + } + + private File createAllTypesIncludedContent() throws IOException { + File includedFile = tmp.newFile("included"); + String includedContent = createAllTypesSampleContent("Alice Muller", + true, 10, 20, 30, CoreConfig.AutoCRLF.TRUE, + "+refs/heads/*:refs/remotes/upstream/*"); + Files.write(includedFile.toPath(), includedContent.getBytes(UTF_8)); + return includedFile; + } + + private static void assertValuesAsIsSaveLoad(FileBasedConfig fbConfig, + Consumer<FileBasedConfig> assertion) + throws IOException, ConfigInvalidException { + assertion.accept(fbConfig); + + fbConfig.save(); + assertion.accept(fbConfig); + + fbConfig = loadConfig(fbConfig.getFile()); + assertion.accept(fbConfig); + } + + private static void setAllValuesNew(Config config) { + config.setString("user", null, "name", "Alice Bauer"); + config.setBoolean("core", null, "fileMode", false); + config.setInt("core", null, "deltaBaseCacheLimit", 12); + config.setLong("core", null, "packedGitLimit", 22); + config.setLong("core", null, "repositoryCacheExpireAfter", 32); + config.setEnum("core", null, "autocrlf", CoreConfig.AutoCRLF.FALSE); + config.setString("remote", "origin", "fetch", + "+refs/heads/*:refs/remotes/backup/*"); + } + + private static void assertValuesAsIncluded(Config config, String... refs) { + assertAllTypesSampleContent("Alice Muller", true, 10, 20, 30, + CoreConfig.AutoCRLF.TRUE, config, refs); + } + + private static void assertValuesAsConfig(Config config, String... refs) { + assertAllTypesSampleContent("Alice Parker", false, 11, 21, 31, + CoreConfig.AutoCRLF.FALSE, config, refs); + } + + private static void assertValuesAsNew(Config config, String... refs) { + assertValuesAsNewWithName(config, "Alice Bauer", refs); + } + + private static void assertValuesAsNewWithName(Config config, String name, + String... refs) { + assertAllTypesSampleContent(name, false, 12, 22, 32, + CoreConfig.AutoCRLF.FALSE, config, refs); + } + + private static void assertSections(Config config, String... sections) { + assertEquals(Arrays.asList(sections), + new ArrayList<>(config.getSections())); + } + + private static String createAllTypesSampleContent(String name, + boolean fileMode, int deltaBaseCacheLimit, long packedGitLimit, + long repositoryCacheExpireAfter, CoreConfig.AutoCRLF autoCRLF, + String fetchRefSpec) { + final StringBuilder builder = new StringBuilder(); + builder.append("[user]\n"); + builder.append("name="); + builder.append(name); + builder.append("\n"); + + builder.append("[core]\n"); + builder.append("fileMode="); + builder.append(fileMode); + builder.append("\n"); + + builder.append("deltaBaseCacheLimit="); + builder.append(deltaBaseCacheLimit); + builder.append("\n"); + + builder.append("packedGitLimit="); + builder.append(packedGitLimit); + builder.append("\n"); + + builder.append("repositoryCacheExpireAfter="); + builder.append(repositoryCacheExpireAfter); + builder.append("\n"); + + builder.append("autocrlf="); + builder.append(autoCRLF.name()); + builder.append("\n"); + + builder.append("[remote \"origin\"]\n"); + builder.append("fetch="); + builder.append(fetchRefSpec); + builder.append("\n"); + return builder.toString(); + } + + private static void assertAllTypesSampleContent(String name, + boolean fileMode, int deltaBaseCacheLimit, long packedGitLimit, + long repositoryCacheExpireAfter, CoreConfig.AutoCRLF autoCRLF, + Config config, String... fetchRefSpecs) { + assertEquals(name, config.getString("user", null, "name")); + assertEquals(fileMode, + config.getBoolean("core", "fileMode", !fileMode)); + assertEquals(deltaBaseCacheLimit, + config.getInt("core", "deltaBaseCacheLimit", -1)); + assertEquals(packedGitLimit, + config.getLong("core", "packedGitLimit", -1)); + assertEquals(repositoryCacheExpireAfter, config.getTimeUnit("core", + null, "repositoryCacheExpireAfter", -1, MILLISECONDS)); + assertEquals(autoCRLF, config.getEnum("core", null, "autocrlf", + CoreConfig.AutoCRLF.INPUT)); + final List<RefSpec> refspecs = new ArrayList<>(); + for (String fetchRefSpec : fetchRefSpecs) { + refspecs.add(new RefSpec(fetchRefSpec)); + } + + assertEquals(refspecs, config.getRefSpecs("remote", "origin", "fetch")); + } + private static void assertReadLong(long exp) throws ConfigInvalidException { assertReadLong(exp, String.valueOf(exp)); } @@ -1229,4 +1525,12 @@ public class ConfigTest { assertEquals(expectedMessage, e.getMessage()); } } + + private static FileBasedConfig loadConfig(File file) + throws IOException, ConfigInvalidException { + final FileBasedConfig config = new FileBasedConfig(null, file, + FS.DETECTED); + config.load(); + return config; + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java index 32a1ec96a5..057e0c881b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java @@ -37,6 +37,7 @@ */ package org.eclipse.jgit.lib; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -343,7 +344,7 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase { ObjectInserter newObjectInserter; newObjectInserter = git.getRepository().newObjectInserter(); ObjectId blobId = newObjectInserter.insert(Constants.OBJ_BLOB, - "data".getBytes()); + "data".getBytes(UTF_8)); newObjectInserter = git.getRepository().newObjectInserter(); FileMode mode = FileMode.REGULAR_FILE; ObjectId insertId = blobId; @@ -366,8 +367,8 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase { insertId = blobId; for (int i = path.length - 1; i >= 0; --i) { TreeFormatter treeFormatter = new TreeFormatter(); - treeFormatter.append(path[i].getBytes(), 0, - path[i].getBytes().length, + treeFormatter.append(path[i].getBytes(UTF_8), 0, + path[i].getBytes(UTF_8).length, mode, insertId, true); insertId = newObjectInserter.insert(treeFormatter); mode = FileMode.TREE; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java index eb87827805..534b323fe6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java @@ -40,6 +40,7 @@ */ package org.eclipse.jgit.lib; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -310,7 +311,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { assertTrue("unexpected content for path " + path + " in index. Expected: <" + expectedValue + ">", Arrays.equals(db.open(read.getEntry(j).getObjectId()) - .getCachedBytes(), i.get(path).getBytes())); + .getCachedBytes(), i.get(path).getBytes(UTF_8))); } } @@ -405,7 +406,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { ObjectId genSha1(String data) { try (ObjectInserter w = db.newObjectInserter()) { - ObjectId id = w.insert(Constants.OBJ_BLOB, data.getBytes()); + ObjectId id = w.insert(Constants.OBJ_BLOB, data.getBytes(UTF_8)); w.flush(); return id; } catch (IOException e) { @@ -928,6 +929,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { "e/g3")); try { checkout(); + fail("did not throw CheckoutConflictException"); } catch (CheckoutConflictException e) { assertWorkDir(mkmap("a", "a", "b/c", "b/c", "d", "d", "e/f", "e/f", "e/g", "e/g3")); @@ -2048,7 +2050,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { assertArrayEquals( "unexpected content for path " + path + " in workDir. ", - buffer, i.get(path).getBytes()); + buffer, i.get(path).getBytes(UTF_8)); } nrFiles++; } else if (file.isDirectory()) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/GpgConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/GpgConfigTest.java new file mode 100644 index 0000000000..2098b17f41 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/GpgConfigTest.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2018, Salesforce. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lib; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.junit.Test; + +public class GpgConfigTest { + + private static Config parse(String content) throws ConfigInvalidException { + final Config c = new Config(null); + c.fromText(content); + return c; + } + + @Test + public void isSignCommits_defaultIsFalse() throws Exception { + Config c = parse(""); + + assertFalse(new GpgConfig(c).isSignCommits()); + } + + @Test + public void isSignCommits_false() throws Exception { + Config c = parse("" // + + "[gpg]\n" // + + " format = x509\n" // + + "[commit]\n" // + + " gpgSign = false\n" // + ); + + assertFalse(new GpgConfig(c).isSignCommits()); + } + + @Test + public void isSignCommits_true() throws Exception { + Config c = parse("" // + + "[commit]\n" // + + " gpgSign = true\n" // + ); + + assertTrue(new GpgConfig(c).isSignCommits()); + } + + @Test + public void testGetKeyFormat_defaultsToOpenpgp() throws Exception { + Config c = parse(""); + + assertEquals(GpgConfig.GpgFormat.OPENPGP, + new GpgConfig(c).getKeyFormat()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetKeyFormat_failsForInvalidValue() throws Exception { + Config c = parse("" // + + "[gpg]\n" // + + " format = invalid\n" // + ); + + new GpgConfig(c).getKeyFormat(); + fail("Call should not have succeeded!"); + } + + @Test + public void testGetKeyFormat_openpgp() throws Exception { + Config c = parse("" // + + "[gpg]\n" // + + " format = openpgp\n" // + ); + + assertEquals(GpgConfig.GpgFormat.OPENPGP, + new GpgConfig(c).getKeyFormat()); + } + + @Test + public void testGetKeyFormat_x509() throws Exception { + Config c = parse("" // + + "[gpg]\n" // + + " format = x509\n" // + ); + + assertEquals(GpgConfig.GpgFormat.X509, new GpgConfig(c).getKeyFormat()); + } + + @Test + public void testGetSigningKey() throws Exception { + Config c = parse("" // + + "[user]\n" // + + " signingKey = 0x2345\n" // + ); + + assertEquals("0x2345", new GpgConfig(c).getSigningKey()); + } + + @Test + public void testGetSigningKey_defaultToNull() throws Exception { + Config c = parse(""); + + assertNull(new GpgConfig(c).getSigningKey()); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java index d89aabe75f..fa7f5ab522 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java @@ -43,14 +43,17 @@ package org.eclipse.jgit.lib; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.Set; +import org.eclipse.jgit.api.CloneCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.errors.NoWorkTreeException; @@ -109,6 +112,59 @@ public class IndexDiffSubmoduleTest extends RepositoryTestCase { assertFalse(indexDiff.diff()); } + private Repository cloneWithoutCloningSubmodule() throws Exception { + File directory = createTempDirectory( + "testCloneWithoutCloningSubmodules"); + CloneCommand clone = Git.cloneRepository(); + clone.setDirectory(directory); + clone.setCloneSubmodules(false); + clone.setURI(db.getDirectory().toURI().toString()); + Git git2 = clone.call(); + addRepoToClose(git2.getRepository()); + return git2.getRepository(); + } + + @Theory + public void testCleanAfterClone(IgnoreSubmoduleMode mode) throws Exception { + Repository db2 = cloneWithoutCloningSubmodule(); + IndexDiff indexDiff = new IndexDiff(db2, Constants.HEAD, + new FileTreeIterator(db2)); + indexDiff.setIgnoreSubmoduleMode(mode); + boolean changed = indexDiff.diff(); + assertFalse(changed); + } + + @Theory + public void testMissingIfDirectoryGone(IgnoreSubmoduleMode mode) + throws Exception { + recursiveDelete(submodule_trash); + IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD, + new FileTreeIterator(db)); + indexDiff.setIgnoreSubmoduleMode(mode); + boolean hasChanges = indexDiff.diff(); + if (mode != IgnoreSubmoduleMode.ALL) { + assertTrue(hasChanges); + assertEquals("[modules/submodule]", + indexDiff.getMissing().toString()); + } else { + assertFalse(hasChanges); + } + } + + @Theory + public void testSubmoduleReplacedByFile(IgnoreSubmoduleMode mode) + throws Exception { + recursiveDelete(submodule_trash); + writeTrashFile("modules/submodule", "nonsense"); + IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD, + new FileTreeIterator(db)); + indexDiff.setIgnoreSubmoduleMode(mode); + assertTrue(indexDiff.diff()); + assertEquals("[]", indexDiff.getMissing().toString()); + assertEquals("[]", indexDiff.getUntracked().toString()); + assertEquals("[modules/submodule]", indexDiff.getModified().toString()); + } + @Theory public void testDirtyRootWorktree(IgnoreSubmoduleMode mode) throws IOException { @@ -210,4 +266,33 @@ public class IndexDiffSubmoduleTest extends RepositoryTestCase { assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL, IgnoreSubmoduleMode.DIRTY, IgnoreSubmoduleMode.UNTRACKED); } + + @Theory + public void testSubmoduleReplacedByMovedFile(IgnoreSubmoduleMode mode) + throws Exception { + Git git = Git.wrap(db); + git.rm().setCached(true).addFilepattern("modules/submodule").call(); + recursiveDelete(submodule_trash); + JGitTestUtil.deleteTrashFile(db, "fileInRoot"); + // Move the fileInRoot file + writeTrashFile("modules/submodule/fileInRoot", "root"); + git.rm().addFilepattern("fileInRoot").addFilepattern("modules/").call(); + git.add().addFilepattern("modules/").call(); + IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD, + new FileTreeIterator(db)); + indexDiff.setIgnoreSubmoduleMode(mode); + assertTrue(indexDiff.diff()); + String[] removed = indexDiff.getRemoved().toArray(new String[0]); + Arrays.sort(removed); + if (IgnoreSubmoduleMode.ALL.equals(mode)) { + assertArrayEquals(new String[] { "fileInRoot" }, removed); + } else { + assertArrayEquals( + new String[] { "fileInRoot", "modules/submodule" }, + removed); + } + assertEquals("[modules/submodule/fileInRoot]", + indexDiff.getAdded().toString()); + } + } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java index 580b08b42f..ba5aaf1b18 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java @@ -119,6 +119,28 @@ public class IndexDiffTest extends RepositoryTestCase { } @Test + public void testMissing() throws Exception { + File file2 = writeTrashFile("file2", "file2"); + File file3 = writeTrashFile("dir/file3", "dir/file3"); + Git git = Git.wrap(db); + git.add().addFilepattern("file2").addFilepattern("dir/file3").call(); + git.commit().setMessage("commit").call(); + assertTrue(file2.delete()); + assertTrue(file3.delete()); + IndexDiff diff = new IndexDiff(db, Constants.HEAD, + new FileTreeIterator(db)); + diff.diff(); + assertEquals(2, diff.getMissing().size()); + assertTrue(diff.getMissing().contains("file2")); + assertTrue(diff.getMissing().contains("dir/file3")); + assertEquals(0, diff.getChanged().size()); + assertEquals(0, diff.getModified().size()); + assertEquals(0, diff.getAdded().size()); + assertEquals(0, diff.getRemoved().size()); + assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); + } + + @Test public void testRemoved() throws IOException { writeTrashFile("file2", "file2"); writeTrashFile("dir/file3", "dir/file3"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectLoaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectLoaderTest.java index 83e61d9ab4..055e66ed81 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectLoaderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectLoaderTest.java @@ -260,6 +260,12 @@ public class ObjectLoaderTest { fail("never should have reached read"); return -1; } + + @Override + public int read(byte b[], int off, int len) { + fail("never should have reached read"); + return -1; + } }; } }; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java index a42027b584..7d2c4a2784 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.lib; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -261,7 +262,7 @@ public class RefTest extends SampleDataRepositoryTestCase { assertEquals(Storage.PACKED, ref.getStorage()); try (FileOutputStream os = new FileOutputStream( new File(db.getDirectory(), "refs/heads/master"))) { - os.write(ref.getObjectId().name().getBytes()); + os.write(ref.getObjectId().name().getBytes(UTF_8)); os.write('\n'); } @@ -333,4 +334,17 @@ public class RefTest extends SampleDataRepositoryTestCase { assertEquals(1, refs.size()); checkContainsRef(refs, db.exactRef("refs/heads/prefix/a")); } + + @Test + public void testGetRefsByPrefixes() throws IOException { + List<Ref> refs = db.getRefDatabase().getRefsByPrefix(); + assertEquals(0, refs.size()); + + refs = db.getRefDatabase().getRefsByPrefix("refs/heads/p", + "refs/tags/A"); + assertEquals(3, refs.size()); + checkContainsRef(refs, db.exactRef("refs/heads/pa")); + checkContainsRef(refs, db.exactRef("refs/heads/prefix/a")); + checkContainsRef(refs, db.exactRef("refs/tags/A")); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java index 87e901fcfe..df5079ae16 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java @@ -270,8 +270,8 @@ public class ValidRefNameTest { @Test public void testNormalizeBranchName() { - assertEquals(true, Repository.normalizeBranchName(null) == ""); - assertEquals(true, Repository.normalizeBranchName("").equals("")); + assertEquals("", Repository.normalizeBranchName(null)); + assertEquals("", Repository.normalizeBranchName("")); assertNormalized("Bug 12345::::Hello World", "Bug_12345-Hello_World"); assertNormalized("Bug 12345 :::: Hello World", "Bug_12345_Hello_World"); assertNormalized("Bug 12345 :::: Hello::: World", diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java index 61ab042890..3da779b4ec 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java @@ -302,7 +302,7 @@ public class MergeAlgorithmTest { MergeResult r = new MergeAlgorithm().merge(RawTextComparator.DEFAULT, T(commonBase), T(ours), T(theirs)); ByteArrayOutputStream bo=new ByteArrayOutputStream(50); - fmt.formatMerge(bo, r, "B", "O", "T", UTF_8.name()); + fmt.formatMerge(bo, r, "B", "O", "T", UTF_8); return new String(bo.toByteArray(), UTF_8); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java index f22b7d6adb..fa02227a58 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java @@ -974,7 +974,7 @@ public class MergerTest extends RepositoryTestCase { merger.getMergeResults().get("file"); try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { fmt.formatMerge(out, merger.getMergeResults().get("file"), - "BASE", "OURS", "THEIRS", UTF_8.name()); + "BASE", "OURS", "THEIRS", UTF_8); String expected = "<<<<<<< OURS\n" + "1master\n" + "=======\n" diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java index f3cd61da69..5100d258d7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java @@ -53,6 +53,7 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.util.StringTokenizer; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.junit.MockSystemReader; @@ -70,16 +71,23 @@ public class FileBasedConfigTest { private static final String NAME = "name"; + private static final String EMAIL = "email"; + private static final String ALICE = "Alice"; private static final String BOB = "Bob"; + private static final String ALICE_EMAIL = "alice@home"; + private static final String CONTENT1 = "[" + USER + "]\n\t" + NAME + " = " + ALICE + "\n"; private static final String CONTENT2 = "[" + USER + "]\n\t" + NAME + " = " + BOB + "\n"; + private static final String CONTENT3 = "[" + USER + "]\n\t" + NAME + " = " + + ALICE + "\n" + "[" + USER + "]\n\t" + EMAIL + " = " + ALICE_EMAIL; + private Path trash; @Before @@ -97,7 +105,7 @@ public class FileBasedConfigTest { @Test public void testSystemEncoding() throws IOException, ConfigInvalidException { - final Path file = createFile(CONTENT1.getBytes()); + final Path file = createFile(CONTENT1.getBytes(UTF_8)); final FileBasedConfig config = new FileBasedConfig(file.toFile(), FS.DETECTED); config.load(); @@ -105,7 +113,7 @@ public class FileBasedConfigTest { config.setString(USER, null, NAME, BOB); config.save(); - assertArrayEquals(CONTENT2.getBytes(), IO.readFully(file.toFile())); + assertArrayEquals(CONTENT2.getBytes(UTF_8), IO.readFully(file.toFile())); } @Test @@ -118,7 +126,7 @@ public class FileBasedConfigTest { config.setString(USER, null, NAME, BOB); config.save(); - assertArrayEquals(CONTENT2.getBytes(), IO.readFully(file.toFile())); + assertArrayEquals(CONTENT2.getBytes(UTF_8), IO.readFully(file.toFile())); } @Test @@ -149,8 +157,8 @@ public class FileBasedConfigTest { @Test public void testLeadingWhitespaces() throws IOException, ConfigInvalidException { final ByteArrayOutputStream bos1 = new ByteArrayOutputStream(); - bos1.write(" \n\t".getBytes()); - bos1.write(CONTENT1.getBytes()); + bos1.write(" \n\t".getBytes(UTF_8)); + bos1.write(CONTENT1.getBytes(UTF_8)); final Path file = createFile(bos1.toByteArray()); final FileBasedConfig config = new FileBasedConfig(file.toFile(), @@ -162,18 +170,18 @@ public class FileBasedConfigTest { config.save(); final ByteArrayOutputStream bos2 = new ByteArrayOutputStream(); - bos2.write(" \n\t".getBytes()); - bos2.write(CONTENT2.getBytes()); + bos2.write(" \n\t".getBytes(UTF_8)); + bos2.write(CONTENT2.getBytes(UTF_8)); assertArrayEquals(bos2.toByteArray(), IO.readFully(file.toFile())); } @Test public void testIncludeAbsolute() throws IOException, ConfigInvalidException { - final Path includedFile = createFile(CONTENT1.getBytes()); + final Path includedFile = createFile(CONTENT1.getBytes(UTF_8)); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bos.write("[include]\npath=".getBytes()); - bos.write(pathToString(includedFile.toFile()).getBytes()); + bos.write("[include]\npath=".getBytes(UTF_8)); + bos.write(pathToString(includedFile.toFile()).getBytes(UTF_8)); final Path file = createFile(bos.toByteArray()); final FileBasedConfig config = new FileBasedConfig(file.toFile(), @@ -185,10 +193,10 @@ public class FileBasedConfigTest { @Test public void testIncludeRelativeDot() throws IOException, ConfigInvalidException { - final Path includedFile = createFile(CONTENT1.getBytes(), "dir1"); + final Path includedFile = createFile(CONTENT1.getBytes(UTF_8), "dir1"); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bos.write("[include]\npath=".getBytes()); - bos.write(("./" + includedFile.getFileName()).getBytes()); + bos.write("[include]\npath=".getBytes(UTF_8)); + bos.write(("./" + includedFile.getFileName()).getBytes(UTF_8)); final Path file = createFile(bos.toByteArray(), "dir1"); final FileBasedConfig config = new FileBasedConfig(file.toFile(), @@ -200,11 +208,11 @@ public class FileBasedConfigTest { @Test public void testIncludeRelativeDotDot() throws IOException, ConfigInvalidException { - final Path includedFile = createFile(CONTENT1.getBytes(), "dir1"); + final Path includedFile = createFile(CONTENT1.getBytes(UTF_8), "dir1"); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bos.write("[include]\npath=".getBytes()); + bos.write("[include]\npath=".getBytes(UTF_8)); bos.write(("../" + includedFile.getParent().getFileName() + "/" - + includedFile.getFileName()).getBytes()); + + includedFile.getFileName()).getBytes(UTF_8)); final Path file = createFile(bos.toByteArray(), "dir2"); final FileBasedConfig config = new FileBasedConfig(file.toFile(), @@ -216,10 +224,10 @@ public class FileBasedConfigTest { @Test public void testIncludeRelativeDotDotNotFound() throws IOException, ConfigInvalidException { - final Path includedFile = createFile(CONTENT1.getBytes()); + final Path includedFile = createFile(CONTENT1.getBytes(UTF_8)); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bos.write("[include]\npath=".getBytes()); - bos.write(("../" + includedFile.getFileName()).getBytes()); + bos.write("[include]\npath=".getBytes(UTF_8)); + bos.write(("../" + includedFile.getFileName()).getBytes(UTF_8)); final Path file = createFile(bos.toByteArray()); final FileBasedConfig config = new FileBasedConfig(file.toFile(), @@ -231,10 +239,10 @@ public class FileBasedConfigTest { @Test public void testIncludeWithTilde() throws IOException, ConfigInvalidException { - final Path includedFile = createFile(CONTENT1.getBytes(), "home"); + final Path includedFile = createFile(CONTENT1.getBytes(UTF_8), "home"); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bos.write("[include]\npath=".getBytes()); - bos.write(("~/" + includedFile.getFileName()).getBytes()); + bos.write("[include]\npath=".getBytes(UTF_8)); + bos.write(("~/" + includedFile.getFileName()).getBytes(UTF_8)); final Path file = createFile(bos.toByteArray(), "repo"); final FS fs = FS.DETECTED.newInstance(); @@ -245,6 +253,51 @@ public class FileBasedConfigTest { assertEquals(ALICE, config.getString(USER, null, NAME)); } + @Test + public void testIncludeDontInlineIncludedLinesOnSave() + throws IOException, ConfigInvalidException { + // use a content with multiple sections and multiple key/value pairs + // because code for first line works different than for subsequent lines + final Path includedFile = createFile(CONTENT3.getBytes(UTF_8), "dir1"); + + final Path file = createFile(new byte[0], "dir2"); + FileBasedConfig config = new FileBasedConfig(file.toFile(), + FS.DETECTED); + config.setString("include", null, "path", + ("../" + includedFile.getParent().getFileName() + "/" + + includedFile.getFileName())); + + // just by setting the include.path, it won't be included + assertEquals(null, config.getString(USER, null, NAME)); + assertEquals(null, config.getString(USER, null, EMAIL)); + config.save(); + + // and it won't be included after saving + assertEquals(null, config.getString(USER, null, NAME)); + assertEquals(null, config.getString(USER, null, EMAIL)); + + final String expectedText = config.toText(); + assertEquals(2, + new StringTokenizer(expectedText, "\n", false).countTokens()); + + config = new FileBasedConfig(file.toFile(), FS.DETECTED); + config.load(); + + String actualText = config.toText(); + assertEquals(expectedText, actualText); + // but it will be included after (re)loading + assertEquals(ALICE, config.getString(USER, null, NAME)); + assertEquals(ALICE_EMAIL, config.getString(USER, null, EMAIL)); + + config.save(); + + actualText = config.toText(); + assertEquals(expectedText, actualText); + // and of course preserved after saving + assertEquals(ALICE, config.getString(USER, null, NAME)); + assertEquals(ALICE_EMAIL, config.getString(USER, null, EMAIL)); + } + private Path createFile(byte[] content) throws IOException { return createFile(content, null); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java index fed22c0262..a0cd37ee5f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java @@ -42,6 +42,7 @@ */ package org.eclipse.jgit.submodule; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_URL; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_SUBMODULE_SECTION; @@ -52,9 +53,10 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Status; @@ -155,10 +157,12 @@ public class SubmoduleWalkTest extends RepositoryTestCase { if (!dotGit.getParentFile().exists()) dotGit.getParentFile().mkdirs(); - File modulesGitDir = new File(db.getDirectory(), "modules" - + File.separatorChar + path); - new FileWriter(dotGit).append( - "gitdir: " + modulesGitDir.getAbsolutePath()).close(); + File modulesGitDir = new File(db.getDirectory(), + "modules" + File.separatorChar + path); + try (BufferedWriter fw = Files.newBufferedWriter(dotGit.toPath(), + UTF_8)) { + fw.append("gitdir: " + modulesGitDir.getAbsolutePath()); + } FileRepositoryBuilder builder = new FileRepositoryBuilder(); builder.setWorkTree(new File(db.getWorkTree(), path)); builder.build().create(); @@ -209,9 +213,11 @@ public class SubmoduleWalkTest extends RepositoryTestCase { File modulesGitDir = new File(db.getDirectory(), "modules" + File.separatorChar + path); - new FileWriter(dotGit).append( - "gitdir: " + "../" + Constants.DOT_GIT + "/modules/" + path) - .close(); + try (BufferedWriter fw = Files.newBufferedWriter(dotGit.toPath(), + UTF_8)) { + fw.append("gitdir: " + "../" + Constants.DOT_GIT + "/modules/" + + path); + } FileRepositoryBuilder builder = new FileRepositoryBuilder(); builder.setWorkTree(new File(db.getWorkTree(), path)); builder.build().create(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JSchSshTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JSchSshTest.java new file mode 100644 index 0000000000..8ff70c4e97 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/JSchSshTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.transport; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.util.Arrays; + +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.transport.OpenSshConfig.Host; +import org.eclipse.jgit.transport.ssh.SshTestBase; +import org.eclipse.jgit.util.FS; +import org.junit.experimental.theories.Theories; +import org.junit.runner.RunWith; + +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; + +@RunWith(Theories.class) +public class JSchSshTest extends SshTestBase { + + private class TestSshSessionFactory extends JschConfigSessionFactory { + + @Override + protected void configure(Host hc, Session session) { + // Nothing + } + + @Override + public synchronized RemoteSession getSession(URIish uri, + CredentialsProvider credentialsProvider, FS fs, int tms) + throws TransportException { + return super.getSession(uri, credentialsProvider, fs, tms); + } + + @Override + protected JSch createDefaultJSch(FS fs) throws JSchException { + JSch defaultJSch = super.createDefaultJSch(fs); + if (knownHosts.exists()) { + defaultJSch.setKnownHosts(knownHosts.getAbsolutePath()); + } + return defaultJSch; + } + } + + @Override + protected SshSessionFactory createSessionFactory() { + return new TestSshSessionFactory(); + } + + @Override + protected void installConfig(String... config) { + SshSessionFactory factory = getSessionFactory(); + assertTrue(factory instanceof JschConfigSessionFactory); + JschConfigSessionFactory j = (JschConfigSessionFactory) factory; + try { + j.setConfig(createConfig(config)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private OpenSshConfig createConfig(String... content) throws IOException { + File configFile = new File(sshDir, Constants.CONFIG); + if (content != null) { + Files.write(configFile.toPath(), Arrays.asList(content)); + } + return new OpenSshConfig(getTemporaryDirectory(), configFile); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ObjectIdMatcher.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ObjectIdMatcher.java new file mode 100644 index 0000000000..4c6e0f0add --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ObjectIdMatcher.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2018, Google LLC. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.transport; + +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Sets; +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +/** + * Multiple tests check that a collection of ObjectIds contain certain SHA1 + * (written as strings). This matcher hides the ObjectId to string conversion to + * make the assertion more readable: + * + * assertThat(req.getWantsIds(), hasOnlyObjectIds("123123", "234234")); + */ +class ObjectIdMatcher extends TypeSafeMatcher<Collection<ObjectId>> { + + private final Set<ObjectId> expectedOids; + + private ObjectIdMatcher(Set<String> oids) { + this.expectedOids = oids.stream().map(ObjectId::fromString) + .collect(Collectors.toSet()); + } + + @Override + public void describeTo(Description desc) { + desc.appendText("Object ids:"); + desc.appendValueList("<", ",", ">", expectedOids); + } + + @Override + protected boolean matchesSafely(Collection<ObjectId> resultOids) { + return resultOids.containsAll(expectedOids) + && expectedOids.containsAll(resultOids); + } + + /** + * Assert that all and only the received {@link ObjectId object ids} are in + * the expected set. + * <p> + * ObjectIds are compared by SHA1. + * + * @param oids + * Object ids to examine. + * @return true if examined and specified sets contains exactly the same + * elements. + */ + @Factory + static Matcher<Collection<ObjectId>> hasOnlyObjectIds( + String... oids) { + return new ObjectIdMatcher(Sets.of(oids)); + } +}
\ No newline at end of file diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java index 0358718cf2..2e5027f7ec 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java @@ -50,7 +50,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; @@ -70,6 +69,7 @@ import org.junit.Before; import org.junit.Test; import com.jcraft.jsch.ConfigRepository; +import com.jcraft.jsch.ConfigRepository.Config; public class OpenSshConfigTest extends RepositoryTestCase { private File home; @@ -173,6 +173,20 @@ public class OpenSshConfigTest extends RepositoryTestCase { } @Test + public void testCaseInsensitiveKeyLookup() throws Exception { + config("Host orcz\n" + "Port 29418\n" + + "\tHostName repo.or.cz\nStrictHostKeyChecking yes\n"); + final Host h = osc.lookup("orcz"); + Config c = h.getConfig(); + String exactCase = c.getValue("StrictHostKeyChecking"); + assertEquals("yes", exactCase); + assertEquals(exactCase, c.getValue("stricthostkeychecking")); + assertEquals(exactCase, c.getValue("STRICTHOSTKEYCHECKING")); + assertEquals(exactCase, c.getValue("sTrIcThostKEYcheckING")); + assertNull(c.getValue("sTrIcThostKEYcheckIN")); + } + + @Test public void testAlias_DoesNotMatch() throws Exception { config("Host orcz\n" + "Port 29418\n" + "\tHostName repo.or.cz\n"); final Host h = osc.lookup("repo.or.cz"); @@ -343,21 +357,6 @@ public class OpenSshConfigTest extends RepositoryTestCase { } @Test - public void testRepeatedLookups() throws Exception { - config("Host orcz\n" + "\tConnectionAttempts 5\n"); - final Host h1 = osc.lookup("orcz"); - final Host h2 = osc.lookup("orcz"); - assertNotNull(h1); - assertSame(h1, h2); - assertEquals(5, h1.getConnectionAttempts()); - assertEquals(h1.getConnectionAttempts(), h2.getConnectionAttempts()); - final ConfigRepository.Config c = osc.getConfig("orcz"); - assertNotNull(c); - assertSame(c, h1.getConfig()); - assertSame(c, h2.getConfig()); - } - - @Test public void testRepeatedLookupsWithModification() throws Exception { config("Host orcz\n" + "\tConnectionAttempts -1\n"); final Host h1 = osc.lookup("orcz"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java new file mode 100644 index 0000000000..2c98c84ae5 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2018, Google LLC. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.transport; + +import static org.eclipse.jgit.transport.ObjectIdMatcher.hasOnlyObjectIds; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.eclipse.jgit.errors.PackProtocolException; +import org.eclipse.jgit.lib.Config; +import org.junit.Test; + +public class ProtocolV0ParserTest { + /* + * Convert the input lines to the PacketLine that the parser reads. + */ + private static PacketLineIn formatAsPacketLine(String... inputLines) + throws IOException { + ByteArrayOutputStream send = new ByteArrayOutputStream(); + PacketLineOut pckOut = new PacketLineOut(send); + for (String line : inputLines) { + if (line == PacketLineIn.END) { + pckOut.end(); + } else if (line == PacketLineIn.DELIM) { + pckOut.writeDelim(); + } else { + pckOut.writeString(line); + } + } + + return new PacketLineIn(new ByteArrayInputStream(send.toByteArray())); + } + + private static TransferConfig defaultConfig() { + Config rc = new Config(); + rc.setBoolean("uploadpack", null, "allowfilter", true); + return new TransferConfig(rc); + } + + @Test + public void testRecvWantsWithCapabilities() + throws PackProtocolException, IOException { + PacketLineIn pckIn = formatAsPacketLine( + String.join(" ", "want", + "4624442d68ee402a94364191085b77137618633e", "thin-pack", + "no-progress", "include-tag", "ofs-delta", "\n"), + "want f900c8326a43303685c46b279b9f70411bff1a4b\n", + PacketLineIn.END); + ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); + FetchV0Request request = parser.recvWants(pckIn); + assertTrue(request.getClientCapabilities() + .contains(GitProtocolConstants.OPTION_THIN_PACK)); + assertTrue(request.getClientCapabilities() + .contains(GitProtocolConstants.OPTION_NO_PROGRESS)); + assertTrue(request.getClientCapabilities() + .contains(GitProtocolConstants.OPTION_INCLUDE_TAG)); + assertTrue(request.getClientCapabilities() + .contains(GitProtocolConstants.CAPABILITY_OFS_DELTA)); + assertThat(request.getWantIds(), + hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e", + "f900c8326a43303685c46b279b9f70411bff1a4b")); + } + + @Test + public void testRecvWantsWithAgent() + throws PackProtocolException, IOException { + PacketLineIn pckIn = formatAsPacketLine( + String.join(" ", "want", + "4624442d68ee402a94364191085b77137618633e", "thin-pack", + "agent=JGit.test/0.0.1", "\n"), + "want f900c8326a43303685c46b279b9f70411bff1a4b\n", + PacketLineIn.END); + ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); + FetchV0Request request = parser.recvWants(pckIn); + assertTrue(request.getClientCapabilities() + .contains(GitProtocolConstants.OPTION_THIN_PACK)); + assertEquals(1, request.getClientCapabilities().size()); + assertEquals("JGit.test/0.0.1", request.getAgent()); + assertThat(request.getWantIds(), + hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e", + "f900c8326a43303685c46b279b9f70411bff1a4b")); + } + + /* + * First round of protocol v0 negotiation. Client send wants, no + * capabilities. + */ + @Test + public void testRecvWantsWithoutCapabilities() + throws PackProtocolException, IOException { + PacketLineIn pckIn = formatAsPacketLine( + "want 4624442d68ee402a94364191085b77137618633e\n", + "want f900c8326a43303685c46b279b9f70411bff1a4b\n", + PacketLineIn.END); + ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); + FetchV0Request request = parser.recvWants(pckIn); + assertTrue(request.getClientCapabilities().isEmpty()); + assertThat(request.getWantIds(), + hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e", + "f900c8326a43303685c46b279b9f70411bff1a4b")); + } + + @Test + public void testRecvWantsDeepen() + throws PackProtocolException, IOException { + PacketLineIn pckIn = formatAsPacketLine( + "want 4624442d68ee402a94364191085b77137618633e\n", + "want f900c8326a43303685c46b279b9f70411bff1a4b\n", "deepen 3\n", + PacketLineIn.END); + ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); + FetchV0Request request = parser.recvWants(pckIn); + assertTrue(request.getClientCapabilities().isEmpty()); + assertEquals(3, request.getDepth()); + assertThat(request.getWantIds(), + hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e", + "f900c8326a43303685c46b279b9f70411bff1a4b")); + } + + @Test + public void testRecvWantsShallow() + throws PackProtocolException, IOException { + PacketLineIn pckIn = formatAsPacketLine( + "want 4624442d68ee402a94364191085b77137618633e\n", + "want f900c8326a43303685c46b279b9f70411bff1a4b\n", + "shallow 4b643d0ef739a1b494e7d6926d8d8ed80d35edf4\n", + PacketLineIn.END); + ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); + FetchV0Request request = parser.recvWants(pckIn); + assertTrue(request.getClientCapabilities().isEmpty()); + assertThat(request.getWantIds(), + hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e", + "f900c8326a43303685c46b279b9f70411bff1a4b")); + assertThat(request.getClientShallowCommits(), + hasOnlyObjectIds("4b643d0ef739a1b494e7d6926d8d8ed80d35edf4")); + } + + @Test + public void testRecvWantsFilter() + throws PackProtocolException, IOException { + PacketLineIn pckIn = formatAsPacketLine( + "want 4624442d68ee402a94364191085b77137618633e\n", + "want f900c8326a43303685c46b279b9f70411bff1a4b\n", + "filter blob:limit=13000\n", + PacketLineIn.END); + ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig()); + FetchV0Request request = parser.recvWants(pckIn); + assertTrue(request.getClientCapabilities().isEmpty()); + assertThat(request.getWantIds(), + hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e", + "f900c8326a43303685c46b279b9f70411bff1a4b")); + assertEquals(13000, request.getFilterBlobLimit()); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java index bf67d46d51..dafa81ecd0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java @@ -44,22 +44,20 @@ package org.eclipse.jgit.transport; import static org.hamcrest.Matchers.hasItems; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.eclipse.jgit.transport.ObjectIdMatcher.hasOnlyObjectIds; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.Config; -import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Before; import org.junit.Rule; @@ -137,12 +135,6 @@ public class ProtocolV2ParserTest { return new PacketLineIn(new ByteArrayInputStream(send.toByteArray())); } - private static List<String> objIdsAsStrings(Collection<ObjectId> objIds) { - // TODO(ifrade) Translate this to a matcher, so it would read as - // assertThat(req.wantsIds(), hasObjectIds("...", "...")) - return objIds.stream().map(ObjectId::name).collect(Collectors.toList()); - } - /* * Succesful fetch with the basic core commands of the protocol. */ @@ -160,19 +152,19 @@ public class ProtocolV2ParserTest { ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); FetchV2Request request = parser.parseFetchRequest(pckIn); - assertTrue(request.getOptions() + assertTrue(request.getClientCapabilities() .contains(GitProtocolConstants.OPTION_THIN_PACK)); - assertTrue(request.getOptions() + assertTrue(request.getClientCapabilities() .contains(GitProtocolConstants.OPTION_NO_PROGRESS)); - assertTrue(request.getOptions() + assertTrue(request.getClientCapabilities() .contains(GitProtocolConstants.OPTION_INCLUDE_TAG)); - assertTrue(request.getOptions() + assertTrue(request.getClientCapabilities() .contains(GitProtocolConstants.CAPABILITY_OFS_DELTA)); - assertThat(objIdsAsStrings(request.getWantsIds()), - hasItems("4624442d68ee402a94364191085b77137618633e", + assertThat(request.getWantIds(), + hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e", "f900c8326a43303685c46b279b9f70411bff1a4b")); - assertThat(objIdsAsStrings(request.getPeerHas()), - hasItems("554f6e41067b9e3e565b6988a8294fac1cb78f4b", + assertThat(request.getPeerHas(), + hasOnlyObjectIds("554f6e41067b9e3e565b6988a8294fac1cb78f4b", "abc760ab9ad72f08209943251b36cb886a578f87")); assertTrue(request.getWantedRefs().isEmpty()); assertTrue(request.wasDoneReceived()); @@ -190,12 +182,12 @@ public class ProtocolV2ParserTest { ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); FetchV2Request request = parser.parseFetchRequest(pckIn); - assertThat(objIdsAsStrings(request.getClientShallowCommits()), - hasItems("28274d02c489f4c7e68153056e9061a46f62d7a0", + assertThat(request.getClientShallowCommits(), + hasOnlyObjectIds("28274d02c489f4c7e68153056e9061a46f62d7a0", "145e683b229dcab9d0e2ccb01b386f9ecc17d29d")); assertTrue(request.getDeepenNotRefs().isEmpty()); assertEquals(15, request.getDepth()); - assertTrue(request.getOptions() + assertTrue(request.getClientCapabilities() .contains(GitProtocolConstants.OPTION_DEEPEN_RELATIVE)); } @@ -209,8 +201,8 @@ public class ProtocolV2ParserTest { ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); FetchV2Request request = parser.parseFetchRequest(pckIn); - assertThat(objIdsAsStrings(request.getClientShallowCommits()), - hasItems("28274d02c489f4c7e68153056e9061a46f62d7a0", + assertThat(request.getClientShallowCommits(), + hasOnlyObjectIds("28274d02c489f4c7e68153056e9061a46f62d7a0", "145e683b229dcab9d0e2ccb01b386f9ecc17d29d")); assertThat(request.getDeepenNotRefs(), hasItems("a08595f76159b09d57553e37a5123f1091bb13e7")); @@ -226,8 +218,8 @@ public class ProtocolV2ParserTest { ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); FetchV2Request request = parser.parseFetchRequest(pckIn); - assertThat(objIdsAsStrings(request.getClientShallowCommits()), - hasItems("28274d02c489f4c7e68153056e9061a46f62d7a0", + assertThat(request.getClientShallowCommits(), + hasOnlyObjectIds("28274d02c489f4c7e68153056e9061a46f62d7a0", "145e683b229dcab9d0e2ccb01b386f9ecc17d29d")); assertEquals(123123123, request.getDeepenSince()); } @@ -256,24 +248,25 @@ public class ProtocolV2ParserTest { @Test public void testFetchMustNotHaveMultipleFilters() throws IOException { - thrown.expect(PackProtocolException.class); PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, "filter blob:none", "filter blob:limit=12", PacketLineIn.END); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.start().allowFilter().done()); - FetchV2Request request = parser.parseFetchRequest(pckIn); - assertEquals(0, request.getFilterBlobLimit()); + + thrown.expect(PackProtocolException.class); + parser.parseFetchRequest(pckIn); } @Test public void testFetchFilterWithoutAllowFilter() throws IOException { - thrown.expect(PackProtocolException.class); PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, "filter blob:limit=12", PacketLineIn.END); ProtocolV2Parser parser = new ProtocolV2Parser( ConfigBuilder.getDefault()); + + thrown.expect(PackProtocolException.class); parser.parseFetchRequest(pckIn); } @@ -293,10 +286,11 @@ public class ProtocolV2ParserTest { FetchV2Request request = parser.parseFetchRequest(pckIn); assertEquals(1, request.getWantedRefs().size()); - assertThat(request.getWantedRefs(), hasItems("refs/heads/branchA")); - assertEquals(1, request.getWantsIds().size()); - assertThat(objIdsAsStrings(request.getWantsIds()), - hasItems("e4980cdc48cfa1301493ca94eb70523f6788b819")); + assertThat(request.getWantedRefs(), + hasItems("refs/heads/branchA")); + assertEquals(1, request.getWantIds().size()); + assertThat(request.getWantIds(), hasOnlyObjectIds( + "e4980cdc48cfa1301493ca94eb70523f6788b819")); } @Test @@ -318,4 +312,60 @@ public class ProtocolV2ParserTest { assertThat(request.getWantedRefs(), hasItems("refs/heads/branchC")); } + @Test + public void testLsRefsMinimalReq() throws IOException { + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + PacketLineIn.END); + + ProtocolV2Parser parser = new ProtocolV2Parser( + ConfigBuilder.getDefault()); + LsRefsV2Request req = parser.parseLsRefsRequest(pckIn); + assertFalse(req.getPeel()); + assertFalse(req.getSymrefs()); + assertEquals(0, req.getRefPrefixes().size()); + } + + @Test + public void testLsRefsSymrefs() throws IOException { + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, "symrefs", + PacketLineIn.END); + + ProtocolV2Parser parser = new ProtocolV2Parser( + ConfigBuilder.getDefault()); + LsRefsV2Request req = parser.parseLsRefsRequest(pckIn); + assertFalse(req.getPeel()); + assertTrue(req.getSymrefs()); + assertEquals(0, req.getRefPrefixes().size()); + + } + + @Test + public void testLsRefsPeel() throws IOException { + PacketLineIn pckIn = formatAsPacketLine( + PacketLineIn.DELIM, + "peel", + PacketLineIn.END); + + ProtocolV2Parser parser = new ProtocolV2Parser( + ConfigBuilder.getDefault()); + LsRefsV2Request req = parser.parseLsRefsRequest(pckIn); + assertTrue(req.getPeel()); + assertFalse(req.getSymrefs()); + assertEquals(0, req.getRefPrefixes().size()); + } + + @Test + public void testLsRefsRefPrefixes() throws IOException { + PacketLineIn pckIn = formatAsPacketLine(PacketLineIn.DELIM, + "ref-prefix refs/for", "ref-prefix refs/heads", + PacketLineIn.END); + + ProtocolV2Parser parser = new ProtocolV2Parser( + ConfigBuilder.getDefault()); + LsRefsV2Request req = parser.parseLsRefsRequest(pckIn); + assertFalse(req.getPeel()); + assertFalse(req.getSymrefs()); + assertEquals(2, req.getRefPrefixes().size()); + assertThat(req.getRefPrefixes(), hasItems("refs/for", "refs/heads")); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java index 0647167eab..4bf26b6288 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java @@ -42,6 +42,7 @@ package org.eclipse.jgit.transport; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -334,7 +335,7 @@ public class PushCertificateParserTest { assertFalse(input.contains(PushCertificateParser.END_CERT)); input += input; Reader reader = new InputStreamReader( - new ByteArrayInputStream(Constants.encode(input))); + new ByteArrayInputStream(Constants.encode(input)), UTF_8); assertNotNull(PushCertificateParser.fromReader(reader)); assertNotNull(PushCertificateParser.fromReader(reader)); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java index 68e0129525..fa4fd65069 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateStoreTest.java @@ -43,6 +43,7 @@ package org.eclipse.jgit.transport; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.lib.ObjectId.zeroId; import static org.eclipse.jgit.lib.RefUpdate.Result.FAST_FORWARD; import static org.eclipse.jgit.lib.RefUpdate.Result.LOCK_FAILURE; @@ -96,7 +97,9 @@ public class PushCertificateStoreTest { + "-----END PGP SIGNATURE-----\n"); try { return PushCertificateParser.fromReader(new InputStreamReader( - new ByteArrayInputStream(Constants.encode(cert.toString())))); + new ByteArrayInputStream( + Constants.encode(cert.toString())), + UTF_8)); } catch (IOException e) { throw new IllegalArgumentException(e); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java index c959f6c497..dfa50b6bb6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java @@ -492,9 +492,8 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas assertSame(PacketLineIn.END, r.readString()); String errorLine = r.readString(); - System.out.println(errorLine); - assertTrue(errorLine.startsWith( - "unpack error Invalid submodule URL '-")); + assertTrue(errorLine.startsWith("unpack error")); + assertTrue(errorLine.contains("Invalid submodule URL '-")); assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString()); assertSame(PacketLineIn.END, r.readString()); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java index 953c9fc30a..1c4d0cfe24 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java @@ -46,6 +46,7 @@ package org.eclipse.jgit.transport; 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 java.util.ArrayList; import java.util.List; @@ -238,6 +239,7 @@ public class TestProtocolTest { .setRemote(user1Uri.toString()) .setRefSpecs(MASTER) .call(); + fail("accepted not permitted fetch"); } catch (InvalidRemoteException expected) { // Expected. } @@ -282,6 +284,7 @@ public class TestProtocolTest { .setRemote(user1Uri.toString()) .setRefSpecs(HEADS) .call(); + fail("accepted not permitted push"); } catch (TransportException expected) { assertTrue(expected.getMessage().contains( JGitText.get().pushNotPermitted)); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index 317ac32e6d..8acbcce36d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java @@ -7,6 +7,7 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.theInstance; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -27,6 +28,7 @@ import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; @@ -427,17 +429,7 @@ public class UploadPackTest { RefFilter refFilter, ProtocolV2Hook hook, String... inputLines) throws Exception { - ByteArrayOutputStream send = new ByteArrayOutputStream(); - PacketLineOut pckOut = new PacketLineOut(send); - for (String line : inputLines) { - if (line == PacketLineIn.END) { - pckOut.end(); - } else if (line == PacketLineIn.DELIM) { - pckOut.writeDelim(); - } else { - pckOut.writeString(line); - } - } + ByteArrayInputStream send = linesAsInputStream(inputLines); server.getConfig().setString("protocol", null, "version", "2"); UploadPack up = new UploadPack(server); @@ -451,11 +443,28 @@ public class UploadPackTest { } ByteArrayOutputStream recv = new ByteArrayOutputStream(); - up.upload(new ByteArrayInputStream(send.toByteArray()), recv, null); + up.upload(send, recv, null); return new ByteArrayInputStream(recv.toByteArray()); } + private static ByteArrayInputStream linesAsInputStream(String... inputLines) + throws IOException { + try (ByteArrayOutputStream send = new ByteArrayOutputStream()) { + PacketLineOut pckOut = new PacketLineOut(send); + for (String line : inputLines) { + if (line == PacketLineIn.END) { + pckOut.end(); + } else if (line == PacketLineIn.DELIM) { + pckOut.writeDelim(); + } else { + pckOut.writeString(line); + } + } + return new ByteArrayInputStream(send.toByteArray()); + } + } + /* * Invokes UploadPack with protocol v2 and sends it the given lines. * Returns UploadPack's output stream, not including the capability @@ -484,6 +493,8 @@ public class UploadPackTest { private LsRefsV2Request lsRefsRequest; + private FetchV2Request fetchRequest; + @Override public void onCapabilities(CapabilitiesV2Request req) { capabilitiesRequest = req; @@ -493,6 +504,11 @@ public class UploadPackTest { public void onLsRefs(LsRefsV2Request req) { lsRefsRequest = req; } + + @Override + public void onFetch(FetchV2Request req) { + fetchRequest = req; + } } @Test @@ -501,18 +517,18 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2Setup(null, null, hook, PacketLineIn.END); PacketLineIn pckIn = new PacketLineIn(recvStream); - assertThat(hook.capabilitiesRequest, notNullValue()); assertThat(pckIn.readString(), is("version 2")); assertThat( - Arrays.asList(pckIn.readString(), pckIn.readString()), - // TODO(jonathantanmy) This check is written this way - // to make it simple to see that we expect this list of - // capabilities, but probably should be loosened to - // allow additional commands to be added to the list, - // and additional capabilities to be added to existing - // commands without requiring test changes. - hasItems("ls-refs", "fetch=shallow")); + Arrays.asList(pckIn.readString(), pckIn.readString(), + pckIn.readString()), + // TODO(jonathantanmy) This check is written this way + // to make it simple to see that we expect this list of + // capabilities, but probably should be loosened to + // allow additional commands to be added to the list, + // and additional capabilities to be added to existing + // commands without requiring test changes. + hasItems("ls-refs", "fetch=shallow", "server-option")); assertTrue(pckIn.readString() == PacketLineIn.END); } @@ -525,10 +541,11 @@ public class UploadPackTest { assertThat(pckIn.readString(), is("version 2")); assertThat( - Arrays.asList(pckIn.readString(), pckIn.readString()), - // TODO(jonathantanmy) This check overspecifies the - // order of the capabilities of "fetch". - hasItems("ls-refs", "fetch=filter shallow")); + Arrays.asList(pckIn.readString(), pckIn.readString(), + pckIn.readString()), + // TODO(jonathantanmy) This check overspecifies the + // order of the capabilities of "fetch". + hasItems("ls-refs", "fetch=filter shallow", "server-option")); assertTrue(pckIn.readString() == PacketLineIn.END); } @@ -541,10 +558,12 @@ public class UploadPackTest { assertThat(pckIn.readString(), is("version 2")); assertThat( - Arrays.asList(pckIn.readString(), pckIn.readString()), - // TODO(jonathantanmy) This check overspecifies the - // order of the capabilities of "fetch". - hasItems("ls-refs", "fetch=ref-in-want shallow")); + Arrays.asList(pckIn.readString(), pckIn.readString(), + pckIn.readString()), + // TODO(jonathantanmy) This check overspecifies the + // order of the capabilities of "fetch". + hasItems("ls-refs", "fetch=ref-in-want shallow", + "server-option")); assertTrue(pckIn.readString() == PacketLineIn.END); } @@ -557,8 +576,9 @@ public class UploadPackTest { assertThat(pckIn.readString(), is("version 2")); assertThat( - Arrays.asList(pckIn.readString(), pckIn.readString()), - hasItems("ls-refs", "fetch=shallow")); + Arrays.asList(pckIn.readString(), pckIn.readString(), + pckIn.readString()), + hasItems("ls-refs", "fetch=shallow", "server-option")); assertTrue(pckIn.readString() == PacketLineIn.END); } @@ -572,8 +592,9 @@ public class UploadPackTest { assertThat(pckIn.readString(), is("version 2")); assertThat( - Arrays.asList(pckIn.readString(), pckIn.readString()), - hasItems("ls-refs", "fetch=shallow")); + Arrays.asList(pckIn.readString(), pckIn.readString(), + pckIn.readString()), + hasItems("ls-refs", "fetch=shallow", "server-option")); assertTrue(pckIn.readString() == PacketLineIn.END); } @@ -718,6 +739,21 @@ public class UploadPackTest { PacketLineIn.END); } + @Test + public void testV2LsRefsServerOptions() throws Exception { + String[] lines = { "command=ls-refs\n", + "server-option=one\n", "server-option=two\n", + PacketLineIn.DELIM, + PacketLineIn.END }; + + TestV2Hook testHook = new TestV2Hook(); + uploadPackV2Setup(null, null, testHook, lines); + + LsRefsV2Request req = testHook.lsRefsRequest; + assertEquals(2, req.getServerOptions().size()); + assertThat(req.getServerOptions(), hasItems("one", "two")); + } + /* * Parse multiplexed packfile output from upload-pack using protocol V2 * into the client repository. @@ -1191,6 +1227,270 @@ public class UploadPackTest { } @Test + public void testV2FetchShallowSince() throws Exception { + PersonIdent person = new PersonIdent(remote.getRepository()); + + RevCommit beyondBoundary = remote.commit() + .committer(new PersonIdent(person, 1510000000, 0)).create(); + RevCommit boundary = remote.commit().parent(beyondBoundary) + .committer(new PersonIdent(person, 1520000000, 0)).create(); + RevCommit tooOld = remote.commit() + .committer(new PersonIdent(person, 1500000000, 0)).create(); + RevCommit merge = remote.commit().parent(boundary).parent(tooOld) + .committer(new PersonIdent(person, 1530000000, 0)).create(); + + remote.update("branch1", merge); + + // Report that we only have "boundary" as a shallow boundary. + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "shallow " + boundary.toObjectId().getName() + "\n", + "deepen-since 1510000\n", + "want " + merge.toObjectId().getName() + "\n", + "have " + boundary.toObjectId().getName() + "\n", + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("shallow-info")); + + // "merge" is shallow because one of its parents is committed + // earlier than the given deepen-since time. + assertThat(pckIn.readString(), is("shallow " + merge.toObjectId().getName())); + + // "boundary" is unshallow because its parent committed at or + // later than the given deepen-since time. + assertThat(pckIn.readString(), is("unshallow " + boundary.toObjectId().getName())); + + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + + // The server does not send this because it is committed + // earlier than the given deepen-since time. + assertFalse(client.hasObject(tooOld.toObjectId())); + + // The server does not send this because the client claims to + // have it. + assertFalse(client.hasObject(boundary.toObjectId())); + + // The server sends both these commits. + assertTrue(client.hasObject(beyondBoundary.toObjectId())); + assertTrue(client.hasObject(merge.toObjectId())); + } + + @Test + public void testV2FetchShallowSince_excludedParentWithMultipleChildren() throws Exception { + PersonIdent person = new PersonIdent(remote.getRepository()); + + RevCommit base = remote.commit() + .committer(new PersonIdent(person, 1500000000, 0)).create(); + RevCommit child1 = remote.commit().parent(base) + .committer(new PersonIdent(person, 1510000000, 0)).create(); + RevCommit child2 = remote.commit().parent(base) + .committer(new PersonIdent(person, 1520000000, 0)).create(); + + remote.update("branch1", child1); + remote.update("branch2", child2); + + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "deepen-since 1510000\n", + "want " + child1.toObjectId().getName() + "\n", + "want " + child2.toObjectId().getName() + "\n", + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("shallow-info")); + + // "base" is excluded, so its children are shallow. + assertThat( + Arrays.asList(pckIn.readString(), pckIn.readString()), + hasItems( + "shallow " + child1.toObjectId().getName(), + "shallow " + child2.toObjectId().getName())); + + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + + // Only the children are sent. + assertFalse(client.hasObject(base.toObjectId())); + assertTrue(client.hasObject(child1.toObjectId())); + assertTrue(client.hasObject(child2.toObjectId())); + } + + @Test + public void testV2FetchShallowSince_noCommitsSelected() throws Exception { + PersonIdent person = new PersonIdent(remote.getRepository()); + + RevCommit tooOld = remote.commit() + .committer(new PersonIdent(person, 1500000000, 0)).create(); + + remote.update("branch1", tooOld); + + thrown.expect(PackProtocolException.class); + thrown.expectMessage("No commits selected for shallow request"); + uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "deepen-since 1510000\n", + "want " + tooOld.toObjectId().getName() + "\n", + "done\n", + PacketLineIn.END); + } + + @Test + public void testV2FetchDeepenNot() throws Exception { + RevCommit one = remote.commit().message("one").create(); + RevCommit two = remote.commit().message("two").parent(one).create(); + RevCommit three = remote.commit().message("three").parent(two).create(); + RevCommit side = remote.commit().message("side").parent(one).create(); + RevCommit merge = remote.commit().message("merge") + .parent(three).parent(side).create(); + + remote.update("branch1", merge); + remote.update("side", side); + + // The client is a shallow clone that only has "three", and + // wants "merge" while excluding "side". + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "shallow " + three.toObjectId().getName() + "\n", + "deepen-not side\n", + "want " + merge.toObjectId().getName() + "\n", + "have " + three.toObjectId().getName() + "\n", + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("shallow-info")); + + // "merge" is shallow because "side" is excluded by deepen-not. + // "two" is shallow because "one" (as parent of "side") is excluded by deepen-not. + assertThat( + Arrays.asList(pckIn.readString(), pckIn.readString()), + hasItems( + "shallow " + merge.toObjectId().getName(), + "shallow " + two.toObjectId().getName())); + + // "three" is unshallow because its parent "two" is now available. + assertThat(pckIn.readString(), is("unshallow " + three.toObjectId().getName())); + + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + + // The server does not send these because they are excluded by + // deepen-not. + assertFalse(client.hasObject(side.toObjectId())); + assertFalse(client.hasObject(one.toObjectId())); + + // The server does not send this because the client claims to + // have it. + assertFalse(client.hasObject(three.toObjectId())); + + // The server sends both these commits. + assertTrue(client.hasObject(merge.toObjectId())); + assertTrue(client.hasObject(two.toObjectId())); + } + + @Test + public void testV2FetchDeepenNot_excludeDescendantOfWant() throws Exception { + RevCommit one = remote.commit().message("one").create(); + RevCommit two = remote.commit().message("two").parent(one).create(); + RevCommit three = remote.commit().message("three").parent(two).create(); + RevCommit four = remote.commit().message("four").parent(three).create(); + + remote.update("two", two); + remote.update("four", four); + + thrown.expect(PackProtocolException.class); + thrown.expectMessage("No commits selected for shallow request"); + uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "deepen-not four\n", + "want " + two.toObjectId().getName() + "\n", + "done\n", + PacketLineIn.END); + } + + @Test + public void testV2FetchDeepenNot_supportAnnotatedTags() throws Exception { + RevCommit one = remote.commit().message("one").create(); + RevCommit two = remote.commit().message("two").parent(one).create(); + RevCommit three = remote.commit().message("three").parent(two).create(); + RevCommit four = remote.commit().message("four").parent(three).create(); + RevTag twoTag = remote.tag("twotag", two); + + remote.update("refs/tags/twotag", twoTag); + remote.update("four", four); + + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "deepen-not twotag\n", + "want " + four.toObjectId().getName() + "\n", + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("shallow-info")); + assertThat(pckIn.readString(), is("shallow " + three.toObjectId().getName())); + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + assertFalse(client.hasObject(one.toObjectId())); + assertFalse(client.hasObject(two.toObjectId())); + assertTrue(client.hasObject(three.toObjectId())); + assertTrue(client.hasObject(four.toObjectId())); + } + + @Test + public void testV2FetchDeepenNot_excludedParentWithMultipleChildren() throws Exception { + PersonIdent person = new PersonIdent(remote.getRepository()); + + RevCommit base = remote.commit() + .committer(new PersonIdent(person, 1500000000, 0)).create(); + RevCommit child1 = remote.commit().parent(base) + .committer(new PersonIdent(person, 1510000000, 0)).create(); + RevCommit child2 = remote.commit().parent(base) + .committer(new PersonIdent(person, 1520000000, 0)).create(); + + remote.update("base", base); + remote.update("branch1", child1); + remote.update("branch2", child2); + + ByteArrayInputStream recvStream = uploadPackV2( + "command=fetch\n", + PacketLineIn.DELIM, + "deepen-not base\n", + "want " + child1.toObjectId().getName() + "\n", + "want " + child2.toObjectId().getName() + "\n", + "done\n", + PacketLineIn.END); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("shallow-info")); + + // "base" is excluded, so its children are shallow. + assertThat( + Arrays.asList(pckIn.readString(), pckIn.readString()), + hasItems( + "shallow " + child1.toObjectId().getName(), + "shallow " + child2.toObjectId().getName())); + + assertThat(pckIn.readString(), theInstance(PacketLineIn.DELIM)); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + + // Only the children are sent. + assertFalse(client.hasObject(base.toObjectId())); + assertTrue(client.hasObject(child1.toObjectId())); + assertTrue(client.hasObject(child2.toObjectId())); + } + + @Test public void testV2FetchUnrecognizedArgument() throws Exception { thrown.expect(PackProtocolException.class); thrown.expectMessage("unexpected invalid-argument"); @@ -1202,6 +1502,21 @@ public class UploadPackTest { } @Test + public void testV2FetchServerOptions() throws Exception { + String[] lines = { "command=fetch\n", "server-option=one\n", + "server-option=two\n", PacketLineIn.DELIM, + PacketLineIn.END }; + + TestV2Hook testHook = new TestV2Hook(); + uploadPackV2Setup(null, null, testHook, lines); + + FetchV2Request req = testHook.fetchRequest; + assertNotNull(req); + assertEquals(2, req.getServerOptions().size()); + assertThat(req.getServerOptions(), hasItems("one", "two")); + } + + @Test public void testV2FetchFilter() throws Exception { RevBlob big = remote.blob("foobar"); RevBlob small = remote.blob("fooba"); @@ -1455,6 +1770,45 @@ public class UploadPackTest { assertTrue(client.hasObject(three.toObjectId())); } + @Test + public void testGetPeerAgentProtocolV0() throws Exception { + RevCommit one = remote.commit().message("1").create(); + remote.update("one", one); + + UploadPack up = new UploadPack(server); + ByteArrayInputStream send = linesAsInputStream( + "want " + one.getName() + " agent=JGit-test/1.2.3\n", + PacketLineIn.END, + "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n"); + + ByteArrayOutputStream recv = new ByteArrayOutputStream(); + up.upload(send, recv, null); + + assertEquals(up.getPeerUserAgent(), "JGit-test/1.2.3"); + } + + @Test + public void testGetPeerAgentProtocolV2() throws Exception { + server.getConfig().setString("protocol", null, "version", "2"); + + RevCommit one = remote.commit().message("1").create(); + remote.update("one", one); + + UploadPack up = new UploadPack(server); + up.setExtraParameters(Sets.of("version=2")); + + ByteArrayInputStream send = linesAsInputStream( + "command=fetch\n", "agent=JGit-test/1.2.4\n", + PacketLineIn.DELIM, "want " + one.getName() + "\n", + "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n", + PacketLineIn.END); + + ByteArrayOutputStream recv = new ByteArrayOutputStream(); + up.upload(send, recv, null); + + assertEquals(up.getPeerUserAgent(), "JGit-test/1.2.4"); + } + private static class RejectAllRefFilter implements RefFilter { @Override public Map<String, Ref> filter(Map<String, Ref> refs) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java index f2fb0224ef..4750d15b3d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java @@ -651,7 +651,8 @@ public class WalkEncryptionTest { Properties props = Props.discover(); props.put(AmazonS3.Keys.PASSWORD, JGIT_PASS); props.put(AmazonS3.Keys.CRYPTO_ALG, algorithm); - try (PrintWriter writer = new PrintWriter(JGIT_CONF_FILE)) { + try (PrintWriter writer = new PrintWriter(JGIT_CONF_FILE, + UTF_8.name())) { props.store(writer, "JGIT S3 connection configuration file."); } } @@ -665,7 +666,8 @@ public class WalkEncryptionTest { static void configCreate(Properties source) throws Exception { Properties target = Props.discover(); target.putAll(source); - try (PrintWriter writer = new PrintWriter(JGIT_CONF_FILE)) { + try (PrintWriter writer = new PrintWriter(JGIT_CONF_FILE, + UTF_8.name())) { target.store(writer, "JGIT S3 connection configuration file."); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/http/JDKHttpConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/http/JDKHttpConnectionTest.java new file mode 100644 index 0000000000..10ee829199 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/http/JDKHttpConnectionTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2018 Matthias Sohn <matthias.sohn@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.transport.http; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.net.HttpURLConnection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +public class JDKHttpConnectionTest { + + private Map<String, List<String>> headers = new HashMap<>(); + + private HttpURLConnection u; + + private JDKHttpConnection c; + + @Before + public void setup() { + u = mock(HttpURLConnection.class); + c = new JDKHttpConnection(u); + headers.put("ABC", asList("x")); + } + + @Test + public void testSingle() { + when(u.getHeaderFields()).thenReturn(headers); + assertValues("AbC", "x"); + } + + @Test + public void testMultiple1() { + headers.put("abc", asList("a")); + headers.put("aBC", asList("d", "e")); + headers.put("ABc", Collections.emptyList()); + headers.put("AbC", (List<String>) null); + when(u.getHeaderFields()).thenReturn(headers); + assertValues("AbC", "a", "d", "e", "x"); + } + + @Test + public void testMultiple2() { + headers.put("ab", asList("y", "z", "z")); + when(u.getHeaderFields()).thenReturn(headers); + assertValues("ab", "z", "y", "z"); + assertValues("abc", "x"); + assertValues("aBc", "x"); + assertValues("AbCd"); + } + + @Test + public void testCommaSeparatedList() { + headers.put("abc", asList("a,b,c", "d")); + when(u.getHeaderFields()).thenReturn(headers); + assertValues("Abc", "a,b,c", "x", "d"); + } + + private void assertValues(String key, String... values) { + List<String> l = new LinkedList<>(); + List<String> hf = c.getHeaderFields(key); + if (hf != null) { + l.addAll(hf); + } + for (String v : values) { + if (!l.remove(v)) { + fail("value " + v + " not found"); + } + } + assertTrue("found unexpected entries " + l, l.isEmpty()); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilterTest.java index cba35d8042..ea5db09349 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilterTest.java @@ -42,6 +42,7 @@ */ package org.eclipse.jgit.treewalk.filter; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -114,7 +115,7 @@ public class InterIndexDiffFilterTest extends LocalDiskRepositoryTestCase { } private ObjectId id(String data) { - byte[] bytes = data.getBytes(); + byte[] bytes = data.getBytes(UTF_8); return db.newObjectInserter().idFor(Constants.OBJ_BLOB, bytes); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/BlockListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/BlockListTest.java index 0a3de85f7c..dca9c57a64 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/BlockListTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/BlockListTest.java @@ -47,6 +47,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.Iterator; @@ -84,18 +85,21 @@ public class BlockListTest { try { list.get(-1); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(-1), badIndex.getMessage()); } try { list.get(0); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(0), badIndex.getMessage()); } try { list.get(4); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(4), badIndex.getMessage()); } @@ -114,6 +118,7 @@ public class BlockListTest { try { list.get(3); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(3), badIndex.getMessage()); } @@ -125,18 +130,21 @@ public class BlockListTest { try { list.set(-1, "foo"); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(-1), badIndex.getMessage()); } try { list.set(0, "foo"); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(0), badIndex.getMessage()); } try { list.set(4, "foo"); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(4), badIndex.getMessage()); } @@ -161,6 +169,7 @@ public class BlockListTest { try { list.set(3, "bar"); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(3), badIndex.getMessage()); } @@ -323,12 +332,14 @@ public class BlockListTest { try { list.add(-1, Integer.valueOf(42)); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(-1), badIndex.getMessage()); } try { list.add(4, Integer.valueOf(42)); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(4), badIndex.getMessage()); } @@ -341,12 +352,14 @@ public class BlockListTest { try { list.remove(-1); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(-1), badIndex.getMessage()); } try { list.remove(4); + fail("accepted out-of-bounds index"); } catch (IndexOutOfBoundsException badIndex) { assertEquals(String.valueOf(4), badIndex.getMessage()); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java index e34c3cebd6..e5fcbf9d7c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java @@ -199,7 +199,8 @@ public class HookTest extends RepositoryTestCase { assumeSupportedPlatform(); writeHookFile(PreCommitHook.NAME, - "#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\necho 1>&2 \"stderr\""); + "#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\n" + + "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\""); ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream(); ProcessResult res = FS.DETECTED.runHookIfPresent(db, @@ -208,7 +209,9 @@ public class HookTest extends RepositoryTestCase { "arg1", "arg2" }, new PrintStream(out), new PrintStream(err), "stdin"); - assertEquals("unexpected hook output", "test arg1 arg2\nstdin\n", + assertEquals("unexpected hook output", + "test arg1 arg2\nstdin\n" + db.getDirectory().getAbsolutePath() + + '\n' + db.getWorkTree().getAbsolutePath() + '\n', out.toString("UTF-8")); assertEquals("unexpected output on stderr stream", "stderr\n", err.toString("UTF-8")); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IOReadLineTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IOReadLineTest.java index 928fb2ed9a..fa303ec286 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IOReadLineTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IOReadLineTest.java @@ -43,6 +43,7 @@ package org.eclipse.jgit.util; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import java.io.BufferedReader; @@ -105,7 +106,7 @@ public class IOReadLineTest { private Reader newReader(String in) { Reader r = new InputStreamReader( - new ByteArrayInputStream(Constants.encode(in))); + new ByteArrayInputStream(Constants.encode(in)), UTF_8); if (buffered) { r = new BufferedReader(r); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java index 7630c11185..e7bfa000ac 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java @@ -85,10 +85,11 @@ public class RawParseUtils_LineMapTest { } @Test - public void testBinary() { + public void testNulByte() { final byte[] buf = "xxxfoo\nb\0ar".getBytes(ISO_8859_1); final IntList map = RawParseUtils.lineMap(buf, 3, buf.length); - assertArrayEquals(new int[]{Integer.MIN_VALUE, 3, buf.length}, asInts(map)); + assertArrayEquals(new int[] { Integer.MIN_VALUE, 3, 7, buf.length }, + asInts(map)); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java index 7c0985ef42..19af83611b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java @@ -43,6 +43,7 @@ package org.eclipse.jgit.util; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import java.io.ByteArrayInputStream; @@ -75,10 +76,10 @@ public class RunExternalScriptTest { File script = writeTempFile("cat -"); int rc = FS.DETECTED.runProcess( new ProcessBuilder("sh", script.getPath()), out, err, - new ByteArrayInputStream(inputStr.getBytes())); + new ByteArrayInputStream(inputStr.getBytes(UTF_8))); assertEquals(0, rc); - assertEquals(inputStr, new String(out.toByteArray())); - assertEquals("", new String(err.toByteArray())); + assertEquals(inputStr, new String(out.toByteArray(), UTF_8)); + assertEquals("", new String(err.toByteArray(), UTF_8)); } @Test @@ -88,8 +89,8 @@ public class RunExternalScriptTest { new ProcessBuilder("sh", script.getPath()), out, err, (InputStream) null); assertEquals(0, rc); - assertEquals("", new String(out.toByteArray())); - assertEquals("", new String(err.toByteArray())); + assertEquals("", new String(out.toByteArray(), UTF_8)); + assertEquals("", new String(err.toByteArray(), UTF_8)); } @Test @@ -99,8 +100,8 @@ public class RunExternalScriptTest { new ProcessBuilder("sh", script.getPath(), "a", "b", "c"), out, err, (InputStream) null); assertEquals(0, rc); - assertEquals("3,a,b,c,,,\n", new String(out.toByteArray())); - assertEquals("", new String(err.toByteArray())); + assertEquals("3,a,b,c,,,\n", new String(out.toByteArray(), UTF_8)); + assertEquals("", new String(err.toByteArray(), UTF_8)); } @Test @@ -110,8 +111,8 @@ public class RunExternalScriptTest { new ProcessBuilder("sh", script.getPath(), "a", "b", "c"), out, err, (InputStream) null); assertEquals(3, rc); - assertEquals("", new String(out.toByteArray())); - assertEquals("", new String(err.toByteArray())); + assertEquals("", new String(out.toByteArray(), UTF_8)); + assertEquals("", new String(err.toByteArray(), UTF_8)); } @Test @@ -121,8 +122,8 @@ public class RunExternalScriptTest { new ProcessBuilder("sh", script.getPath()), null, err, (InputStream) null); assertEquals(0, rc); - assertEquals("", new String(out.toByteArray())); - assertEquals("", new String(err.toByteArray())); + assertEquals("", new String(out.toByteArray(), UTF_8)); + assertEquals("", new String(err.toByteArray(), UTF_8)); } @Test @@ -132,8 +133,8 @@ public class RunExternalScriptTest { new ProcessBuilder("sh", script.getPath()), null, err, (InputStream) null); assertEquals(0, rc); - assertEquals("", new String(out.toByteArray())); - assertEquals("hi" + LF, new String(err.toByteArray())); + assertEquals("", new String(out.toByteArray(), UTF_8)); + assertEquals("hi" + LF, new String(err.toByteArray(), UTF_8)); } @Test @@ -142,10 +143,10 @@ public class RunExternalScriptTest { File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5"); int rc = FS.DETECTED.runProcess( new ProcessBuilder("sh", script.getPath(), "a", "b", "c"), - out, err, new ByteArrayInputStream(inputStr.getBytes())); + out, err, new ByteArrayInputStream(inputStr.getBytes(UTF_8))); assertEquals(5, rc); - assertEquals(inputStr, new String(out.toByteArray())); - assertEquals("3,a,b,c,,," + LF, new String(err.toByteArray())); + assertEquals(inputStr, new String(out.toByteArray(), UTF_8)); + assertEquals("3,a,b,c,,," + LF, new String(err.toByteArray(), UTF_8)); } @Test(expected = IOException.class) @@ -172,10 +173,11 @@ public class RunExternalScriptTest { File script = writeTempFile("cat -"); ProcessBuilder pb = new ProcessBuilder("sh", script.getPath()); ExecutionResult res = FS.DETECTED.execute(pb, - new ByteArrayInputStream(inputStr.getBytes())); + new ByteArrayInputStream(inputStr.getBytes(UTF_8))); assertEquals(0, res.getRc()); - assertEquals(inputStr, new String(res.getStdout().toByteArray())); - assertEquals("", new String(res.getStderr().toByteArray())); + assertEquals(inputStr, + new String(res.getStdout().toByteArray(), UTF_8)); + assertEquals("", new String(res.getStderr().toByteArray(), UTF_8)); } @Test @@ -184,8 +186,9 @@ public class RunExternalScriptTest { ProcessBuilder pb = new ProcessBuilder("sh", script.getPath()); ExecutionResult res = FS.DETECTED.execute(pb, null); assertEquals(0, res.getRc()); - assertEquals("", new String(res.getStdout().toByteArray())); - assertEquals("hi" + LF, new String(res.getStderr().toByteArray())); + assertEquals("", new String(res.getStdout().toByteArray(), UTF_8)); + assertEquals("hi" + LF, + new String(res.getStderr().toByteArray(), UTF_8)); } @Test @@ -197,11 +200,12 @@ public class RunExternalScriptTest { ProcessBuilder pb = new ProcessBuilder("sh", script.getPath(), "a", "b", "c"); ExecutionResult res = FS.DETECTED.execute(pb, - new ByteArrayInputStream(inputStr.getBytes())); + new ByteArrayInputStream(inputStr.getBytes(UTF_8))); assertEquals(5, res.getRc()); - assertEquals(inputStr, new String(res.getStdout().toByteArray())); + assertEquals(inputStr, + new String(res.getStdout().toByteArray(), UTF_8)); assertEquals("3,a,b,c,,," + LF, - new String(res.getStderr().toByteArray())); + new String(res.getStderr().toByteArray(), UTF_8)); } private File writeTempFile(String body) throws IOException { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFInputStreamTest.java index 1272e16173..8f77c55af2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFInputStreamTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFInputStreamTest.java @@ -43,6 +43,8 @@ package org.eclipse.jgit.util.io; +import static java.nio.charset.StandardCharsets.UTF_8; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -89,8 +91,8 @@ public class AutoCRLFInputStreamTest { private void assertNoCrLfHelper(String expect, String input) throws IOException { - byte[] inbytes = input.getBytes(); - byte[] expectBytes = expect.getBytes(); + byte[] inbytes = input.getBytes(UTF_8); + byte[] expectBytes = expect.getBytes(UTF_8); for (int i = 0; i < 5; ++i) { byte[] buf = new byte[i]; try (ByteArrayInputStream bis = new ByteArrayInputStream(inbytes); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java index 0655827310..3a3dc8117f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/AutoCRLFOutputStreamTest.java @@ -44,6 +44,8 @@ package org.eclipse.jgit.util.io; +import static java.nio.charset.StandardCharsets.UTF_8; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -91,8 +93,8 @@ public class AutoCRLFOutputStreamTest { private void assertNoCrLfHelper(String expect, String input) throws IOException { - byte[] inbytes = input.getBytes(); - byte[] expectBytes = expect.getBytes(); + byte[] inbytes = input.getBytes(UTF_8); + byte[] expectBytes = expect.getBytes(UTF_8); for (int i = -4; i < 5; ++i) { int size = Math.abs(i); byte[] buf = new byte[size]; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java index b824fae9fd..a6e0eedfbc 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java @@ -167,6 +167,8 @@ public class UnionInputStreamTest { u.add(new ByteArrayInputStream(new byte[] { 20, 30 }) { @Override + @SuppressWarnings("UnsynchronizedOverridesSynchronized") + // This is only used in tests and is thread-safe public long skip(long n) { return 0; } @@ -259,6 +261,11 @@ public class UnionInputStreamTest { public int read() throws IOException { throw new IOException("Expected"); } + + @Override + public int read(byte b[], int off, int len) throws IOException { + throw new IOException("Expected"); + } }; @SuppressWarnings("resource" /* java 7 */) final UnionInputStream u = new UnionInputStream( |