Split a big test in ReadTreeTest into smaller tests
[egit.git] / org.spearce.jgit.test / tst / org / spearce / jgit / lib / ReadTreeTest.java
blob70c13968b97e0978f8410f0f1b0c7dc42d8d2811
1 /*
2 * Copyright (C) 2007 Dave Watson <dwatson@mimvista.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License, version 2, as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18 package org.spearce.jgit.lib;
20 import java.io.ByteArrayInputStream;
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.HashMap;
26 import org.spearce.jgit.errors.CheckoutConflictException;
28 public class ReadTreeTest extends RepositoryTestCase {
30 private Tree head;
31 private Tree merge;
32 private GitIndex index;
33 private WorkDirCheckout readTree;
34 // Each of these rules are from the read-tree manpage
35 // go there to see what they mean.
36 // Rule 0 is left out for obvious reasons :)
37 public void testRules1thru3_NoIndexEntry() throws IOException {
38 GitIndex index = new GitIndex(db);
40 Tree head = new Tree(db);
41 FileTreeEntry headFile = head.addFile("foo");
42 ObjectId objectId = new ObjectId("ba78e065e2c261d4f7b8f42107588051e87e18e9");
43 headFile.setId(objectId);
44 Tree merge = new Tree(db);
46 WorkDirCheckout readTree = new WorkDirCheckout(db, trash, head, index, merge);
47 readTree.prescanTwoTrees();
49 assertTrue(readTree.removed.contains("foo"));
51 readTree = new WorkDirCheckout(db, trash, merge, index, head);
52 readTree.prescanTwoTrees();
54 assertEquals(objectId, readTree.updated.get("foo"));
56 ObjectId anotherId = new ObjectId("ba78e065e2c261d4f7b8f42107588051e87e18ee");
57 merge.addFile("foo").setId(anotherId);
59 readTree = new WorkDirCheckout(db, trash, head, index, merge);
60 readTree.prescanTwoTrees();
62 assertEquals(anotherId, readTree.updated.get("foo"));
65 void setupCase(HashMap<String, String> headEntries,
66 HashMap<String, String> mergeEntries,
67 HashMap<String, String> indexEntries) throws IOException {
68 head = buildTree(headEntries);
69 merge = buildTree(mergeEntries);
70 index = buildIndex(indexEntries);
73 private GitIndex buildIndex(HashMap<String, String> indexEntries) throws IOException {
74 GitIndex index = new GitIndex(db);
76 if (indexEntries == null)
77 return index;
78 for (java.util.Map.Entry<String,String> e : indexEntries.entrySet()) {
79 index.add(trash, writeTrashFile(e.getKey(), e.getValue())).forceRecheck();
82 return index;
85 private Tree buildTree(HashMap<String, String> headEntries) throws IOException {
86 Tree tree = new Tree(db);
88 if (headEntries == null)
89 return tree;
90 for (java.util.Map.Entry<String,String> e : headEntries.entrySet()) {
91 tree.addFile(e.getKey()).setId(genSha1(e.getValue()));
94 return tree;
97 ObjectId genSha1(String data) {
98 InputStream is = new ByteArrayInputStream(data.getBytes());
99 ObjectWriter objectWriter = new ObjectWriter(db);
100 try {
101 return objectWriter.writeObject(Constants.OBJ_BLOB, Constants.TYPE_BLOB, data.getBytes().length, is,
102 true);
103 } catch (IOException e) {
104 fail(e.toString());
106 return null;
109 private WorkDirCheckout go() throws IOException {
110 readTree = new WorkDirCheckout(db, trash, head, index, merge);
111 readTree.prescanTwoTrees();
112 return readTree;
115 // for these rules, they all have clean yes/no options
116 // but it doesn't matter if the entry is clean or not
117 // so we can just ignore the state in the filesystem entirely
118 public void testRules4thru13_IndexEntryNotInHead() throws IOException {
119 // rules 4 and 5
120 HashMap<String, String> idxMap;
122 idxMap = new HashMap<String, String>();
123 idxMap.put("foo", "foo");
124 setupCase(null, null, idxMap);
125 readTree = go();
127 assertTrue(readTree.updated.isEmpty());
128 assertTrue(readTree.removed.isEmpty());
129 assertTrue(readTree.conflicts.isEmpty());
131 // rules 6 and 7
132 idxMap = new HashMap<String, String>();
133 idxMap.put("foo", "foo");
134 setupCase(null, idxMap, idxMap);
135 readTree = go();
137 assertAllEmpty();
139 // rules 8 and 9
140 HashMap<String, String> mergeMap;
141 mergeMap = new HashMap<String, String>();
143 mergeMap.put("foo", "merge");
144 setupCase(null, mergeMap, idxMap);
145 go();
147 assertTrue(readTree.updated.isEmpty());
148 assertTrue(readTree.removed.isEmpty());
149 assertTrue(readTree.conflicts.contains("foo"));
151 // rule 10
153 HashMap<String, String> headMap = new HashMap<String, String>();
154 headMap.put("foo", "foo");
155 setupCase(headMap, null, idxMap);
156 go();
158 assertTrue(readTree.removed.contains("foo"));
159 assertTrue(readTree.updated.isEmpty());
160 assertTrue(readTree.conflicts.isEmpty());
162 // rule 11
163 setupCase(headMap, null, idxMap);
164 new File(trash, "foo").delete();
165 writeTrashFile("foo", "bar");
166 index.getMembers()[0].forceRecheck();
167 go();
169 assertTrue(readTree.removed.isEmpty());
170 assertTrue(readTree.updated.isEmpty());
171 assertTrue(readTree.conflicts.contains("foo"));
173 // rule 12 & 13
174 headMap.put("foo", "head");
175 setupCase(headMap, null, idxMap);
176 go();
178 assertTrue(readTree.removed.isEmpty());
179 assertTrue(readTree.updated.isEmpty());
180 assertTrue(readTree.conflicts.contains("foo"));
182 // rules 14 & 15
183 setupCase(headMap, headMap, idxMap);
184 go();
186 assertAllEmpty();
188 // rules 16 & 17
189 setupCase(headMap, mergeMap, idxMap); go();
190 assertTrue(readTree.conflicts.contains("foo"));
192 // rules 18 & 19
193 setupCase(headMap, idxMap, idxMap); go();
194 assertAllEmpty();
196 // rule 20
197 setupCase(idxMap, mergeMap, idxMap); go();
198 assertTrue(readTree.updated.containsKey("foo"));
200 // rules 21
201 setupCase(idxMap, mergeMap, idxMap);
202 new File(trash, "foo").delete();
203 writeTrashFile("foo", "bar");
204 index.getMembers()[0].forceRecheck();
205 go();
206 assertTrue(readTree.conflicts.contains("foo"));
209 private void assertAllEmpty() {
210 assertTrue(readTree.removed.isEmpty());
211 assertTrue(readTree.updated.isEmpty());
212 assertTrue(readTree.conflicts.isEmpty());
215 public void testDirectoryFileSimple() throws IOException {
216 index = new GitIndex(db);
217 index.add(trash, writeTrashFile("DF", "DF"));
218 Tree treeDF = db.mapTree(index.writeTree());
220 recursiveDelete(new File(trash, "DF"));
221 index = new GitIndex(db);
222 index.add(trash, writeTrashFile("DF/DF", "DF/DF"));
223 Tree treeDFDF = db.mapTree(index.writeTree());
225 index = new GitIndex(db);
226 recursiveDelete(new File(trash, "DF"));
228 index.add(trash, writeTrashFile("DF", "DF"));
229 readTree = new WorkDirCheckout(db, trash, treeDF, index, treeDFDF);
230 readTree.prescanTwoTrees();
232 assertTrue(readTree.removed.contains("DF"));
233 assertTrue(readTree.updated.containsKey("DF/DF"));
235 recursiveDelete(new File(trash, "DF"));
236 index = new GitIndex(db);
237 index.add(trash, writeTrashFile("DF/DF", "DF/DF"));
239 readTree = new WorkDirCheckout(db, trash, treeDFDF, index, treeDF);
240 readTree.prescanTwoTrees();
241 assertTrue(readTree.removed.contains("DF/DF"));
242 assertTrue(readTree.updated.containsKey("DF"));
246 * Directory/File Conflict cases:
247 * It's entirely possible that in practice a number of these may be equivalent
248 * to the cases described in git-read-tree.txt. As long as it does the right thing,
249 * that's all I care about. These are basically reverse-engineered from
250 * what git currently does. If there are tests for these in git, it's kind of
251 * hard to track them all down...
253 * H I M Clean H==M H==I I==M Result
254 * ------------------------------------------------------------------
255 *1 D D F Y N Y N Update
256 *2 D D F N N Y N Conflict
257 *3 D F D Y N N Update
258 *4 D F D N N N Update
259 *5 D F F Y N N Y Keep
260 *6 D F F N N N Y Keep
261 *7 F D F Y Y N N Update
262 *8 F D F N Y N N Conflict
263 *9 F D F Y N N N Update
264 *10 F D D N N Y Keep
265 *11 F D D N N N Conflict
266 *12 F F D Y N Y N Update
267 *13 F F D N N Y N Conflict
268 *14 F F D N N N Conflict
269 *15 0 F D N N N Conflict
270 *16 0 D F Y N N N Update
271 *17 0 D F N N N Conflict
272 *18 F 0 D Update
273 *19 D 0 F Update
276 public void testDirectoryFileConflicts_1() throws Exception {
277 // 1
278 doit(mk("DF/DF"), mk("DF"), mk("DF/DF"));
279 assertNoConflicts();
280 assertUpdated("DF");
281 assertRemoved("DF/DF");
284 public void testDirectoryFileConflicts_2() throws Exception {
285 // 2
286 setupCase(mk("DF/DF"), mk("DF"), mk("DF/DF"));
287 writeTrashFile("DF/DF", "different");
288 go();
289 assertConflict("DF/DF");
293 public void testDirectoryFileConflicts_3() throws Exception {
294 // 3 - the first to break!
295 doit(mk("DF/DF"), mk("DF/DF"), mk("DF"));
296 assertUpdated("DF/DF");
297 assertRemoved("DF");
300 public void testDirectoryFileConflicts_4() throws Exception {
301 // 4 (basically same as 3, just with H and M different)
302 doit(mk("DF/DF"), mkmap("DF/DF", "foo"), mk("DF"));
303 assertUpdated("DF/DF");
304 assertRemoved("DF");
308 public void testDirectoryFileConflicts_5() throws Exception {
309 // 5
310 doit(mk("DF/DF"), mk("DF"), mk("DF"));
311 assertRemoved("DF/DF");
315 public void testDirectoryFileConflicts_6() throws Exception {
316 // 6
317 setupCase(mk("DF/DF"), mk("DF"), mk("DF"));
318 writeTrashFile("DF", "different");
319 go();
320 assertRemoved("DF/DF");
323 public void testDirectoryFileConflicts_7() throws Exception {
324 // 7
325 doit(mk("DF"), mk("DF"), mk("DF/DF"));
326 assertUpdated("DF");
327 assertRemoved("DF/DF");
329 cleanUpDF();
330 setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
331 go();
332 assertRemoved("DF/DF/DF/DF/DF");
333 assertUpdated("DF/DF");
335 cleanUpDF();
336 setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
337 writeTrashFile("DF/DF/DF/DF/DF", "diff");
338 go();
339 assertConflict("DF/DF/DF/DF/DF");
340 assertUpdated("DF/DF");
344 // 8 ?
346 public void testDirectoryFileConflicts_9() throws Exception {
347 // 9
348 doit(mk("DF"), mkmap("DF", "QP"), mk("DF/DF"));
349 assertRemoved("DF/DF");
350 assertUpdated("DF");
353 public void testDirectoryFileConflicts_10() throws Exception {
354 // 10
355 cleanUpDF();
356 doit(mk("DF"), mk("DF/DF"), mk("DF/DF"));
357 assertNoConflicts();
361 public void testDirectoryFileConflicts_11() throws Exception {
362 // 11
363 doit(mk("DF"), mk("DF/DF"), mkmap("DF/DF", "asdf"));
364 assertConflict("DF/DF");
367 public void testDirectoryFileConflicts_12() throws Exception {
368 // 12
369 cleanUpDF();
370 doit(mk("DF"), mk("DF/DF"), mk("DF"));
371 assertRemoved("DF");
372 assertUpdated("DF/DF");
375 public void testDirectoryFileConflicts_13() throws Exception {
376 // 13
377 cleanUpDF();
378 setupCase(mk("DF"), mk("DF/DF"), mk("DF"));
379 writeTrashFile("DF", "asdfsdf");
380 go();
381 assertConflict("DF");
382 assertUpdated("DF/DF");
385 public void testDirectoryFileConflicts_14() throws Exception {
386 // 14
387 cleanUpDF();
388 doit(mk("DF"), mk("DF/DF"), mkmap("DF", "Foo"));
389 assertConflict("DF");
390 assertUpdated("DF/DF");
393 public void testDirectoryFileConflicts_15() throws Exception {
394 // 15
395 doit(mkmap(), mk("DF/DF"), mk("DF"));
396 assertRemoved("DF");
397 assertUpdated("DF/DF");
400 public void testDirectoryFileConflicts_15b() throws Exception {
401 // 15, take 2, just to check multi-leveled
402 doit(mkmap(), mk("DF/DF/DF/DF"), mk("DF"));
403 assertRemoved("DF");
404 assertUpdated("DF/DF/DF/DF");
407 public void testDirectoryFileConflicts_16() throws Exception {
408 // 16
409 cleanUpDF();
410 doit(mkmap(), mk("DF"), mk("DF/DF/DF"));
411 assertRemoved("DF/DF/DF");
412 assertUpdated("DF");
415 public void testDirectoryFileConflicts_17() throws Exception {
416 // 17
417 cleanUpDF();
418 setupCase(mkmap(), mk("DF"), mk("DF/DF/DF"));
419 writeTrashFile("DF/DF/DF", "asdf");
420 go();
421 assertConflict("DF/DF/DF");
422 assertUpdated("DF");
425 public void testDirectoryFileConflicts_18() throws Exception {
426 // 18
427 cleanUpDF();
428 doit(mk("DF/DF"), mk("DF/DF/DF/DF"), null);
429 assertRemoved("DF/DF");
430 assertUpdated("DF/DF/DF/DF");
433 public void testDirectoryFileConflicts_19() throws Exception {
434 // 19
435 cleanUpDF();
436 doit(mk("DF/DF/DF/DF"), mk("DF/DF/DF"), null);
437 assertRemoved("DF/DF/DF/DF");
438 assertUpdated("DF/DF/DF");
441 private void cleanUpDF() throws Exception {
442 tearDown();
443 setUp();
444 recursiveDelete(new File(trash, "DF"));
447 private void assertConflict(String s) {
448 assertTrue(readTree.conflicts.contains(s));
451 private void assertUpdated(String s) {
452 assertTrue(readTree.updated.containsKey(s));
455 private void assertRemoved(String s) {
456 assertTrue(readTree.removed.contains(s));
459 private void assertNoConflicts() {
460 assertTrue(readTree.conflicts.isEmpty());
463 private void doit(HashMap<String, String> h, HashMap<String, String>m,
464 HashMap<String, String> i) throws IOException {
465 setupCase(h, m, i);
466 go();
469 private static HashMap<String, String> mk(String a) {
470 return mkmap(a, a);
473 private static HashMap<String, String> mkmap(String... args) {
474 if ((args.length % 2) > 0)
475 throw new IllegalArgumentException("needs to be pairs");
477 HashMap<String, String> map = new HashMap<String, String>();
478 for (int i = 0; i < args.length; i += 2) {
479 map.put(args[i], args[i+1]);
482 return map;
485 public void testUntrackedConflicts() throws IOException {
486 setupCase(null, mk("foo"), null);
487 writeTrashFile("foo", "foo");
488 go();
490 assertConflict("foo");
492 recursiveDelete(new File(trash, "foo"));
493 setupCase(null, mk("foo"), null);
494 writeTrashFile("foo/bar/baz", "");
495 writeTrashFile("foo/blahblah", "");
496 go();
498 assertConflict("foo/bar/baz");
499 assertConflict("foo/blahblah");
501 recursiveDelete(new File(trash, "foo"));
503 setupCase(mkmap("foo/bar", "", "foo/baz", ""),
504 mk("foo"), mkmap("foo/bar", "", "foo/baz", ""));
505 assertTrue(new File(trash, "foo/bar").exists());
506 go();
508 assertNoConflicts();
511 public void testCloseNameConflictsX0() throws IOException {
512 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") );
513 checkout();
514 go();
515 assertNoConflicts();
518 public void testCloseNameConflicts1() throws IOException {
519 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") );
520 checkout();
521 go();
522 assertNoConflicts();
525 private void checkout() throws IOException {
526 readTree = new WorkDirCheckout(db, trash, head, index, merge);
527 readTree.checkout();
530 public void testCheckoutOutChanges() throws IOException {
531 setupCase(mk("foo"), mk("foo/bar"), mk("foo"));
532 checkout();
534 assertFalse(new File(trash, "foo").isFile());
535 assertTrue(new File(trash, "foo/bar").isFile());
536 recursiveDelete(new File(trash, "foo"));
538 setupCase(mk("foo/bar"), mk("foo"), mk("foo/bar"));
539 checkout();
541 assertFalse(new File(trash, "foo/bar").isFile());
542 assertTrue(new File(trash, "foo").isFile());
544 setupCase(mk("foo"), mkmap("foo", "qux"), mkmap("foo", "bar"));
546 try {
547 checkout();
548 fail("did not throw exception");
549 } catch (CheckoutConflictException e) {
550 // should have thrown