diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2015-03-12 19:30:37 -0700 |
---|---|---|
committer | Christian Halstrick <christian.halstrick@sap.com> | 2015-03-23 14:23:07 +0100 |
commit | 197e3393a51424fae45e51dce4a649ba26e5a368 (patch) | |
tree | f372aafc8cdd3b52aa41688fa3a07e3581ac4d51 /org.eclipse.jgit.test/tst/org | |
parent | 8ec01500e2eb8860e9e42dd20ead265cc2fb6735 (diff) | |
download | jgit-197e3393a51424fae45e51dce4a649ba26e5a368.tar.gz jgit-197e3393a51424fae45e51dce4a649ba26e5a368.zip |
Merge bundle org.eclipse.jgit.java7 into org.eclipse.jgit
As we moved minimum Java version to 7 we don't need a separate bundle
and feature for JGit features depending on Java 7 anymore.
Change-Id: Ib5da61b0886ddbdea65298f1e8c6d65c9879ced1
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit.test/tst/org')
8 files changed, 1176 insertions, 1 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java index 64bb8bfa4d..2220a536f1 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java @@ -140,7 +140,8 @@ public class GitConstructionTest extends RepositoryTestCase { public void testClose() throws IOException, JGitInternalException, GitAPIException { File workTree = db.getWorkTree(); - Git git = Git.wrap(db); + db.close(); + Git git = Git.open(workTree); git.gc().setExpire(null).call(); git.checkout().setName(git.getRepository().resolve("HEAD^").getName()) .call(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTestWithSymlinks.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTestWithSymlinks.java new file mode 100644 index 0000000000..b0d31cd372 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTestWithSymlinks.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2013, Christian Halstrick <christian.halstrick@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v1.0 which accompanies this + * distribution, is reproduced below, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lib; + +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.internal.storage.file.FileRepository; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FileUtils; +import org.junit.Before; +import org.junit.Test; + +public class DirCacheCheckoutTestWithSymlinks extends RepositoryTestCase { + @Before + public void beforeMethod() { + // If this assumption fails the tests are skipped. When running on a + // filesystem not supporting symlinks I don't want this tests + org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); + } + + @Test + public void testDontDeleteSymlinkOnTopOfRootDir() throws Exception { + // create a parent folder containing a folder with a test repository + File repos = createTempDirectory("repos"); + File testRepo = new File(repos, "repo"); + testRepo.mkdirs(); + Git git = Git.init().setDirectory(testRepo).call(); + db = (FileRepository) git.getRepository(); + + // Create a situation where a checkout of master whould delete a file in + // a subfolder of the root of the worktree. No other files/folders exist + writeTrashFile("d/f", "f"); + git.add().addFilepattern(".").call(); + RevCommit initial = git.commit().setMessage("inital").call(); + git.rm().addFilepattern("d/f").call(); + git.commit().setMessage("modifyOnMaster").call(); + git.checkout().setCreateBranch(true).setName("side") + .setStartPoint(initial).call(); + writeTrashFile("d/f", "f2"); + git.add().addFilepattern(".").call(); + git.commit().setMessage("modifyOnSide").call(); + git.getRepository().close(); + + // Create a symlink pointing to the parent folder of the repo and open + // the repo with the path containing the symlink + File reposSymlink = createTempFile(); + FileUtils.createSymLink(reposSymlink, repos.getPath()); + + Repository symlinkDB = FileRepositoryBuilder.create(new File( + reposSymlink, "repo/.git")); + Git symlinkRepo = Git.wrap(symlinkDB); + symlinkRepo.checkout().setName("master").call(); + + // check that the symlink still exists + assertTrue("The symlink to the repo should exist after a checkout", + reposSymlink.exists()); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java new file mode 100644 index 0000000000..3ddc3ded8c --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2013, Axel Richard <axel.richard@obeo.fr> + * 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.symlinks; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.util.List; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FileUtils; +import org.junit.Before; +import org.junit.Test; + +public class SymlinksTest extends RepositoryTestCase { + @Before + public void beforeMethod() { + // If this assumption fails the tests are skipped. When running on a + // filesystem not supporting symlinks I don't want this tests + org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); + } + + /** + * Steps: 1.Add file 'a' 2.Commit 3.Create branch '1' 4.Replace file 'a' by + * symlink 'a' 5.Commit 6.Checkout branch '1' + * + * The working tree should contain 'a' with FileMode.REGULAR_FILE after the + * checkout. + * + * @throws Exception + */ + @Test + public void fileModeTestFileThenSymlink() throws Exception { + Git git = new Git(db); + writeTrashFile("a", "Hello world a"); + writeTrashFile("b", "Hello world b"); + git.add().addFilepattern(".").call(); + git.commit().setMessage("add files a & b").call(); + Ref branch_1 = git.branchCreate().setName("branch_1").call(); + git.rm().addFilepattern("a").call(); + FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("add symlink a").call(); + + FileEntry entry = new FileTreeIterator.FileEntry(new File( + db.getWorkTree(), "a"), db.getFS()); + assertEquals(FileMode.SYMLINK, entry.getMode()); + + git.checkout().setName(branch_1.getName()).call(); + + entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"), + db.getFS()); + assertEquals(FileMode.REGULAR_FILE, entry.getMode()); + } + + /** + * Steps: 1.Add symlink 'a' 2.Commit 3.Create branch '1' 4.Replace symlink + * 'a' by file 'a' 5.Commit 6.Checkout branch '1' + * + * The working tree should contain 'a' with FileMode.SYMLINK after the + * checkout. + * + * @throws Exception + */ + @Test + public void fileModeTestSymlinkThenFile() throws Exception { + Git git = new Git(db); + writeTrashFile("b", "Hello world b"); + FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b"); + git.add().addFilepattern(".").call(); + git.commit().setMessage("add file b & symlink a").call(); + Ref branch_1 = git.branchCreate().setName("branch_1").call(); + git.rm().addFilepattern("a").call(); + writeTrashFile("a", "Hello world a"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("add file a").call(); + + FileEntry entry = new FileTreeIterator.FileEntry(new File( + db.getWorkTree(), "a"), db.getFS()); + assertEquals(FileMode.REGULAR_FILE, entry.getMode()); + + git.checkout().setName(branch_1.getName()).call(); + + entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"), + db.getFS()); + assertEquals(FileMode.SYMLINK, entry.getMode()); + } + + /** + * Steps: 1.Add folder 'a' 2.Commit 3.Create branch '1' 4.Replace folder 'a' + * by symlink 'a' 5.Commit 6.Checkout branch '1' + * + * The working tree should contain 'a' with FileMode.TREE after the + * checkout. + * + * @throws Exception + */ + @Test + public void fileModeTestFolderThenSymlink() throws Exception { + Git git = new Git(db); + FileUtils.mkdirs(new File(db.getWorkTree(), "a")); + writeTrashFile("a/b", "Hello world b"); + writeTrashFile("c", "Hello world c"); + git.add().addFilepattern(".").call(); + git.commit().setMessage("add folder a").call(); + Ref branch_1 = git.branchCreate().setName("branch_1").call(); + git.rm().addFilepattern("a").call(); + FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "c"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("add symlink a").call(); + + FileEntry entry = new FileTreeIterator.FileEntry(new File( + db.getWorkTree(), "a"), db.getFS()); + assertEquals(FileMode.SYMLINK, entry.getMode()); + + git.checkout().setName(branch_1.getName()).call(); + + entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"), + db.getFS()); + assertEquals(FileMode.TREE, entry.getMode()); + } + + /** + * Steps: 1.Add symlink 'a' 2.Commit 3.Create branch '1' 4.Replace symlink + * 'a' by folder 'a' 5.Commit 6.Checkout branch '1' + * + * The working tree should contain 'a' with FileMode.SYMLINK after the + * checkout. + * + * @throws Exception + */ + @Test + public void fileModeTestSymlinkThenFolder() throws Exception { + Git git = new Git(db); + writeTrashFile("c", "Hello world c"); + FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "c"); + git.add().addFilepattern(".").call(); + git.commit().setMessage("add symlink a").call(); + Ref branch_1 = git.branchCreate().setName("branch_1").call(); + git.rm().addFilepattern("a").call(); + FileUtils.mkdirs(new File(db.getWorkTree(), "a")); + writeTrashFile("a/b", "Hello world b"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("add folder a").call(); + + FileEntry entry = new FileTreeIterator.FileEntry(new File( + db.getWorkTree(), "a"), db.getFS()); + assertEquals(FileMode.TREE, entry.getMode()); + + git.checkout().setName(branch_1.getName()).call(); + + entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"), + db.getFS()); + assertEquals(FileMode.SYMLINK, entry.getMode()); + } + + /** + * Steps: 1.Add file 'b' 2.Commit 3.Create branch '1' 4.Add symlink 'a' + * 5.Commit 6.Checkout branch '1' + * + * The working tree should not contain 'a' -> FileMode.MISSING after the + * checkout. + * + * @throws Exception + */ + @Test + public void fileModeTestMissingThenSymlink() throws Exception { + Git git = new Git(db); + writeTrashFile("b", "Hello world b"); + git.add().addFilepattern(".").call(); + RevCommit commit1 = git.commit().setMessage("add file b").call(); + Ref branch_1 = git.branchCreate().setName("branch_1").call(); + FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b"); + git.add().addFilepattern("a").call(); + RevCommit commit2 = git.commit().setMessage("add symlink a").call(); + + git.checkout().setName(branch_1.getName()).call(); + + TreeWalk tw = new TreeWalk(db); + tw.addTree(commit1.getTree()); + tw.addTree(commit2.getTree()); + List<DiffEntry> scan = DiffEntry.scan(tw); + assertEquals(1, scan.size()); + assertEquals(FileMode.SYMLINK, scan.get(0).getNewMode()); + assertEquals(FileMode.MISSING, scan.get(0).getOldMode()); + } + + /** + * Steps: 1.Add symlink 'a' 2.Commit 3.Create branch '1' 4.Delete symlink + * 'a' 5.Commit 6.Checkout branch '1' + * + * The working tree should contain 'a' with FileMode.SYMLINK after the + * checkout. + * + * @throws Exception + */ + @Test + public void fileModeTestSymlinkThenMissing() throws Exception { + Git git = new Git(db); + writeTrashFile("b", "Hello world b"); + FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b"); + git.add().addFilepattern(".").call(); + RevCommit commit1 = git.commit().setMessage("add file b & symlink a") + .call(); + Ref branch_1 = git.branchCreate().setName("branch_1").call(); + git.rm().addFilepattern("a").call(); + RevCommit commit2 = git.commit().setMessage("delete symlink a").call(); + + git.checkout().setName(branch_1.getName()).call(); + + TreeWalk tw = new TreeWalk(db); + tw.addTree(commit1.getTree()); + tw.addTree(commit2.getTree()); + List<DiffEntry> scan = DiffEntry.scan(tw); + assertEquals(1, scan.size()); + assertEquals(FileMode.MISSING, scan.get(0).getNewMode()); + assertEquals(FileMode.SYMLINK, scan.get(0).getOldMode()); + } + + @Test + public void createSymlinkAfterTarget() throws Exception { + Git git = new Git(db); + writeTrashFile("a", "start"); + git.add().addFilepattern("a").call(); + RevCommit base = git.commit().setMessage("init").call(); + writeTrashFile("target", "someData"); + FileUtils.createSymLink(new File(db.getWorkTree(), "link"), "target"); + git.add().addFilepattern("target").addFilepattern("link").call(); + git.commit().setMessage("add target").call(); + assertEquals(4, db.getWorkTree().list().length); // self-check + git.checkout().setName(base.name()).call(); + assertEquals(2, db.getWorkTree().list().length); // self-check + git.checkout().setName("master").call(); + assertEquals(4, db.getWorkTree().list().length); + String data = read(new File(db.getWorkTree(), "target")); + assertEquals(8, new File(db.getWorkTree(), "target").length()); + assertEquals("someData", data); + data = read(new File(db.getWorkTree(), "link")); + assertEquals("target", + FileUtils.readSymLink(new File(db.getWorkTree(), "link"))); + assertEquals("someData", data); + } + + @Test + public void createFileSymlinkBeforeTarget() throws Exception { + Git git = new Git(db); + writeTrashFile("a", "start"); + git.add().addFilepattern("a").call(); + RevCommit base = git.commit().setMessage("init").call(); + writeTrashFile("target", "someData"); + FileUtils.createSymLink(new File(db.getWorkTree(), "tlink"), "target"); + git.add().addFilepattern("target").addFilepattern("tlink").call(); + git.commit().setMessage("add target").call(); + assertEquals(4, db.getWorkTree().list().length); // self-check + git.checkout().setName(base.name()).call(); + assertEquals(2, db.getWorkTree().list().length); // self-check + git.checkout().setName("master").call(); + assertEquals(4, db.getWorkTree().list().length); + String data = read(new File(db.getWorkTree(), "target")); + assertEquals(8, new File(db.getWorkTree(), "target").length()); + assertEquals("someData", data); + data = read(new File(db.getWorkTree(), "tlink")); + assertEquals("target", + FileUtils.readSymLink(new File(db.getWorkTree(), "tlink"))); + assertEquals("someData", data); + } + + @Test + public void createDirSymlinkBeforeTarget() throws Exception { + Git git = new Git(db); + writeTrashFile("a", "start"); + git.add().addFilepattern("a").call(); + RevCommit base = git.commit().setMessage("init").call(); + FileUtils.createSymLink(new File(db.getWorkTree(), "link"), "target"); + FileUtils.mkdir(new File(db.getWorkTree(), "target")); + writeTrashFile("target/file", "someData"); + git.add().addFilepattern("target").addFilepattern("link").call(); + git.commit().setMessage("add target").call(); + assertEquals(4, db.getWorkTree().list().length); // self-check + git.checkout().setName(base.name()).call(); + assertEquals(2, db.getWorkTree().list().length); // self-check + git.checkout().setName("master").call(); + assertEquals(4, db.getWorkTree().list().length); + String data = read(new File(db.getWorkTree(), "target/file")); + assertEquals(8, new File(db.getWorkTree(), "target/file").length()); + assertEquals("someData", data); + data = read(new File(db.getWorkTree(), "link/file")); + assertEquals("target", + FileUtils.readSymLink(new File(db.getWorkTree(), "link"))); + assertEquals("someData", data); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java new file mode 100644 index 0000000000..741396c519 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2012-2013, Robin Rosenberg <robin.rosenberg@dewire.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.treewalk; + +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 org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheEditor; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.dircache.DirCacheIterator; +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.ObjectInserter; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FileUtils; +import org.junit.Test; + +public class FileTreeIteratorJava7Test extends RepositoryTestCase { + @Test + public void testFileModeSymLinkIsNotATree() throws IOException { + FS fs = db.getFS(); + // mål = target in swedish, just to get som unicode in here + writeTrashFile("mål/data", "targetdata"); + fs.createSymLink(new File(trash, "länk"), "mål"); + FileTreeIterator fti = new FileTreeIterator(db); + assertFalse(fti.eof()); + assertEquals("länk", fti.getEntryPathString()); + assertEquals(FileMode.SYMLINK, fti.getEntryFileMode()); + fti.next(1); + assertFalse(fti.eof()); + assertEquals("mål", fti.getEntryPathString()); + assertEquals(FileMode.TREE, fti.getEntryFileMode()); + fti.next(1); + assertTrue(fti.eof()); + } + + @Test + public void testSymlinkNotModifiedThoughNormalized() throws Exception { + DirCache dc = db.lockDirCache(); + DirCacheEditor dce = dc.editor(); + final String UNNORMALIZED = "target/"; + final byte[] UNNORMALIZED_BYTES = Constants.encode(UNNORMALIZED); + ObjectInserter oi = db.newObjectInserter(); + final ObjectId linkid = oi.insert(Constants.OBJ_BLOB, + UNNORMALIZED_BYTES, 0, + UNNORMALIZED_BYTES.length); + oi.release(); + dce.add(new DirCacheEditor.PathEdit("link") { + @Override + public void apply(DirCacheEntry ent) { + ent.setFileMode(FileMode.SYMLINK); + ent.setObjectId(linkid); + ent.setLength(UNNORMALIZED_BYTES.length); + } + }); + assertTrue(dce.commit()); + new Git(db).commit().setMessage("Adding link").call(); + new Git(db).reset().setMode(ResetType.HARD).call(); + DirCacheIterator dci = new DirCacheIterator(db.readDirCache()); + FileTreeIterator fti = new FileTreeIterator(db); + + // self-check + assertEquals("link", fti.getEntryPathString()); + assertEquals("link", dci.getEntryPathString()); + + // test + assertFalse(fti.isModified(dci.getDirCacheEntry(), true, + db.newObjectReader())); + } + + /** + * Like #testSymlinkNotModifiedThoughNormalized but there is no + * normalization being done. + * + * @throws Exception + */ + @Test + public void testSymlinkModifiedNotNormalized() throws Exception { + DirCache dc = db.lockDirCache(); + DirCacheEditor dce = dc.editor(); + final String NORMALIZED = "target"; + final byte[] NORMALIZED_BYTES = Constants.encode(NORMALIZED); + ObjectInserter oi = db.newObjectInserter(); + final ObjectId linkid = oi.insert(Constants.OBJ_BLOB, NORMALIZED_BYTES, + 0, NORMALIZED_BYTES.length); + oi.release(); + dce.add(new DirCacheEditor.PathEdit("link") { + @Override + public void apply(DirCacheEntry ent) { + ent.setFileMode(FileMode.SYMLINK); + ent.setObjectId(linkid); + ent.setLength(NORMALIZED_BYTES.length); + } + }); + assertTrue(dce.commit()); + new Git(db).commit().setMessage("Adding link").call(); + new Git(db).reset().setMode(ResetType.HARD).call(); + DirCacheIterator dci = new DirCacheIterator(db.readDirCache()); + FileTreeIterator fti = new FileTreeIterator(db); + + // self-check + assertEquals("link", fti.getEntryPathString()); + assertEquals("link", dci.getEntryPathString()); + + // test + assertFalse(fti.isModified(dci.getDirCacheEntry(), true, + db.newObjectReader())); + } + + /** + * Like #testSymlinkNotModifiedThoughNormalized but here the link is + * modified. + * + * @throws Exception + */ + @Test + public void testSymlinkActuallyModified() throws Exception { + final String NORMALIZED = "target"; + final byte[] NORMALIZED_BYTES = Constants.encode(NORMALIZED); + ObjectInserter oi = db.newObjectInserter(); + final ObjectId linkid = oi.insert(Constants.OBJ_BLOB, NORMALIZED_BYTES, + 0, NORMALIZED_BYTES.length); + oi.release(); + DirCache dc = db.lockDirCache(); + DirCacheEditor dce = dc.editor(); + dce.add(new DirCacheEditor.PathEdit("link") { + @Override + public void apply(DirCacheEntry ent) { + ent.setFileMode(FileMode.SYMLINK); + ent.setObjectId(linkid); + ent.setLength(NORMALIZED_BYTES.length); + } + }); + assertTrue(dce.commit()); + new Git(db).commit().setMessage("Adding link").call(); + new Git(db).reset().setMode(ResetType.HARD).call(); + + FileUtils.delete(new File(trash, "link"), FileUtils.NONE); + FS.DETECTED.createSymLink(new File(trash, "link"), "newtarget"); + DirCacheIterator dci = new DirCacheIterator(db.readDirCache()); + FileTreeIterator fti = new FileTreeIterator(db); + + // self-check + assertEquals("link", fti.getEntryPathString()); + assertEquals("link", dci.getEntryPathString()); + + // test + assertTrue(fti.isModified(dci.getDirCacheEntry(), true, + db.newObjectReader())); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java new file mode 100644 index 0000000000..bb1f2a639b --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012-2013, Robin Rosenberg <robin.rosenberg@dewire.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.treewalk; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.util.FS; +import org.junit.Test; + +public class TreeWalkJava7Test extends RepositoryTestCase { + @Test + public void testSymlinkToDirNotRecursingViaSymlink() throws Exception { + FS fs = db.getFS(); + assertTrue(fs.supportsSymlinks()); + writeTrashFile("target/data", "targetdata"); + fs.createSymLink(new File(trash, "link"), "target"); + TreeWalk tw = new TreeWalk(db); + tw.setRecursive(true); + tw.addTree(new FileTreeIterator(db)); + assertTrue(tw.next()); + assertEquals("link", tw.getPathString()); + assertTrue(tw.next()); + assertEquals("target/data", tw.getPathString()); + assertFalse(tw.next()); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java new file mode 100644 index 0000000000..9fba374dcd --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2012-2013, Robin Rosenberg <robin.rosenberg@dewire.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeNotNull; +import static org.junit.Assume.assumeTrue; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFileAttributeView; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; + +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class FSJava7Test { + private File trash; + + @Before + public void setUp() throws Exception { + trash = File.createTempFile("tmp_", ""); + trash.delete(); + assertTrue("mkdir " + trash, trash.mkdir()); + } + + @After + public void tearDown() throws Exception { + FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.RETRY); + } + + /** + * The old File methods traverse symbolic links and look at the targets. + * With symbolic links we usually want to modify/look at the link. For some + * reason the executable attribute seems to always look at the target, but + * for the other attributes like lastModified, hidden and exists we must + * differ between the link and the target. + * + * @throws IOException + * @throws InterruptedException + */ + @Test + public void testSymlinkAttributes() throws IOException, InterruptedException { + FS fs = FS.DETECTED; + File link = new File(trash, "ä"); + File target = new File(trash, "å"); + fs.createSymLink(link, "å"); + assertTrue(fs.exists(link)); + String targetName = fs.readSymLink(link); + assertEquals("å", targetName); + assertTrue(fs.lastModified(link) > 0); + assertTrue(fs.exists(link)); + assertFalse(fs.canExecute(link)); + assertEquals(2, fs.length(link)); + assertFalse(fs.exists(target)); + assertFalse(fs.isFile(target)); + assertFalse(fs.isDirectory(target)); + assertFalse(fs.canExecute(target)); + + RepositoryTestCase.fsTick(link); + // Now create the link target + FileUtils.createNewFile(target); + assertTrue(fs.exists(link)); + assertTrue(fs.lastModified(link) > 0); + assertTrue(fs.lastModified(target) > fs.lastModified(link)); + assertFalse(fs.canExecute(link)); + fs.setExecute(target, true); + assertFalse(fs.canExecute(link)); + assumeTrue(fs.supportsExecute()); + assertTrue(fs.canExecute(target)); + } + + @Test + public void testExecutableAttributes() throws Exception { + FS fs = FS.DETECTED; + // If this assumption fails the test is halted and ignored. + assumeTrue(fs instanceof FS_POSIX); + + File f = new File(trash, "bla"); + assertTrue(f.createNewFile()); + assertFalse(fs.canExecute(f)); + + String umask = readUmask(); + assumeNotNull(umask); + + char others = umask.charAt(umask.length() - 1); + + boolean badUmask; + if (others != '0' && others != '2' && others != '4' && others != '6') { + // umask is set in the way that "others" can not "execute" => git + // CLI will not set "execute" attribute for "others", so we also + // don't care + badUmask = true; + } else { + badUmask = false; + } + + Set<PosixFilePermission> permissions = readPermissions(f); + assertTrue(!permissions.contains(PosixFilePermission.OTHERS_EXECUTE)); + assertTrue(!permissions.contains(PosixFilePermission.GROUP_EXECUTE)); + assertTrue(!permissions.contains(PosixFilePermission.OWNER_EXECUTE)); + + fs.setExecute(f, true); + + permissions = readPermissions(f); + assertTrue("'owner' execute permission not set", + permissions.contains(PosixFilePermission.OWNER_EXECUTE)); + assertTrue("'group' execute permission not set", + permissions.contains(PosixFilePermission.GROUP_EXECUTE)); + if (badUmask) { + assertFalse("'others' execute permission set", + permissions.contains(PosixFilePermission.OTHERS_EXECUTE)); + System.err.println("WARNING: your system's umask: \"" + umask + + "\" doesn't allow FSJava7Test to test if setting posix" + + " permissions for \"others\" works properly"); + assumeFalse(badUmask); + } else { + assertTrue("'others' execute permission not set", + permissions.contains(PosixFilePermission.OTHERS_EXECUTE)); + } + } + + private String readUmask() throws Exception { + Process p = Runtime.getRuntime().exec( + new String[] { "sh", "-c", "umask" }, null, null); + final BufferedReader lineRead = new BufferedReader( + new InputStreamReader(p.getInputStream(), Charset + .defaultCharset().name())); + p.waitFor(); + return lineRead.readLine(); + } + + private Set<PosixFilePermission> readPermissions(File f) throws IOException { + return Files + .getFileAttributeView(f.toPath(), PosixFileAttributeView.class) + .readAttributes().permissions(); + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java new file mode 100644 index 0000000000..9dc5fac5d8 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013, Robin Rosenberg <robin.rosenberg@dewire.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.util; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class FileUtils7Test { + + private final File trash = new File(new File("target"), "trash"); + + @Before + public void setUp() throws Exception { + FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.RETRY | FileUtils.SKIP_MISSING); + assertTrue(trash.mkdirs()); + } + + @After + public void tearDown() throws Exception { + FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.RETRY); + } + + @Test + public void testDeleteSymlinkToDirectoryDoesNotDeleteTarget() + throws IOException { + FS fs = FS.DETECTED; + File dir = new File(trash, "dir"); + File file = new File(dir, "file"); + File link = new File(trash, "link"); + FileUtils.mkdirs(dir); + FileUtils.createNewFile(file); + fs.createSymLink(link, "dir"); + FileUtils.delete(link, FileUtils.RECURSIVE); + assertFalse(link.exists()); + assertTrue(dir.exists()); + assertTrue(file.exists()); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java new file mode 100644 index 0000000000..b14a9bf2fa --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2014 Matthias Sohn <matthias.sohn@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.AbortedByHookException; +import org.eclipse.jgit.hooks.CommitMsgHook; +import org.eclipse.jgit.hooks.PreCommitHook; +import org.eclipse.jgit.junit.JGitTestUtil; +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Assume; +import org.junit.Test; + +public class HookTest extends RepositoryTestCase { + + @Test + public void testFindHook() throws Exception { + assumeSupportedPlatform(); + + assertNull("no hook should be installed", + FS.DETECTED.findHook(db, PreCommitHook.NAME)); + File hookFile = writeHookFile(PreCommitHook.NAME, + "#!/bin/bash\necho \"test $1 $2\""); + assertEquals("expected to find pre-commit hook", hookFile, + FS.DETECTED.findHook(db, PreCommitHook.NAME)); + } + + @Test + public void testFailedCommitMsgHookBlocksCommit() throws Exception { + assumeSupportedPlatform(); + + writeHookFile(CommitMsgHook.NAME, + "#!/bin/sh\necho \"test\"\n\necho 1>&2 \"stderr\"\nexit 1"); + Git git = Git.wrap(db); + String path = "a.txt"; + writeTrashFile(path, "content"); + git.add().addFilepattern(path).call(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + git.commit().setMessage("commit") + .setHookOutputStream(new PrintStream(out)).call(); + fail("expected commit-msg hook to abort commit"); + } catch (AbortedByHookException e) { + assertEquals("unexpected error message from commit-msg hook", + "Rejected by \"commit-msg\" hook.\nstderr\n", + e.getMessage()); + assertEquals("unexpected output from commit-msg hook", "test\n", + out.toString()); + } + } + + @Test + public void testCommitMsgHookReceivesCorrectParameter() throws Exception { + assumeSupportedPlatform(); + + writeHookFile(CommitMsgHook.NAME, + "#!/bin/sh\necho $1\n\necho 1>&2 \"stderr\"\nexit 0"); + Git git = Git.wrap(db); + String path = "a.txt"; + writeTrashFile(path, "content"); + git.add().addFilepattern(path).call(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + git.commit().setMessage("commit") + .setHookOutputStream(new PrintStream(out)).call(); + assertEquals(".git/COMMIT_EDITMSG\n", out.toString("UTF-8")); + } + + @Test + public void testCommitMsgHookCanModifyCommitMessage() throws Exception { + assumeSupportedPlatform(); + + writeHookFile(CommitMsgHook.NAME, + "#!/bin/sh\necho \"new message\" > $1\nexit 0"); + Git git = Git.wrap(db); + String path = "a.txt"; + writeTrashFile(path, "content"); + git.add().addFilepattern(path).call(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + RevCommit revCommit = git.commit().setMessage("commit") + .setHookOutputStream(new PrintStream(out)).call(); + assertEquals("new message\n", revCommit.getFullMessage()); + } + + @Test + public void testRunHook() throws Exception { + assumeSupportedPlatform(); + + writeHookFile(PreCommitHook.NAME, + "#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\necho 1>&2 \"stderr\""); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + ProcessResult res = FS.DETECTED.runHookIfPresent(db, + PreCommitHook.NAME, + new String[] { + "arg1", "arg2" }, + new PrintStream(out), new PrintStream(err), "stdin"); + assertEquals("unexpected hook output", "test arg1 arg2\nstdin\n", + out.toString("UTF-8")); + assertEquals("unexpected output on stderr stream", "stderr\n", + err.toString("UTF-8")); + assertEquals("unexpected exit code", 0, res.getExitCode()); + assertEquals("unexpected process status", ProcessResult.Status.OK, + res.getStatus()); + } + + @Test + public void testFailedPreCommitHookBlockCommit() throws Exception { + assumeSupportedPlatform(); + + writeHookFile(PreCommitHook.NAME, + "#!/bin/sh\necho \"test\"\n\necho 1>&2 \"stderr\"\nexit 1"); + Git git = Git.wrap(db); + String path = "a.txt"; + writeTrashFile(path, "content"); + git.add().addFilepattern(path).call(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + git.commit().setMessage("commit") + .setHookOutputStream(new PrintStream(out)).call(); + fail("expected pre-commit hook to abort commit"); + } catch (AbortedByHookException e) { + assertEquals("unexpected error message from pre-commit hook", + "Rejected by \"pre-commit\" hook.\nstderr\n", + e.getMessage()); + assertEquals("unexpected output from pre-commit hook", "test\n", + out.toString()); + } + } + + private File writeHookFile(final String name, final String data) + throws IOException { + File path = new File(db.getWorkTree() + "/.git/hooks/", name); + JGitTestUtil.write(path, data); + FS.DETECTED.setExecute(path, true); + return path; + } + + private void assumeSupportedPlatform() { + Assume.assumeTrue(FS.DETECTED instanceof FS_POSIX + || FS.DETECTED instanceof FS_Win32_Cygwin); + } +} |