diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2016-01-21 17:03:20 +0100 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2016-01-21 17:07:31 +0100 |
commit | 4ec84fac86c9652847630efc2dda3e69954fdb61 (patch) | |
tree | 537cf6ffb986dc361f25a91296c04c4b5599b705 /org.eclipse.jgit.test/tst/org/eclipse | |
parent | 7e8e4ec019f4ca4d9a1892c7c882eba6013fdeaa (diff) | |
parent | 7b6122908b2aa31555cee3e0cc9dde304e0d90b3 (diff) | |
download | jgit-4ec84fac86c9652847630efc2dda3e69954fdb61.tar.gz jgit-4ec84fac86c9652847630efc2dda3e69954fdb61.zip |
Merge branch 'master' into stable-4.2
Change-Id: Ieec4f51aedadf5734ae0e3f4e8713248a3c4fc52
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse')
29 files changed, 2588 insertions, 1531 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 d4bd68e686..4fefdfddab 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 org.eclipse.jgit.util.FileUtils.RECURSIVE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -797,7 +798,6 @@ public class AddCommandTest extends RepositoryTestCase { assertEquals("[a.txt, mode:100644, content:more content," + " assume-unchanged:false][b.txt, mode:100644," - + "" + "" + " content:content, assume-unchanged:true]", indexState(CONTENT | ASSUME_UNCHANGED)); @@ -805,6 +805,102 @@ public class AddCommandTest extends RepositoryTestCase { } @Test + public void testReplaceFileWithDirectory() + throws IOException, NoFilepatternException, GitAPIException { + try (Git git = new Git(db)) { + writeTrashFile("df", "before replacement"); + git.add().addFilepattern("df").call(); + assertEquals("[df, mode:100644, content:before replacement]", + indexState(CONTENT)); + FileUtils.delete(new File(db.getWorkTree(), "df")); + writeTrashFile("df/f", "after replacement"); + git.add().addFilepattern("df").call(); + assertEquals("[df/f, mode:100644, content:after replacement]", + indexState(CONTENT)); + } + } + + @Test + public void testReplaceDirectoryWithFile() + throws IOException, NoFilepatternException, GitAPIException { + try (Git git = new Git(db)) { + writeTrashFile("df/f", "before replacement"); + git.add().addFilepattern("df").call(); + assertEquals("[df/f, mode:100644, content:before replacement]", + indexState(CONTENT)); + FileUtils.delete(new File(db.getWorkTree(), "df"), RECURSIVE); + writeTrashFile("df", "after replacement"); + git.add().addFilepattern("df").call(); + assertEquals("[df, mode:100644, content:after replacement]", + indexState(CONTENT)); + } + } + + @Test + public void testReplaceFileByPartOfDirectory() + throws IOException, NoFilepatternException, GitAPIException { + try (Git git = new Git(db)) { + writeTrashFile("src/main", "df", "before replacement"); + writeTrashFile("src/main", "z", "z"); + writeTrashFile("z", "z2"); + git.add().addFilepattern("src/main/df") + .addFilepattern("src/main/z") + .addFilepattern("z") + .call(); + assertEquals( + "[src/main/df, mode:100644, content:before replacement]" + + "[src/main/z, mode:100644, content:z]" + + "[z, mode:100644, content:z2]", + indexState(CONTENT)); + FileUtils.delete(new File(db.getWorkTree(), "src/main/df")); + writeTrashFile("src/main/df", "a", "after replacement"); + writeTrashFile("src/main/df", "b", "unrelated file"); + git.add().addFilepattern("src/main/df/a").call(); + assertEquals( + "[src/main/df/a, mode:100644, content:after replacement]" + + "[src/main/z, mode:100644, content:z]" + + "[z, mode:100644, content:z2]", + indexState(CONTENT)); + } + } + + @Test + public void testReplaceDirectoryConflictsWithFile() + throws IOException, NoFilepatternException, GitAPIException { + DirCache dc = db.lockDirCache(); + try (ObjectInserter oi = db.newObjectInserter()) { + DirCacheBuilder builder = dc.builder(); + File f = writeTrashFile("a", "df", "content"); + addEntryToBuilder("a", f, oi, builder, 1); + + f = writeTrashFile("a", "df", "other content"); + addEntryToBuilder("a/df", f, oi, builder, 3); + + f = writeTrashFile("a", "df", "our content"); + addEntryToBuilder("a/df", f, oi, builder, 2); + + f = writeTrashFile("z", "z"); + addEntryToBuilder("z", f, oi, builder, 0); + builder.commit(); + } + assertEquals( + "[a, mode:100644, stage:1, content:content]" + + "[a/df, mode:100644, stage:2, content:our content]" + + "[a/df, mode:100644, stage:3, content:other content]" + + "[z, mode:100644, content:z]", + indexState(CONTENT)); + + try (Git git = new Git(db)) { + FileUtils.delete(new File(db.getWorkTree(), "a"), RECURSIVE); + writeTrashFile("a", "merged"); + git.add().addFilepattern("a").call(); + assertEquals("[a, mode:100644, content:merged]" + + "[z, mode:100644, content:z]", + indexState(CONTENT)); + } + } + + @Test public void testExecutableRetention() throws Exception { StoredConfig config = db.getConfig(); config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java index 0d03047d53..b39a68a22e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java @@ -46,12 +46,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; import java.io.File; import java.util.Date; import java.util.List; import java.util.TimeZone; +import org.eclipse.jgit.api.errors.EmtpyCommitException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.dircache.DirCache; @@ -477,6 +480,34 @@ public class CommitCommandTest extends RepositoryTestCase { } @Test + public void commitEmptyCommits() throws Exception { + try (Git git = new Git(db)) { + + writeTrashFile("file1", "file1"); + git.add().addFilepattern("file1").call(); + RevCommit initial = git.commit().setMessage("initial commit") + .call(); + + RevCommit emptyFollowUp = git.commit() + .setAuthor("New Author", "newauthor@example.org") + .setMessage("no change").call(); + + assertNotEquals(initial.getId(), emptyFollowUp.getId()); + assertEquals(initial.getTree().getId(), + emptyFollowUp.getTree().getId()); + + try { + git.commit().setAuthor("New Author", "newauthor@example.org") + .setMessage("again no change").setAllowEmpty(false) + .call(); + fail("Didn't get the expected EmtpyCommitException"); + } catch (EmtpyCommitException e) { + // expect this exception + } + } + } + + @Test public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers() throws Exception { DirCache index = db.lockDirCache(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java index db811cdf59..3343af06dd 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java @@ -43,10 +43,12 @@ package org.eclipse.jgit.api; 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.nio.file.Path; import org.eclipse.jgit.api.CheckoutCommand.Stage; import org.eclipse.jgit.api.errors.JGitInternalException; @@ -59,6 +61,9 @@ import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FileUtils; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; @@ -73,6 +78,8 @@ public class PathCheckoutCommandTest extends RepositoryTestCase { private static final String FILE3 = "Test3.txt"; + private static final String LINK = "link"; + Git git; RevCommit initialCommit; @@ -99,6 +106,64 @@ public class PathCheckoutCommandTest extends RepositoryTestCase { } @Test + public void testUpdateSymLink() throws Exception { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); + + Path path = writeLink(LINK, FILE1); + git.add().addFilepattern(LINK).call(); + git.commit().setMessage("Added link").call(); + assertEquals("3", read(path.toFile())); + + writeLink(LINK, FILE2); + assertEquals("c", read(path.toFile())); + + CheckoutCommand co = git.checkout(); + co.addPath(LINK).call(); + + assertEquals("3", read(path.toFile())); + } + + @Test + public void testUpdateBrokenSymLinkToDirectory() throws Exception { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); + + Path path = writeLink(LINK, "f"); + git.add().addFilepattern(LINK).call(); + git.commit().setMessage("Added link").call(); + assertEquals("f", FileUtils.readSymLink(path.toFile())); + assertTrue(path.toFile().exists()); + + writeLink(LINK, "link_to_nowhere"); + assertFalse(path.toFile().exists()); + assertEquals("link_to_nowhere", FileUtils.readSymLink(path.toFile())); + + CheckoutCommand co = git.checkout(); + co.addPath(LINK).call(); + + assertEquals("f", FileUtils.readSymLink(path.toFile())); + } + + @Test + public void testUpdateBrokenSymLink() throws Exception { + Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); + + Path path = writeLink(LINK, FILE1); + git.add().addFilepattern(LINK).call(); + git.commit().setMessage("Added link").call(); + assertEquals("3", read(path.toFile())); + assertEquals(FILE1, FileUtils.readSymLink(path.toFile())); + + writeLink(LINK, "link_to_nowhere"); + assertFalse(path.toFile().exists()); + assertEquals("link_to_nowhere", FileUtils.readSymLink(path.toFile())); + + CheckoutCommand co = git.checkout(); + co.addPath(LINK).call(); + + assertEquals("3", read(path.toFile())); + } + + @Test public void testUpdateWorkingDirectory() throws Exception { CheckoutCommand co = git.checkout(); File written = writeTrashFile(FILE1, ""); 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 a67f2b912a..66f25e8e51 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 @@ -65,6 +65,7 @@ import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; @@ -139,8 +140,8 @@ public class ResetCommandTest extends RepositoryTestCase { AmbiguousObjectException, IOException, GitAPIException { setupRepository(); ObjectId prevHead = db.resolve(Constants.HEAD); - git.reset().setMode(ResetType.HARD).setRef(initialCommit.getName()) - .call(); + assertSameAsHead(git.reset().setMode(ResetType.HARD) + .setRef(initialCommit.getName()).call()); // check if HEAD points to initial commit now ObjectId head = db.resolve(Constants.HEAD); assertEquals(initialCommit, head); @@ -176,8 +177,8 @@ public class ResetCommandTest extends RepositoryTestCase { AmbiguousObjectException, IOException, GitAPIException { setupRepository(); ObjectId prevHead = db.resolve(Constants.HEAD); - git.reset().setMode(ResetType.SOFT).setRef(initialCommit.getName()) - .call(); + assertSameAsHead(git.reset().setMode(ResetType.SOFT) + .setRef(initialCommit.getName()).call()); // check if HEAD points to initial commit now ObjectId head = db.resolve(Constants.HEAD); assertEquals(initialCommit, head); @@ -197,8 +198,8 @@ public class ResetCommandTest extends RepositoryTestCase { AmbiguousObjectException, IOException, GitAPIException { setupRepository(); ObjectId prevHead = db.resolve(Constants.HEAD); - git.reset().setMode(ResetType.MIXED).setRef(initialCommit.getName()) - .call(); + assertSameAsHead(git.reset().setMode(ResetType.MIXED) + .setRef(initialCommit.getName()).call()); // check if HEAD points to initial commit now ObjectId head = db.resolve(Constants.HEAD); assertEquals(initialCommit, head); @@ -241,7 +242,8 @@ public class ResetCommandTest extends RepositoryTestCase { assertTrue(bEntry.getLength() > 0); assertTrue(bEntry.getLastModified() > 0); - git.reset().setMode(ResetType.MIXED).setRef(commit2.getName()).call(); + assertSameAsHead(git.reset().setMode(ResetType.MIXED) + .setRef(commit2.getName()).call()); cache = db.readDirCache(); @@ -280,7 +282,7 @@ public class ResetCommandTest extends RepositoryTestCase { + "[a.txt, mode:100644, stage:3]", indexState(0)); - git.reset().setMode(ResetType.MIXED).call(); + assertSameAsHead(git.reset().setMode(ResetType.MIXED).call()); assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]", indexState(0)); @@ -298,8 +300,8 @@ public class ResetCommandTest extends RepositoryTestCase { // 'a.txt' has already been modified in setupRepository // 'notAddedToIndex.txt' has been added to repository - git.reset().addPath(indexFile.getName()) - .addPath(untrackedFile.getName()).call(); + assertSameAsHead(git.reset().addPath(indexFile.getName()) + .addPath(untrackedFile.getName()).call()); DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS()) .getEntry(indexFile.getName()); @@ -329,7 +331,7 @@ public class ResetCommandTest extends RepositoryTestCase { git.add().addFilepattern(untrackedFile.getName()).call(); // 'dir/b.txt' has already been modified in setupRepository - git.reset().addPath("dir").call(); + assertSameAsHead(git.reset().addPath("dir").call()); DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS()) .getEntry("dir/b.txt"); @@ -358,9 +360,9 @@ public class ResetCommandTest extends RepositoryTestCase { // 'a.txt' has already been modified in setupRepository // 'notAddedToIndex.txt' has been added to repository // reset to the inital commit - git.reset().setRef(initialCommit.getName()) - .addPath(indexFile.getName()) - .addPath(untrackedFile.getName()).call(); + assertSameAsHead(git.reset().setRef(initialCommit.getName()) + .addPath(indexFile.getName()).addPath(untrackedFile.getName()) + .call()); // check that HEAD hasn't moved ObjectId head = db.resolve(Constants.HEAD); @@ -397,7 +399,7 @@ public class ResetCommandTest extends RepositoryTestCase { + "[b.txt, mode:100644]", indexState(0)); - git.reset().addPath(file).call(); + assertSameAsHead(git.reset().addPath(file).call()); assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]", indexState(0)); @@ -409,7 +411,7 @@ public class ResetCommandTest extends RepositoryTestCase { writeTrashFile("a.txt", "content"); git.add().addFilepattern("a.txt").call(); // Should assume an empty tree, like in C Git 1.8.2 - git.reset().addPath("a.txt").call(); + assertSameAsHead(git.reset().addPath("a.txt").call()); DirCache cache = db.readDirCache(); DirCacheEntry aEntry = cache.getEntry("a.txt"); @@ -421,7 +423,8 @@ public class ResetCommandTest extends RepositoryTestCase { git = new Git(db); writeTrashFile("a.txt", "content"); git.add().addFilepattern("a.txt").call(); - git.reset().setRef("doesnotexist").addPath("a.txt").call(); + assertSameAsHead( + git.reset().setRef("doesnotexist").addPath("a.txt").call()); } @Test @@ -431,7 +434,7 @@ public class ResetCommandTest extends RepositoryTestCase { git.add().addFilepattern("a.txt").call(); writeTrashFile("a.txt", "modified"); // should use default mode MIXED - git.reset().call(); + assertSameAsHead(git.reset().call()); DirCache cache = db.readDirCache(); DirCacheEntry aEntry = cache.getEntry("a.txt"); @@ -452,7 +455,7 @@ public class ResetCommandTest extends RepositoryTestCase { git.add().addFilepattern(untrackedFile.getName()).call(); - git.reset().setRef(tagName).setMode(HARD).call(); + assertSameAsHead(git.reset().setRef(tagName).setMode(HARD).call()); ObjectId head = db.resolve(Constants.HEAD); assertEquals(secondCommit, head); @@ -486,7 +489,8 @@ public class ResetCommandTest extends RepositoryTestCase { result.getMergeStatus()); assertNotNull(db.readSquashCommitMsg()); - g.reset().setMode(ResetType.HARD).setRef(first.getName()).call(); + assertSameAsHead(g.reset().setMode(ResetType.HARD) + .setRef(first.getName()).call()); assertNull(db.readSquashCommitMsg()); } @@ -497,7 +501,7 @@ public class ResetCommandTest extends RepositoryTestCase { File fileA = writeTrashFile("a.txt", "content"); git.add().addFilepattern("a.txt").call(); // Should assume an empty tree, like in C Git 1.8.2 - git.reset().setMode(ResetType.HARD).call(); + assertSameAsHead(git.reset().setMode(ResetType.HARD).call()); DirCache cache = db.readDirCache(); DirCacheEntry aEntry = cache.getEntry("a.txt"); @@ -558,4 +562,14 @@ public class ResetCommandTest extends RepositoryTestCase { return dc.getEntry(path) != null; } + /** + * Asserts that a certain ref is similar to repos HEAD. + * @param ref + * @throws IOException + */ + private void assertSameAsHead(Ref ref) throws IOException { + Ref headRef = db.getRef(Constants.HEAD); + assertEquals(headRef.getName(), ref.getName()); + assertEquals(headRef.getObjectId(), ref.getObjectId()); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java index 63ec85861d..c85e156352 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java @@ -43,11 +43,13 @@ package org.eclipse.jgit.dircache; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.List; import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; +import org.eclipse.jgit.errors.DirCacheNameConflictException; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; @@ -154,6 +156,125 @@ public class DirCachePathEditTest { assertEquals(DirCacheEntry.STAGE_3, entries.get(2).getStage()); } + @Test + public void testFileReplacesTree() throws Exception { + DirCache dc = DirCache.newInCore(); + DirCacheEditor editor = dc.editor(); + editor.add(new AddEdit("a")); + editor.add(new AddEdit("b/c")); + editor.add(new AddEdit("b/d")); + editor.add(new AddEdit("e")); + editor.finish(); + + editor = dc.editor(); + editor.add(new AddEdit("b")); + editor.finish(); + + assertEquals(3, dc.getEntryCount()); + assertEquals("a", dc.getEntry(0).getPathString()); + assertEquals("b", dc.getEntry(1).getPathString()); + assertEquals("e", dc.getEntry(2).getPathString()); + + dc.clear(); + editor = dc.editor(); + editor.add(new AddEdit("A.c")); + editor.add(new AddEdit("A/c")); + editor.add(new AddEdit("A0c")); + editor.finish(); + + editor = dc.editor(); + editor.add(new AddEdit("A")); + editor.finish(); + assertEquals(3, dc.getEntryCount()); + assertEquals("A", dc.getEntry(0).getPathString()); + assertEquals("A.c", dc.getEntry(1).getPathString()); + assertEquals("A0c", dc.getEntry(2).getPathString()); + } + + @Test + public void testTreeReplacesFile() throws Exception { + DirCache dc = DirCache.newInCore(); + DirCacheEditor editor = dc.editor(); + editor.add(new AddEdit("a")); + editor.add(new AddEdit("ab")); + editor.add(new AddEdit("b")); + editor.add(new AddEdit("e")); + editor.finish(); + + editor = dc.editor(); + editor.add(new AddEdit("b/c/d/f")); + editor.add(new AddEdit("b/g/h/i")); + editor.finish(); + + assertEquals(5, dc.getEntryCount()); + assertEquals("a", dc.getEntry(0).getPathString()); + assertEquals("ab", dc.getEntry(1).getPathString()); + assertEquals("b/c/d/f", dc.getEntry(2).getPathString()); + assertEquals("b/g/h/i", dc.getEntry(3).getPathString()); + assertEquals("e", dc.getEntry(4).getPathString()); + } + + @Test + public void testDuplicateFiles() throws Exception { + DirCache dc = DirCache.newInCore(); + DirCacheEditor editor = dc.editor(); + editor.add(new AddEdit("a")); + editor.add(new AddEdit("a")); + + try { + editor.finish(); + fail("Expected DirCacheNameConflictException to be thrown"); + } catch (DirCacheNameConflictException e) { + assertEquals("a a", e.getMessage()); + assertEquals("a", e.getPath1()); + assertEquals("a", e.getPath2()); + } + } + + @Test + public void testFileOverlapsTree() throws Exception { + DirCache dc = DirCache.newInCore(); + DirCacheEditor editor = dc.editor(); + editor.add(new AddEdit("a")); + editor.add(new AddEdit("a/b").setReplace(false)); + try { + editor.finish(); + fail("Expected DirCacheNameConflictException to be thrown"); + } catch (DirCacheNameConflictException e) { + assertEquals("a a/b", e.getMessage()); + assertEquals("a", e.getPath1()); + assertEquals("a/b", e.getPath2()); + } + + editor = dc.editor(); + editor.add(new AddEdit("A.c")); + editor.add(new AddEdit("A/c").setReplace(false)); + editor.add(new AddEdit("A0c")); + editor.add(new AddEdit("A")); + try { + editor.finish(); + fail("Expected DirCacheNameConflictException to be thrown"); + } catch (DirCacheNameConflictException e) { + assertEquals("A A/c", e.getMessage()); + assertEquals("A", e.getPath1()); + assertEquals("A/c", e.getPath2()); + } + + editor = dc.editor(); + editor.add(new AddEdit("A.c")); + editor.add(new AddEdit("A/b/c/d").setReplace(false)); + editor.add(new AddEdit("A/b/c")); + editor.add(new AddEdit("A0c")); + try { + editor.finish(); + fail("Expected DirCacheNameConflictException to be thrown"); + } catch (DirCacheNameConflictException e) { + assertEquals("A/b/c A/b/c/d", e.getMessage()); + assertEquals("A/b/c", e.getPath1()); + assertEquals("A/b/c/d", e.getPath2()); + } + } + private static DirCacheEntry createEntry(String path, int stage) { DirCacheEntry entry = new DirCacheEntry(path, stage); entry.setFileMode(FileMode.REGULAR_FILE); 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 b6649b3f05..524d0b8e7e 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 @@ -409,6 +409,7 @@ public class RepoCommandTest extends RepositoryTestCase { .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("</project>").append("</manifest>"); JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", xmlContent.toString()); @@ -423,8 +424,12 @@ public class RepoCommandTest extends RepositoryTestCase { .getRepository(); // The Hello file should exist File hello = new File(localDb.getWorkTree(), "Hello"); - localDb.close(); 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()); + localDb.close(); // The content of Hello file should be expected BufferedReader reader = new BufferedReader(new FileReader(hello)); String content = reader.readLine(); 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 2d72d2373b..dca356434b 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 @@ -107,7 +107,7 @@ public class FileRepositoryBuilderTest extends LocalDiskRepositoryTestCase { Repository r = createWorkRepository(); StoredConfig config = r.getConfig(); config.setLong(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 1); + ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 999999); config.save(); try { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java index bc880a13ef..01d6ee68e8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java @@ -43,11 +43,13 @@ package org.eclipse.jgit.internal.storage.file; +import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -66,19 +68,19 @@ import java.util.Set; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; import org.eclipse.jgit.internal.storage.pack.PackWriter; -import org.eclipse.jgit.internal.storage.pack.PackWriter.ObjectIdSet; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRepository.BranchBuilder; -import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdSet; import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.pack.PackConfig; +import org.eclipse.jgit.storage.pack.PackStatistics; import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; import org.eclipse.jgit.transport.PackParser; import org.junit.After; @@ -87,9 +89,6 @@ import org.junit.Test; public class PackWriterTest extends SampleDataRepositoryTestCase { - private static final Set<ObjectId> EMPTY_SET_OBJECT = Collections - .<ObjectId> emptySet(); - private static final List<RevObject> EMPTY_LIST_REVS = Collections .<RevObject> emptyList(); @@ -170,7 +169,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { */ @Test public void testWriteEmptyPack1() throws IOException { - createVerifyOpenPack(EMPTY_SET_OBJECT, EMPTY_SET_OBJECT, false, false); + createVerifyOpenPack(NONE, NONE, false, false); assertEquals(0, writer.getObjectCount()); assertEquals(0, pack.getObjectCount()); @@ -203,8 +202,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { final ObjectId nonExisting = ObjectId .fromString("0000000000000000000000000000000000000001"); try { - createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton( - nonExisting), false, false); + createVerifyOpenPack(NONE, Collections.singleton(nonExisting), + false, false); fail("Should have thrown MissingObjectException"); } catch (MissingObjectException x) { // expected @@ -220,8 +219,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { public void testIgnoreNonExistingObjects() throws IOException { final ObjectId nonExisting = ObjectId .fromString("0000000000000000000000000000000000000001"); - createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton( - nonExisting), false, true); + createVerifyOpenPack(NONE, Collections.singleton(nonExisting), + false, true); // shouldn't throw anything } @@ -239,8 +238,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { final ObjectId nonExisting = ObjectId .fromString("0000000000000000000000000000000000000001"); new GC(db).gc(); - createVerifyOpenPack(EMPTY_SET_OBJECT, - Collections.singleton(nonExisting), false, true, true); + createVerifyOpenPack(NONE, Collections.singleton(nonExisting), false, + true, true); // shouldn't throw anything } @@ -438,6 +437,38 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { } @Test + public void testDeltaStatistics() throws Exception { + config.setDeltaCompress(true); + FileRepository repo = createBareRepository(); + TestRepository<FileRepository> testRepo = new TestRepository<FileRepository>(repo); + ArrayList<RevObject> blobs = new ArrayList<>(); + blobs.add(testRepo.blob(genDeltableData(1000))); + blobs.add(testRepo.blob(genDeltableData(1005))); + + try (PackWriter pw = new PackWriter(repo)) { + NullProgressMonitor m = NullProgressMonitor.INSTANCE; + pw.preparePack(blobs.iterator()); + pw.writePack(m, m, os); + PackStatistics stats = pw.getStatistics(); + assertEquals(1, stats.getTotalDeltas()); + assertTrue("Delta bytes not set.", + stats.byObjectType(OBJ_BLOB).getDeltaBytes() > 0); + } + } + + // Generate consistent junk data for building files that delta well + private String genDeltableData(int length) { + assertTrue("Generated data must have a length > 0", length > 0); + char[] data = {'a', 'b', 'c', '\n'}; + StringBuilder builder = new StringBuilder(length); + for (int i = 0; i < length; i++) { + builder.append(data[i % 4]); + } + return builder.toString(); + } + + + @Test public void testWriteIndex() throws Exception { config.setIndexVersion(2); writeVerifyPack4(false); @@ -494,7 +525,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { RevCommit c2 = bb.commit().add("f", contentB).create(); testRepo.getRevWalk().parseHeaders(c2); PackIndex pf2 = writePack(repo, Collections.singleton(c2), - Collections.singleton(objectIdSet(pf1))); + Collections.<ObjectIdSet> singleton(pf1)); assertContent( pf2, Arrays.asList(c2.getId(), c2.getTree().getId(), @@ -519,8 +550,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { pw.setReuseDeltaCommits(false); for (ObjectIdSet idx : excludeObjects) pw.excludeObjects(idx); - pw.preparePack(NullProgressMonitor.INSTANCE, want, - Collections.<ObjectId> emptySet()); + pw.preparePack(NullProgressMonitor.INSTANCE, want, NONE); String id = pw.computeName().getName(); File packdir = new File(repo.getObjectsDirectory(), "pack"); File packFile = new File(packdir, "pack-" + id + ".pack"); @@ -543,7 +573,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { final HashSet<ObjectId> interestings = new HashSet<ObjectId>(); interestings.add(ObjectId .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")); - createVerifyOpenPack(interestings, EMPTY_SET_OBJECT, false, false); + createVerifyOpenPack(interestings, NONE, false, false); final ObjectId expectedOrder[] = new ObjectId[] { ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"), @@ -699,12 +729,4 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { assertEquals(objectsOrder[i++].toObjectId(), me.toObjectId()); } } - - private static ObjectIdSet objectIdSet(final PackIndex idx) { - return new ObjectIdSet() { - public boolean contains(AnyObjectId objectId) { - return idx.hasObject(objectId); - } - }; - } } 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 a92ff8d04e..f4d655f86b 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 @@ -67,7 +67,6 @@ import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; -import org.eclipse.jgit.lib.FileTreeEntry; import org.eclipse.jgit.lib.ObjectDatabase; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; @@ -75,7 +74,6 @@ import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.TagBuilder; -import org.eclipse.jgit.lib.Tree; import org.eclipse.jgit.lib.TreeFormatter; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevTag; @@ -420,29 +418,6 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { } @Test - public void test012_SubtreeExternalSorting() throws IOException { - final ObjectId emptyBlob = insertEmptyBlob(); - final Tree t = new Tree(db); - final FileTreeEntry e0 = t.addFile("a-"); - final FileTreeEntry e1 = t.addFile("a-b"); - final FileTreeEntry e2 = t.addFile("a/b"); - final FileTreeEntry e3 = t.addFile("a="); - final FileTreeEntry e4 = t.addFile("a=b"); - - e0.setId(emptyBlob); - e1.setId(emptyBlob); - e2.setId(emptyBlob); - e3.setId(emptyBlob); - e4.setId(emptyBlob); - - final Tree a = (Tree) t.findTreeMember("a"); - a.setId(insertTree(a)); - assertEquals(ObjectId - .fromString("b47a8f0a4190f7572e11212769090523e23eb1ea"), - insertTree(t)); - } - - @Test public void test020_createBlobTag() throws IOException { final ObjectId emptyId = insertEmptyBlob(); final TagBuilder t = new TagBuilder(); @@ -465,9 +440,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { @Test public void test021_createTreeTag() throws IOException { final ObjectId emptyId = insertEmptyBlob(); - final Tree almostEmptyTree = new Tree(db); - almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, - "empty".getBytes(), false)); + TreeFormatter almostEmptyTree = new TreeFormatter(); + almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); final TagBuilder t = new TagBuilder(); t.setObjectId(almostEmptyTreeId, Constants.OBJ_TREE); @@ -489,9 +463,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { @Test public void test022_createCommitTag() throws IOException { final ObjectId emptyId = insertEmptyBlob(); - final Tree almostEmptyTree = new Tree(db); - almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, - "empty".getBytes(), false)); + TreeFormatter almostEmptyTree = new TreeFormatter(); + almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); final CommitBuilder almostEmptyCommit = new CommitBuilder(); almostEmptyCommit.setAuthor(new PersonIdent(author, 1154236443000L, @@ -521,9 +494,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { @Test public void test023_createCommitNonAnullii() throws IOException { final ObjectId emptyId = insertEmptyBlob(); - final Tree almostEmptyTree = new Tree(db); - almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, - "empty".getBytes(), false)); + TreeFormatter almostEmptyTree = new TreeFormatter(); + almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); CommitBuilder commit = new CommitBuilder(); commit.setTreeId(almostEmptyTreeId); @@ -543,9 +515,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { @Test public void test024_createCommitNonAscii() throws IOException { final ObjectId emptyId = insertEmptyBlob(); - final Tree almostEmptyTree = new Tree(db); - almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, - "empty".getBytes(), false)); + TreeFormatter almostEmptyTree = new TreeFormatter(); + almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); CommitBuilder commit = new CommitBuilder(); commit.setTreeId(almostEmptyTreeId); @@ -747,14 +718,6 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { return emptyId; } - private ObjectId insertTree(Tree tree) throws IOException { - try (ObjectInserter oi = db.newObjectInserter()) { - ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format()); - oi.flush(); - return id; - } - } - private ObjectId insertTree(TreeFormatter tree) throws IOException { try (ObjectInserter oi = db.newObjectInserter()) { ObjectId id = oi.insert(tree); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java new file mode 100644 index 0000000000..020d1b1b51 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java @@ -0,0 +1,685 @@ +/* + * Copyright (C) 2010, 2013, 2016 Google Inc. + * 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.storage.reftree; + +import static org.eclipse.jgit.lib.Constants.HEAD; +import static org.eclipse.jgit.lib.Constants.R_HEADS; +import static org.eclipse.jgit.lib.Constants.R_TAGS; +import static org.eclipse.jgit.lib.Ref.Storage.LOOSE; +import static org.eclipse.jgit.lib.Ref.Storage.PACKED; +import static org.eclipse.jgit.lib.RefDatabase.ALL; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.eclipse.jgit.internal.JGitText; +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.AnyObjectId; +import org.eclipse.jgit.lib.BatchRefUpdate; +import org.eclipse.jgit.lib.CommitBuilder; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.SymbolicRef; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.junit.Before; +import org.junit.Test; + +public class RefTreeDatabaseTest { + private InMemRefTreeRepo repo; + private RefTreeDatabase refdb; + private RefDatabase bootstrap; + + private TestRepository<InMemRefTreeRepo> testRepo; + private RevCommit A; + private RevCommit B; + private RevTag v1_0; + + @Before + public void setUp() throws Exception { + repo = new InMemRefTreeRepo(new DfsRepositoryDescription("test")); + bootstrap = refdb.getBootstrap(); + + testRepo = new TestRepository<>(repo); + A = testRepo.commit().create(); + B = testRepo.commit(testRepo.getRevWalk().parseCommit(A)); + v1_0 = testRepo.tag("v1_0", B); + testRepo.getRevWalk().parseBody(v1_0); + } + + @Test + public void testSupportsAtomic() { + assertTrue(refdb.performsAtomicTransactions()); + } + + @Test + public void testGetRefs_EmptyDatabase() throws IOException { + assertTrue("no references", refdb.getRefs(ALL).isEmpty()); + assertTrue("no references", refdb.getRefs(R_HEADS).isEmpty()); + assertTrue("no references", refdb.getRefs(R_TAGS).isEmpty()); + } + + @Test + public void testGetRefs_HeadOnOneBranch() throws IOException { + symref(HEAD, "refs/heads/master"); + update("refs/heads/master", A); + + Map<String, Ref> all = refdb.getRefs(ALL); + assertEquals(2, all.size()); + assertTrue("has HEAD", all.containsKey(HEAD)); + assertTrue("has master", all.containsKey("refs/heads/master")); + + Ref head = all.get(HEAD); + Ref master = all.get("refs/heads/master"); + + assertEquals(HEAD, head.getName()); + assertTrue(head.isSymbolic()); + assertSame(LOOSE, head.getStorage()); + assertSame("uses same ref as target", master, head.getTarget()); + + assertEquals("refs/heads/master", master.getName()); + assertFalse(master.isSymbolic()); + assertSame(PACKED, master.getStorage()); + assertEquals(A, master.getObjectId()); + } + + @Test + public void testGetRefs_DetachedHead() throws IOException { + update(HEAD, A); + + Map<String, Ref> all = refdb.getRefs(ALL); + assertEquals(1, all.size()); + assertTrue("has HEAD", all.containsKey(HEAD)); + + Ref head = all.get(HEAD); + assertEquals(HEAD, head.getName()); + assertFalse(head.isSymbolic()); + assertSame(PACKED, head.getStorage()); + assertEquals(A, head.getObjectId()); + } + + @Test + public void testGetRefs_DeeplyNestedBranch() throws IOException { + String name = "refs/heads/a/b/c/d/e/f/g/h/i/j/k"; + update(name, A); + + Map<String, Ref> all = refdb.getRefs(ALL); + assertEquals(1, all.size()); + + Ref r = all.get(name); + assertEquals(name, r.getName()); + assertFalse(r.isSymbolic()); + assertSame(PACKED, r.getStorage()); + assertEquals(A, r.getObjectId()); + } + + @Test + public void testGetRefs_HeadBranchNotBorn() throws IOException { + update("refs/heads/A", A); + update("refs/heads/B", B); + + Map<String, Ref> all = refdb.getRefs(ALL); + assertEquals(2, all.size()); + assertFalse("no HEAD", all.containsKey(HEAD)); + + Ref a = all.get("refs/heads/A"); + Ref b = all.get("refs/heads/B"); + + assertEquals(A, a.getObjectId()); + assertEquals(B, b.getObjectId()); + + assertEquals("refs/heads/A", a.getName()); + assertEquals("refs/heads/B", b.getName()); + } + + @Test + public void testGetRefs_HeadsOnly() throws IOException { + update("refs/heads/A", A); + update("refs/heads/B", B); + update("refs/tags/v1.0", v1_0); + + Map<String, Ref> heads = refdb.getRefs(R_HEADS); + assertEquals(2, heads.size()); + + Ref a = heads.get("A"); + Ref b = heads.get("B"); + + assertEquals("refs/heads/A", a.getName()); + assertEquals("refs/heads/B", b.getName()); + + assertEquals(A, a.getObjectId()); + assertEquals(B, b.getObjectId()); + } + + @Test + public void testGetRefs_TagsOnly() throws IOException { + update("refs/heads/A", A); + update("refs/heads/B", B); + update("refs/tags/v1.0", v1_0); + + Map<String, Ref> tags = refdb.getRefs(R_TAGS); + assertEquals(1, tags.size()); + + Ref a = tags.get("v1.0"); + assertEquals("refs/tags/v1.0", a.getName()); + assertEquals(v1_0, a.getObjectId()); + assertTrue(a.isPeeled()); + assertEquals(v1_0.getObject(), a.getPeeledObjectId()); + } + + @Test + public void testGetRefs_HeadsSymref() throws IOException { + symref("refs/heads/other", "refs/heads/master"); + update("refs/heads/master", A); + + Map<String, Ref> heads = refdb.getRefs(R_HEADS); + assertEquals(2, heads.size()); + + Ref master = heads.get("master"); + Ref other = heads.get("other"); + + assertEquals("refs/heads/master", master.getName()); + assertEquals(A, master.getObjectId()); + + assertEquals("refs/heads/other", other.getName()); + assertEquals(A, other.getObjectId()); + assertSame(master, other.getTarget()); + } + + @Test + public void testGetRefs_InvalidPrefixes() throws IOException { + update("refs/heads/A", A); + + assertTrue("empty refs/heads", refdb.getRefs("refs/heads").isEmpty()); + assertTrue("empty objects", refdb.getRefs("objects").isEmpty()); + assertTrue("empty objects/", refdb.getRefs("objects/").isEmpty()); + } + + @Test + public void testGetRefs_DiscoversNew() throws IOException { + update("refs/heads/master", A); + Map<String, Ref> orig = refdb.getRefs(ALL); + + update("refs/heads/next", B); + Map<String, Ref> next = refdb.getRefs(ALL); + + assertEquals(1, orig.size()); + assertEquals(2, next.size()); + + assertFalse(orig.containsKey("refs/heads/next")); + assertTrue(next.containsKey("refs/heads/next")); + + assertEquals(A, next.get("refs/heads/master").getObjectId()); + assertEquals(B, next.get("refs/heads/next").getObjectId()); + } + + @Test + public void testGetRefs_DiscoversModified() throws IOException { + symref(HEAD, "refs/heads/master"); + update("refs/heads/master", A); + + Map<String, Ref> all = refdb.getRefs(ALL); + assertEquals(A, all.get(HEAD).getObjectId()); + + update("refs/heads/master", B); + all = refdb.getRefs(ALL); + assertEquals(B, all.get(HEAD).getObjectId()); + assertEquals(B, refdb.exactRef(HEAD).getObjectId()); + } + + @Test + public void testGetRefs_CycleInSymbolicRef() throws IOException { + symref("refs/1", "refs/2"); + symref("refs/2", "refs/3"); + symref("refs/3", "refs/4"); + symref("refs/4", "refs/5"); + symref("refs/5", "refs/end"); + update("refs/end", A); + + Map<String, Ref> all = refdb.getRefs(ALL); + Ref r = all.get("refs/1"); + assertNotNull("has 1", r); + + assertEquals("refs/1", r.getName()); + assertEquals(A, r.getObjectId()); + assertTrue(r.isSymbolic()); + + r = r.getTarget(); + assertEquals("refs/2", r.getName()); + assertEquals(A, r.getObjectId()); + assertTrue(r.isSymbolic()); + + r = r.getTarget(); + assertEquals("refs/3", r.getName()); + assertEquals(A, r.getObjectId()); + assertTrue(r.isSymbolic()); + + r = r.getTarget(); + assertEquals("refs/4", r.getName()); + assertEquals(A, r.getObjectId()); + assertTrue(r.isSymbolic()); + + r = r.getTarget(); + assertEquals("refs/5", r.getName()); + assertEquals(A, r.getObjectId()); + assertTrue(r.isSymbolic()); + + r = r.getTarget(); + assertEquals("refs/end", r.getName()); + assertEquals(A, r.getObjectId()); + assertFalse(r.isSymbolic()); + + symref("refs/5", "refs/6"); + symref("refs/6", "refs/end"); + all = refdb.getRefs(ALL); + assertNull("mising 1 due to cycle", all.get("refs/1")); + assertEquals(A, all.get("refs/2").getObjectId()); + assertEquals(A, all.get("refs/3").getObjectId()); + assertEquals(A, all.get("refs/4").getObjectId()); + assertEquals(A, all.get("refs/5").getObjectId()); + assertEquals(A, all.get("refs/6").getObjectId()); + assertEquals(A, all.get("refs/end").getObjectId()); + } + + @Test + public void testGetRef_NonExistingBranchConfig() throws IOException { + assertNull("find branch config", refdb.getRef("config")); + assertNull("find branch config", refdb.getRef("refs/heads/config")); + } + + @Test + public void testGetRef_FindBranchConfig() throws IOException { + update("refs/heads/config", A); + + for (String t : new String[] { "config", "refs/heads/config" }) { + Ref r = refdb.getRef(t); + assertNotNull("find branch config (" + t + ")", r); + assertEquals("for " + t, "refs/heads/config", r.getName()); + assertEquals("for " + t, A, r.getObjectId()); + } + } + + @Test + public void testFirstExactRef() throws IOException { + update("refs/heads/A", A); + update("refs/tags/v1.0", v1_0); + + Ref a = refdb.firstExactRef("refs/heads/A", "refs/tags/v1.0"); + Ref one = refdb.firstExactRef("refs/tags/v1.0", "refs/heads/A"); + + assertEquals("refs/heads/A", a.getName()); + assertEquals("refs/tags/v1.0", one.getName()); + + assertEquals(A, a.getObjectId()); + assertEquals(v1_0, one.getObjectId()); + } + + @Test + public void testExactRef_DiscoversModified() throws IOException { + symref(HEAD, "refs/heads/master"); + update("refs/heads/master", A); + assertEquals(A, refdb.exactRef(HEAD).getObjectId()); + + update("refs/heads/master", B); + assertEquals(B, refdb.exactRef(HEAD).getObjectId()); + } + + @Test + public void testIsNameConflicting() throws IOException { + update("refs/heads/a/b", A); + update("refs/heads/q", B); + + // new references cannot replace an existing container + assertTrue(refdb.isNameConflicting("refs")); + assertTrue(refdb.isNameConflicting("refs/heads")); + assertTrue(refdb.isNameConflicting("refs/heads/a")); + + // existing reference is not conflicting + assertFalse(refdb.isNameConflicting("refs/heads/a/b")); + + // new references are not conflicting + assertFalse(refdb.isNameConflicting("refs/heads/a/d")); + assertFalse(refdb.isNameConflicting("refs/heads/master")); + + // existing reference must not be used as a container + assertTrue(refdb.isNameConflicting("refs/heads/a/b/c")); + assertTrue(refdb.isNameConflicting("refs/heads/q/master")); + + // refs/txn/ names always conflict. + assertTrue(refdb.isNameConflicting(refdb.getTxnCommitted())); + assertTrue(refdb.isNameConflicting("refs/txn/foo")); + } + + @Test + public void testUpdate_RefusesRefsTxnNamespace() throws IOException { + ObjectId txnId = getTxnCommitted(); + + RefUpdate u = refdb.newUpdate("refs/txn/tmp", false); + u.setNewObjectId(B); + assertEquals(RefUpdate.Result.LOCK_FAILURE, u.update()); + assertEquals(txnId, getTxnCommitted()); + + ReceiveCommand cmd = command(null, B, "refs/txn/tmp"); + BatchRefUpdate batch = refdb.newBatchUpdate(); + batch.addCommand(cmd); + batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + + assertEquals(REJECTED_OTHER_REASON, cmd.getResult()); + assertEquals(MessageFormat.format(JGitText.get().invalidRefName, + "refs/txn/tmp"), cmd.getMessage()); + assertEquals(txnId, getTxnCommitted()); + } + + @Test + public void testUpdate_RefusesDotLockInRefName() throws IOException { + ObjectId txnId = getTxnCommitted(); + + RefUpdate u = refdb.newUpdate("refs/heads/pu.lock", false); + u.setNewObjectId(B); + assertEquals(RefUpdate.Result.REJECTED, u.update()); + assertEquals(txnId, getTxnCommitted()); + + ReceiveCommand cmd = command(null, B, "refs/heads/pu.lock"); + BatchRefUpdate batch = refdb.newBatchUpdate(); + batch.addCommand(cmd); + batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + + assertEquals(REJECTED_OTHER_REASON, cmd.getResult()); + assertEquals(JGitText.get().funnyRefname, cmd.getMessage()); + assertEquals(txnId, getTxnCommitted()); + } + + @Test + public void testBatchRefUpdate_NonFastForwardAborts() throws IOException { + update("refs/heads/master", A); + update("refs/heads/masters", B); + ObjectId txnId = getTxnCommitted(); + + List<ReceiveCommand> commands = Arrays.asList( + command(A, B, "refs/heads/master"), + command(B, A, "refs/heads/masters")); + BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); + batchUpdate.addCommand(commands); + batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + assertEquals(txnId, getTxnCommitted()); + + assertEquals(REJECTED_NONFASTFORWARD, + commands.get(1).getResult()); + assertEquals(REJECTED_OTHER_REASON, + commands.get(0).getResult()); + assertEquals(JGitText.get().transactionAborted, + commands.get(0).getMessage()); + } + + @Test + public void testBatchRefUpdate_ForceUpdate() throws IOException { + update("refs/heads/master", A); + update("refs/heads/masters", B); + ObjectId txnId = getTxnCommitted(); + + List<ReceiveCommand> commands = Arrays.asList( + command(A, B, "refs/heads/master"), + command(B, A, "refs/heads/masters")); + BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); + batchUpdate.setAllowNonFastForwards(true); + batchUpdate.addCommand(commands); + batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + assertNotEquals(txnId, getTxnCommitted()); + + Map<String, Ref> refs = refdb.getRefs(ALL); + assertEquals(OK, commands.get(0).getResult()); + assertEquals(OK, commands.get(1).getResult()); + assertEquals( + "[refs/heads/master, refs/heads/masters]", + refs.keySet().toString()); + assertEquals(B.getId(), refs.get("refs/heads/master").getObjectId()); + assertEquals(A.getId(), refs.get("refs/heads/masters").getObjectId()); + } + + @Test + public void testBatchRefUpdate_NonFastForwardDoesNotDoExpensiveMergeCheck() + throws IOException { + update("refs/heads/master", B); + ObjectId txnId = getTxnCommitted(); + + List<ReceiveCommand> commands = Arrays.asList( + command(B, A, "refs/heads/master")); + BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); + batchUpdate.setAllowNonFastForwards(true); + batchUpdate.addCommand(commands); + batchUpdate.execute(new RevWalk(repo) { + @Override + public boolean isMergedInto(RevCommit base, RevCommit tip) { + fail("isMergedInto() should not be called"); + return false; + } + }, NullProgressMonitor.INSTANCE); + assertNotEquals(txnId, getTxnCommitted()); + + Map<String, Ref> refs = refdb.getRefs(ALL); + assertEquals(OK, commands.get(0).getResult()); + assertEquals(A.getId(), refs.get("refs/heads/master").getObjectId()); + } + + @Test + public void testBatchRefUpdate_ConflictCausesAbort() throws IOException { + update("refs/heads/master", A); + update("refs/heads/masters", B); + ObjectId txnId = getTxnCommitted(); + + List<ReceiveCommand> commands = Arrays.asList( + command(A, B, "refs/heads/master"), + command(null, A, "refs/heads/master/x"), + command(null, A, "refs/heads")); + BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); + batchUpdate.setAllowNonFastForwards(true); + batchUpdate.addCommand(commands); + batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + assertEquals(txnId, getTxnCommitted()); + + assertEquals(LOCK_FAILURE, commands.get(0).getResult()); + + assertEquals(REJECTED_OTHER_REASON, commands.get(1).getResult()); + assertEquals(JGitText.get().transactionAborted, + commands.get(1).getMessage()); + + assertEquals(REJECTED_OTHER_REASON, commands.get(2).getResult()); + assertEquals(JGitText.get().transactionAborted, + commands.get(2).getMessage()); + } + + @Test + public void testBatchRefUpdate_NoConflictIfDeleted() throws IOException { + update("refs/heads/master", A); + update("refs/heads/masters", B); + ObjectId txnId = getTxnCommitted(); + + List<ReceiveCommand> commands = Arrays.asList( + command(A, B, "refs/heads/master"), + command(null, A, "refs/heads/masters/x"), + command(B, null, "refs/heads/masters")); + BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); + batchUpdate.setAllowNonFastForwards(true); + batchUpdate.addCommand(commands); + batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + assertNotEquals(txnId, getTxnCommitted()); + + assertEquals(OK, commands.get(0).getResult()); + assertEquals(OK, commands.get(1).getResult()); + assertEquals(OK, commands.get(2).getResult()); + + Map<String, Ref> refs = refdb.getRefs(ALL); + assertEquals( + "[refs/heads/master, refs/heads/masters/x]", + refs.keySet().toString()); + assertEquals(A.getId(), refs.get("refs/heads/masters/x").getObjectId()); + } + + private ObjectId getTxnCommitted() throws IOException { + Ref r = bootstrap.exactRef(refdb.getTxnCommitted()); + if (r != null && r.getObjectId() != null) { + return r.getObjectId(); + } + return ObjectId.zeroId(); + } + + private static ReceiveCommand command(AnyObjectId a, AnyObjectId b, + String name) { + return new ReceiveCommand( + a != null ? a.copy() : ObjectId.zeroId(), + b != null ? b.copy() : ObjectId.zeroId(), + name); + } + + private void symref(final String name, final String dst) + throws IOException { + commit(new Function() { + @Override + public boolean apply(ObjectReader reader, RefTree tree) + throws IOException { + Ref old = tree.exactRef(reader, name); + Command n = new Command( + old, + new SymbolicRef( + name, + new ObjectIdRef.Unpeeled(Ref.Storage.NEW, dst, null))); + return tree.apply(Collections.singleton(n)); + } + }); + } + + private void update(final String name, final ObjectId id) + throws IOException { + commit(new Function() { + @Override + public boolean apply(ObjectReader reader, RefTree tree) + throws IOException { + Ref old = tree.exactRef(reader, name); + Command n; + try (RevWalk rw = new RevWalk(repo)) { + n = new Command(old, Command.toRef(rw, id, name, true)); + } + return tree.apply(Collections.singleton(n)); + } + }); + } + + interface Function { + boolean apply(ObjectReader reader, RefTree tree) throws IOException; + } + + private void commit(Function fun) throws IOException { + try (ObjectReader reader = repo.newObjectReader(); + ObjectInserter inserter = repo.newObjectInserter(); + RevWalk rw = new RevWalk(reader)) { + RefUpdate u = bootstrap.newUpdate(refdb.getTxnCommitted(), false); + CommitBuilder cb = new CommitBuilder(); + testRepo.setAuthorAndCommitter(cb); + + Ref ref = bootstrap.exactRef(refdb.getTxnCommitted()); + RefTree tree; + if (ref != null && ref.getObjectId() != null) { + tree = RefTree.read(reader, rw.parseTree(ref.getObjectId())); + cb.setParentId(ref.getObjectId()); + u.setExpectedOldObjectId(ref.getObjectId()); + } else { + tree = RefTree.newEmptyTree(); + u.setExpectedOldObjectId(ObjectId.zeroId()); + } + + assertTrue(fun.apply(reader, tree)); + cb.setTreeId(tree.writeTree(inserter)); + u.setNewObjectId(inserter.insert(cb)); + inserter.flush(); + switch (u.update(rw)) { + case NEW: + case FAST_FORWARD: + break; + default: + fail("Expected " + u.getName() + " to update"); + } + } + } + + private class InMemRefTreeRepo extends InMemoryRepository { + private final RefTreeDatabase refs; + + InMemRefTreeRepo(DfsRepositoryDescription repoDesc) { + super(repoDesc); + refs = new RefTreeDatabase(this, super.getRefDatabase(), + "refs/txn/committed"); + RefTreeDatabaseTest.this.refdb = refs; + } + + public RefDatabase getRefDatabase() { + return refs; + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java new file mode 100644 index 0000000000..8e0f38c69a --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2016, Google Inc. + * 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.storage.reftree; + +import static org.eclipse.jgit.lib.Constants.HEAD; +import static org.eclipse.jgit.lib.Constants.R_HEADS; +import static org.eclipse.jgit.lib.Constants.R_TAGS; +import static org.eclipse.jgit.lib.Ref.Storage.LOOSE; +import static org.eclipse.jgit.lib.Ref.Storage.NEW; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; + +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.internal.JGitText; +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.ObjectId; +import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.SymbolicRef; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.junit.Before; +import org.junit.Test; + +public class RefTreeTest { + private static final String R_MASTER = R_HEADS + "master"; + private InMemoryRepository repo; + private TestRepository<InMemoryRepository> git; + + @Before + public void setUp() throws IOException { + repo = new InMemoryRepository(new DfsRepositoryDescription("RefTree")); + git = new TestRepository<>(repo); + } + + @Test + public void testEmptyTree() throws IOException { + RefTree tree = RefTree.newEmptyTree(); + try (ObjectReader reader = repo.newObjectReader()) { + assertNull(HEAD, tree.exactRef(reader, HEAD)); + assertNull("master", tree.exactRef(reader, R_MASTER)); + } + } + + @Test + public void testApplyThenReadMaster() throws Exception { + RefTree tree = RefTree.newEmptyTree(); + RevBlob id = git.blob("A"); + Command cmd = new Command(null, ref(R_MASTER, id)); + assertTrue(tree.apply(Collections.singletonList(cmd))); + assertSame(NOT_ATTEMPTED, cmd.getResult()); + + try (ObjectReader reader = repo.newObjectReader()) { + Ref m = tree.exactRef(reader, R_MASTER); + assertNotNull(R_MASTER, m); + assertEquals(R_MASTER, m.getName()); + assertEquals(id, m.getObjectId()); + assertTrue("peeled", m.isPeeled()); + } + } + + @Test + public void testUpdateMaster() throws Exception { + RefTree tree = RefTree.newEmptyTree(); + RevBlob id1 = git.blob("A"); + Command cmd1 = new Command(null, ref(R_MASTER, id1)); + assertTrue(tree.apply(Collections.singletonList(cmd1))); + assertSame(NOT_ATTEMPTED, cmd1.getResult()); + + RevBlob id2 = git.blob("B"); + Command cmd2 = new Command(ref(R_MASTER, id1), ref(R_MASTER, id2)); + assertTrue(tree.apply(Collections.singletonList(cmd2))); + assertSame(NOT_ATTEMPTED, cmd2.getResult()); + + try (ObjectReader reader = repo.newObjectReader()) { + Ref m = tree.exactRef(reader, R_MASTER); + assertNotNull(R_MASTER, m); + assertEquals(R_MASTER, m.getName()); + assertEquals(id2, m.getObjectId()); + assertTrue("peeled", m.isPeeled()); + } + } + + @Test + public void testHeadSymref() throws Exception { + RefTree tree = RefTree.newEmptyTree(); + RevBlob id = git.blob("A"); + Command cmd1 = new Command(null, ref(R_MASTER, id)); + Command cmd2 = new Command(null, symref(HEAD, R_MASTER)); + assertTrue(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 }))); + assertSame(NOT_ATTEMPTED, cmd1.getResult()); + assertSame(NOT_ATTEMPTED, cmd2.getResult()); + + try (ObjectReader reader = repo.newObjectReader()) { + Ref m = tree.exactRef(reader, HEAD); + assertNotNull(HEAD, m); + assertEquals(HEAD, m.getName()); + assertTrue("symbolic", m.isSymbolic()); + assertNotNull(m.getTarget()); + assertEquals(R_MASTER, m.getTarget().getName()); + assertEquals(id, m.getTarget().getObjectId()); + } + + // Writing flushes some buffers, re-read from blob. + ObjectId newId = write(tree); + try (ObjectReader reader = repo.newObjectReader(); + RevWalk rw = new RevWalk(reader)) { + tree = RefTree.read(reader, rw.parseTree(newId)); + Ref m = tree.exactRef(reader, HEAD); + assertEquals(R_MASTER, m.getTarget().getName()); + } + } + + @Test + public void testTagIsPeeled() throws Exception { + String name = "v1.0"; + RefTree tree = RefTree.newEmptyTree(); + RevBlob id = git.blob("A"); + RevTag tag = git.tag(name, id); + + String ref = R_TAGS + name; + Command cmd = create(ref, tag); + assertTrue(tree.apply(Collections.singletonList(cmd))); + assertSame(NOT_ATTEMPTED, cmd.getResult()); + + try (ObjectReader reader = repo.newObjectReader()) { + Ref m = tree.exactRef(reader, ref); + assertNotNull(ref, m); + assertEquals(ref, m.getName()); + assertEquals(tag, m.getObjectId()); + assertTrue("peeled", m.isPeeled()); + assertEquals(id, m.getPeeledObjectId()); + } + } + + @Test + public void testApplyAlreadyExists() throws Exception { + RefTree tree = RefTree.newEmptyTree(); + RevBlob a = git.blob("A"); + Command cmd = new Command(null, ref(R_MASTER, a)); + assertTrue(tree.apply(Collections.singletonList(cmd))); + ObjectId treeId = write(tree); + + RevBlob b = git.blob("B"); + Command cmd1 = create(R_MASTER, b); + Command cmd2 = create(R_MASTER, b); + assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 }))); + assertSame(LOCK_FAILURE, cmd1.getResult()); + assertSame(REJECTED_OTHER_REASON, cmd2.getResult()); + assertEquals(JGitText.get().transactionAborted, cmd2.getMessage()); + assertEquals(treeId, write(tree)); + } + + @Test + public void testApplyWrongOldId() throws Exception { + RefTree tree = RefTree.newEmptyTree(); + RevBlob a = git.blob("A"); + Command cmd = new Command(null, ref(R_MASTER, a)); + assertTrue(tree.apply(Collections.singletonList(cmd))); + ObjectId treeId = write(tree); + + RevBlob b = git.blob("B"); + RevBlob c = git.blob("C"); + Command cmd1 = update(R_MASTER, b, c); + Command cmd2 = create(R_MASTER, b); + assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 }))); + assertSame(LOCK_FAILURE, cmd1.getResult()); + assertSame(REJECTED_OTHER_REASON, cmd2.getResult()); + assertEquals(JGitText.get().transactionAborted, cmd2.getMessage()); + assertEquals(treeId, write(tree)); + } + + @Test + public void testApplyWrongOldIdButAlreadyCurrentIsNoOp() throws Exception { + RefTree tree = RefTree.newEmptyTree(); + RevBlob a = git.blob("A"); + Command cmd = new Command(null, ref(R_MASTER, a)); + assertTrue(tree.apply(Collections.singletonList(cmd))); + ObjectId treeId = write(tree); + + RevBlob b = git.blob("B"); + cmd = update(R_MASTER, b, a); + assertTrue(tree.apply(Collections.singletonList(cmd))); + assertEquals(treeId, write(tree)); + } + + @Test + public void testApplyCannotCreateSubdirectory() throws Exception { + RefTree tree = RefTree.newEmptyTree(); + RevBlob a = git.blob("A"); + Command cmd = new Command(null, ref(R_MASTER, a)); + assertTrue(tree.apply(Collections.singletonList(cmd))); + ObjectId treeId = write(tree); + + RevBlob b = git.blob("B"); + Command cmd1 = create(R_MASTER + "/fail", b); + assertFalse(tree.apply(Collections.singletonList(cmd1))); + assertSame(LOCK_FAILURE, cmd1.getResult()); + assertEquals(treeId, write(tree)); + } + + @Test + public void testApplyCannotCreateParentRef() throws Exception { + RefTree tree = RefTree.newEmptyTree(); + RevBlob a = git.blob("A"); + Command cmd = new Command(null, ref(R_MASTER, a)); + assertTrue(tree.apply(Collections.singletonList(cmd))); + ObjectId treeId = write(tree); + + RevBlob b = git.blob("B"); + Command cmd1 = create("refs/heads", b); + assertFalse(tree.apply(Collections.singletonList(cmd1))); + assertSame(LOCK_FAILURE, cmd1.getResult()); + assertEquals(treeId, write(tree)); + } + + private static Ref ref(String name, ObjectId id) { + return new ObjectIdRef.PeeledNonTag(LOOSE, name, id); + } + + private static Ref symref(String name, String dest) { + Ref d = new ObjectIdRef.PeeledNonTag(NEW, dest, null); + return new SymbolicRef(name, d); + } + + private Command create(String name, ObjectId id) + throws MissingObjectException, IOException { + return update(name, ObjectId.zeroId(), id); + } + + private Command update(String name, ObjectId oldId, ObjectId newId) + throws MissingObjectException, IOException { + try (RevWalk rw = new RevWalk(repo)) { + return new Command(rw, new ReceiveCommand(oldId, newId, name)); + } + } + + private ObjectId write(RefTree tree) throws IOException { + try (ObjectInserter ins = repo.newObjectInserter()) { + ObjectId id = tree.writeTree(ins); + ins.flush(); + return id; + } + } +} 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 d768e0fa0b..92901f826b 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 @@ -1084,7 +1084,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { assertWorkDir(mkmap(linkName, "a", fname, "a")); Status st = git.status().call(); - assertFalse(st.isClean()); + assertTrue(st.isClean()); } @Test @@ -1213,9 +1213,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { assertWorkDir(mkmap(fname, "a")); Status st = git.status().call(); - assertFalse(st.isClean()); - assertEquals(1, st.getAdded().size()); - assertTrue(st.getAdded().contains(fname + "/dir/file1")); + assertTrue(st.isClean()); } @Test 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 a5cd7b5c0b..7fcee3dc82 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 @@ -99,8 +99,7 @@ public class IndexDiffTest extends RepositoryTestCase { public void testAdded() throws IOException { writeTrashFile("file1", "file1"); writeTrashFile("dir/subfile", "dir/subfile"); - Tree tree = new Tree(db); - tree.setId(insertTree(tree)); + ObjectId tree = insertTree(new TreeFormatter()); DirCache index = db.lockDirCache(); DirCacheEditor editor = index.editor(); @@ -108,7 +107,7 @@ public class IndexDiffTest extends RepositoryTestCase { editor.add(add(db, trash, "dir/subfile")); editor.commit(); FileTreeIterator iterator = new FileTreeIterator(db); - IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); + IndexDiff diff = new IndexDiff(db, tree, iterator); diff.diff(); assertEquals(2, diff.getAdded().size()); assertTrue(diff.getAdded().contains("file1")); @@ -124,18 +123,16 @@ public class IndexDiffTest extends RepositoryTestCase { writeTrashFile("file2", "file2"); writeTrashFile("dir/file3", "dir/file3"); - Tree tree = new Tree(db); - tree.addFile("file2"); - tree.addFile("dir/file3"); - assertEquals(2, tree.memberCount()); - tree.findBlobMember("file2").setId(ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad")); - Tree tree2 = (Tree) tree.findTreeMember("dir"); - tree2.findBlobMember("file3").setId(ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b")); - tree2.setId(insertTree(tree2)); - tree.setId(insertTree(tree)); + TreeFormatter dir = new TreeFormatter(); + dir.append("file3", FileMode.REGULAR_FILE, ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b")); + + TreeFormatter tree = new TreeFormatter(); + tree.append("file2", FileMode.REGULAR_FILE, ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad")); + tree.append("dir", FileMode.TREE, insertTree(dir)); + ObjectId treeId = insertTree(tree); FileTreeIterator iterator = new FileTreeIterator(db); - IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); + IndexDiff diff = new IndexDiff(db, treeId, iterator); diff.diff(); assertEquals(2, diff.getRemoved().size()); assertTrue(diff.getRemoved().contains("file2")); @@ -157,16 +154,16 @@ public class IndexDiffTest extends RepositoryTestCase { writeTrashFile("dir/file3", "changed"); - Tree tree = new Tree(db); - tree.addFile("file2").setId(ObjectId.fromString("0123456789012345678901234567890123456789")); - tree.addFile("dir/file3").setId(ObjectId.fromString("0123456789012345678901234567890123456789")); - assertEquals(2, tree.memberCount()); + TreeFormatter dir = new TreeFormatter(); + dir.append("file3", FileMode.REGULAR_FILE, ObjectId.fromString("0123456789012345678901234567890123456789")); + + TreeFormatter tree = new TreeFormatter(); + tree.append("dir", FileMode.TREE, insertTree(dir)); + tree.append("file2", FileMode.REGULAR_FILE, ObjectId.fromString("0123456789012345678901234567890123456789")); + ObjectId treeId = insertTree(tree); - Tree tree2 = (Tree) tree.findTreeMember("dir"); - tree2.setId(insertTree(tree2)); - tree.setId(insertTree(tree)); FileTreeIterator iterator = new FileTreeIterator(db); - IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); + IndexDiff diff = new IndexDiff(db, treeId, iterator); diff.diff(); assertEquals(2, diff.getChanged().size()); assertTrue(diff.getChanged().contains("file2")); @@ -314,17 +311,16 @@ public class IndexDiffTest extends RepositoryTestCase { git.add().addFilepattern("a=c").call(); git.add().addFilepattern("a=d").call(); - Tree tree = new Tree(db); + TreeFormatter tree = new TreeFormatter(); // got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin - tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); - tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); - tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); - tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); - - tree.setId(insertTree(tree)); + tree.append("a.b", FileMode.REGULAR_FILE, ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); + tree.append("a.c", FileMode.REGULAR_FILE, ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); + tree.append("a=c", FileMode.REGULAR_FILE, ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); + tree.append("a=d", FileMode.REGULAR_FILE, ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); + ObjectId treeId = insertTree(tree); FileTreeIterator iterator = new FileTreeIterator(db); - IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); + IndexDiff diff = new IndexDiff(db, treeId, iterator); diff.diff(); assertEquals(0, diff.getChanged().size()); assertEquals(0, diff.getAdded().size()); @@ -356,24 +352,27 @@ public class IndexDiffTest extends RepositoryTestCase { .addFilepattern("a/c").addFilepattern("a=c") .addFilepattern("a=d").call(); - Tree tree = new Tree(db); + // got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin - tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); - tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); - tree.addFile("a/b.b/b").setId(ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd")); - tree.addFile("a/b").setId(ObjectId.fromString("db89c972fc57862eae378f45b74aca228037d415")); - tree.addFile("a/c").setId(ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007")); - tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); - tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); - - Tree tree3 = (Tree) tree.findTreeMember("a/b.b"); - tree3.setId(insertTree(tree3)); - Tree tree2 = (Tree) tree.findTreeMember("a"); - tree2.setId(insertTree(tree2)); - tree.setId(insertTree(tree)); + TreeFormatter bb = new TreeFormatter(); + bb.append("b", FileMode.REGULAR_FILE, ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd")); + + TreeFormatter a = new TreeFormatter(); + a.append("b", FileMode.REGULAR_FILE, ObjectId + .fromString("db89c972fc57862eae378f45b74aca228037d415")); + a.append("b.b", FileMode.TREE, insertTree(bb)); + a.append("c", FileMode.REGULAR_FILE, ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007")); + + TreeFormatter tree = new TreeFormatter(); + tree.append("a.b", FileMode.REGULAR_FILE, ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); + tree.append("a.c", FileMode.REGULAR_FILE, ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); + tree.append("a", FileMode.TREE, insertTree(a)); + tree.append("a=c", FileMode.REGULAR_FILE, ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); + tree.append("a=d", FileMode.REGULAR_FILE, ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); + ObjectId treeId = insertTree(tree); FileTreeIterator iterator = new FileTreeIterator(db); - IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); + IndexDiff diff = new IndexDiff(db, treeId, iterator); diff.diff(); assertEquals(0, diff.getChanged().size()); assertEquals(0, diff.getAdded().size()); @@ -383,9 +382,9 @@ public class IndexDiffTest extends RepositoryTestCase { assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); } - private ObjectId insertTree(Tree tree) throws IOException { + private ObjectId insertTree(TreeFormatter tree) throws IOException { try (ObjectInserter oi = db.newObjectInserter()) { - ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format()); + ObjectId id = oi.insert(tree); oi.flush(); return id; } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java index 3abe81cf85..43160fb115 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java @@ -45,8 +45,25 @@ package org.eclipse.jgit.lib; import static java.lang.Integer.valueOf; -import static java.lang.Long.valueOf; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH; +import static org.eclipse.jgit.lib.Constants.OBJ_BAD; +import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; +import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT; +import static org.eclipse.jgit.lib.Constants.OBJ_TAG; +import static org.eclipse.jgit.lib.Constants.OBJ_TREE; +import static org.eclipse.jgit.lib.Constants.encode; +import static org.eclipse.jgit.lib.Constants.encodeASCII; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.DUPLICATE_ENTRIES; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.EMPTY_NAME; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.FULL_PATHNAME; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOT; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTDOT; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTGIT; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.NULL_SHA1; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.TREE_NOT_SORTED; +import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import java.io.UnsupportedEncodingException; @@ -67,15 +84,10 @@ public class ObjectCheckerTest { @Test public void testInvalidType() { - try { - checker.check(Constants.OBJ_BAD, new byte[0]); - fail("Did not throw CorruptObjectException"); - } catch (CorruptObjectException e) { - final String m = e.getMessage(); - assertEquals(MessageFormat.format( - JGitText.get().corruptObjectInvalidType2, - valueOf(Constants.OBJ_BAD)), m); - } + String msg = MessageFormat.format( + JGitText.get().corruptObjectInvalidType2, + valueOf(OBJ_BAD)); + assertCorrupt(msg, OBJ_BAD, new byte[0]); } @Test @@ -84,13 +96,13 @@ public class ObjectCheckerTest { checker.checkBlob(new byte[0]); checker.checkBlob(new byte[1]); - checker.check(Constants.OBJ_BLOB, new byte[0]); - checker.check(Constants.OBJ_BLOB, new byte[1]); + checker.check(OBJ_BLOB, new byte[0]); + checker.check(OBJ_BLOB, new byte[1]); } @Test public void testValidCommitNoParent() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); @@ -99,14 +111,14 @@ public class ObjectCheckerTest { b.append("author A. U. Thor <author@localhost> 1 +0000\n"); b.append("committer A. U. Thor <author@localhost> 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkCommit(data); - checker.check(Constants.OBJ_COMMIT, data); + checker.check(OBJ_COMMIT, data); } @Test public void testValidCommitBlankAuthor() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); @@ -115,9 +127,9 @@ public class ObjectCheckerTest { b.append("author <> 0 +0000\n"); b.append("committer <> 0 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkCommit(data); - checker.check(Constants.OBJ_COMMIT, data); + checker.check(OBJ_COMMIT, data); } @Test @@ -127,15 +139,13 @@ public class ObjectCheckerTest { b.append("author b <b@c> <b@c> 0 +0000\n"); b.append("committer <> 0 +0000\n"); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad date", OBJ_COMMIT, data); checker.setAllowInvalidPersonIdent(true); checker.checkCommit(data); + + checker.setAllowInvalidPersonIdent(false); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test @@ -145,20 +155,18 @@ public class ObjectCheckerTest { b.append("author <> 0 +0000\n"); b.append("committer b <b@c> <b@c> 0 +0000\n"); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid committer", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad date", OBJ_COMMIT, data); checker.setAllowInvalidPersonIdent(true); checker.checkCommit(data); + + checker.setAllowInvalidPersonIdent(false); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test public void testValidCommit1Parent() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); @@ -171,14 +179,14 @@ public class ObjectCheckerTest { b.append("author A. U. Thor <author@localhost> 1 +0000\n"); b.append("committer A. U. Thor <author@localhost> 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkCommit(data); - checker.check(Constants.OBJ_COMMIT, data); + checker.check(OBJ_COMMIT, data); } @Test public void testValidCommit2Parent() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); @@ -195,14 +203,14 @@ public class ObjectCheckerTest { b.append("author A. U. Thor <author@localhost> 1 +0000\n"); b.append("committer A. U. Thor <author@localhost> 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkCommit(data); - checker.check(Constants.OBJ_COMMIT, data); + checker.check(OBJ_COMMIT, data); } @Test public void testValidCommit128Parent() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); @@ -217,15 +225,15 @@ public class ObjectCheckerTest { b.append("author A. U. Thor <author@localhost> 1 +0000\n"); b.append("committer A. U. Thor <author@localhost> 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkCommit(data); - checker.check(Constants.OBJ_COMMIT, data); + checker.check(OBJ_COMMIT, data); } @Test public void testValidCommitNormalTime() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); - final String when = "1222757360 -0730"; + StringBuilder b = new StringBuilder(); + String when = "1222757360 -0730"; b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); @@ -234,843 +242,539 @@ public class ObjectCheckerTest { b.append("author A. U. Thor <author@localhost> " + when + "\n"); b.append("committer A. U. Thor <author@localhost> " + when + "\n"); - final byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkCommit(data); - checker.check(Constants.OBJ_COMMIT, data); + checker.check(OBJ_COMMIT, data); } @Test public void testInvalidCommitNoTree1() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("parent "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("no tree header", e.getMessage()); - } + assertCorrupt("no tree header", OBJ_COMMIT, b); } @Test public void testInvalidCommitNoTree2() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("trie "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("no tree header", e.getMessage()); - } + assertCorrupt("no tree header", OBJ_COMMIT, b); } @Test public void testInvalidCommitNoTree3() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree"); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("no tree header", e.getMessage()); - } + assertCorrupt("no tree header", OBJ_COMMIT, b); } @Test public void testInvalidCommitNoTree4() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree\t"); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("no tree header", e.getMessage()); - } + assertCorrupt("no tree header", OBJ_COMMIT, b); } @Test public void testInvalidCommitInvalidTree1() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid tree", e.getMessage()); - } + assertCorrupt("invalid tree", OBJ_COMMIT, b); } @Test public void testInvalidCommitInvalidTree2() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append("z\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid tree", e.getMessage()); - } + assertCorrupt("invalid tree", OBJ_COMMIT, b); } @Test public void testInvalidCommitInvalidTree3() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9b"); b.append("\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid tree", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid tree", OBJ_COMMIT, data); } @Test public void testInvalidCommitInvalidTree4() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid tree", e.getMessage()); - } + assertCorrupt("invalid tree", OBJ_COMMIT, b); } @Test public void testInvalidCommitInvalidParent1() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("parent "); b.append("\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid parent", e.getMessage()); - } + assertCorrupt("invalid parent", OBJ_COMMIT, b); } @Test public void testInvalidCommitInvalidParent2() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("parent "); b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append("\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid parent", e.getMessage()); - } + assertCorrupt("invalid parent", OBJ_COMMIT, b); } @Test public void testInvalidCommitInvalidParent3() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("parent "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append("\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid parent", e.getMessage()); - } + assertCorrupt("invalid parent", OBJ_COMMIT, b); } @Test public void testInvalidCommitInvalidParent4() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("parent "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append("z\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - assertEquals("invalid parent", e.getMessage()); - } + assertCorrupt("invalid parent", OBJ_COMMIT, b); } @Test public void testInvalidCommitInvalidParent5() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("parent\t"); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append("\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("no author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + // Yes, really, we complain about author not being + // found as the invalid parent line wasn't consumed. + assertCorrupt("no author", OBJ_COMMIT, data); } @Test - public void testInvalidCommitNoAuthor() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitNoAuthor() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("committer A. U. Thor <author@localhost> 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("no author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("no author", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitNoCommitter1() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitNoCommitter1() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author A. U. Thor <author@localhost> 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("no committer", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("no committer", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitNoCommitter2() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitNoCommitter2() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author A. U. Thor <author@localhost> 1 +0000\n"); b.append("\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("no committer", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("no committer", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitInvalidAuthor1() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitInvalidAuthor1() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author A. U. Thor <foo 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("invalid author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad email", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitInvalidAuthor2() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitInvalidAuthor2() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author A. U. Thor foo> 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("invalid author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("missing email", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitInvalidAuthor3() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitInvalidAuthor3() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("invalid author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("missing email", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitInvalidAuthor4() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitInvalidAuthor4() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author a <b> +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("invalid author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad date", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitInvalidAuthor5() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitInvalidAuthor5() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author a <b>\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("invalid author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad date", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitInvalidAuthor6() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitInvalidAuthor6() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author a <b> z"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("invalid author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad date", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitInvalidAuthor7() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitInvalidAuthor7() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author a <b> 1 z"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("invalid author", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad time zone", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test - public void testInvalidCommitInvalidCommitter() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidCommitInvalidCommitter() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("tree "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("author a <b> 1 +0000\n"); b.append("committer a <"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkCommit(data); - fail("Did not catch corrupt object"); - } catch (CorruptObjectException e) { - // Yes, really, we complain about author not being - // found as the invalid parent line wasn't consumed. - assertEquals("invalid committer", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad email", OBJ_COMMIT, data); + assertSkipListAccepts(OBJ_COMMIT, data); } @Test public void testValidTag() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type commit\n"); b.append("tag test-tag\n"); b.append("tagger A. U. Thor <author@localhost> 1 +0000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkTag(data); - checker.check(Constants.OBJ_TAG, data); + checker.check(OBJ_TAG, data); } @Test public void testInvalidTagNoObject1() { - final StringBuilder b = new StringBuilder(); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no object header", e.getMessage()); - } + assertCorrupt("no object header", OBJ_TAG, new byte[0]); } @Test public void testInvalidTagNoObject2() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object\t"); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no object header", e.getMessage()); - } + assertCorrupt("no object header", OBJ_TAG, b); } @Test public void testInvalidTagNoObject3() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("obejct "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no object header", e.getMessage()); - } + assertCorrupt("no object header", OBJ_TAG, b); } @Test public void testInvalidTagNoObject4() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("zz9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("invalid object", e.getMessage()); - } + assertCorrupt("invalid object", OBJ_TAG, b); } @Test public void testInvalidTagNoObject5() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append(" \n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("invalid object", e.getMessage()); - } + assertCorrupt("invalid object", OBJ_TAG, b); } @Test public void testInvalidTagNoObject6() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("invalid object", e.getMessage()); - } + assertCorrupt("invalid object", OBJ_TAG, b); } @Test public void testInvalidTagNoType1() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no type header", e.getMessage()); - } + assertCorrupt("no type header", OBJ_TAG, b); } @Test public void testInvalidTagNoType2() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type\tcommit\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no type header", e.getMessage()); - } + assertCorrupt("no type header", OBJ_TAG, b); } @Test public void testInvalidTagNoType3() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("tpye commit\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no type header", e.getMessage()); - } + assertCorrupt("no type header", OBJ_TAG, b); } @Test public void testInvalidTagNoType4() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type commit"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no tag header", e.getMessage()); - } + assertCorrupt("no tag header", OBJ_TAG, b); } @Test public void testInvalidTagNoTagHeader1() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type commit\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no tag header", e.getMessage()); - } + assertCorrupt("no tag header", OBJ_TAG, b); } @Test public void testInvalidTagNoTagHeader2() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type commit\n"); b.append("tag\tfoo\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no tag header", e.getMessage()); - } + assertCorrupt("no tag header", OBJ_TAG, b); } @Test public void testInvalidTagNoTagHeader3() { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type commit\n"); b.append("tga foo\n"); - - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("no tag header", e.getMessage()); - } + assertCorrupt("no tag header", OBJ_TAG, b); } @Test public void testValidTagHasNoTaggerHeader() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type commit\n"); b.append("tag foo\n"); - - checker.checkTag(Constants.encodeASCII(b.toString())); + checker.checkTag(encodeASCII(b.toString())); } @Test public void testInvalidTagInvalidTaggerHeader1() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); - + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type commit\n"); b.append("tag foo\n"); b.append("tagger \n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("invalid tagger", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("missing email", OBJ_TAG, data); checker.setAllowInvalidPersonIdent(true); checker.checkTag(data); + + checker.setAllowInvalidPersonIdent(false); + assertSkipListAccepts(OBJ_TAG, data); } @Test - public void testInvalidTagInvalidTaggerHeader3() { - final StringBuilder b = new StringBuilder(); - + public void testInvalidTagInvalidTaggerHeader3() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); b.append("object "); b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189"); b.append('\n'); - b.append("type commit\n"); b.append("tag foo\n"); b.append("tagger a < 1 +000\n"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTag(data); - fail("incorrectly accepted invalid tag"); - } catch (CorruptObjectException e) { - assertEquals("invalid tagger", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("bad email", OBJ_TAG, data); + assertSkipListAccepts(OBJ_TAG, data); } @Test public void testValidEmptyTree() throws CorruptObjectException { checker.checkTree(new byte[0]); - checker.check(Constants.OBJ_TREE, new byte[0]); + checker.check(OBJ_TREE, new byte[0]); } @Test public void testValidTree1() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "100644 regular-file"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTree2() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "100755 executable"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTree3() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "40000 tree"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTree4() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "120000 symlink"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTree5() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "160000 git link"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTree6() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "100644 .a"); - final byte[] data = Constants.encodeASCII(b.toString()); + checker.checkTree(encodeASCII(b.toString())); + } + + @Test + public void testNullSha1InTreeEntry() throws CorruptObjectException { + byte[] data = concat( + encodeASCII("100644 A"), new byte[] { '\0' }, + new byte[OBJECT_ID_LENGTH]); + assertCorrupt("entry points to null SHA-1", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(NULL_SHA1, true); checker.checkTree(data); } @@ -1084,357 +788,326 @@ public class ObjectCheckerTest { @Test public void testValidTreeSorting1() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "100644 fooaaa"); entry(b, "100755 foobar"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTreeSorting2() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "100755 fooaaa"); entry(b, "100644 foobar"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTreeSorting3() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "40000 a"); entry(b, "100644 b"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTreeSorting4() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "100644 a"); entry(b, "40000 b"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTreeSorting5() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "100644 a.c"); entry(b, "40000 a"); entry(b, "100644 a0c"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTreeSorting6() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "40000 a"); entry(b, "100644 apple"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTreeSorting7() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "40000 an orang"); entry(b, "40000 an orange"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testValidTreeSorting8() throws CorruptObjectException { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "100644 a"); entry(b, "100644 a0c"); entry(b, "100644 b"); - final byte[] data = Constants.encodeASCII(b.toString()); - checker.checkTree(data); + checker.checkTree(encodeASCII(b.toString())); } @Test public void testAcceptTreeModeWithZero() throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "040000 a"); + byte[] data = encodeASCII(b.toString()); checker.setAllowLeadingZeroFileMode(true); - checker.checkTree(Constants.encodeASCII(b.toString())); + checker.checkTree(data); + + checker.setAllowLeadingZeroFileMode(false); + assertSkipListAccepts(OBJ_TREE, data); + + checker.setIgnore(ZERO_PADDED_FILEMODE, true); + checker.checkTree(data); } @Test public void testInvalidTreeModeStartsWithZero1() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "0 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("mode starts with '0'", e.getMessage()); - } + assertCorrupt("mode starts with '0'", OBJ_TREE, b); } @Test public void testInvalidTreeModeStartsWithZero2() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "0100644 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("mode starts with '0'", e.getMessage()); - } + assertCorrupt("mode starts with '0'", OBJ_TREE, b); } @Test public void testInvalidTreeModeStartsWithZero3() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "040000 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("mode starts with '0'", e.getMessage()); - } + assertCorrupt("mode starts with '0'", OBJ_TREE, b); } @Test public void testInvalidTreeModeNotOctal1() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "8 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid mode character", e.getMessage()); - } + assertCorrupt("invalid mode character", OBJ_TREE, b); } @Test public void testInvalidTreeModeNotOctal2() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "Z a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid mode character", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid mode character", OBJ_TREE, data); + assertSkipListRejects("invalid mode character", OBJ_TREE, data); } @Test public void testInvalidTreeModeNotSupportedMode1() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "1 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid mode 1", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid mode 1", OBJ_TREE, data); + assertSkipListRejects("invalid mode 1", OBJ_TREE, data); } @Test public void testInvalidTreeModeNotSupportedMode2() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); entry(b, "170000 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid mode " + 0170000, e.getMessage()); - } + assertCorrupt("invalid mode " + 0170000, OBJ_TREE, b); } @Test public void testInvalidTreeModeMissingName() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); b.append("100644"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("truncated in mode", e.getMessage()); - } + assertCorrupt("truncated in mode", OBJ_TREE, b); } @Test - public void testInvalidTreeNameContainsSlash() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeNameContainsSlash() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 a/b"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("name contains '/'", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("name contains '/'", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(FULL_PATHNAME, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsEmpty() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeNameIsEmpty() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 "); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("zero length name", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("zero length name", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(EMPTY_NAME, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsDot() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeNameIsDot() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 ."); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name '.'", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name '.'", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsDotDot() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeNameIsDotDot() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 .."); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name '..'", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name '..'", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTDOT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsGit() { + public void testInvalidTreeNameIsGit() throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git"); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name '.git'", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name '.git'", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsMixedCaseGit() { + public void testInvalidTreeNameIsMixedCaseGit() + throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .GiT"); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name '.GiT'", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name '.GiT'", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsMacHFSGit() { + public void testInvalidTreeNameIsMacHFSGit() throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .gi\u200Ct"); - byte[] data = Constants.encode(b.toString()); - try { - checker.setSafeForMacOS(true); - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals( - "invalid name '.gi\u200Ct' contains ignorable Unicode characters", - e.getMessage()); - } + byte[] data = encode(b.toString()); + + // Fine on POSIX. + checker.checkTree(data); + + // Rejected on Mac OS. + checker.setSafeForMacOS(true); + assertCorrupt( + "invalid name '.gi\u200Ct' contains ignorable Unicode characters", + OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsMacHFSGit2() { + public void testInvalidTreeNameIsMacHFSGit2() + throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 \u206B.git"); - byte[] data = Constants.encode(b.toString()); - try { - checker.setSafeForMacOS(true); - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals( - "invalid name '\u206B.git' contains ignorable Unicode characters", - e.getMessage()); - } + byte[] data = encode(b.toString()); + + // Fine on POSIX. + checker.checkTree(data); + + // Rejected on Mac OS. + checker.setSafeForMacOS(true); + assertCorrupt( + "invalid name '\u206B.git' contains ignorable Unicode characters", + OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsMacHFSGit3() { + public void testInvalidTreeNameIsMacHFSGit3() + throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git\uFEFF"); - byte[] data = Constants.encode(b.toString()); - try { - checker.setSafeForMacOS(true); - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals( - "invalid name '.git\uFEFF' contains ignorable Unicode characters", - e.getMessage()); - } + byte[] data = encode(b.toString()); + + // Fine on POSIX. + checker.checkTree(data); + + // Rejected on Mac OS. + checker.setSafeForMacOS(true); + assertCorrupt( + "invalid name '.git\uFEFF' contains ignorable Unicode characters", + OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } - private static byte[] concat(byte[] b1, byte[] b2) { - byte[] data = new byte[b1.length + b2.length]; - System.arraycopy(b1, 0, data, 0, b1.length); - System.arraycopy(b2, 0, data, b1.length, b2.length); + private static byte[] concat(byte[]... b) { + int n = 0; + for (byte[] a : b) { + n += a.length; + } + + byte[] data = new byte[n]; + n = 0; + for (byte[] a : b) { + System.arraycopy(a, 0, data, n, a.length); + n += a.length; + } return data; } @Test - public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd() { - byte[] data = concat(Constants.encode("100644 .git"), + public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd() + throws CorruptObjectException { + byte[] data = concat(encode("100644 .git"), new byte[] { (byte) 0xef }); StringBuilder b = new StringBuilder(); entry(b, ""); - data = concat(data, Constants.encode(b.toString())); - try { - checker.setSafeForMacOS(true); - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals( - "invalid name contains byte sequence '0xef' which is not a valid UTF-8 character", - e.getMessage()); - } + data = concat(data, encode(b.toString())); + + // Fine on POSIX. + checker.checkTree(data); + + // Rejected on Mac OS. + checker.setSafeForMacOS(true); + assertCorrupt( + "invalid name contains byte sequence '0xef' which is not a valid UTF-8 character", + OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); } @Test - public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd2() { - byte[] data = concat(Constants.encode("100644 .git"), new byte[] { + public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd2() + throws CorruptObjectException { + byte[] data = concat(encode("100644 .git"), + new byte[] { (byte) 0xe2, (byte) 0xab }); StringBuilder b = new StringBuilder(); entry(b, ""); - data = concat(data, Constants.encode(b.toString())); - try { - checker.setSafeForMacOS(true); - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals( - "invalid name contains byte sequence '0xe2ab' which is not a valid UTF-8 character", - e.getMessage()); - } + data = concat(data, encode(b.toString())); + + // Fine on POSIX. + checker.checkTree(data); + + // Rejected on Mac OS. + checker.setSafeForMacOS(true); + assertCorrupt( + "invalid name contains byte sequence '0xe2ab' which is not a valid UTF-8 character", + OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); } @Test @@ -1442,7 +1115,7 @@ public class ObjectCheckerTest { throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git\u200Cx"); - byte[] data = Constants.encode(b.toString()); + byte[] data = encode(b.toString()); checker.setSafeForMacOS(true); checker.checkTree(data); } @@ -1452,7 +1125,7 @@ public class ObjectCheckerTest { throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .kit\u200C"); - byte[] data = Constants.encode(b.toString()); + byte[] data = encode(b.toString()); checker.setSafeForMacOS(true); checker.checkTree(data); } @@ -1462,21 +1135,19 @@ public class ObjectCheckerTest { throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git\u200C"); - byte[] data = Constants.encode(b.toString()); + byte[] data = encode(b.toString()); checker.checkTree(data); } @Test - public void testInvalidTreeNameIsDotGitDot() { + public void testInvalidTreeNameIsDotGitDot() throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git."); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name '.git.'", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name '.git.'", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test @@ -1484,20 +1155,19 @@ public class ObjectCheckerTest { throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git.."); - checker.checkTree(Constants.encodeASCII(b.toString())); + checker.checkTree(encodeASCII(b.toString())); } @Test - public void testInvalidTreeNameIsDotGitSpace() { + public void testInvalidTreeNameIsDotGitSpace() + throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git "); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name '.git '", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name '.git '", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test @@ -1505,7 +1175,7 @@ public class ObjectCheckerTest { throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .gitfoobar"); - byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkTree(data); } @@ -1514,7 +1184,7 @@ public class ObjectCheckerTest { throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .gitfoo bar"); - byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkTree(data); } @@ -1523,7 +1193,7 @@ public class ObjectCheckerTest { throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .gitfoobar."); - byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkTree(data); } @@ -1532,251 +1202,236 @@ public class ObjectCheckerTest { throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .gitfoobar.."); - byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkTree(data); } @Test - public void testInvalidTreeNameIsDotGitDotSpace() { + public void testInvalidTreeNameIsDotGitDotSpace() + throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git. "); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name '.git. '", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name '.git. '", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsDotGitSpaceDot() { + public void testInvalidTreeNameIsDotGitSpaceDot() + throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 .git . "); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name '.git . '", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name '.git . '", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsGITTilde1() { + public void testInvalidTreeNameIsGITTilde1() throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 GIT~1"); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name 'GIT~1'", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name 'GIT~1'", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test - public void testInvalidTreeNameIsGiTTilde1() { + public void testInvalidTreeNameIsGiTTilde1() throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 GiT~1"); - byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("invalid name 'GiT~1'", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("invalid name 'GiT~1'", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(HAS_DOTGIT, true); + checker.checkTree(data); } @Test public void testValidTreeNameIsGitTilde11() throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 GIT~11"); - byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); checker.checkTree(data); } @Test public void testInvalidTreeTruncatedInName() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); b.append("100644 b"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("truncated in name", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("truncated in name", OBJ_TREE, data); + assertSkipListRejects("truncated in name", OBJ_TREE, data); } @Test public void testInvalidTreeTruncatedInObjectId() { - final StringBuilder b = new StringBuilder(); + StringBuilder b = new StringBuilder(); b.append("100644 b\0\1\2"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("truncated in object id", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("truncated in object id", OBJ_TREE, data); + assertSkipListRejects("truncated in object id", OBJ_TREE, data); } @Test - public void testInvalidTreeBadSorting1() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeBadSorting1() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 foobar"); entry(b, "100644 fooaaa"); - final byte[] data = Constants.encodeASCII(b.toString()); + byte[] data = encodeASCII(b.toString()); + + assertCorrupt("incorrectly sorted", OBJ_TREE, data); + + ObjectId id = idFor(OBJ_TREE, data); try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); + checker.check(id, OBJ_TREE, data); + fail("Did not throw CorruptObjectException"); } catch (CorruptObjectException e) { - assertEquals("incorrectly sorted", e.getMessage()); + assertSame(TREE_NOT_SORTED, e.getErrorType()); + assertEquals("treeNotSorted: object " + id.name() + + ": incorrectly sorted", e.getMessage()); } + + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(TREE_NOT_SORTED, true); + checker.checkTree(data); } @Test - public void testInvalidTreeBadSorting2() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeBadSorting2() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "40000 a"); entry(b, "100644 a.c"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("incorrectly sorted", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("incorrectly sorted", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(TREE_NOT_SORTED, true); + checker.checkTree(data); } @Test - public void testInvalidTreeBadSorting3() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeBadSorting3() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 a0c"); entry(b, "40000 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("incorrectly sorted", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("incorrectly sorted", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(TREE_NOT_SORTED, true); + checker.checkTree(data); } @Test - public void testInvalidTreeDuplicateNames1() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeDuplicateNames1_File() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 a"); entry(b, "100644 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("duplicate entry names", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("duplicate entry names", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(DUPLICATE_ENTRIES, true); + checker.checkTree(data); + } + + @Test + public void testInvalidTreeDuplicateNames1_Tree() + throws CorruptObjectException { + StringBuilder b = new StringBuilder(); + entry(b, "40000 a"); + entry(b, "40000 a"); + byte[] data = encodeASCII(b.toString()); + assertCorrupt("duplicate entry names", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(DUPLICATE_ENTRIES, true); + checker.checkTree(data); } @Test - public void testInvalidTreeDuplicateNames2() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeDuplicateNames2() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 a"); entry(b, "100755 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("duplicate entry names", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("duplicate entry names", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(DUPLICATE_ENTRIES, true); + checker.checkTree(data); } @Test - public void testInvalidTreeDuplicateNames3() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeDuplicateNames3() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 a"); entry(b, "40000 a"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("duplicate entry names", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("duplicate entry names", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(DUPLICATE_ENTRIES, true); + checker.checkTree(data); } @Test - public void testInvalidTreeDuplicateNames4() { - final StringBuilder b = new StringBuilder(); + public void testInvalidTreeDuplicateNames4() throws CorruptObjectException { + StringBuilder b = new StringBuilder(); entry(b, "100644 a"); entry(b, "100644 a.c"); entry(b, "100644 a.d"); entry(b, "100644 a.e"); entry(b, "40000 a"); entry(b, "100644 zoo"); - final byte[] data = Constants.encodeASCII(b.toString()); - try { - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("duplicate entry names", e.getMessage()); - } + byte[] data = encodeASCII(b.toString()); + assertCorrupt("duplicate entry names", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(DUPLICATE_ENTRIES, true); + checker.checkTree(data); } @Test public void testInvalidTreeDuplicateNames5() - throws UnsupportedEncodingException { + throws UnsupportedEncodingException, CorruptObjectException { StringBuilder b = new StringBuilder(); - entry(b, "100644 a"); entry(b, "100644 A"); + entry(b, "100644 a"); byte[] data = b.toString().getBytes("UTF-8"); - try { - checker.setSafeForWindows(true); - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("duplicate entry names", e.getMessage()); - } + checker.setSafeForWindows(true); + assertCorrupt("duplicate entry names", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(DUPLICATE_ENTRIES, true); + checker.checkTree(data); } @Test public void testInvalidTreeDuplicateNames6() - throws UnsupportedEncodingException { + throws UnsupportedEncodingException, CorruptObjectException { StringBuilder b = new StringBuilder(); - entry(b, "100644 a"); entry(b, "100644 A"); + entry(b, "100644 a"); byte[] data = b.toString().getBytes("UTF-8"); - try { - checker.setSafeForMacOS(true); - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("duplicate entry names", e.getMessage()); - } + checker.setSafeForMacOS(true); + assertCorrupt("duplicate entry names", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(DUPLICATE_ENTRIES, true); + checker.checkTree(data); } @Test public void testInvalidTreeDuplicateNames7() - throws UnsupportedEncodingException { - try { - Class.forName("java.text.Normalizer"); - } catch (ClassNotFoundException e) { - // Ignore this test on Java 5 platform. - return; - } - + throws UnsupportedEncodingException, CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 \u0065\u0301"); entry(b, "100644 \u00e9"); byte[] data = b.toString().getBytes("UTF-8"); - try { - checker.setSafeForMacOS(true); - checker.checkTree(data); - fail("incorrectly accepted an invalid tree"); - } catch (CorruptObjectException e) { - assertEquals("duplicate entry names", e.getMessage()); - } + checker.setSafeForMacOS(true); + assertCorrupt("duplicate entry names", OBJ_TREE, data); + assertSkipListAccepts(OBJ_TREE, data); + checker.setIgnore(DUPLICATE_ENTRIES, true); + checker.checkTree(data); } @Test @@ -1791,7 +1446,7 @@ public class ObjectCheckerTest { @Test public void testRejectNulInPathSegment() { try { - checker.checkPathSegment(Constants.encodeASCII("a\u0000b"), 0, 3); + checker.checkPathSegment(encodeASCII("a\u0000b"), 0, 3); fail("incorrectly accepted NUL in middle of name"); } catch (CorruptObjectException e) { assertEquals("name contains byte 0x00", e.getMessage()); @@ -1893,13 +1548,65 @@ public class ObjectCheckerTest { private void checkOneName(String name) throws CorruptObjectException { StringBuilder b = new StringBuilder(); entry(b, "100644 " + name); - checker.checkTree(Constants.encodeASCII(b.toString())); + checker.checkTree(encodeASCII(b.toString())); } - private static void entry(final StringBuilder b, final String modeName) { + private static void entry(StringBuilder b, final String modeName) { b.append(modeName); b.append('\0'); - for (int i = 0; i < Constants.OBJECT_ID_LENGTH; i++) + for (int i = 0; i < OBJECT_ID_LENGTH; i++) b.append((char) i); } + + private void assertCorrupt(String msg, int type, StringBuilder b) { + assertCorrupt(msg, type, encodeASCII(b.toString())); + } + + private void assertCorrupt(String msg, int type, byte[] data) { + try { + checker.check(type, data); + fail("Did not throw CorruptObjectException"); + } catch (CorruptObjectException e) { + assertEquals(msg, e.getMessage()); + } + } + + private void assertSkipListAccepts(int type, byte[] data) + throws CorruptObjectException { + ObjectId id = idFor(type, data); + checker.setSkipList(set(id)); + checker.check(id, type, data); + checker.setSkipList(null); + } + + private void assertSkipListRejects(String msg, int type, byte[] data) { + ObjectId id = idFor(type, data); + checker.setSkipList(set(id)); + try { + checker.check(id, type, data); + fail("Did not throw CorruptObjectException"); + } catch (CorruptObjectException e) { + assertEquals(msg, e.getMessage()); + } + checker.setSkipList(null); + } + + private static ObjectIdSet set(final ObjectId... ids) { + return new ObjectIdSet() { + @Override + public boolean contains(AnyObjectId objectId) { + for (ObjectId id : ids) { + if (id.equals(objectId)) { + return true; + } + } + return false; + } + }; + } + + @SuppressWarnings("resource") + private static ObjectId idFor(int type, byte[] raw) { + return new ObjectInserter.Formatter().idFor(type, raw); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java deleted file mode 100644 index 651e62c9ca..0000000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> - * 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.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; -import org.junit.Test; - -@SuppressWarnings("deprecation") -public class T0002_TreeTest extends SampleDataRepositoryTestCase { - private static final ObjectId SOME_FAKE_ID = ObjectId.fromString( - "0123456789abcdef0123456789abcdef01234567"); - - private static int compareNamesUsingSpecialCompare(String a, String b) - throws UnsupportedEncodingException { - char lasta = '\0'; - byte[] abytes; - if (a.length() > 0 && a.charAt(a.length()-1) == '/') { - lasta = '/'; - a = a.substring(0, a.length() - 1); - } - abytes = a.getBytes("ISO-8859-1"); - char lastb = '\0'; - byte[] bbytes; - if (b.length() > 0 && b.charAt(b.length()-1) == '/') { - lastb = '/'; - b = b.substring(0, b.length() - 1); - } - bbytes = b.getBytes("ISO-8859-1"); - return Tree.compareNames(abytes, bbytes, lasta, lastb); - } - - @Test - public void test000_sort_01() throws UnsupportedEncodingException { - assertEquals(0, compareNamesUsingSpecialCompare("a","a")); - } - - @Test - public void test000_sort_02() throws UnsupportedEncodingException { - assertEquals(-1, compareNamesUsingSpecialCompare("a","b")); - assertEquals(1, compareNamesUsingSpecialCompare("b","a")); - } - - @Test - public void test000_sort_03() throws UnsupportedEncodingException { - assertEquals(1, compareNamesUsingSpecialCompare("a:","a")); - assertEquals(1, compareNamesUsingSpecialCompare("a/","a")); - assertEquals(-1, compareNamesUsingSpecialCompare("a","a/")); - assertEquals(-1, compareNamesUsingSpecialCompare("a","a:")); - assertEquals(1, compareNamesUsingSpecialCompare("a:","a/")); - assertEquals(-1, compareNamesUsingSpecialCompare("a/","a:")); - } - - @Test - public void test000_sort_04() throws UnsupportedEncodingException { - assertEquals(-1, compareNamesUsingSpecialCompare("a.a","a/a")); - assertEquals(1, compareNamesUsingSpecialCompare("a/a","a.a")); - } - - @Test - public void test000_sort_05() throws UnsupportedEncodingException { - assertEquals(-1, compareNamesUsingSpecialCompare("a.","a/")); - assertEquals(1, compareNamesUsingSpecialCompare("a/","a.")); - - } - - @Test - public void test001_createEmpty() throws IOException { - final Tree t = new Tree(db); - assertTrue("isLoaded", t.isLoaded()); - assertTrue("isModified", t.isModified()); - assertTrue("no parent", t.getParent() == null); - assertTrue("isRoot", t.isRoot()); - assertTrue("no name", t.getName() == null); - assertTrue("no nameUTF8", t.getNameUTF8() == null); - assertTrue("has entries array", t.members() != null); - assertEquals("entries is empty", 0, t.members().length); - assertEquals("full name is empty", "", t.getFullName()); - assertTrue("no id", t.getId() == null); - assertTrue("database is r", t.getRepository() == db); - assertTrue("no foo child", t.findTreeMember("foo") == null); - assertTrue("no foo child", t.findBlobMember("foo") == null); - } - - @Test - public void test002_addFile() throws IOException { - final Tree t = new Tree(db); - t.setId(SOME_FAKE_ID); - assertTrue("has id", t.getId() != null); - assertFalse("not modified", t.isModified()); - - final String n = "bob"; - final FileTreeEntry f = t.addFile(n); - assertNotNull("have file", f); - assertEquals("name matches", n, f.getName()); - assertEquals("name matches", f.getName(), new String(f.getNameUTF8(), - "UTF-8")); - assertEquals("full name matches", n, f.getFullName()); - assertTrue("no id", f.getId() == null); - assertTrue("is modified", t.isModified()); - assertTrue("has no id", t.getId() == null); - assertTrue("found bob", t.findBlobMember(f.getName()) == f); - - final TreeEntry[] i = t.members(); - assertNotNull("members array not null", i); - assertTrue("iterator is not empty", i != null && i.length > 0); - assertTrue("iterator returns file", i != null && i[0] == f); - assertTrue("iterator is empty", i != null && i.length == 1); - } - - @Test - public void test004_addTree() throws IOException { - final Tree t = new Tree(db); - t.setId(SOME_FAKE_ID); - assertTrue("has id", t.getId() != null); - assertFalse("not modified", t.isModified()); - - final String n = "bob"; - final Tree f = t.addTree(n); - assertNotNull("have tree", f); - assertEquals("name matches", n, f.getName()); - assertEquals("name matches", f.getName(), new String(f.getNameUTF8(), - "UTF-8")); - assertEquals("full name matches", n, f.getFullName()); - assertTrue("no id", f.getId() == null); - assertTrue("parent matches", f.getParent() == t); - assertTrue("repository matches", f.getRepository() == db); - assertTrue("isLoaded", f.isLoaded()); - assertFalse("has items", f.members().length > 0); - assertFalse("is root", f.isRoot()); - assertTrue("parent is modified", t.isModified()); - assertTrue("parent has no id", t.getId() == null); - assertTrue("found bob child", t.findTreeMember(f.getName()) == f); - - final TreeEntry[] i = t.members(); - assertTrue("iterator is not empty", i.length > 0); - assertTrue("iterator returns file", i[0] == f); - assertEquals("iterator is empty", 1, i.length); - } - - @Test - public void test005_addRecursiveFile() throws IOException { - final Tree t = new Tree(db); - final FileTreeEntry f = t.addFile("a/b/c"); - assertNotNull("created f", f); - assertEquals("c", f.getName()); - assertEquals("b", f.getParent().getName()); - assertEquals("a", f.getParent().getParent().getName()); - assertTrue("t is great-grandparent", t == f.getParent().getParent() - .getParent()); - } - - @Test - public void test005_addRecursiveTree() throws IOException { - final Tree t = new Tree(db); - final Tree f = t.addTree("a/b/c"); - assertNotNull("created f", f); - assertEquals("c", f.getName()); - assertEquals("b", f.getParent().getName()); - assertEquals("a", f.getParent().getParent().getName()); - assertTrue("t is great-grandparent", t == f.getParent().getParent() - .getParent()); - } - - @Test - public void test006_addDeepTree() throws IOException { - final Tree t = new Tree(db); - - final Tree e = t.addTree("e"); - assertNotNull("have e", e); - assertTrue("e.parent == t", e.getParent() == t); - final Tree f = t.addTree("f"); - assertNotNull("have f", f); - assertTrue("f.parent == t", f.getParent() == t); - final Tree g = f.addTree("g"); - assertNotNull("have g", g); - assertTrue("g.parent == f", g.getParent() == f); - final Tree h = g.addTree("h"); - assertNotNull("have h", h); - assertTrue("h.parent = g", h.getParent() == g); - - h.setId(SOME_FAKE_ID); - assertTrue("h not modified", !h.isModified()); - g.setId(SOME_FAKE_ID); - assertTrue("g not modified", !g.isModified()); - f.setId(SOME_FAKE_ID); - assertTrue("f not modified", !f.isModified()); - e.setId(SOME_FAKE_ID); - assertTrue("e not modified", !e.isModified()); - t.setId(SOME_FAKE_ID); - assertTrue("t not modified.", !t.isModified()); - - assertEquals("full path of h ok", "f/g/h", h.getFullName()); - assertTrue("Can find h", t.findTreeMember(h.getFullName()) == h); - assertTrue("Can't find f/z", t.findBlobMember("f/z") == null); - assertTrue("Can't find y/z", t.findBlobMember("y/z") == null); - - final FileTreeEntry i = h.addFile("i"); - assertNotNull(i); - assertEquals("full path of i ok", "f/g/h/i", i.getFullName()); - assertTrue("Can find i", t.findBlobMember(i.getFullName()) == i); - assertTrue("h modified", h.isModified()); - assertTrue("g modified", g.isModified()); - assertTrue("f modified", f.isModified()); - assertTrue("e not modified", !e.isModified()); - assertTrue("t modified", t.isModified()); - - assertTrue("h no id", h.getId() == null); - assertTrue("g no id", g.getId() == null); - assertTrue("f no id", f.getId() == null); - assertTrue("e has id", e.getId() != null); - assertTrue("t no id", t.getId() == null); - } - - @Test - public void test007_manyFileLookup() throws IOException { - final Tree t = new Tree(db); - final List<FileTreeEntry> files = new ArrayList<FileTreeEntry>(26 * 26); - for (char level1 = 'a'; level1 <= 'z'; level1++) { - for (char level2 = 'a'; level2 <= 'z'; level2++) { - final String n = "." + level1 + level2 + "9"; - final FileTreeEntry f = t.addFile(n); - assertNotNull("File " + n + " added.", f); - assertEquals(n, f.getName()); - files.add(f); - } - } - assertEquals(files.size(), t.memberCount()); - final TreeEntry[] ents = t.members(); - assertNotNull(ents); - assertEquals(files.size(), ents.length); - for (int k = 0; k < ents.length; k++) { - assertTrue("File " + files.get(k).getName() - + " is at " + k + ".", files.get(k) == ents[k]); - } - } - - @Test - public void test008_SubtreeInternalSorting() throws IOException { - final Tree t = new Tree(db); - final FileTreeEntry e0 = t.addFile("a-b"); - final FileTreeEntry e1 = t.addFile("a-"); - final FileTreeEntry e2 = t.addFile("a=b"); - final Tree e3 = t.addTree("a"); - final FileTreeEntry e4 = t.addFile("a="); - - final TreeEntry[] ents = t.members(); - assertSame(e1, ents[0]); - assertSame(e0, ents[1]); - assertSame(e3, ents[2]); - assertSame(e4, ents[3]); - assertSame(e2, ents[4]); - } - - @Test - public void test009_SymlinkAndGitlink() throws IOException { - final Tree symlinkTree = mapTree("symlink"); - assertTrue("Symlink entry exists", symlinkTree.existsBlob("symlink.txt")); - final Tree gitlinkTree = mapTree("gitlink"); - assertTrue("Gitlink entry exists", gitlinkTree.existsBlob("submodule")); - } - - private Tree mapTree(String name) throws IOException { - ObjectId id = db.resolve(name + "^{tree}"); - return new Tree(db, id, db.open(id).getCachedBytes()); - } -} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java index 2a59f58c66..9c9edc1476 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java @@ -47,11 +47,10 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.FileTreeEntry; +import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; -import org.eclipse.jgit.lib.Tree; +import org.eclipse.jgit.lib.TreeFormatter; import org.junit.Test; @SuppressWarnings("deprecation") @@ -220,28 +219,24 @@ public class ObjectWalkTest extends RevWalkTestCase { .fromString("abbbfafe3129f85747aba7bfac992af77134c607"); final RevTree tree_root, tree_A, tree_AB; final RevCommit b; - { - Tree root = new Tree(db); - Tree A = root.addTree("A"); - FileTreeEntry B = root.addFile("B"); - B.setId(bId); - - Tree A_A = A.addTree("A"); - Tree A_B = A.addTree("B"); - - try (final ObjectInserter inserter = db.newObjectInserter()) { - A_A.setId(inserter.insert(Constants.OBJ_TREE, A_A.format())); - A_B.setId(inserter.insert(Constants.OBJ_TREE, A_B.format())); - A.setId(inserter.insert(Constants.OBJ_TREE, A.format())); - root.setId(inserter.insert(Constants.OBJ_TREE, root.format())); - inserter.flush(); - } - - tree_root = rw.parseTree(root.getId()); - tree_A = rw.parseTree(A.getId()); - tree_AB = rw.parseTree(A_A.getId()); - assertSame(tree_AB, rw.parseTree(A_B.getId())); - b = commit(rw.parseTree(root.getId())); + try (ObjectInserter inserter = db.newObjectInserter()) { + ObjectId empty = inserter.insert(new TreeFormatter()); + + TreeFormatter A = new TreeFormatter(); + A.append("A", FileMode.TREE, empty); + A.append("B", FileMode.TREE, empty); + ObjectId idA = inserter.insert(A); + + TreeFormatter root = new TreeFormatter(); + root.append("A", FileMode.TREE, idA); + root.append("B", FileMode.REGULAR_FILE, bId); + ObjectId idRoot = inserter.insert(root); + inserter.flush(); + + tree_root = objw.parseTree(idRoot); + tree_A = objw.parseTree(idA); + tree_AB = objw.parseTree(empty); + b = commit(tree_root); } markStart(b); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java index beda2a7b97..885c1b5b2d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java @@ -43,13 +43,18 @@ package org.eclipse.jgit.revwalk; +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; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; import java.util.TimeZone; import org.eclipse.jgit.junit.RepositoryTestCase; @@ -304,6 +309,86 @@ public class RevCommitParseTest extends RepositoryTestCase { } @Test + public void testParse_incorrectUtf8Name() throws Exception { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n" + .getBytes(UTF_8)); + b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8)); + b.write("committer co <c@example.com> 1218123390 -0500\n" + .getBytes(UTF_8)); + b.write("encoding 'utf8'\n".getBytes(UTF_8)); + b.write("\n".getBytes(UTF_8)); + b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8)); + + RevCommit c = new RevCommit( + id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); + c.parseCanonical(new RevWalk(db), b.toByteArray()); + assertEquals("'utf8'", c.getEncodingName()); + assertEquals("Sm\u00f6rg\u00e5sbord\n", c.getFullMessage()); + + try { + c.getEncoding(); + fail("Expected " + IllegalCharsetNameException.class); + } catch (IllegalCharsetNameException badName) { + assertEquals("'utf8'", badName.getMessage()); + } + } + + @Test + public void testParse_illegalEncoding() throws Exception { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8)); + b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8)); + b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(UTF_8)); + b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8)); + b.write("\n".getBytes(UTF_8)); + b.write("message\n".getBytes(UTF_8)); + + RevCommit c = new RevCommit( + id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); + c.parseCanonical(new RevWalk(db), b.toByteArray()); + assertEquals("utf-8logoutputencoding=gbk", c.getEncodingName()); + assertEquals("message\n", c.getFullMessage()); + assertEquals("message", c.getShortMessage()); + assertTrue(c.getFooterLines().isEmpty()); + assertEquals("au", c.getAuthorIdent().getName()); + + try { + c.getEncoding(); + fail("Expected " + IllegalCharsetNameException.class); + } catch (IllegalCharsetNameException badName) { + assertEquals("utf-8logoutputencoding=gbk", badName.getMessage()); + } + } + + @Test + public void testParse_unsupportedEncoding() throws Exception { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8)); + b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8)); + b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(UTF_8)); + b.write("encoding it_IT.UTF8\n".getBytes(UTF_8)); + b.write("\n".getBytes(UTF_8)); + b.write("message\n".getBytes(UTF_8)); + + RevCommit c = new RevCommit( + id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); + c.parseCanonical(new RevWalk(db), b.toByteArray()); + assertEquals("it_IT.UTF8", c.getEncodingName()); + assertEquals("message\n", c.getFullMessage()); + assertEquals("message", c.getShortMessage()); + assertTrue(c.getFooterLines().isEmpty()); + assertEquals("au", c.getAuthorIdent().getName()); + + try { + c.getEncoding(); + fail("Expected " + UnsupportedCharsetException.class); + } catch (UnsupportedCharsetException badName) { + assertEquals("it_IT.UTF8", badName.getMessage()); + } + } + + @Test public void testParse_NoMessage() throws Exception { final String msg = ""; final RevCommit c = create(msg); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java index 614f49bf03..82505caf22 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java @@ -43,6 +43,7 @@ package org.eclipse.jgit.revwalk; +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; @@ -362,6 +363,44 @@ public class RevTagParseTest extends RepositoryTestCase { } @Test + public void testParse_illegalEncoding() throws Exception { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8)); + b.write("type tree\n".getBytes(UTF_8)); + b.write("tag v1.0\n".getBytes(UTF_8)); + b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8)); + b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8)); + b.write("\n".getBytes(UTF_8)); + b.write("message\n".getBytes(UTF_8)); + + RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); + t.parseCanonical(new RevWalk(db), b.toByteArray()); + + assertEquals("t", t.getTaggerIdent().getName()); + assertEquals("message", t.getShortMessage()); + assertEquals("message\n", t.getFullMessage()); + } + + @Test + public void testParse_unsupportedEncoding() throws Exception { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8)); + b.write("type tree\n".getBytes(UTF_8)); + b.write("tag v1.0\n".getBytes(UTF_8)); + b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8)); + b.write("encoding it_IT.UTF8\n".getBytes(UTF_8)); + b.write("\n".getBytes(UTF_8)); + b.write("message\n".getBytes(UTF_8)); + + RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); + t.parseCanonical(new RevWalk(db), b.toByteArray()); + + assertEquals("t", t.getTaggerIdent().getName()); + assertEquals("message", t.getShortMessage()); + assertEquals("message\n", t.getFullMessage()); + } + + @Test public void testParse_NoMessage() throws Exception { final String msg = ""; final RevTag c = create(msg); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java index 782e414b62..c1e078d10d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java @@ -112,12 +112,9 @@ public class AtomicPushTest { public void pushNonAtomic() throws Exception { PushResult r; server.setPerformsAtomicTransactions(false); - Transport tn = testProtocol.open(uri, client, "server"); - try { + try (Transport tn = testProtocol.open(uri, client, "server")) { tn.setPushAtomic(false); r = tn.push(NullProgressMonitor.INSTANCE, commands()); - } finally { - tn.close(); } RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one"); @@ -131,12 +128,9 @@ public class AtomicPushTest { @Test public void pushAtomicClientGivesUpEarly() throws Exception { PushResult r; - Transport tn = testProtocol.open(uri, client, "server"); - try { + try (Transport tn = testProtocol.open(uri, client, "server")) { tn.setPushAtomic(true); r = tn.push(NullProgressMonitor.INSTANCE, commands()); - } finally { - tn.close(); } RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one"); @@ -167,8 +161,7 @@ public class AtomicPushTest { ObjectId.zeroId())); server.setPerformsAtomicTransactions(false); - Transport tn = testProtocol.open(uri, client, "server"); - try { + try (Transport tn = testProtocol.open(uri, client, "server")) { tn.setPushAtomic(true); tn.push(NullProgressMonitor.INSTANCE, cmds); fail("did not throw TransportException"); @@ -176,8 +169,6 @@ public class AtomicPushTest { assertEquals( uri + ": " + JGitText.get().atomicPushNotSupported, e.getMessage()); - } finally { - tn.close(); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java index 461530896d..a83a993330 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java @@ -168,8 +168,10 @@ public class BundleWriterTest extends SampleDataRepositoryTestCase { final ByteArrayInputStream in = new ByteArrayInputStream(bundle); final RefSpec rs = new RefSpec("refs/heads/*:refs/heads/*"); final Set<RefSpec> refs = Collections.singleton(rs); - return new TransportBundleStream(newRepo, uri, in).fetch( - NullProgressMonitor.INSTANCE, refs); + try (TransportBundleStream transport = new TransportBundleStream( + newRepo, uri, in)) { + return transport.fetch(NullProgressMonitor.INSTANCE, refs); + } } private byte[] makeBundle(final String name, 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 aa5914fe03..94bc383db7 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 @@ -116,12 +116,9 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas // Clone from dst into src // - Transport t = Transport.open(src, uriOf(dst)); - try { + try (Transport t = Transport.open(src, uriOf(dst))) { t.fetch(PM, Collections.singleton(new RefSpec("+refs/*:refs/*"))); assertEquals(B, src.resolve(R_MASTER)); - } finally { - t.close(); } // Now put private stuff into dst. @@ -144,7 +141,8 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas @Test public void testFilterHidesPrivate() throws Exception { Map<String, Ref> refs; - TransportLocal t = new TransportLocal(src, uriOf(dst), dst.getDirectory()) { + try (TransportLocal t = new TransportLocal(src, uriOf(dst), + dst.getDirectory()) { @Override ReceivePack createReceivePack(final Repository db) { db.close(); @@ -154,16 +152,10 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas rp.setAdvertiseRefsHook(new HidePrivateHook()); return rp; } - }; - try { - PushConnection c = t.openPush(); - try { + }) { + try (PushConnection c = t.openPush()) { refs = c.getRefsMap(); - } finally { - c.close(); } - } finally { - t.close(); } assertNotNull(refs); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java index 3f5fcbbf07..4f833509d9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java @@ -341,6 +341,41 @@ public class RefSpecTest { } @Test + public void testWildcardAfterText1() { + RefSpec a = new RefSpec("refs/heads/*/for-linus:refs/remotes/mine/*-blah"); + assertTrue(a.isWildcard()); + assertTrue(a.matchDestination("refs/remotes/mine/x-blah")); + assertTrue(a.matchDestination("refs/remotes/mine/foo-blah")); + assertTrue(a.matchDestination("refs/remotes/mine/foo/x-blah")); + assertFalse(a.matchDestination("refs/remotes/origin/foo/x-blah")); + + RefSpec b = a.expandFromSource("refs/heads/foo/for-linus"); + assertEquals("refs/remotes/mine/foo-blah", b.getDestination()); + RefSpec c = a.expandFromDestination("refs/remotes/mine/foo-blah"); + assertEquals("refs/heads/foo/for-linus", c.getSource()); + } + + @Test + public void testWildcardAfterText2() { + RefSpec a = new RefSpec("refs/heads*/for-linus:refs/remotes/mine/*"); + assertTrue(a.isWildcard()); + assertTrue(a.matchSource("refs/headsx/for-linus")); + assertTrue(a.matchSource("refs/headsfoo/for-linus")); + assertTrue(a.matchSource("refs/headsx/foo/for-linus")); + assertFalse(a.matchSource("refs/headx/for-linus")); + + RefSpec b = a.expandFromSource("refs/headsx/for-linus"); + assertEquals("refs/remotes/mine/x", b.getDestination()); + RefSpec c = a.expandFromDestination("refs/remotes/mine/x"); + assertEquals("refs/headsx/for-linus", c.getSource()); + + RefSpec d = a.expandFromSource("refs/headsx/foo/for-linus"); + assertEquals("refs/remotes/mine/x/foo", d.getDestination()); + RefSpec e = a.expandFromDestination("refs/remotes/mine/x/foo"); + assertEquals("refs/headsx/foo/for-linus", e.getSource()); + } + + @Test public void testWildcardMirror() { RefSpec a = new RefSpec("*:*"); assertTrue(a.isWildcard()); @@ -404,21 +439,6 @@ public class RefSpecTest { } @Test(expected = IllegalArgumentException.class) - public void invalidWhenWildcardAfterText() { - assertNotNull(new RefSpec("refs/heads/wrong*:refs/heads/right/*")); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidWhenWildcardBeforeText() { - assertNotNull(new RefSpec("*wrong:right/*")); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidWhenWildcardBeforeTextAtEnd() { - assertNotNull(new RefSpec("refs/heads/*wrong:right/*")); - } - - @Test(expected = IllegalArgumentException.class) public void invalidSourceDoubleSlashes() { assertNotNull(new RefSpec("refs/heads//wrong")); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java index 55e1e44206..5519f61ac2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java @@ -61,13 +61,10 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; -import org.junit.After; import org.junit.Before; import org.junit.Test; public class TransportTest extends SampleDataRepositoryTestCase { - private Transport transport; - private RemoteConfig remoteConfig; @Override @@ -77,17 +74,6 @@ public class TransportTest extends SampleDataRepositoryTestCase { final Config config = db.getConfig(); remoteConfig = new RemoteConfig(config, "test"); remoteConfig.addURI(new URIish("http://everyones.loves.git/u/2")); - transport = null; - } - - @Override - @After - public void tearDown() throws Exception { - if (transport != null) { - transport.close(); - transport = null; - } - super.tearDown(); } /** @@ -99,10 +85,11 @@ public class TransportTest extends SampleDataRepositoryTestCase { @Test public void testFindRemoteRefUpdatesNoWildcardNoTracking() throws IOException { - transport = Transport.open(db, remoteConfig); - final Collection<RemoteRefUpdate> result = transport - .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( - "refs/heads/master:refs/heads/x"))); + Collection<RemoteRefUpdate> result; + try (Transport transport = Transport.open(db, remoteConfig)) { + result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1, + new RefSpec("refs/heads/master:refs/heads/x"))); + } assertEquals(1, result.size()); final RemoteRefUpdate rru = result.iterator().next(); @@ -122,10 +109,11 @@ public class TransportTest extends SampleDataRepositoryTestCase { @Test public void testFindRemoteRefUpdatesNoWildcardNoDestination() throws IOException { - transport = Transport.open(db, remoteConfig); - final Collection<RemoteRefUpdate> result = transport - .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( - "+refs/heads/master"))); + Collection<RemoteRefUpdate> result; + try (Transport transport = Transport.open(db, remoteConfig)) { + result = transport.findRemoteRefUpdatesFor( + Collections.nCopies(1, new RefSpec("+refs/heads/master"))); + } assertEquals(1, result.size()); final RemoteRefUpdate rru = result.iterator().next(); @@ -143,10 +131,11 @@ public class TransportTest extends SampleDataRepositoryTestCase { */ @Test public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException { - transport = Transport.open(db, remoteConfig); - final Collection<RemoteRefUpdate> result = transport - .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( - "+refs/heads/*:refs/heads/test/*"))); + Collection<RemoteRefUpdate> result; + try (Transport transport = Transport.open(db, remoteConfig)) { + result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1, + new RefSpec("+refs/heads/*:refs/heads/test/*"))); + } assertEquals(12, result.size()); boolean foundA = false; @@ -171,12 +160,14 @@ public class TransportTest extends SampleDataRepositoryTestCase { */ @Test public void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException { - transport = Transport.open(db, remoteConfig); final RefSpec specA = new RefSpec("+refs/heads/a:refs/heads/b"); final RefSpec specC = new RefSpec("+refs/heads/c:refs/heads/d"); final Collection<RefSpec> specs = Arrays.asList(specA, specC); - final Collection<RemoteRefUpdate> result = transport - .findRemoteRefUpdatesFor(specs); + + Collection<RemoteRefUpdate> result; + try (Transport transport = Transport.open(db, remoteConfig)) { + result = transport.findRemoteRefUpdatesFor(specs); + } assertEquals(2, result.size()); boolean foundA = false; @@ -202,10 +193,12 @@ public class TransportTest extends SampleDataRepositoryTestCase { public void testFindRemoteRefUpdatesTrackingRef() throws IOException { remoteConfig.addFetchRefSpec(new RefSpec( "refs/heads/*:refs/remotes/test/*")); - transport = Transport.open(db, remoteConfig); - final Collection<RemoteRefUpdate> result = transport - .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( - "+refs/heads/a:refs/heads/a"))); + + Collection<RemoteRefUpdate> result; + try (Transport transport = Transport.open(db, remoteConfig)) { + result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1, + new RefSpec("+refs/heads/a:refs/heads/a"))); + } assertEquals(1, result.size()); final TrackingRefUpdate tru = result.iterator().next() @@ -225,20 +218,18 @@ public class TransportTest extends SampleDataRepositoryTestCase { config.addURI(new URIish("../" + otherDir)); // Should not throw NoRemoteRepositoryException - transport = Transport.open(db, config); + Transport.open(db, config).close(); } @Test public void testLocalTransportFetchWithoutLocalRepository() throws Exception { URIish uri = new URIish("file://" + db.getWorkTree().getAbsolutePath()); - transport = Transport.open(uri); - FetchConnection fetchConnection = transport.openFetch(); - try { - Ref head = fetchConnection.getRef(Constants.HEAD); - assertNotNull(head); - } finally { - fetchConnection.close(); + try (Transport transport = Transport.open(uri)) { + try (FetchConnection fetchConnection = transport.openFetch()) { + Ref head = fetchConnection.getRef(Constants.HEAD); + assertNotNull(head); + } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java index 2078dd337b..e55d373347 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java @@ -460,6 +460,48 @@ public class URIishTest { } @Test + public void testSshProtoWithEmailUserAndPort() throws Exception { + final String str = "ssh://user.name@email.com@example.com:33/some/p ath"; + URIish u = new URIish(str); + assertEquals("ssh", u.getScheme()); + assertTrue(u.isRemote()); + assertEquals("/some/p ath", u.getRawPath()); + assertEquals("/some/p ath", u.getPath()); + assertEquals("example.com", u.getHost()); + assertEquals("user.name@email.com", u.getUser()); + assertNull(u.getPass()); + assertEquals(33, u.getPort()); + assertEquals("ssh://user.name%40email.com@example.com:33/some/p ath", + u.toPrivateString()); + assertEquals("ssh://user.name%40email.com@example.com:33/some/p%20ath", + u.toPrivateASCIIString()); + assertEquals(u.setPass(null).toPrivateString(), u.toString()); + assertEquals(u.setPass(null).toPrivateASCIIString(), u.toASCIIString()); + assertEquals(u, new URIish(str)); + } + + @Test + public void testSshProtoWithEmailUserPassAndPort() throws Exception { + final String str = "ssh://user.name@email.com:pass@wor:d@example.com:33/some/p ath"; + URIish u = new URIish(str); + assertEquals("ssh", u.getScheme()); + assertTrue(u.isRemote()); + assertEquals("/some/p ath", u.getRawPath()); + assertEquals("/some/p ath", u.getPath()); + assertEquals("example.com", u.getHost()); + assertEquals("user.name@email.com", u.getUser()); + assertEquals("pass@wor:d", u.getPass()); + assertEquals(33, u.getPort()); + assertEquals("ssh://user.name%40email.com:pass%40wor%3ad@example.com:33/some/p ath", + u.toPrivateString()); + assertEquals("ssh://user.name%40email.com:pass%40wor%3ad@example.com:33/some/p%20ath", + u.toPrivateASCIIString()); + assertEquals(u.setPass(null).toPrivateString(), u.toString()); + assertEquals(u.setPass(null).toPrivateASCIIString(), u.toASCIIString()); + assertEquals(u, new URIish(str)); + } + + @Test public void testSshProtoWithADUserPassAndPort() throws Exception { final String str = "ssh://DOMAIN\\user:pass@example.com:33/some/p ath"; URIish u = new URIish(str); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java index aca7c80fd7..c3ff7df8f2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java @@ -44,7 +44,6 @@ package org.eclipse.jgit.treewalk; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; -import static org.eclipse.jgit.lib.Constants.OBJ_TREE; import static org.eclipse.jgit.lib.Constants.encode; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -54,11 +53,10 @@ import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; -import org.eclipse.jgit.lib.Tree; +import org.eclipse.jgit.lib.TreeFormatter; import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.junit.Test; -@SuppressWarnings("deprecation") public class TreeWalkBasicDiffTest extends RepositoryTestCase { @Test public void testMissingSubtree_DetectFileAdded_FileModified() @@ -72,62 +70,63 @@ public class TreeWalkBasicDiffTest extends RepositoryTestCase { // Create sub-a/empty, sub-c/empty = hello. { - final Tree root = new Tree(db); + TreeFormatter root = new TreeFormatter(); { - final Tree subA = root.addTree("sub-a"); - subA.addFile("empty").setId(aFileId); - subA.setId(inserter.insert(OBJ_TREE, subA.format())); + TreeFormatter subA = new TreeFormatter(); + subA.append("empty", FileMode.REGULAR_FILE, aFileId); + root.append("sub-a", FileMode.TREE, inserter.insert(subA)); } { - final Tree subC = root.addTree("sub-c"); - subC.addFile("empty").setId(cFileId1); - subC.setId(inserter.insert(OBJ_TREE, subC.format())); + TreeFormatter subC = new TreeFormatter(); + subC.append("empty", FileMode.REGULAR_FILE, cFileId1); + root.append("sub-c", FileMode.TREE, inserter.insert(subC)); } - oldTree = inserter.insert(OBJ_TREE, root.format()); + oldTree = inserter.insert(root); } // Create sub-a/empty, sub-b/empty, sub-c/empty. { - final Tree root = new Tree(db); + TreeFormatter root = new TreeFormatter(); { - final Tree subA = root.addTree("sub-a"); - subA.addFile("empty").setId(aFileId); - subA.setId(inserter.insert(OBJ_TREE, subA.format())); + TreeFormatter subA = new TreeFormatter(); + subA.append("empty", FileMode.REGULAR_FILE, aFileId); + root.append("sub-a", FileMode.TREE, inserter.insert(subA)); } { - final Tree subB = root.addTree("sub-b"); - subB.addFile("empty").setId(bFileId); - subB.setId(inserter.insert(OBJ_TREE, subB.format())); + TreeFormatter subB = new TreeFormatter(); + subB.append("empty", FileMode.REGULAR_FILE, bFileId); + root.append("sub-b", FileMode.TREE, inserter.insert(subB)); } { - final Tree subC = root.addTree("sub-c"); - subC.addFile("empty").setId(cFileId2); - subC.setId(inserter.insert(OBJ_TREE, subC.format())); + TreeFormatter subC = new TreeFormatter(); + subC.append("empty", FileMode.REGULAR_FILE, cFileId2); + root.append("sub-c", FileMode.TREE, inserter.insert(subC)); } - newTree = inserter.insert(OBJ_TREE, root.format()); + newTree = inserter.insert(root); } inserter.flush(); } - final TreeWalk tw = new TreeWalk(db); - tw.reset(oldTree, newTree); - tw.setRecursive(true); - tw.setFilter(TreeFilter.ANY_DIFF); + try (TreeWalk tw = new TreeWalk(db)) { + tw.reset(oldTree, newTree); + tw.setRecursive(true); + tw.setFilter(TreeFilter.ANY_DIFF); - assertTrue(tw.next()); - assertEquals("sub-b/empty", tw.getPathString()); - assertEquals(FileMode.MISSING, tw.getFileMode(0)); - assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1)); - assertEquals(ObjectId.zeroId(), tw.getObjectId(0)); - assertEquals(bFileId, tw.getObjectId(1)); + assertTrue(tw.next()); + assertEquals("sub-b/empty", tw.getPathString()); + assertEquals(FileMode.MISSING, tw.getFileMode(0)); + assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1)); + assertEquals(ObjectId.zeroId(), tw.getObjectId(0)); + assertEquals(bFileId, tw.getObjectId(1)); - assertTrue(tw.next()); - assertEquals("sub-c/empty", tw.getPathString()); - assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(0)); - assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1)); - assertEquals(cFileId1, tw.getObjectId(0)); - assertEquals(cFileId2, tw.getObjectId(1)); + assertTrue(tw.next()); + assertEquals("sub-c/empty", tw.getPathString()); + assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(0)); + assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1)); + assertEquals(cFileId1, tw.getObjectId(0)); + assertEquals(cFileId2, tw.getObjectId(1)); - assertFalse(tw.next()); + assertFalse(tw.next()); + } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java index d0062e1990..5edc1924f2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java @@ -43,11 +43,18 @@ package org.eclipse.jgit.treewalk.filter; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheEditor; @@ -58,6 +65,7 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.StopWalkException; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Sets; import org.eclipse.jgit.treewalk.TreeWalk; import org.junit.Before; import org.junit.Test; @@ -66,6 +74,8 @@ public class PathFilterGroupTest { private TreeFilter filter; + private Map<String, TreeFilter> singles; + @Before public void setup() { // @formatter:off @@ -81,64 +91,75 @@ public class PathFilterGroupTest { }; // @formatter:on filter = PathFilterGroup.createFromStrings(paths); + singles = new HashMap<>(); + for (String path : paths) { + singles.put(path, PathFilterGroup.createFromStrings(path)); + } } @Test public void testExact() throws MissingObjectException, IncorrectObjectTypeException, IOException { - assertTrue(filter.include(fakeWalk("a"))); - assertTrue(filter.include(fakeWalk("b/c"))); - assertTrue(filter.include(fakeWalk("c/d/e"))); - assertTrue(filter.include(fakeWalk("c/d/f"))); - assertTrue(filter.include(fakeWalk("d/e/f/g"))); - assertTrue(filter.include(fakeWalk("d/e/f/g.x"))); + assertMatches(Sets.of("a"), fakeWalk("a")); + assertMatches(Sets.of("b/c"), fakeWalk("b/c")); + assertMatches(Sets.of("c/d/e"), fakeWalk("c/d/e")); + assertMatches(Sets.of("c/d/f"), fakeWalk("c/d/f")); + assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g")); + assertMatches(Sets.of("d/e/f/g.x"), fakeWalk("d/e/f/g.x")); } @Test public void testNoMatchButClose() throws MissingObjectException, IncorrectObjectTypeException, IOException { - assertFalse(filter.include(fakeWalk("a+"))); - assertFalse(filter.include(fakeWalk("b+/c"))); - assertFalse(filter.include(fakeWalk("c+/d/e"))); - assertFalse(filter.include(fakeWalk("c+/d/f"))); - assertFalse(filter.include(fakeWalk("c/d.a"))); - assertFalse(filter.include(fakeWalk("d+/e/f/g"))); + assertNoMatches(fakeWalk("a+")); + assertNoMatches(fakeWalk("b+/c")); + assertNoMatches(fakeWalk("c+/d/e")); + assertNoMatches(fakeWalk("c+/d/f")); + assertNoMatches(fakeWalk("c/d.a")); + assertNoMatches(fakeWalk("d+/e/f/g")); } @Test public void testJustCommonPrefixIsNotMatch() throws MissingObjectException, IncorrectObjectTypeException, IOException { - assertFalse(filter.include(fakeWalk("b/a"))); - assertFalse(filter.include(fakeWalk("b/d"))); - assertFalse(filter.include(fakeWalk("c/d/a"))); - assertFalse(filter.include(fakeWalk("d/e/e"))); + assertNoMatches(fakeWalk("b/a")); + assertNoMatches(fakeWalk("b/d")); + assertNoMatches(fakeWalk("c/d/a")); + assertNoMatches(fakeWalk("d/e/e")); + assertNoMatches(fakeWalk("d/e/f/g.y")); } @Test public void testKeyIsPrefixOfFilter() throws MissingObjectException, IncorrectObjectTypeException, IOException { - assertTrue(filter.include(fakeWalk("b"))); - assertTrue(filter.include(fakeWalk("c/d"))); - assertTrue(filter.include(fakeWalk("c/d"))); - assertTrue(filter.include(fakeWalk("c"))); - assertTrue(filter.include(fakeWalk("d/e/f"))); - assertTrue(filter.include(fakeWalk("d/e"))); - assertTrue(filter.include(fakeWalk("d"))); + assertMatches(Sets.of("b/c"), fakeWalkAtSubtree("b")); + assertMatches(Sets.of("c/d/e", "c/d/f"), fakeWalkAtSubtree("c/d")); + assertMatches(Sets.of("c/d/e", "c/d/f"), fakeWalkAtSubtree("c")); + assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"), + fakeWalkAtSubtree("d/e/f")); + assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"), + fakeWalkAtSubtree("d/e")); + assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"), fakeWalkAtSubtree("d")); + + assertNoMatches(fakeWalk("b")); + assertNoMatches(fakeWalk("c/d")); + assertNoMatches(fakeWalk("c")); + assertNoMatches(fakeWalk("d/e/f")); + assertNoMatches(fakeWalk("d/e")); + assertNoMatches(fakeWalk("d")); + } @Test public void testFilterIsPrefixOfKey() throws MissingObjectException, IncorrectObjectTypeException, IOException { - assertTrue(filter.include(fakeWalk("a/b"))); - assertTrue(filter.include(fakeWalk("b/c/d"))); - assertTrue(filter.include(fakeWalk("c/d/e/f"))); - assertTrue(filter.include(fakeWalk("c/d/f/g"))); - assertTrue(filter.include(fakeWalk("d/e/f/g/h"))); - assertTrue(filter.include(fakeWalk("d/e/f/g/y"))); - assertTrue(filter.include(fakeWalk("d/e/f/g.x/h"))); - // listed before g/y, so can't StopWalk here, but it's not included - // either - assertFalse(filter.include(fakeWalk("d/e/f/g.y"))); + assertMatches(Sets.of("a"), fakeWalk("a/b")); + assertMatches(Sets.of("b/c"), fakeWalk("b/c/d")); + assertMatches(Sets.of("c/d/e"), fakeWalk("c/d/e/f")); + assertMatches(Sets.of("c/d/f"), fakeWalk("c/d/f/g")); + assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g/h")); + assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g/y")); + assertMatches(Sets.of("d/e/f/g.x"), fakeWalk("d/e/f/g.x/h")); } @Test @@ -182,6 +203,10 @@ public class PathFilterGroupTest { // less obvious #2 due to git sorting order filter.include(fakeWalk("d/e/f/g/h.txt")); + // listed before g/y, so can't StopWalk here + filter.include(fakeWalk("d/e/f/g.y")); + singles.get("d/e/f/g").include(fakeWalk("d/e/f/g.y")); + // non-ascii try { filter.include(fakeWalk("\u00C0")); @@ -191,6 +216,44 @@ public class PathFilterGroupTest { } } + private void assertNoMatches(TreeWalk tw) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + assertMatches(Sets.<String> of(), tw); + } + + private void assertMatches(Set<String> expect, TreeWalk tw) + throws MissingObjectException, IncorrectObjectTypeException, + IOException { + List<String> actual = new ArrayList<>(); + for (String path : singles.keySet()) { + if (includes(singles.get(path), tw)) { + actual.add(path); + } + } + + String[] e = expect.toArray(new String[expect.size()]); + String[] a = actual.toArray(new String[actual.size()]); + Arrays.sort(e); + Arrays.sort(a); + assertArrayEquals(e, a); + + if (expect.isEmpty()) { + assertFalse(includes(filter, tw)); + } else { + assertTrue(includes(filter, tw)); + } + } + + private static boolean includes(TreeFilter f, TreeWalk tw) + throws MissingObjectException, IncorrectObjectTypeException, + IOException { + try { + return f.include(tw); + } catch (StopWalkException e) { + return false; + } + } + TreeWalk fakeWalk(final String path) throws IOException { DirCache dc = DirCache.newInCore(); DirCacheEditor dce = dc.editor(); @@ -210,4 +273,25 @@ public class PathFilterGroupTest { return ret; } + TreeWalk fakeWalkAtSubtree(final String path) throws IOException { + DirCache dc = DirCache.newInCore(); + DirCacheEditor dce = dc.editor(); + dce.add(new DirCacheEditor.PathEdit(path + "/README") { + public void apply(DirCacheEntry ent) { + ent.setFileMode(FileMode.REGULAR_FILE); + } + }); + dce.finish(); + + TreeWalk ret = new TreeWalk((ObjectReader) null); + ret.addTree(new DirCacheIterator(dc)); + ret.next(); + while (!path.equals(ret.getPathString())) { + if (ret.isSubtree()) { + ret.enterSubtree(); + } + ret.next(); + } + return ret; + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java index 7273cdbabc..aaeb79c64a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java @@ -45,7 +45,6 @@ package org.eclipse.jgit.util; import static org.junit.Assert.assertEquals; -import java.io.IOException; import java.util.concurrent.TimeUnit; import org.eclipse.jgit.junit.MockSystemReader; @@ -113,7 +112,7 @@ public class ChangeIdUtilTest { } @Test - public void testId() throws IOException { + public void testId() { String msg = "A\nMessage\n"; ObjectId id = ChangeIdUtil.computeChangeId(treeId, parentId, p, q, msg); assertEquals("73f3751208ac92cbb76f9a26ac4a0d9d472e381b", ObjectId diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java index 0d7d31b3ad..1f78e02087 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java @@ -54,6 +54,7 @@ import java.util.regex.Matcher; import org.eclipse.jgit.junit.JGitTestUtil; import org.junit.After; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; @@ -424,19 +425,28 @@ public class FileUtilTest { @Test public void testCreateSymlink() throws IOException { FS fs = FS.DETECTED; - try { - fs.createSymLink(new File(trash, "x"), "y"); - } catch (IOException e) { - if (fs.supportsSymlinks()) - fail("FS claims to support symlinks but attempt to create symlink failed"); - return; - } - assertTrue(fs.supportsSymlinks()); + // show test as ignored if the FS doesn't support symlinks + Assume.assumeTrue(fs.supportsSymlinks()); + fs.createSymLink(new File(trash, "x"), "y"); String target = fs.readSymLink(new File(trash, "x")); assertEquals("y", target); } @Test + public void testCreateSymlinkOverrideExisting() throws IOException { + FS fs = FS.DETECTED; + // show test as ignored if the FS doesn't support symlinks + Assume.assumeTrue(fs.supportsSymlinks()); + File file = new File(trash, "x"); + fs.createSymLink(file, "y"); + String target = fs.readSymLink(file); + assertEquals("y", target); + fs.createSymLink(file, "z"); + target = fs.readSymLink(file); + assertEquals("z", target); + } + + @Test public void testRelativize_doc() { // This is the javadoc example String base = toOSPathString("c:\\Users\\jdoe\\eclipse\\git\\project"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java new file mode 100644 index 0000000000..7542ec8910 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2016, Google Inc. + * 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.util; + +import static org.eclipse.jgit.util.Paths.compare; +import static org.eclipse.jgit.util.Paths.compareSameName; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.FileMode; +import org.junit.Test; + +public class PathsTest { + @Test + public void testStripTrailingSeparator() { + assertNull(Paths.stripTrailingSeparator(null)); + assertEquals("", Paths.stripTrailingSeparator("")); + assertEquals("a", Paths.stripTrailingSeparator("a")); + assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo")); + assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo/")); + assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo//")); + assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo///")); + } + + @Test + public void testPathCompare() { + byte[] a = Constants.encode("afoo/bar.c"); + byte[] b = Constants.encode("bfoo/bar.c"); + + assertEquals(0, compare(a, 1, a.length, 0, b, 1, b.length, 0)); + assertEquals(-1, compare(a, 0, a.length, 0, b, 0, b.length, 0)); + assertEquals(1, compare(b, 0, b.length, 0, a, 0, a.length, 0)); + + a = Constants.encode("a"); + b = Constants.encode("aa"); + assertEquals(-97, compare(a, 0, a.length, 0, b, 0, b.length, 0)); + assertEquals(0, compare(a, 0, a.length, 0, b, 0, 1, 0)); + assertEquals(0, compare(a, 0, a.length, 0, b, 1, 2, 0)); + assertEquals(0, compareSameName(a, 0, a.length, b, 1, b.length, 0)); + assertEquals(0, compareSameName(a, 0, a.length, b, 0, 1, 0)); + assertEquals(-50, compareSameName(a, 0, a.length, b, 0, b.length, 0)); + assertEquals(97, compareSameName(b, 0, b.length, a, 0, a.length, 0)); + + a = Constants.encode("a"); + b = Constants.encode("a"); + assertEquals(0, compare( + a, 0, a.length, FileMode.TREE.getBits(), + b, 0, b.length, FileMode.TREE.getBits())); + assertEquals(0, compare( + a, 0, a.length, FileMode.REGULAR_FILE.getBits(), + b, 0, b.length, FileMode.REGULAR_FILE.getBits())); + assertEquals(-47, compare( + a, 0, a.length, FileMode.REGULAR_FILE.getBits(), + b, 0, b.length, FileMode.TREE.getBits())); + assertEquals(47, compare( + a, 0, a.length, FileMode.TREE.getBits(), + b, 0, b.length, FileMode.REGULAR_FILE.getBits())); + + assertEquals(0, compareSameName( + a, 0, a.length, + b, 0, b.length, FileMode.TREE.getBits())); + assertEquals(0, compareSameName( + a, 0, a.length, + b, 0, b.length, FileMode.REGULAR_FILE.getBits())); + + a = Constants.encode("a.c"); + b = Constants.encode("a"); + byte[] c = Constants.encode("a0c"); + assertEquals(-1, compare( + a, 0, a.length, FileMode.REGULAR_FILE.getBits(), + b, 0, b.length, FileMode.TREE.getBits())); + assertEquals(-1, compare( + b, 0, b.length, FileMode.TREE.getBits(), + c, 0, c.length, FileMode.REGULAR_FILE.getBits())); + } +} |