From 4be88168b69465ccb81a44ddcc614b0e60d7956d Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Thu, 1 Jul 2010 18:02:00 +0200 Subject: [PATCH] Allow ReadTreeTest to test arbitrary Checkouts ReadTreeTest was hardcoded to test WorkDirCheckout. Since we want alternative checkout implementations (especially DirCacheCheckout) this class has been refactored so that the tests can be reused to test other implementations The following changes have been done: - abstract methods for checkout and prescanTwoTrees have been introduced. Parameters are only the two trees. As index we will implicitly use the current index of the repo. - whenever tests needed a manipulated index before checkout and prescanTwoTrees it was ensured that the correct index was persisted (before we could use not-persisted instantiations of GitIndex passed as parameters to checkout, prescanTwoTrees - abstract methods for getting updated, conflicting, removed entries resulting from the last checkout, prescanTwoTrees have been introduced - an implementation for all these abstract methods using WorkDirCheckout has been added - method to assert a certain state of the index and the working tree has been added Signed-off-by: Christian Halstrick Change-Id: Icf177cf8043487169a32ddd72b6f8f9246a433f7 --- .../org/eclipse/jgit/lib/ReadTreeTest.java | 285 +++++++++++------- .../lib/WorkDirCheckout_ReadTreeTest.java | 76 +++++ 2 files changed, 244 insertions(+), 117 deletions(-) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WorkDirCheckout_ReadTreeTest.java 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 8b5c6b646b..a1428eb641 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 @@ public class ReadTreeTest extends RepositoryTestCase { 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 @@ public class ReadTreeTest extends RepositoryTestCase { 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 class ReadTreeTest extends RepositoryTestCase { 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 class ReadTreeTest extends RepositoryTestCase { 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 class ReadTreeTest extends RepositoryTestCase { 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 class ReadTreeTest extends RepositoryTestCase { // 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 class ReadTreeTest extends RepositoryTestCase { // 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 class ReadTreeTest extends RepositoryTestCase { recursiveDelete(new File(trash, "DF")); theIndex.add(trash, writeTrashFile("DF", "DF")); - theReadTree = getCheckoutImpl(treeDF, theIndex, treeDFDF); - theReadTree.prescanTwoTrees(); + theIndex.write(); + + prescanTwoTrees(treeDF, treeDFDF); - assertTrue(theReadTree.removed().contains("DF")); - assertTrue(theReadTree.updated().containsKey("DF/DF")); + 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 @@ public class ReadTreeTest extends RepositoryTestCase { } 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 class ReadTreeTest extends RepositoryTestCase { 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 @@ public class ReadTreeTest extends RepositoryTestCase { 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); - } - - /** - * 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 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++; + } } - - public ArrayList removed() { - return removed; - } - - public void prescanTwoTrees() throws IOException { - super.prescanTwoTrees(); + assertEquals("WorkDir has not the right size.", i.size(), nrFiles); + } + + + 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 0000000000..ecaac5846e --- /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(); + } +} + -- 2.39.5