diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java index 8b5c6b646..a1428eb64 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java @@ -43,53 +43,51 @@ * 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 java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import org.eclipse.jgit.errors.CheckoutConflictException; +import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.util.FS; -public class ReadTreeTest extends RepositoryTestCase { +public abstract class ReadTreeTest extends RepositoryTestCase { + protected Tree theHead; + protected Tree theMerge; - private Tree theHead; - private Tree theMerge; - private GitIndex theIndex; - private Checkout theReadTree; // Each of these rules are from the read-tree manpage // go there to see what they mean. // Rule 0 is left out for obvious reasons :) public void testRules1thru3_NoIndexEntry() throws IOException { - GitIndex index = new GitIndex(db); - Tree head = new Tree(db); FileTreeEntry headFile = head.addFile("foo"); ObjectId objectId = ObjectId.fromString("ba78e065e2c261d4f7b8f42107588051e87e18e9"); headFile.setId(objectId); Tree merge = new Tree(db); - Checkout readTree = getCheckoutImpl(head, index, merge); - readTree.prescanTwoTrees(); + prescanTwoTrees(head, merge); - assertTrue(readTree.removed().contains("foo")); + assertTrue(getRemoved().contains("foo")); - readTree = getCheckoutImpl(merge, index, head); - readTree.prescanTwoTrees(); + prescanTwoTrees(merge, head); - assertEquals(objectId, readTree.updated().get("foo")); + assertEquals(objectId, getUpdated().get("foo")); ObjectId anotherId = ObjectId.fromString("ba78e065e2c261d4f7b8f42107588051e87e18ee"); merge.addFile("foo").setId(anotherId); - readTree = getCheckoutImpl(head, index, merge); - readTree.prescanTwoTrees(); + prescanTwoTrees(head, merge); - assertEquals(anotherId, readTree.updated().get("foo")); + assertEquals(anotherId, getUpdated().get("foo")); } void setupCase(HashMap headEntries, @@ -97,28 +95,36 @@ void setupCase(HashMap headEntries, HashMap indexEntries) throws IOException { theHead = buildTree(headEntries); theMerge = buildTree(mergeEntries); - theIndex = buildIndex(indexEntries); + buildIndex(indexEntries); } - private GitIndex buildIndex(HashMap indexEntries) throws IOException { + private void buildIndex(HashMap indexEntries) throws IOException { GitIndex index = new GitIndex(db); - if (indexEntries == null) - return index; - for (java.util.Map.Entry e : indexEntries.entrySet()) { - index.add(trash, writeTrashFile(e.getKey(), e.getValue())).forceRecheck(); + if (indexEntries != null) { + for (java.util.Map.Entry e : indexEntries.entrySet()) { + index.add(trash, writeTrashFile(e.getKey(), e.getValue())).forceRecheck(); + } } - return index; + index.write(); } private Tree buildTree(HashMap headEntries) throws IOException { Tree tree = new Tree(db); - + ObjectWriter ow = new ObjectWriter(db); if (headEntries == null) return tree; - for (java.util.Map.Entry e : headEntries.entrySet()) { - tree.addFile(e.getKey()).setId(genSha1(e.getValue())); + FileTreeEntry fileEntry; + Tree parent; + for (java.util.Map.Entry e : headEntries.entrySet()) { + fileEntry = tree.addFile(e.getKey()); + fileEntry.setId(genSha1(e.getValue())); + parent = fileEntry.getParent(); + while (parent != null) { + parent.setId(ow.writeTree(parent)); + parent = parent.getParent(); + } } return tree; @@ -136,13 +142,11 @@ ObjectId genSha1(String data) { return null; } - private Checkout go() throws IOException { - theReadTree = getCheckoutImpl(theHead, theIndex, theMerge); - theReadTree.prescanTwoTrees(); - return theReadTree; + protected void go() throws IllegalStateException, IOException { + prescanTwoTrees(theHead, theMerge); } - // for these rules, they all have clean yes/no options + // for these rules, they all have clean yes/no options // but it doesn't matter if the entry is clean or not // so we can just ignore the state in the filesystem entirely public void testRules4thru13_IndexEntryNotInHead() throws IOException { @@ -152,17 +156,17 @@ public void testRules4thru13_IndexEntryNotInHead() throws IOException { idxMap = new HashMap(); idxMap.put("foo", "foo"); setupCase(null, null, idxMap); - theReadTree = go(); + go(); - assertTrue(theReadTree.updated().isEmpty()); - assertTrue(theReadTree.removed().isEmpty()); - assertTrue(theReadTree.conflicts().isEmpty()); + assertTrue(getUpdated().isEmpty()); + assertTrue(getRemoved().isEmpty()); + assertTrue(getConflicts().isEmpty()); // rules 6 and 7 idxMap = new HashMap(); idxMap.put("foo", "foo"); setupCase(null, idxMap, idxMap); - theReadTree = go(); + go(); assertAllEmpty(); @@ -174,9 +178,9 @@ public void testRules4thru13_IndexEntryNotInHead() throws IOException { setupCase(null, mergeMap, idxMap); go(); - assertTrue(theReadTree.updated().isEmpty()); - assertTrue(theReadTree.removed().isEmpty()); - assertTrue(theReadTree.conflicts().contains("foo")); + assertTrue(getUpdated().isEmpty()); + assertTrue(getRemoved().isEmpty()); + assertTrue(getConflicts().contains("foo")); // rule 10 @@ -185,29 +189,29 @@ public void testRules4thru13_IndexEntryNotInHead() throws IOException { setupCase(headMap, null, idxMap); go(); - assertTrue(theReadTree.removed().contains("foo")); - assertTrue(theReadTree.updated().isEmpty()); - assertTrue(theReadTree.conflicts().isEmpty()); + assertTrue(getRemoved().contains("foo")); + assertTrue(getUpdated().isEmpty()); + assertTrue(getConflicts().isEmpty()); // rule 11 setupCase(headMap, null, idxMap); new File(trash, "foo").delete(); writeTrashFile("foo", "bar"); - theIndex.getMembers()[0].forceRecheck(); + db.getIndex().getMembers()[0].forceRecheck(); go(); - assertTrue(theReadTree.removed().isEmpty()); - assertTrue(theReadTree.updated().isEmpty()); - assertTrue(theReadTree.conflicts().contains("foo")); + assertTrue(getRemoved().isEmpty()); + assertTrue(getUpdated().isEmpty()); + assertTrue(getConflicts().contains("foo")); // rule 12 & 13 headMap.put("foo", "head"); setupCase(headMap, null, idxMap); go(); - assertTrue(theReadTree.removed().isEmpty()); - assertTrue(theReadTree.updated().isEmpty()); - assertTrue(theReadTree.conflicts().contains("foo")); + assertTrue(getRemoved().isEmpty()); + assertTrue(getUpdated().isEmpty()); + assertTrue(getConflicts().contains("foo")); // rules 14 & 15 setupCase(headMap, headMap, idxMap); @@ -217,7 +221,7 @@ public void testRules4thru13_IndexEntryNotInHead() throws IOException { // rules 16 & 17 setupCase(headMap, mergeMap, idxMap); go(); - assertTrue(theReadTree.conflicts().contains("foo")); + assertTrue(getConflicts().contains("foo")); // rules 18 & 19 setupCase(headMap, idxMap, idxMap); go(); @@ -225,25 +229,25 @@ public void testRules4thru13_IndexEntryNotInHead() throws IOException { // rule 20 setupCase(idxMap, mergeMap, idxMap); go(); - assertTrue(theReadTree.updated().containsKey("foo")); + assertTrue(getUpdated().containsKey("foo")); // rules 21 setupCase(idxMap, mergeMap, idxMap); new File(trash, "foo").delete(); writeTrashFile("foo", "bar"); - theIndex.getMembers()[0].forceRecheck(); + db.getIndex().getMembers()[0].forceRecheck(); go(); - assertTrue(theReadTree.conflicts().contains("foo")); + assertTrue(getConflicts().contains("foo")); } private void assertAllEmpty() { - assertTrue(theReadTree.removed().isEmpty()); - assertTrue(theReadTree.updated().isEmpty()); - assertTrue(theReadTree.conflicts().isEmpty()); + assertTrue(getRemoved().isEmpty()); + assertTrue(getUpdated().isEmpty()); + assertTrue(getConflicts().isEmpty()); } public void testDirectoryFileSimple() throws IOException { - theIndex = new GitIndex(db); + GitIndex theIndex = new GitIndex(db); theIndex.add(trash, writeTrashFile("DF", "DF")); Tree treeDF = db.mapTree(theIndex.writeTree()); @@ -256,20 +260,21 @@ public void testDirectoryFileSimple() throws IOException { recursiveDelete(new File(trash, "DF")); theIndex.add(trash, writeTrashFile("DF", "DF")); - theReadTree = getCheckoutImpl(treeDF, theIndex, treeDFDF); - theReadTree.prescanTwoTrees(); + theIndex.write(); - assertTrue(theReadTree.removed().contains("DF")); - assertTrue(theReadTree.updated().containsKey("DF/DF")); + prescanTwoTrees(treeDF, treeDFDF); + + assertTrue(getRemoved().contains("DF")); + assertTrue(getUpdated().containsKey("DF/DF")); recursiveDelete(new File(trash, "DF")); theIndex = new GitIndex(db); theIndex.add(trash, writeTrashFile("DF/DF", "DF/DF")); + theIndex.write(); - theReadTree = getCheckoutImpl(treeDFDF, theIndex, treeDF); - theReadTree.prescanTwoTrees(); - assertTrue(theReadTree.removed().contains("DF/DF")); - assertTrue(theReadTree.updated().containsKey("DF")); + prescanTwoTrees(treeDFDF, treeDF); + assertTrue(getRemoved().contains("DF/DF")); + assertTrue(getUpdated().containsKey("DF")); } /* @@ -475,32 +480,32 @@ private void cleanUpDF() throws Exception { } private void assertConflict(String s) { - assertTrue(theReadTree.conflicts().contains(s)); + assertTrue(getConflicts().contains(s)); } private void assertUpdated(String s) { - assertTrue(theReadTree.updated().containsKey(s)); + assertTrue(getUpdated().containsKey(s)); } private void assertRemoved(String s) { - assertTrue(theReadTree.removed().contains(s)); + assertTrue(getRemoved().contains(s)); } private void assertNoConflicts() { - assertTrue(theReadTree.conflicts().isEmpty()); + assertTrue(getConflicts().isEmpty()); } - private void doit(HashMap h, HashMapm, + private void doit(HashMap h, HashMap m, HashMap i) throws IOException { setupCase(h, m, i); go(); } - private static HashMap mk(String a) { + protected static HashMap mk(String a) { return mkmap(a, a); } - private static HashMap mkmap(String... args) { + protected static HashMap mkmap(String... args) { if ((args.length % 2) > 0) throw new IllegalArgumentException("needs to be pairs"); @@ -541,46 +546,69 @@ public void testUntrackedConflicts() throws IOException { public void testCloseNameConflictsX0() throws IOException { setupCase(mkmap("a/a", "a/a-c"), mkmap("a/a","a/a", "b.b/b.b","b.b/b.bs"), mkmap("a/a", "a/a-c") ); checkout(); + assertIndex(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs")); + assertWorkDir(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs")); go(); + assertIndex(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs")); + assertWorkDir(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs")); assertNoConflicts(); } public void testCloseNameConflicts1() throws IOException { setupCase(mkmap("a/a", "a/a-c"), mkmap("a/a","a/a", "a.a/a.a","a.a/a.a"), mkmap("a/a", "a/a-c") ); checkout(); + assertIndex(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a")); + assertWorkDir(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a")); go(); + assertIndex(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a")); + assertWorkDir(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a")); assertNoConflicts(); } - private void checkout() throws IOException { - theReadTree = getCheckoutImpl(theHead, theIndex, theMerge); - theReadTree.checkout(); - } - public void testCheckoutOutChanges() throws IOException { setupCase(mk("foo"), mk("foo/bar"), mk("foo")); checkout(); + assertIndex(mk("foo/bar")); + assertWorkDir(mk("foo/bar")); assertFalse(new File(trash, "foo").isFile()); assertTrue(new File(trash, "foo/bar").isFile()); recursiveDelete(new File(trash, "foo")); + assertWorkDir(mkmap()); + setupCase(mk("foo/bar"), mk("foo"), mk("foo/bar")); checkout(); + assertIndex(mk("foo")); + assertWorkDir(mk("foo")); + assertFalse(new File(trash, "foo/bar").isFile()); assertTrue(new File(trash, "foo").isFile()); setupCase(mk("foo"), mkmap("foo", "qux"), mkmap("foo", "bar")); + assertIndex(mkmap("foo", "bar")); + assertWorkDir(mkmap("foo", "bar")); + try { checkout(); fail("did not throw exception"); } catch (CheckoutConflictException e) { - // should have thrown + assertIndex(mkmap("foo", "bar")); + assertWorkDir(mkmap("foo", "bar")); } } + public void testCheckoutUncachedChanges() throws IOException { + setupCase(mk("foo"), mk("foo"), mk("foo")); + writeTrashFile("foo", "otherData"); + checkout(); + assertIndex(mk("foo")); + assertWorkDir(mkmap("foo", "otherData")); + assertTrue(new File(trash, "foo").isFile()); + } + /** * The interface these tests need from a class implementing a checkout */ @@ -592,45 +620,68 @@ interface Checkout { void checkout() throws IOException; } - /** - * Return the current implementation of the {@link Checkout} interface. - *

- * May be overridden by subclasses which would inherit all tests but can - * specify their own implementation of a Checkout - * - * @param head - * @param index - * @param merge - * @return the current implementation of {@link Checkout} - */ - protected Checkout getCheckoutImpl(Tree head, GitIndex index, - Tree merge) { - return new WorkdirCheckoutImpl(head, index, merge); + public void assertWorkDir(HashMap i) + throws CorruptObjectException, IOException { + TreeWalk walk = new TreeWalk(db); + walk.reset(); + walk.setRecursive(true); + walk.addTree(new FileTreeIterator(db.getWorkDir(), FS.DETECTED)); + String expectedValue; + String path; + int nrFiles = 0; + FileTreeIterator ft; + while (walk.next()) { + ft = walk.getTree(0, FileTreeIterator.class); + path = ft.getEntryPathString(); + expectedValue = i.get(path); + assertNotNull("found unexpected file for path " + + path + " in workdir", expectedValue); + File file = new File(db.getWorkDir(), path); + assertTrue(file.exists()); + if (file.isFile()) { + FileInputStream is = new FileInputStream(file); + byte[] buffer = new byte[(int) file.length()]; + int offset = 0; + int numRead = 0; + while (offset < buffer.length + && (numRead = is.read(buffer, offset, buffer.length + - offset)) >= 0) { + offset += numRead; + } + is.close(); + assertTrue("unexpected content for path " + path + + " in workDir. Expected: <" + expectedValue + ">", + Arrays.equals(buffer, i.get(path).getBytes())); + nrFiles++; + } + } + assertEquals("WorkDir has not the right size.", i.size(), nrFiles); } - /** - * An implementation of the {@link Checkout} interface which uses WorkDirCheckout - */ - class WorkdirCheckoutImpl extends WorkDirCheckout implements Checkout { - public WorkdirCheckoutImpl(Tree head, GitIndex index, - Tree merge) { - super(db, trash, head, index, merge); - } - public HashMap updated() { - return updated; - } - - public ArrayList conflicts() { - return conflicts; - } - - public ArrayList removed() { - return removed; - } - - public void prescanTwoTrees() throws IOException { - super.prescanTwoTrees(); + public void assertIndex(HashMap i) + throws CorruptObjectException, IOException { + String expectedValue; + String path; + GitIndex theIndex=db.getIndex(); + assertEquals("Index has not the right size.", i.size(), + theIndex.getMembers().length); + for (int j = 0; j < theIndex.getMembers().length; j++) { + path = theIndex.getMembers()[j].getName(); + expectedValue = i.get(path); + assertNotNull("found unexpected entry for path " + path + + " in index", expectedValue); + assertTrue("unexpected content for path " + path + + " in index. Expected: <" + expectedValue + ">", + Arrays.equals( + db.openBlob(theIndex.getMembers()[j].getObjectId()) + .getBytes(), i.get(path).getBytes())); } } + + public abstract void prescanTwoTrees(Tree head, Tree merge) throws IllegalStateException, IOException; + public abstract void checkout() throws IOException; + public abstract ArrayList getRemoved(); + public abstract HashMap getUpdated(); + public abstract ArrayList getConflicts(); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WorkDirCheckout_ReadTreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WorkDirCheckout_ReadTreeTest.java new file mode 100644 index 000000000..ecaac5846 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WorkDirCheckout_ReadTreeTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010, Christian Halstrick + * 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 java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Test cases for ReadTree operations as implemented in WorkDirCheckout + */ +public class WorkDirCheckout_ReadTreeTest extends ReadTreeTest { + private WorkDirCheckout wdc; + public void prescanTwoTrees(Tree head, Tree merge) throws IllegalStateException, IOException { + wdc = new WorkDirCheckout(db, db.getWorkDir(), head, db.getIndex(), merge); + wdc.prescanTwoTrees(); + } + + public void checkout() throws IOException { + wdc = new WorkDirCheckout(db, db.getWorkDir(), theHead, db.getIndex(), theMerge); + wdc.checkout(); + } + + public ArrayList getRemoved() { + return wdc.getRemoved(); + } + + public HashMap getUpdated() { + return wdc.updated; + } + + public ArrayList getConflicts() { + return wdc.getConflicts(); + } +} +