diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2017-07-07 11:26:02 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2017-08-15 16:52:00 -0400 |
commit | b13a285098305149b34924bce2679a0cd98d9b2c (patch) | |
tree | 1fcbaf3d00e2cd486481f7d8f036f7857bcbbc7d /org.eclipse.jgit.test | |
parent | 81d020aba9d48825a70d17a5fefc4b5472795e2e (diff) | |
download | jgit-b13a285098305149b34924bce2679a0cd98d9b2c.tar.gz jgit-b13a285098305149b34924bce2679a0cd98d9b2c.zip |
Send a detailed event on working tree modifications
Currently there is no way to determine the precise changes done
to the working tree by a JGit command. Only the CheckoutCommand
actually provides access to the lists of modified, deleted, and
to-be-deleted files, but those lists may be inaccurate (since they
are determined up-front before the working tree is modified) if
the actual checkout then fails halfway through. Moreover, other
JGit commands that modify the working tree do not offer any way to
figure out which files were changed.
This poses problems for EGit, which may need to refresh parts of the
Eclipse workspace when JGit has done java.io file operations.
Provide the foundations for better file change tracking: the working
tree is modified exclusively in DirCacheCheckout. Make it emit a new
type of RepositoryEvent that lists all files that were modified or
deleted, even if the checkout failed halfway through. We update the
'updated' and 'removed' lists determined up-front in case of file
system problems to reflect the actual state of changes made.
EGit thus can register a listener for these events and then knows
exactly which parts of the Eclipse workspace may need to be refreshed.
Two commands manage checking out individual DirCacheEntries themselves:
checkout specific paths, and applying a stash with untracked files.
Make those two also emit such a new WorkingTreeModifiedEvent.
Furthermore, merges may modify files, and clean, rm, and stash create
may delete files.
CQ: 13969
Bug: 500106
Change-Id: I7a100aee315791fa1201f43bbad61fbae60b35cb
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.jgit.test')
4 files changed, 879 insertions, 467 deletions
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml index dad1e3cacf..084014c61e 100644 --- a/org.eclipse.jgit.test/pom.xml +++ b/org.eclipse.jgit.test/pom.xml @@ -66,7 +66,6 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> - <scope>test</scope> </dependency> <!-- Optional security provider for encryption tests. --> diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java new file mode 100644 index 0000000000..c5582a8601 --- /dev/null +++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017, Thomas Wolf <thomas.wolf@paranor.ch> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.events; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * A {@link WorkingTreeModifiedListener} that can be used in tests to check + * expected events. + */ +public class ChangeRecorder implements WorkingTreeModifiedListener { + + public static final String[] EMPTY = new String[0]; + + private Set<String> modified = new HashSet<>(); + + private Set<String> deleted = new HashSet<>(); + + private int eventCount; + + @Override + public void onWorkingTreeModified(WorkingTreeModifiedEvent event) { + eventCount++; + modified.removeAll(event.getDeleted()); + deleted.removeAll(event.getModified()); + modified.addAll(event.getModified()); + deleted.addAll(event.getDeleted()); + } + + private String[] getModified() { + return modified.toArray(new String[modified.size()]); + } + + private String[] getDeleted() { + return deleted.toArray(new String[deleted.size()]); + } + + private void reset() { + eventCount = 0; + modified.clear(); + deleted.clear(); + } + + public void assertNoEvent() { + assertEquals("Unexpected WorkingTreeModifiedEvent ", 0, eventCount); + } + + public void assertEvent(String[] expectedModified, + String[] expectedDeleted) { + String[] actuallyModified = getModified(); + String[] actuallyDeleted = getDeleted(); + Arrays.sort(actuallyModified); + Arrays.sort(expectedModified); + Arrays.sort(actuallyDeleted); + Arrays.sort(expectedDeleted); + assertArrayEquals("Unexpected modifications reported", expectedModified, + actuallyModified); + assertArrayEquals("Unexpected deletions reported", expectedDeleted, + actuallyDeleted); + reset(); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java index f2e4d5b3b3..ad3ab7fbdf 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashApplyCommandTest.java @@ -55,12 +55,15 @@ import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.StashApplyFailureException; +import org.eclipse.jgit.events.ChangeRecorder; +import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.util.FileUtils; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -77,15 +80,31 @@ public class StashApplyCommandTest extends RepositoryTestCase { private File committedFile; + private ChangeRecorder recorder; + + private ListenerHandle handle; + @Override @Before public void setUp() throws Exception { super.setUp(); git = Git.wrap(db); + recorder = new ChangeRecorder(); + handle = db.getListenerList().addWorkingTreeModifiedListener(recorder); committedFile = writeTrashFile(PATH, "content"); git.add().addFilepattern(PATH).call(); head = git.commit().setMessage("add file").call(); assertNotNull(head); + recorder.assertNoEvent(); + } + + @Override + @After + public void tearDown() throws Exception { + if (handle != null) { + handle.remove(); + } + super.tearDown(); } @Test @@ -95,10 +114,12 @@ public class StashApplyCommandTest extends RepositoryTestCase { RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertEquals("content", read(committedFile)); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertFalse(committedFile.exists()); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { PATH }); Status status = git.status().call(); assertTrue(status.getAdded().isEmpty()); @@ -121,11 +142,13 @@ public class StashApplyCommandTest extends RepositoryTestCase { RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertFalse(addedFile.exists()); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { addedPath }); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertTrue(addedFile.exists()); assertEquals("content2", read(addedFile)); + recorder.assertEvent(new String[] { addedPath }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertTrue(status.getChanged().isEmpty()); @@ -142,14 +165,17 @@ public class StashApplyCommandTest extends RepositoryTestCase { @Test public void indexDelete() throws Exception { git.rm().addFilepattern("file.txt").call(); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { "file.txt" }); RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertEquals("content", read(committedFile)); + recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertFalse(committedFile.exists()); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { "file.txt" }); Status status = git.status().call(); assertTrue(status.getAdded().isEmpty()); @@ -170,10 +196,12 @@ public class StashApplyCommandTest extends RepositoryTestCase { RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertEquals("content", read(committedFile)); + recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertEquals("content2", read(committedFile)); + recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertTrue(status.getAdded().isEmpty()); @@ -193,16 +221,21 @@ public class StashApplyCommandTest extends RepositoryTestCase { File subfolderFile = writeTrashFile(path, "content"); git.add().addFilepattern(path).call(); head = git.commit().setMessage("add file").call(); + recorder.assertNoEvent(); writeTrashFile(path, "content2"); RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertEquals("content", read(subfolderFile)); + recorder.assertEvent(new String[] { "d1/d2/f.txt" }, + ChangeRecorder.EMPTY); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertEquals("content2", read(subfolderFile)); + recorder.assertEvent(new String[] { "d1/d2/f.txt", "d1/d2", "d1" }, + ChangeRecorder.EMPTY); Status status = git.status().call(); assertTrue(status.getAdded().isEmpty()); @@ -225,10 +258,12 @@ public class StashApplyCommandTest extends RepositoryTestCase { RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertEquals("content", read(committedFile)); + recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertEquals("content3", read(committedFile)); + recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertTrue(status.getAdded().isEmpty()); @@ -252,10 +287,12 @@ public class StashApplyCommandTest extends RepositoryTestCase { RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertEquals("content", read(committedFile)); + recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertEquals("content2", read(committedFile)); + recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertTrue(status.getAdded().isEmpty()); @@ -281,10 +318,12 @@ public class StashApplyCommandTest extends RepositoryTestCase { RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertFalse(added.exists()); + recorder.assertNoEvent(); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertEquals("content2", read(added)); + recorder.assertEvent(new String[] { path }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertTrue(status.getChanged().isEmpty()); @@ -308,10 +347,12 @@ public class StashApplyCommandTest extends RepositoryTestCase { RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertEquals("content", read(committedFile)); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); assertFalse(committedFile.exists()); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { PATH }); Status status = git.status().call(); assertTrue(status.getAdded().isEmpty()); @@ -337,9 +378,13 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertNotNull(stashed); assertTrue(committedFile.exists()); assertFalse(addedFile.exists()); + recorder.assertEvent(new String[] { PATH }, + new String[] { "file2.txt" }); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); + recorder.assertEvent(new String[] { "file2.txt" }, + new String[] { PATH }); Status status = git.status().call(); assertTrue(status.getChanged().isEmpty()); @@ -362,6 +407,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertNotNull(stashed); assertEquals("content", read(committedFile)); assertTrue(git.status().call().isClean()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); writeTrashFile(PATH, "content3"); @@ -372,6 +418,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { // expected } assertEquals("content3", read(PATH)); + recorder.assertNoEvent(); } @Test @@ -391,10 +438,12 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertEquals("content\nhead change\nmore content\n", read(committedFile)); assertTrue(git.status().call().isClean()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); writeTrashFile(PATH, "content\nmore content\ncommitted change\n"); git.add().addFilepattern(PATH).call(); git.commit().setMessage("committed change").call(); + recorder.assertNoEvent(); try { git.stashApply().call(); @@ -402,6 +451,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { } catch (StashApplyFailureException e) { // expected } + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); Status status = new StatusCommand(db).call(); assertEquals(1, status.getConflicting().size()); assertEquals( @@ -426,12 +476,15 @@ public class StashApplyCommandTest extends RepositoryTestCase { writeTrashFile(PATH, "master content"); git.add().addFilepattern(PATH).call(); git.commit().setMessage("even content").call(); + recorder.assertNoEvent(); git.checkout().setName(otherBranch).call(); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); writeTrashFile(PATH, "otherBranch content"); git.add().addFilepattern(PATH).call(); git.commit().setMessage("even more content").call(); + recorder.assertNoEvent(); writeTrashFile(path2, "content\nstashed change\nmore content\n"); @@ -442,12 +495,15 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertEquals("otherBranch content", read(committedFile)); assertTrue(git.status().call().isClean()); + recorder.assertEvent(new String[] { path2 }, ChangeRecorder.EMPTY); git.checkout().setName("master").call(); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); git.stashApply().call(); assertEquals("content\nstashed change\nmore content\n", read(file2)); assertEquals("master content", read(committedFile)); + recorder.assertEvent(new String[] { path2 }, ChangeRecorder.EMPTY); } @Test @@ -467,12 +523,15 @@ public class StashApplyCommandTest extends RepositoryTestCase { writeTrashFile(PATH, "master content"); git.add().addFilepattern(PATH).call(); git.commit().setMessage("even content").call(); + recorder.assertNoEvent(); git.checkout().setName(otherBranch).call(); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); writeTrashFile(PATH, "otherBranch content"); git.add().addFilepattern(PATH).call(); git.commit().setMessage("even more content").call(); + recorder.assertNoEvent(); writeTrashFile(path2, "content\nstashed change in index\nmore content\n"); @@ -485,8 +544,10 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertEquals("content\nmore content\n", read(file2)); assertEquals("otherBranch content", read(committedFile)); assertTrue(git.status().call().isClean()); + recorder.assertEvent(new String[] { path2 }, ChangeRecorder.EMPTY); git.checkout().setName("master").call(); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); git.stashApply().call(); assertEquals("content\nstashed change\nmore content\n", read(file2)); assertEquals( @@ -494,6 +555,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { + "[file2.txt, mode:100644, content:content\nstashed change in index\nmore content\n]", indexState(CONTENT)); assertEquals("master content", read(committedFile)); + recorder.assertEvent(new String[] { path2 }, ChangeRecorder.EMPTY); } @Test @@ -501,6 +563,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { writeTrashFile(PATH, "content\nmore content\n"); git.add().addFilepattern(PATH).call(); git.commit().setMessage("more content").call(); + recorder.assertNoEvent(); writeTrashFile(PATH, "content\nstashed change\nmore content\n"); @@ -508,15 +571,18 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertNotNull(stashed); assertEquals("content\nmore content\n", read(committedFile)); assertTrue(git.status().call().isClean()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); writeTrashFile(PATH, "content\nmore content\ncommitted change\n"); git.add().addFilepattern(PATH).call(); git.commit().setMessage("committed change").call(); + recorder.assertNoEvent(); git.stashApply().call(); assertEquals( "content\nstashed change\nmore content\ncommitted change\n", read(committedFile)); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); } @Test @@ -527,6 +593,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertNotNull(stashed); assertEquals("content", read(committedFile)); assertTrue(git.status().call().isClean()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); writeTrashFile(PATH, "content3"); git.add().addFilepattern(PATH).call(); @@ -538,6 +605,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { } catch (StashApplyFailureException e) { // expected } + recorder.assertNoEvent(); assertEquals("content2", read(PATH)); } @@ -549,6 +617,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertNotNull(stashed); assertEquals("content", read(committedFile)); assertTrue(git.status().call().isClean()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); String path2 = "file2.txt"; writeTrashFile(path2, "content3"); @@ -557,6 +626,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertTrue(status.getAdded().isEmpty()); @@ -583,12 +653,15 @@ public class StashApplyCommandTest extends RepositoryTestCase { RevCommit stashed = git.stashCreate().call(); assertNotNull(stashed); assertTrue(git.status().call().isClean()); + recorder.assertEvent(ChangeRecorder.EMPTY, + new String[] { subdir, path }); git.branchCreate().setName(otherBranch).call(); git.checkout().setName(otherBranch).call(); ObjectId unstashed = git.stashApply().call(); assertEquals(stashed, unstashed); + recorder.assertEvent(new String[] { path }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertTrue(status.getChanged().isEmpty()); @@ -643,12 +716,15 @@ public class StashApplyCommandTest extends RepositoryTestCase { git.commit().setMessage("x").call(); file.delete(); git.rm().addFilepattern("file").call(); + recorder.assertNoEvent(); git.stashCreate().call(); + recorder.assertEvent(new String[] { "file" }, ChangeRecorder.EMPTY); file.delete(); git.stashApply().setStashRef("stash@{0}").call(); assertFalse(file.exists()); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { "file" }); } @Test @@ -660,9 +736,11 @@ public class StashApplyCommandTest extends RepositoryTestCase { git.add().addFilepattern(PATH).call(); git.stashCreate().call(); assertTrue(untrackedFile.exists()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); git.stashApply().setStashRef("stash@{0}").call(); assertTrue(untrackedFile.exists()); + recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertEquals(1, status.getUntracked().size()); @@ -684,11 +762,14 @@ public class StashApplyCommandTest extends RepositoryTestCase { .call(); assertNotNull(stashedCommit); assertFalse(untrackedFile.exists()); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { path }); + deleteTrashFile("a/b"); // checkout should create parent dirs git.stashApply().setStashRef("stash@{0}").call(); assertTrue(untrackedFile.exists()); assertEquals("content", read(path)); + recorder.assertEvent(new String[] { path }, ChangeRecorder.EMPTY); Status status = git.status().call(); assertEquals(1, status.getUntracked().size()); @@ -706,6 +787,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { String path = "untracked.txt"; writeTrashFile(path, "untracked"); git.stashCreate().setIncludeUntracked(true).call(); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { path }); writeTrashFile(path, "committed"); head = git.commit().setMessage("add file").call(); @@ -719,6 +801,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertEquals(e.getMessage(), JGitText.get().stashApplyConflict); } assertEquals("committed", read(path)); + recorder.assertNoEvent(); } @Test @@ -727,6 +810,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { String path = "untracked.txt"; writeTrashFile(path, "untracked"); git.stashCreate().setIncludeUntracked(true).call(); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { path }); writeTrashFile(path, "working-directory"); try { @@ -736,6 +820,7 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertEquals(e.getMessage(), JGitText.get().stashApplyConflict); } assertEquals("working-directory", read(path)); + recorder.assertNoEvent(); } @Test @@ -747,11 +832,13 @@ public class StashApplyCommandTest extends RepositoryTestCase { assertTrue(PATH + " should exist", check(PATH)); assertEquals(PATH + " should have been reset", "content", read(PATH)); assertFalse(path + " should not exist", check(path)); + recorder.assertEvent(new String[] { PATH }, new String[] { path }); git.stashApply().setStashRef("stash@{0}").call(); assertTrue(PATH + " should exist", check(PATH)); assertEquals(PATH + " should have new content", "changed", read(PATH)); assertTrue(path + " should exist", check(path)); assertEquals(path + " should have new content", "untracked", read(path)); + recorder.assertEvent(new String[] { PATH, path }, ChangeRecorder.EMPTY); } } 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 f8c2d4536d..05573b9468 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 @@ -72,6 +72,8 @@ import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.errors.CheckoutConflictException; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.events.ChangeRecorder; +import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRepository.BranchBuilder; @@ -141,14 +143,19 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { @Test public void testResetHard() throws IOException, NoFilepatternException, GitAPIException { + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); writeTrashFile("f", "f()"); writeTrashFile("D/g", "g()"); git.add().addFilepattern(".").call(); git.commit().setMessage("inital").call(); assertIndex(mkmap("f", "f()", "D/g", "g()")); - + recorder.assertNoEvent(); git.branchCreate().setName("topic").call(); + recorder.assertNoEvent(); writeTrashFile("f", "f()\nmaster"); writeTrashFile("D/g", "g()\ng2()"); @@ -156,9 +163,12 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { git.add().addFilepattern(".").call(); RevCommit master = git.commit().setMessage("master-1").call(); assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()")); + recorder.assertNoEvent(); checkoutBranch("refs/heads/topic"); assertIndex(mkmap("f", "f()", "D/g", "g()")); + recorder.assertEvent(new String[] { "f", "D/g" }, + new String[] { "E/h" }); writeTrashFile("f", "f()\nside"); assertTrue(new File(db.getWorkTree(), "D/g").delete()); @@ -167,26 +177,41 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { git.add().addFilepattern(".").setUpdate(true).call(); RevCommit topic = git.commit().setMessage("topic-1").call(); assertIndex(mkmap("f", "f()\nside", "G/i", "i()")); + recorder.assertNoEvent(); writeTrashFile("untracked", "untracked"); resetHard(master); assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()")); + recorder.assertEvent(new String[] { "f", "D/g", "E/h" }, + new String[] { "G", "G/i" }); + resetHard(topic); assertIndex(mkmap("f", "f()\nside", "G/i", "i()")); assertWorkDir(mkmap("f", "f()\nside", "G/i", "i()", "untracked", "untracked")); + recorder.assertEvent(new String[] { "f", "G/i" }, + new String[] { "D", "D/g", "E", "E/h" }); assertEquals(MergeStatus.CONFLICTING, git.merge().include(master) .call().getMergeStatus()); assertEquals( "[D/g, mode:100644, stage:1][D/g, mode:100644, stage:3][E/h, mode:100644][G/i, mode:100644][f, mode:100644, stage:1][f, mode:100644, stage:2][f, mode:100644, stage:3]", indexState(0)); + recorder.assertEvent(new String[] { "f", "D/g", "E/h" }, + ChangeRecorder.EMPTY); resetHard(master); assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()")); assertWorkDir(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()", "untracked", "untracked")); + recorder.assertEvent(new String[] { "f", "D/g" }, + new String[] { "G", "G/i" }); + + } finally { + if (handle != null) { + handle.remove(); + } } } @@ -202,13 +227,18 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { @Test public void testResetHardFromIndexEntryWithoutFileToTreeWithoutFile() throws Exception { + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); writeTrashFile("x", "x"); git.add().addFilepattern("x").call(); RevCommit id1 = git.commit().setMessage("c1").call(); writeTrashFile("f/g", "f/g"); git.rm().addFilepattern("x").call(); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { "x" }); git.add().addFilepattern("f/g").call(); git.commit().setMessage("c2").call(); deleteTrashFile("f/g"); @@ -217,6 +247,11 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { // The actual test git.reset().setMode(ResetType.HARD).setRef(id1.getName()).call(); assertIndex(mkmap("x", "x")); + recorder.assertEvent(new String[] { "x" }, ChangeRecorder.EMPTY); + } finally { + if (handle != null) { + handle.remove(); + } } } @@ -227,13 +262,22 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { */ @Test public void testInitialCheckout() throws Exception { + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); TestRepository<Repository> db_t = new TestRepository<>(db); BranchBuilder master = db_t.branch("master"); master.commit().add("f", "1").message("m0").create(); assertFalse(new File(db.getWorkTree(), "f").exists()); git.checkout().setName("master").call(); assertTrue(new File(db.getWorkTree(), "f").exists()); + recorder.assertEvent(new String[] { "f" }, ChangeRecorder.EMPTY); + } finally { + if (handle != null) { + handle.remove(); + } } } @@ -930,120 +974,154 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { public void testCheckoutChangeLinkToEmptyDir() throws Exception { Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "was_file"; - Git git = Git.wrap(db); - - // Add a file - writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - - // Add a link to file - String linkName = "link"; - File link = writeLink(linkName, fname).toFile(); - git.add().addFilepattern(linkName).call(); - git.commit().setMessage("Added file and link").call(); - - assertWorkDir(mkmap(linkName, "a", fname, "a")); - - // replace link with empty directory - FileUtils.delete(link); - FileUtils.mkdir(link); - assertTrue("Link must be a directory now", link.isDirectory()); - - // modify file - writeTrashFile(fname, "b"); - assertWorkDir(mkmap(fname, "b", linkName, "/")); - - // revert both paths to HEAD state - git.checkout().setStartPoint(Constants.HEAD) - .addPath(fname).addPath(linkName).call(); - - assertWorkDir(mkmap(fname, "a", linkName, "a")); - - Status st = git.status().call(); - assertTrue(st.isClean()); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); + + // Add a link to file + String linkName = "link"; + File link = writeLink(linkName, fname).toFile(); + git.add().addFilepattern(linkName).call(); + git.commit().setMessage("Added file and link").call(); + + assertWorkDir(mkmap(linkName, "a", fname, "a")); + + // replace link with empty directory + FileUtils.delete(link); + FileUtils.mkdir(link); + assertTrue("Link must be a directory now", link.isDirectory()); + + // modify file + writeTrashFile(fname, "b"); + assertWorkDir(mkmap(fname, "b", linkName, "/")); + recorder.assertNoEvent(); + + // revert both paths to HEAD state + git.checkout().setStartPoint(Constants.HEAD).addPath(fname) + .addPath(linkName).call(); + + assertWorkDir(mkmap(fname, "a", linkName, "a")); + recorder.assertEvent(new String[] { fname, linkName }, + ChangeRecorder.EMPTY); + + Status st = git.status().call(); + assertTrue(st.isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test public void testCheckoutChangeLinkToEmptyDirs() throws Exception { Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "was_file"; - Git git = Git.wrap(db); - - // Add a file - writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - - // Add a link to file - String linkName = "link"; - File link = writeLink(linkName, fname).toFile(); - git.add().addFilepattern(linkName).call(); - git.commit().setMessage("Added file and link").call(); - - assertWorkDir(mkmap(linkName, "a", fname, "a")); - - // replace link with directory containing only directories, no files - FileUtils.delete(link); - FileUtils.mkdirs(new File(link, "dummyDir")); - assertTrue("Link must be a directory now", link.isDirectory()); - - assertFalse("Must not delete non empty directory", link.delete()); - - // modify file - writeTrashFile(fname, "b"); - assertWorkDir(mkmap(fname, "b", linkName + "/dummyDir", "/")); - - // revert both paths to HEAD state - git.checkout().setStartPoint(Constants.HEAD) - .addPath(fname).addPath(linkName).call(); - - assertWorkDir(mkmap(fname, "a", linkName, "a")); - - Status st = git.status().call(); - assertTrue(st.isClean()); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); + + // Add a link to file + String linkName = "link"; + File link = writeLink(linkName, fname).toFile(); + git.add().addFilepattern(linkName).call(); + git.commit().setMessage("Added file and link").call(); + + assertWorkDir(mkmap(linkName, "a", fname, "a")); + + // replace link with directory containing only directories, no files + FileUtils.delete(link); + FileUtils.mkdirs(new File(link, "dummyDir")); + assertTrue("Link must be a directory now", link.isDirectory()); + + assertFalse("Must not delete non empty directory", link.delete()); + + // modify file + writeTrashFile(fname, "b"); + assertWorkDir(mkmap(fname, "b", linkName + "/dummyDir", "/")); + recorder.assertNoEvent(); + + // revert both paths to HEAD state + git.checkout().setStartPoint(Constants.HEAD).addPath(fname) + .addPath(linkName).call(); + + assertWorkDir(mkmap(fname, "a", linkName, "a")); + recorder.assertEvent(new String[] { fname, linkName }, + ChangeRecorder.EMPTY); + + Status st = git.status().call(); + assertTrue(st.isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test public void testCheckoutChangeLinkToNonEmptyDirs() throws Exception { Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "file"; - Git git = Git.wrap(db); - - // Add a file - writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); - // Add a link to file - String linkName = "link"; - File link = writeLink(linkName, fname).toFile(); - git.add().addFilepattern(linkName).call(); - git.commit().setMessage("Added file and link").call(); + // Add a link to file + String linkName = "link"; + File link = writeLink(linkName, fname).toFile(); + git.add().addFilepattern(linkName).call(); + git.commit().setMessage("Added file and link").call(); - assertWorkDir(mkmap(linkName, "a", fname, "a")); + assertWorkDir(mkmap(linkName, "a", fname, "a")); - // replace link with directory containing only directories, no files - FileUtils.delete(link); + // replace link with directory containing only directories, no files + FileUtils.delete(link); - // create but do not add a file in the new directory to the index - writeTrashFile(linkName + "/dir1", "file1", "c"); + // create but do not add a file in the new directory to the index + writeTrashFile(linkName + "/dir1", "file1", "c"); - // create but do not add a file in the new directory to the index - writeTrashFile(linkName + "/dir2", "file2", "d"); + // create but do not add a file in the new directory to the index + writeTrashFile(linkName + "/dir2", "file2", "d"); - assertTrue("File must be a directory now", link.isDirectory()); - assertFalse("Must not delete non empty directory", link.delete()); + assertTrue("File must be a directory now", link.isDirectory()); + assertFalse("Must not delete non empty directory", link.delete()); - // 2 extra files are created - assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c", - linkName + "/dir2/file2", "d")); + // 2 extra files are created + assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c", + linkName + "/dir2/file2", "d")); + recorder.assertNoEvent(); - // revert path to HEAD state - git.checkout().setStartPoint(Constants.HEAD).addPath(linkName).call(); + // revert path to HEAD state + git.checkout().setStartPoint(Constants.HEAD).addPath(linkName) + .call(); - // expect only the one added to the index - assertWorkDir(mkmap(linkName, "a", fname, "a")); + // expect only the one added to the index + assertWorkDir(mkmap(linkName, "a", fname, "a")); + recorder.assertEvent(new String[] { linkName }, + ChangeRecorder.EMPTY); - Status st = git.status().call(); - assertTrue(st.isClean()); + Status st = git.status().call(); + assertTrue(st.isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test @@ -1051,174 +1129,222 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { throws Exception { Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "file"; - Git git = Git.wrap(db); - - // Add a file - writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); - // Add a link to file - String linkName = "link"; - File link = writeLink(linkName, fname).toFile(); - git.add().addFilepattern(linkName).call(); - git.commit().setMessage("Added file and link").call(); + // Add a link to file + String linkName = "link"; + File link = writeLink(linkName, fname).toFile(); + git.add().addFilepattern(linkName).call(); + git.commit().setMessage("Added file and link").call(); - assertWorkDir(mkmap(linkName, "a", fname, "a")); + assertWorkDir(mkmap(linkName, "a", fname, "a")); - // replace link with directory containing only directories, no files - FileUtils.delete(link); + // replace link with directory containing only directories, no files + FileUtils.delete(link); - // create and add a file in the new directory to the index - writeTrashFile(linkName + "/dir1", "file1", "c"); - git.add().addFilepattern(linkName + "/dir1/file1").call(); + // create and add a file in the new directory to the index + writeTrashFile(linkName + "/dir1", "file1", "c"); + git.add().addFilepattern(linkName + "/dir1/file1").call(); - // create but do not add a file in the new directory to the index - writeTrashFile(linkName + "/dir2", "file2", "d"); + // create but do not add a file in the new directory to the index + writeTrashFile(linkName + "/dir2", "file2", "d"); - assertTrue("File must be a directory now", link.isDirectory()); - assertFalse("Must not delete non empty directory", link.delete()); + assertTrue("File must be a directory now", link.isDirectory()); + assertFalse("Must not delete non empty directory", link.delete()); - // 2 extra files are created - assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c", - linkName + "/dir2/file2", "d")); + // 2 extra files are created + assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c", + linkName + "/dir2/file2", "d")); + recorder.assertNoEvent(); - // revert path to HEAD state - git.checkout().setStartPoint(Constants.HEAD).addPath(linkName).call(); + // revert path to HEAD state + git.checkout().setStartPoint(Constants.HEAD).addPath(linkName) + .call(); - // original file and link - assertWorkDir(mkmap(linkName, "a", fname, "a")); + // original file and link + assertWorkDir(mkmap(linkName, "a", fname, "a")); + recorder.assertEvent(new String[] { linkName }, + ChangeRecorder.EMPTY); - Status st = git.status().call(); - assertTrue(st.isClean()); + Status st = git.status().call(); + assertTrue(st.isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test public void testCheckoutChangeFileToEmptyDir() throws Exception { String fname = "was_file"; - Git git = Git.wrap(db); - - // Add a file - File file = writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - git.commit().setMessage("Added file").call(); - - // replace file with empty directory - FileUtils.delete(file); - FileUtils.mkdir(file); - assertTrue("File must be a directory now", file.isDirectory()); - - assertWorkDir(mkmap(fname, "/")); - - // revert path to HEAD state - git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call(); - - assertWorkDir(mkmap(fname, "a")); - - Status st = git.status().call(); - assertTrue(st.isClean()); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + File file = writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); + git.commit().setMessage("Added file").call(); + + // replace file with empty directory + FileUtils.delete(file); + FileUtils.mkdir(file); + assertTrue("File must be a directory now", file.isDirectory()); + assertWorkDir(mkmap(fname, "/")); + recorder.assertNoEvent(); + + // revert path to HEAD state + git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call(); + assertWorkDir(mkmap(fname, "a")); + recorder.assertEvent(new String[] { fname }, ChangeRecorder.EMPTY); + + Status st = git.status().call(); + assertTrue(st.isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test public void testCheckoutChangeFileToEmptyDirs() throws Exception { String fname = "was_file"; - Git git = Git.wrap(db); - - // Add a file - File file = writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - git.commit().setMessage("Added file").call(); - - // replace file with directory containing only directories, no files - FileUtils.delete(file); - FileUtils.mkdirs(new File(file, "dummyDir")); - assertTrue("File must be a directory now", file.isDirectory()); - assertFalse("Must not delete non empty directory", file.delete()); - - assertWorkDir(mkmap(fname + "/dummyDir", "/")); - - // revert path to HEAD state - git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call(); - - assertWorkDir(mkmap(fname, "a")); - - Status st = git.status().call(); - assertTrue(st.isClean()); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + File file = writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); + git.commit().setMessage("Added file").call(); + + // replace file with directory containing only directories, no files + FileUtils.delete(file); + FileUtils.mkdirs(new File(file, "dummyDir")); + assertTrue("File must be a directory now", file.isDirectory()); + assertFalse("Must not delete non empty directory", file.delete()); + + assertWorkDir(mkmap(fname + "/dummyDir", "/")); + recorder.assertNoEvent(); + + // revert path to HEAD state + git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call(); + assertWorkDir(mkmap(fname, "a")); + recorder.assertEvent(new String[] { fname }, ChangeRecorder.EMPTY); + + Status st = git.status().call(); + assertTrue(st.isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test public void testCheckoutChangeFileToNonEmptyDirs() throws Exception { String fname = "was_file"; - Git git = Git.wrap(db); - - // Add a file - File file = writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - git.commit().setMessage("Added file").call(); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + File file = writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); + git.commit().setMessage("Added file").call(); - assertWorkDir(mkmap(fname, "a")); + assertWorkDir(mkmap(fname, "a")); - // replace file with directory containing only directories, no files - FileUtils.delete(file); + // replace file with directory containing only directories, no files + FileUtils.delete(file); - // create but do not add a file in the new directory to the index - writeTrashFile(fname + "/dir1", "file1", "c"); + // create but do not add a file in the new directory to the index + writeTrashFile(fname + "/dir1", "file1", "c"); - // create but do not add a file in the new directory to the index - writeTrashFile(fname + "/dir2", "file2", "d"); + // create but do not add a file in the new directory to the index + writeTrashFile(fname + "/dir2", "file2", "d"); - assertTrue("File must be a directory now", file.isDirectory()); - assertFalse("Must not delete non empty directory", file.delete()); + assertTrue("File must be a directory now", file.isDirectory()); + assertFalse("Must not delete non empty directory", file.delete()); - // 2 extra files are created - assertWorkDir( - mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d")); + // 2 extra files are created + assertWorkDir(mkmap(fname + "/dir1/file1", "c", + fname + "/dir2/file2", "d")); + recorder.assertNoEvent(); - // revert path to HEAD state - git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call(); + // revert path to HEAD state + git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call(); - // expect only the one added to the index - assertWorkDir(mkmap(fname, "a")); + // expect only the one added to the index + assertWorkDir(mkmap(fname, "a")); + recorder.assertEvent(new String[] { fname }, ChangeRecorder.EMPTY); - Status st = git.status().call(); - assertTrue(st.isClean()); + Status st = git.status().call(); + assertTrue(st.isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test public void testCheckoutChangeFileToNonEmptyDirsAndNewIndexEntry() throws Exception { String fname = "was_file"; - Git git = Git.wrap(db); - - // Add a file - File file = writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - git.commit().setMessage("Added file").call(); - - assertWorkDir(mkmap(fname, "a")); - - // replace file with directory containing only directories, no files - FileUtils.delete(file); - - // create and add a file in the new directory to the index - writeTrashFile(fname + "/dir", "file1", "c"); - git.add().addFilepattern(fname + "/dir/file1").call(); - - // create but do not add a file in the new directory to the index - writeTrashFile(fname + "/dir", "file2", "d"); - - assertTrue("File must be a directory now", file.isDirectory()); - assertFalse("Must not delete non empty directory", file.delete()); - - // 2 extra files are created - assertWorkDir( - mkmap(fname + "/dir/file1", "c", fname + "/dir/file2", "d")); - - // revert path to HEAD state - git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call(); - assertWorkDir(mkmap(fname, "a")); - - Status st = git.status().call(); - assertTrue(st.isClean()); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + File file = writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); + git.commit().setMessage("Added file").call(); + + assertWorkDir(mkmap(fname, "a")); + + // replace file with directory containing only directories, no files + FileUtils.delete(file); + + // create and add a file in the new directory to the index + writeTrashFile(fname + "/dir", "file1", "c"); + git.add().addFilepattern(fname + "/dir/file1").call(); + + // create but do not add a file in the new directory to the index + writeTrashFile(fname + "/dir", "file2", "d"); + + assertTrue("File must be a directory now", file.isDirectory()); + assertFalse("Must not delete non empty directory", file.delete()); + + // 2 extra files are created + assertWorkDir(mkmap(fname + "/dir/file1", "c", fname + "/dir/file2", + "d")); + recorder.assertNoEvent(); + + // revert path to HEAD state + git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call(); + assertWorkDir(mkmap(fname, "a")); + recorder.assertEvent(new String[] { fname }, ChangeRecorder.EMPTY); + Status st = git.status().call(); + assertTrue(st.isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test @@ -1293,76 +1419,100 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { public void testOverwriteUntrackedIgnoredFile() throws IOException, GitAPIException { String fname="file.txt"; - Git git = Git.wrap(db); - - // Add a file - writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - git.commit().setMessage("create file").call(); - - // Create branch - git.branchCreate().setName("side").call(); - - // Modify file - writeTrashFile(fname, "b"); - git.add().addFilepattern(fname).call(); - git.commit().setMessage("modify file").call(); - - // Switch branches - git.checkout().setName("side").call(); - git.rm().addFilepattern(fname).call(); - writeTrashFile(".gitignore", fname); - git.add().addFilepattern(".gitignore").call(); - git.commit().setMessage("delete and ignore file").call(); - - writeTrashFile(fname, "Something different"); - git.checkout().setName("master").call(); - assertWorkDir(mkmap(fname, "b")); - assertTrue(git.status().call().isClean()); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); + git.commit().setMessage("create file").call(); + + // Create branch + git.branchCreate().setName("side").call(); + + // Modify file + writeTrashFile(fname, "b"); + git.add().addFilepattern(fname).call(); + git.commit().setMessage("modify file").call(); + recorder.assertNoEvent(); + + // Switch branches + git.checkout().setName("side").call(); + recorder.assertEvent(new String[] { fname }, ChangeRecorder.EMPTY); + git.rm().addFilepattern(fname).call(); + recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { fname }); + writeTrashFile(".gitignore", fname); + git.add().addFilepattern(".gitignore").call(); + git.commit().setMessage("delete and ignore file").call(); + + writeTrashFile(fname, "Something different"); + recorder.assertNoEvent(); + git.checkout().setName("master").call(); + assertWorkDir(mkmap(fname, "b")); + recorder.assertEvent(new String[] { fname }, + new String[] { ".gitignore" }); + assertTrue(git.status().call().isClean()); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test public void testOverwriteUntrackedFileModeChange() throws IOException, GitAPIException { String fname = "file.txt"; - Git git = Git.wrap(db); - - // Add a file - File file = writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - git.commit().setMessage("create file").call(); - assertWorkDir(mkmap(fname, "a")); - - // Create branch - git.branchCreate().setName("side").call(); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + File file = writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); + git.commit().setMessage("create file").call(); + assertWorkDir(mkmap(fname, "a")); - // Switch branches - git.checkout().setName("side").call(); + // Create branch + git.branchCreate().setName("side").call(); - // replace file with directory containing files - FileUtils.delete(file); + // Switch branches + git.checkout().setName("side").call(); + recorder.assertNoEvent(); - // create and add a file in the new directory to the index - writeTrashFile(fname + "/dir1", "file1", "c"); - git.add().addFilepattern(fname + "/dir1/file1").call(); + // replace file with directory containing files + FileUtils.delete(file); - // create but do not add a file in the new directory to the index - writeTrashFile(fname + "/dir2", "file2", "d"); + // create and add a file in the new directory to the index + writeTrashFile(fname + "/dir1", "file1", "c"); + git.add().addFilepattern(fname + "/dir1/file1").call(); - assertTrue("File must be a directory now", file.isDirectory()); - assertFalse("Must not delete non empty directory", file.delete()); + // create but do not add a file in the new directory to the index + writeTrashFile(fname + "/dir2", "file2", "d"); - // 2 extra files are created - assertWorkDir( - mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d")); + assertTrue("File must be a directory now", file.isDirectory()); + assertFalse("Must not delete non empty directory", file.delete()); - try { - git.checkout().setName("master").call(); - fail("did not throw exception"); - } catch (Exception e) { - // 2 extra files are still there + // 2 extra files are created assertWorkDir(mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d")); + + try { + git.checkout().setName("master").call(); + fail("did not throw exception"); + } catch (Exception e) { + // 2 extra files are still there + assertWorkDir(mkmap(fname + "/dir1/file1", "c", + fname + "/dir2/file2", "d")); + } + recorder.assertNoEvent(); + } finally { + if (handle != null) { + handle.remove(); + } } } @@ -1371,50 +1521,60 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { throws Exception { Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); String fname = "file.txt"; - Git git = Git.wrap(db); - - // Add a file - writeTrashFile(fname, "a"); - git.add().addFilepattern(fname).call(); - - // Add a link to file - String linkName = "link"; - File link = writeLink(linkName, fname).toFile(); - git.add().addFilepattern(linkName).call(); - git.commit().setMessage("Added file and link").call(); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add a file + writeTrashFile(fname, "a"); + git.add().addFilepattern(fname).call(); - assertWorkDir(mkmap(linkName, "a", fname, "a")); + // Add a link to file + String linkName = "link"; + File link = writeLink(linkName, fname).toFile(); + git.add().addFilepattern(linkName).call(); + git.commit().setMessage("Added file and link").call(); - // Create branch - git.branchCreate().setName("side").call(); + assertWorkDir(mkmap(linkName, "a", fname, "a")); - // Switch branches - git.checkout().setName("side").call(); + // Create branch + git.branchCreate().setName("side").call(); - // replace link with directory containing files - FileUtils.delete(link); + // Switch branches + git.checkout().setName("side").call(); + recorder.assertNoEvent(); - // create and add a file in the new directory to the index - writeTrashFile(linkName + "/dir1", "file1", "c"); - git.add().addFilepattern(linkName + "/dir1/file1").call(); + // replace link with directory containing files + FileUtils.delete(link); - // create but do not add a file in the new directory to the index - writeTrashFile(linkName + "/dir2", "file2", "d"); + // create and add a file in the new directory to the index + writeTrashFile(linkName + "/dir1", "file1", "c"); + git.add().addFilepattern(linkName + "/dir1/file1").call(); - assertTrue("Link must be a directory now", link.isDirectory()); - assertFalse("Must not delete non empty directory", link.delete()); + // create but do not add a file in the new directory to the index + writeTrashFile(linkName + "/dir2", "file2", "d"); - // 2 extra files are created - assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c", - linkName + "/dir2/file2", "d")); + assertTrue("Link must be a directory now", link.isDirectory()); + assertFalse("Must not delete non empty directory", link.delete()); - try { - git.checkout().setName("master").call(); - fail("did not throw exception"); - } catch (Exception e) { - // 2 extra files are still there + // 2 extra files are created assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c", linkName + "/dir2/file2", "d")); + + try { + git.checkout().setName("master").call(); + fail("did not throw exception"); + } catch (Exception e) { + // 2 extra files are still there + assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c", + linkName + "/dir2/file2", "d")); + } + recorder.assertNoEvent(); + } finally { + if (handle != null) { + handle.remove(); + } } } @@ -1423,36 +1583,47 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { if (!FS.DETECTED.supportsExecute()) return; - Git git = Git.wrap(db); - - // Add non-executable file - File file = writeTrashFile("file.txt", "a"); - git.add().addFilepattern("file.txt").call(); - git.commit().setMessage("commit1").call(); - assertFalse(db.getFS().canExecute(file)); - - // Create branch - git.branchCreate().setName("b1").call(); - - // Make file executable - db.getFS().setExecute(file, true); - git.add().addFilepattern("file.txt").call(); - git.commit().setMessage("commit2").call(); - - // Verify executable and working directory is clean - Status status = git.status().call(); - assertTrue(status.getModified().isEmpty()); - assertTrue(status.getChanged().isEmpty()); - assertTrue(db.getFS().canExecute(file)); - - // Switch branches - git.checkout().setName("b1").call(); - - // Verify not executable and working directory is clean - status = git.status().call(); - assertTrue(status.getModified().isEmpty()); - assertTrue(status.getChanged().isEmpty()); - assertFalse(db.getFS().canExecute(file)); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add non-executable file + File file = writeTrashFile("file.txt", "a"); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("commit1").call(); + assertFalse(db.getFS().canExecute(file)); + + // Create branch + git.branchCreate().setName("b1").call(); + + // Make file executable + db.getFS().setExecute(file, true); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("commit2").call(); + recorder.assertNoEvent(); + + // Verify executable and working directory is clean + Status status = git.status().call(); + assertTrue(status.getModified().isEmpty()); + assertTrue(status.getChanged().isEmpty()); + assertTrue(db.getFS().canExecute(file)); + + // Switch branches + git.checkout().setName("b1").call(); + + // Verify not executable and working directory is clean + status = git.status().call(); + assertTrue(status.getModified().isEmpty()); + assertTrue(status.getChanged().isEmpty()); + assertFalse(db.getFS().canExecute(file)); + recorder.assertEvent(new String[] { "file.txt" }, + ChangeRecorder.EMPTY); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test @@ -1460,41 +1631,50 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { if (!FS.DETECTED.supportsExecute()) return; - Git git = Git.wrap(db); - - // Add non-executable file - File file = writeTrashFile("file.txt", "a"); - git.add().addFilepattern("file.txt").call(); - git.commit().setMessage("commit1").call(); - assertFalse(db.getFS().canExecute(file)); - - // Create branch - git.branchCreate().setName("b1").call(); - - // Make file executable - db.getFS().setExecute(file, true); - git.add().addFilepattern("file.txt").call(); - git.commit().setMessage("commit2").call(); - - // Verify executable and working directory is clean - Status status = git.status().call(); - assertTrue(status.getModified().isEmpty()); - assertTrue(status.getChanged().isEmpty()); - assertTrue(db.getFS().canExecute(file)); - - writeTrashFile("file.txt", "b"); - - // Switch branches - CheckoutCommand checkout = git.checkout().setName("b1"); - try { - checkout.call(); - fail("Checkout exception not thrown"); - } catch (org.eclipse.jgit.api.errors.CheckoutConflictException e) { - CheckoutResult result = checkout.getResult(); - assertNotNull(result); - assertNotNull(result.getConflictList()); - assertEquals(1, result.getConflictList().size()); - assertTrue(result.getConflictList().contains("file.txt")); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add non-executable file + File file = writeTrashFile("file.txt", "a"); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("commit1").call(); + assertFalse(db.getFS().canExecute(file)); + + // Create branch + git.branchCreate().setName("b1").call(); + + // Make file executable + db.getFS().setExecute(file, true); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("commit2").call(); + + // Verify executable and working directory is clean + Status status = git.status().call(); + assertTrue(status.getModified().isEmpty()); + assertTrue(status.getChanged().isEmpty()); + assertTrue(db.getFS().canExecute(file)); + + writeTrashFile("file.txt", "b"); + + // Switch branches + CheckoutCommand checkout = git.checkout().setName("b1"); + try { + checkout.call(); + fail("Checkout exception not thrown"); + } catch (org.eclipse.jgit.api.errors.CheckoutConflictException e) { + CheckoutResult result = checkout.getResult(); + assertNotNull(result); + assertNotNull(result.getConflictList()); + assertEquals(1, result.getConflictList().size()); + assertTrue(result.getConflictList().contains("file.txt")); + } + recorder.assertNoEvent(); + } finally { + if (handle != null) { + handle.remove(); + } } } @@ -1504,40 +1684,52 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { if (!FS.DETECTED.supportsExecute()) return; - Git git = Git.wrap(db); - - // Add non-executable file - File file = writeTrashFile("file.txt", "a"); - git.add().addFilepattern("file.txt").call(); - git.commit().setMessage("commit1").call(); - assertFalse(db.getFS().canExecute(file)); - - // Create branch - git.branchCreate().setName("b1").call(); - - // Create second commit and don't touch file - writeTrashFile("file2.txt", ""); - git.add().addFilepattern("file2.txt").call(); - git.commit().setMessage("commit2").call(); - - // stage a mode change - writeTrashFile("file.txt", "a"); - db.getFS().setExecute(file, true); - git.add().addFilepattern("file.txt").call(); - - // dirty the file - writeTrashFile("file.txt", "b"); - - assertEquals( - "[file.txt, mode:100755, content:a][file2.txt, mode:100644, content:]", - indexState(CONTENT)); - assertWorkDir(mkmap("file.txt", "b", "file2.txt", "")); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add non-executable file + File file = writeTrashFile("file.txt", "a"); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("commit1").call(); + assertFalse(db.getFS().canExecute(file)); + + // Create branch + git.branchCreate().setName("b1").call(); + + // Create second commit and don't touch file + writeTrashFile("file2.txt", ""); + git.add().addFilepattern("file2.txt").call(); + git.commit().setMessage("commit2").call(); + + // stage a mode change + writeTrashFile("file.txt", "a"); + db.getFS().setExecute(file, true); + git.add().addFilepattern("file.txt").call(); + + // dirty the file + writeTrashFile("file.txt", "b"); - // Switch branches and check that the dirty file survived in worktree - // and index - git.checkout().setName("b1").call(); - assertEquals("[file.txt, mode:100755, content:a]", indexState(CONTENT)); - assertWorkDir(mkmap("file.txt", "b")); + assertEquals( + "[file.txt, mode:100755, content:a][file2.txt, mode:100644, content:]", + indexState(CONTENT)); + assertWorkDir(mkmap("file.txt", "b", "file2.txt", "")); + recorder.assertNoEvent(); + + // Switch branches and check that the dirty file survived in + // worktree and index + git.checkout().setName("b1").call(); + assertEquals("[file.txt, mode:100755, content:a]", + indexState(CONTENT)); + assertWorkDir(mkmap("file.txt", "b")); + recorder.assertEvent(ChangeRecorder.EMPTY, + new String[] { "file2.txt" }); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test @@ -1546,40 +1738,53 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { if (!FS.DETECTED.supportsExecute()) return; - Git git = Git.wrap(db); - - // Add non-executable file - File file = writeTrashFile("file.txt", "a"); - git.add().addFilepattern("file.txt").call(); - git.commit().setMessage("commit1").call(); - assertFalse(db.getFS().canExecute(file)); - - // Create branch - git.branchCreate().setName("b1").call(); - - // Create second commit with executable file - file = writeTrashFile("file.txt", "b"); - db.getFS().setExecute(file, true); - git.add().addFilepattern("file.txt").call(); - git.commit().setMessage("commit2").call(); - - // stage the same content as in the branch we want to switch to - writeTrashFile("file.txt", "a"); - db.getFS().setExecute(file, false); - git.add().addFilepattern("file.txt").call(); - - // dirty the file - writeTrashFile("file.txt", "c"); - db.getFS().setExecute(file, true); - - assertEquals("[file.txt, mode:100644, content:a]", indexState(CONTENT)); - assertWorkDir(mkmap("file.txt", "c")); - - // Switch branches and check that the dirty file survived in worktree - // and index - git.checkout().setName("b1").call(); - assertEquals("[file.txt, mode:100644, content:a]", indexState(CONTENT)); - assertWorkDir(mkmap("file.txt", "c")); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add non-executable file + File file = writeTrashFile("file.txt", "a"); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("commit1").call(); + assertFalse(db.getFS().canExecute(file)); + + // Create branch + git.branchCreate().setName("b1").call(); + + // Create second commit with executable file + file = writeTrashFile("file.txt", "b"); + db.getFS().setExecute(file, true); + git.add().addFilepattern("file.txt").call(); + git.commit().setMessage("commit2").call(); + + // stage the same content as in the branch we want to switch to + writeTrashFile("file.txt", "a"); + db.getFS().setExecute(file, false); + git.add().addFilepattern("file.txt").call(); + + // dirty the file + writeTrashFile("file.txt", "c"); + db.getFS().setExecute(file, true); + + assertEquals("[file.txt, mode:100644, content:a]", + indexState(CONTENT)); + assertWorkDir(mkmap("file.txt", "c")); + recorder.assertNoEvent(); + + // Switch branches and check that the dirty file survived in + // worktree + // and index + git.checkout().setName("b1").call(); + assertEquals("[file.txt, mode:100644, content:a]", + indexState(CONTENT)); + assertWorkDir(mkmap("file.txt", "c")); + recorder.assertNoEvent(); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test @@ -1587,31 +1792,44 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { if (!FS.DETECTED.supportsExecute()) return; - Git git = Git.wrap(db); - - // Add first file - File file1 = writeTrashFile("file1.txt", "a"); - git.add().addFilepattern("file1.txt").call(); - git.commit().setMessage("commit1").call(); - assertFalse(db.getFS().canExecute(file1)); - - // Add second file - File file2 = writeTrashFile("file2.txt", "b"); - git.add().addFilepattern("file2.txt").call(); - git.commit().setMessage("commit2").call(); - assertFalse(db.getFS().canExecute(file2)); - - // Create branch from first commit - assertNotNull(git.checkout().setCreateBranch(true).setName("b1") - .setStartPoint(Constants.HEAD + "~1").call()); - - // Change content and file mode in working directory and index - file1 = writeTrashFile("file1.txt", "c"); - db.getFS().setExecute(file1, true); - git.add().addFilepattern("file1.txt").call(); - - // Switch back to 'master' - assertNotNull(git.checkout().setName(Constants.MASTER).call()); + ChangeRecorder recorder = new ChangeRecorder(); + ListenerHandle handle = null; + try (Git git = new Git(db)) { + handle = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + // Add first file + File file1 = writeTrashFile("file1.txt", "a"); + git.add().addFilepattern("file1.txt").call(); + git.commit().setMessage("commit1").call(); + assertFalse(db.getFS().canExecute(file1)); + + // Add second file + File file2 = writeTrashFile("file2.txt", "b"); + git.add().addFilepattern("file2.txt").call(); + git.commit().setMessage("commit2").call(); + assertFalse(db.getFS().canExecute(file2)); + recorder.assertNoEvent(); + + // Create branch from first commit + assertNotNull(git.checkout().setCreateBranch(true).setName("b1") + .setStartPoint(Constants.HEAD + "~1").call()); + recorder.assertEvent(ChangeRecorder.EMPTY, + new String[] { "file2.txt" }); + + // Change content and file mode in working directory and index + file1 = writeTrashFile("file1.txt", "c"); + db.getFS().setExecute(file1, true); + git.add().addFilepattern("file1.txt").call(); + + // Switch back to 'master' + assertNotNull(git.checkout().setName(Constants.MASTER).call()); + recorder.assertEvent(new String[] { "file2.txt" }, + ChangeRecorder.EMPTY); + } finally { + if (handle != null) { + handle.remove(); + } + } } @Test(expected = CheckoutConflictException.class) |