Rename fields to avoid hiding of field names in ReadTreeTest
[egit/qmx.git] / org.spearce.jgit.test / tst / org / spearce / jgit / lib / ReadTreeTest.java
blobc9d056550a5ea59fcf3f8fd03addba21509cc59a
1 /*
2 * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
3 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or
9 * without modification, are permitted provided that the following
10 * conditions are met:
12 * - Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
20 * - Neither the name of the Git Development Community nor the
21 * names of its contributors may be used to endorse or promote
22 * products derived from this software without specific prior
23 * written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
26 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
27 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
30 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
37 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 package org.spearce.jgit.lib;
42 import java.io.ByteArrayInputStream;
43 import java.io.File;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.util.HashMap;
48 import org.spearce.jgit.errors.CheckoutConflictException;
50 public class ReadTreeTest extends RepositoryTestCase {
52 private Tree theHead;
53 private Tree theMerge;
54 private GitIndex theIndex;
55 private WorkDirCheckout theReadTree;
56 // Each of these rules are from the read-tree manpage
57 // go there to see what they mean.
58 // Rule 0 is left out for obvious reasons :)
59 public void testRules1thru3_NoIndexEntry() throws IOException {
60 GitIndex index = new GitIndex(db);
62 Tree head = new Tree(db);
63 FileTreeEntry headFile = head.addFile("foo");
64 ObjectId objectId = ObjectId.fromString("ba78e065e2c261d4f7b8f42107588051e87e18e9");
65 headFile.setId(objectId);
66 Tree merge = new Tree(db);
68 WorkDirCheckout readTree = new WorkDirCheckout(db, trash, head, index, merge);
69 readTree.prescanTwoTrees();
71 assertTrue(readTree.removed.contains("foo"));
73 readTree = new WorkDirCheckout(db, trash, merge, index, head);
74 readTree.prescanTwoTrees();
76 assertEquals(objectId, readTree.updated.get("foo"));
78 ObjectId anotherId = ObjectId.fromString("ba78e065e2c261d4f7b8f42107588051e87e18ee");
79 merge.addFile("foo").setId(anotherId);
81 readTree = new WorkDirCheckout(db, trash, head, index, merge);
82 readTree.prescanTwoTrees();
84 assertEquals(anotherId, readTree.updated.get("foo"));
87 void setupCase(HashMap<String, String> headEntries,
88 HashMap<String, String> mergeEntries,
89 HashMap<String, String> indexEntries) throws IOException {
90 theHead = buildTree(headEntries);
91 theMerge = buildTree(mergeEntries);
92 theIndex = buildIndex(indexEntries);
95 private GitIndex buildIndex(HashMap<String, String> indexEntries) throws IOException {
96 GitIndex index = new GitIndex(db);
98 if (indexEntries == null)
99 return index;
100 for (java.util.Map.Entry<String,String> e : indexEntries.entrySet()) {
101 index.add(trash, writeTrashFile(e.getKey(), e.getValue())).forceRecheck();
104 return index;
107 private Tree buildTree(HashMap<String, String> headEntries) throws IOException {
108 Tree tree = new Tree(db);
110 if (headEntries == null)
111 return tree;
112 for (java.util.Map.Entry<String,String> e : headEntries.entrySet()) {
113 tree.addFile(e.getKey()).setId(genSha1(e.getValue()));
116 return tree;
119 ObjectId genSha1(String data) {
120 InputStream is = new ByteArrayInputStream(data.getBytes());
121 ObjectWriter objectWriter = new ObjectWriter(db);
122 try {
123 return objectWriter.writeObject(Constants.OBJ_BLOB, data
124 .getBytes().length, is, true);
125 } catch (IOException e) {
126 fail(e.toString());
128 return null;
131 private WorkDirCheckout go() throws IOException {
132 theReadTree = new WorkDirCheckout(db, trash, theHead, theIndex, theMerge);
133 theReadTree.prescanTwoTrees();
134 return theReadTree;
137 // for these rules, they all have clean yes/no options
138 // but it doesn't matter if the entry is clean or not
139 // so we can just ignore the state in the filesystem entirely
140 public void testRules4thru13_IndexEntryNotInHead() throws IOException {
141 // rules 4 and 5
142 HashMap<String, String> idxMap;
144 idxMap = new HashMap<String, String>();
145 idxMap.put("foo", "foo");
146 setupCase(null, null, idxMap);
147 theReadTree = go();
149 assertTrue(theReadTree.updated.isEmpty());
150 assertTrue(theReadTree.removed.isEmpty());
151 assertTrue(theReadTree.conflicts.isEmpty());
153 // rules 6 and 7
154 idxMap = new HashMap<String, String>();
155 idxMap.put("foo", "foo");
156 setupCase(null, idxMap, idxMap);
157 theReadTree = go();
159 assertAllEmpty();
161 // rules 8 and 9
162 HashMap<String, String> mergeMap;
163 mergeMap = new HashMap<String, String>();
165 mergeMap.put("foo", "merge");
166 setupCase(null, mergeMap, idxMap);
167 go();
169 assertTrue(theReadTree.updated.isEmpty());
170 assertTrue(theReadTree.removed.isEmpty());
171 assertTrue(theReadTree.conflicts.contains("foo"));
173 // rule 10
175 HashMap<String, String> headMap = new HashMap<String, String>();
176 headMap.put("foo", "foo");
177 setupCase(headMap, null, idxMap);
178 go();
180 assertTrue(theReadTree.removed.contains("foo"));
181 assertTrue(theReadTree.updated.isEmpty());
182 assertTrue(theReadTree.conflicts.isEmpty());
184 // rule 11
185 setupCase(headMap, null, idxMap);
186 new File(trash, "foo").delete();
187 writeTrashFile("foo", "bar");
188 theIndex.getMembers()[0].forceRecheck();
189 go();
191 assertTrue(theReadTree.removed.isEmpty());
192 assertTrue(theReadTree.updated.isEmpty());
193 assertTrue(theReadTree.conflicts.contains("foo"));
195 // rule 12 & 13
196 headMap.put("foo", "head");
197 setupCase(headMap, null, idxMap);
198 go();
200 assertTrue(theReadTree.removed.isEmpty());
201 assertTrue(theReadTree.updated.isEmpty());
202 assertTrue(theReadTree.conflicts.contains("foo"));
204 // rules 14 & 15
205 setupCase(headMap, headMap, idxMap);
206 go();
208 assertAllEmpty();
210 // rules 16 & 17
211 setupCase(headMap, mergeMap, idxMap); go();
212 assertTrue(theReadTree.conflicts.contains("foo"));
214 // rules 18 & 19
215 setupCase(headMap, idxMap, idxMap); go();
216 assertAllEmpty();
218 // rule 20
219 setupCase(idxMap, mergeMap, idxMap); go();
220 assertTrue(theReadTree.updated.containsKey("foo"));
222 // rules 21
223 setupCase(idxMap, mergeMap, idxMap);
224 new File(trash, "foo").delete();
225 writeTrashFile("foo", "bar");
226 theIndex.getMembers()[0].forceRecheck();
227 go();
228 assertTrue(theReadTree.conflicts.contains("foo"));
231 private void assertAllEmpty() {
232 assertTrue(theReadTree.removed.isEmpty());
233 assertTrue(theReadTree.updated.isEmpty());
234 assertTrue(theReadTree.conflicts.isEmpty());
237 public void testDirectoryFileSimple() throws IOException {
238 theIndex = new GitIndex(db);
239 theIndex.add(trash, writeTrashFile("DF", "DF"));
240 Tree treeDF = db.mapTree(theIndex.writeTree());
242 recursiveDelete(new File(trash, "DF"));
243 theIndex = new GitIndex(db);
244 theIndex.add(trash, writeTrashFile("DF/DF", "DF/DF"));
245 Tree treeDFDF = db.mapTree(theIndex.writeTree());
247 theIndex = new GitIndex(db);
248 recursiveDelete(new File(trash, "DF"));
250 theIndex.add(trash, writeTrashFile("DF", "DF"));
251 theReadTree = new WorkDirCheckout(db, trash, treeDF, theIndex, treeDFDF);
252 theReadTree.prescanTwoTrees();
254 assertTrue(theReadTree.removed.contains("DF"));
255 assertTrue(theReadTree.updated.containsKey("DF/DF"));
257 recursiveDelete(new File(trash, "DF"));
258 theIndex = new GitIndex(db);
259 theIndex.add(trash, writeTrashFile("DF/DF", "DF/DF"));
261 theReadTree = new WorkDirCheckout(db, trash, treeDFDF, theIndex, treeDF);
262 theReadTree.prescanTwoTrees();
263 assertTrue(theReadTree.removed.contains("DF/DF"));
264 assertTrue(theReadTree.updated.containsKey("DF"));
268 * Directory/File Conflict cases:
269 * It's entirely possible that in practice a number of these may be equivalent
270 * to the cases described in git-read-tree.txt. As long as it does the right thing,
271 * that's all I care about. These are basically reverse-engineered from
272 * what git currently does. If there are tests for these in git, it's kind of
273 * hard to track them all down...
275 * H I M Clean H==M H==I I==M Result
276 * ------------------------------------------------------------------
277 *1 D D F Y N Y N Update
278 *2 D D F N N Y N Conflict
279 *3 D F D Y N N Update
280 *4 D F D N N N Update
281 *5 D F F Y N N Y Keep
282 *6 D F F N N N Y Keep
283 *7 F D F Y Y N N Update
284 *8 F D F N Y N N Conflict
285 *9 F D F Y N N N Update
286 *10 F D D N N Y Keep
287 *11 F D D N N N Conflict
288 *12 F F D Y N Y N Update
289 *13 F F D N N Y N Conflict
290 *14 F F D N N N Conflict
291 *15 0 F D N N N Conflict
292 *16 0 D F Y N N N Update
293 *17 0 D F N N N Conflict
294 *18 F 0 D Update
295 *19 D 0 F Update
298 public void testDirectoryFileConflicts_1() throws Exception {
299 // 1
300 doit(mk("DF/DF"), mk("DF"), mk("DF/DF"));
301 assertNoConflicts();
302 assertUpdated("DF");
303 assertRemoved("DF/DF");
306 public void testDirectoryFileConflicts_2() throws Exception {
307 // 2
308 setupCase(mk("DF/DF"), mk("DF"), mk("DF/DF"));
309 writeTrashFile("DF/DF", "different");
310 go();
311 assertConflict("DF/DF");
315 public void testDirectoryFileConflicts_3() throws Exception {
316 // 3 - the first to break!
317 doit(mk("DF/DF"), mk("DF/DF"), mk("DF"));
318 assertUpdated("DF/DF");
319 assertRemoved("DF");
322 public void testDirectoryFileConflicts_4() throws Exception {
323 // 4 (basically same as 3, just with H and M different)
324 doit(mk("DF/DF"), mkmap("DF/DF", "foo"), mk("DF"));
325 assertUpdated("DF/DF");
326 assertRemoved("DF");
330 public void testDirectoryFileConflicts_5() throws Exception {
331 // 5
332 doit(mk("DF/DF"), mk("DF"), mk("DF"));
333 assertRemoved("DF/DF");
337 public void testDirectoryFileConflicts_6() throws Exception {
338 // 6
339 setupCase(mk("DF/DF"), mk("DF"), mk("DF"));
340 writeTrashFile("DF", "different");
341 go();
342 assertRemoved("DF/DF");
345 public void testDirectoryFileConflicts_7() throws Exception {
346 // 7
347 doit(mk("DF"), mk("DF"), mk("DF/DF"));
348 assertUpdated("DF");
349 assertRemoved("DF/DF");
351 cleanUpDF();
352 setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
353 go();
354 assertRemoved("DF/DF/DF/DF/DF");
355 assertUpdated("DF/DF");
357 cleanUpDF();
358 setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
359 writeTrashFile("DF/DF/DF/DF/DF", "diff");
360 go();
361 assertConflict("DF/DF/DF/DF/DF");
362 assertUpdated("DF/DF");
366 // 8 ?
368 public void testDirectoryFileConflicts_9() throws Exception {
369 // 9
370 doit(mk("DF"), mkmap("DF", "QP"), mk("DF/DF"));
371 assertRemoved("DF/DF");
372 assertUpdated("DF");
375 public void testDirectoryFileConflicts_10() throws Exception {
376 // 10
377 cleanUpDF();
378 doit(mk("DF"), mk("DF/DF"), mk("DF/DF"));
379 assertNoConflicts();
383 public void testDirectoryFileConflicts_11() throws Exception {
384 // 11
385 doit(mk("DF"), mk("DF/DF"), mkmap("DF/DF", "asdf"));
386 assertConflict("DF/DF");
389 public void testDirectoryFileConflicts_12() throws Exception {
390 // 12
391 cleanUpDF();
392 doit(mk("DF"), mk("DF/DF"), mk("DF"));
393 assertRemoved("DF");
394 assertUpdated("DF/DF");
397 public void testDirectoryFileConflicts_13() throws Exception {
398 // 13
399 cleanUpDF();
400 setupCase(mk("DF"), mk("DF/DF"), mk("DF"));
401 writeTrashFile("DF", "asdfsdf");
402 go();
403 assertConflict("DF");
404 assertUpdated("DF/DF");
407 public void testDirectoryFileConflicts_14() throws Exception {
408 // 14
409 cleanUpDF();
410 doit(mk("DF"), mk("DF/DF"), mkmap("DF", "Foo"));
411 assertConflict("DF");
412 assertUpdated("DF/DF");
415 public void testDirectoryFileConflicts_15() throws Exception {
416 // 15
417 doit(mkmap(), mk("DF/DF"), mk("DF"));
418 assertRemoved("DF");
419 assertUpdated("DF/DF");
422 public void testDirectoryFileConflicts_15b() throws Exception {
423 // 15, take 2, just to check multi-leveled
424 doit(mkmap(), mk("DF/DF/DF/DF"), mk("DF"));
425 assertRemoved("DF");
426 assertUpdated("DF/DF/DF/DF");
429 public void testDirectoryFileConflicts_16() throws Exception {
430 // 16
431 cleanUpDF();
432 doit(mkmap(), mk("DF"), mk("DF/DF/DF"));
433 assertRemoved("DF/DF/DF");
434 assertUpdated("DF");
437 public void testDirectoryFileConflicts_17() throws Exception {
438 // 17
439 cleanUpDF();
440 setupCase(mkmap(), mk("DF"), mk("DF/DF/DF"));
441 writeTrashFile("DF/DF/DF", "asdf");
442 go();
443 assertConflict("DF/DF/DF");
444 assertUpdated("DF");
447 public void testDirectoryFileConflicts_18() throws Exception {
448 // 18
449 cleanUpDF();
450 doit(mk("DF/DF"), mk("DF/DF/DF/DF"), null);
451 assertRemoved("DF/DF");
452 assertUpdated("DF/DF/DF/DF");
455 public void testDirectoryFileConflicts_19() throws Exception {
456 // 19
457 cleanUpDF();
458 doit(mk("DF/DF/DF/DF"), mk("DF/DF/DF"), null);
459 assertRemoved("DF/DF/DF/DF");
460 assertUpdated("DF/DF/DF");
463 private void cleanUpDF() throws Exception {
464 tearDown();
465 setUp();
466 recursiveDelete(new File(trash, "DF"));
469 private void assertConflict(String s) {
470 assertTrue(theReadTree.conflicts.contains(s));
473 private void assertUpdated(String s) {
474 assertTrue(theReadTree.updated.containsKey(s));
477 private void assertRemoved(String s) {
478 assertTrue(theReadTree.removed.contains(s));
481 private void assertNoConflicts() {
482 assertTrue(theReadTree.conflicts.isEmpty());
485 private void doit(HashMap<String, String> h, HashMap<String, String>m,
486 HashMap<String, String> i) throws IOException {
487 setupCase(h, m, i);
488 go();
491 private static HashMap<String, String> mk(String a) {
492 return mkmap(a, a);
495 private static HashMap<String, String> mkmap(String... args) {
496 if ((args.length % 2) > 0)
497 throw new IllegalArgumentException("needs to be pairs");
499 HashMap<String, String> map = new HashMap<String, String>();
500 for (int i = 0; i < args.length; i += 2) {
501 map.put(args[i], args[i+1]);
504 return map;
507 public void testUntrackedConflicts() throws IOException {
508 setupCase(null, mk("foo"), null);
509 writeTrashFile("foo", "foo");
510 go();
512 assertConflict("foo");
514 recursiveDelete(new File(trash, "foo"));
515 setupCase(null, mk("foo"), null);
516 writeTrashFile("foo/bar/baz", "");
517 writeTrashFile("foo/blahblah", "");
518 go();
520 assertConflict("foo/bar/baz");
521 assertConflict("foo/blahblah");
523 recursiveDelete(new File(trash, "foo"));
525 setupCase(mkmap("foo/bar", "", "foo/baz", ""),
526 mk("foo"), mkmap("foo/bar", "", "foo/baz", ""));
527 assertTrue(new File(trash, "foo/bar").exists());
528 go();
530 assertNoConflicts();
533 public void testCloseNameConflictsX0() throws IOException {
534 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") );
535 checkout();
536 go();
537 assertNoConflicts();
540 public void testCloseNameConflicts1() throws IOException {
541 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") );
542 checkout();
543 go();
544 assertNoConflicts();
547 private void checkout() throws IOException {
548 theReadTree = new WorkDirCheckout(db, trash, theHead, theIndex, theMerge);
549 theReadTree.checkout();
552 public void testCheckoutOutChanges() throws IOException {
553 setupCase(mk("foo"), mk("foo/bar"), mk("foo"));
554 checkout();
556 assertFalse(new File(trash, "foo").isFile());
557 assertTrue(new File(trash, "foo/bar").isFile());
558 recursiveDelete(new File(trash, "foo"));
560 setupCase(mk("foo/bar"), mk("foo"), mk("foo/bar"));
561 checkout();
563 assertFalse(new File(trash, "foo/bar").isFile());
564 assertTrue(new File(trash, "foo").isFile());
566 setupCase(mk("foo"), mkmap("foo", "qux"), mkmap("foo", "bar"));
568 try {
569 checkout();
570 fail("did not throw exception");
571 } catch (CheckoutConflictException e) {
572 // should have thrown