1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.notes;
45
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertTrue;
48 import static org.junit.Assert.fail;
49
50 import java.io.IOException;
51 import java.util.Iterator;
52
53 import org.eclipse.jgit.junit.RepositoryTestCase;
54 import org.eclipse.jgit.junit.TestRepository;
55 import org.eclipse.jgit.lib.ObjectInserter;
56 import org.eclipse.jgit.lib.ObjectReader;
57 import org.eclipse.jgit.lib.Repository;
58 import org.eclipse.jgit.merge.MergeStrategy;
59 import org.eclipse.jgit.revwalk.RevBlob;
60 import org.eclipse.jgit.revwalk.RevCommit;
61 import org.junit.After;
62 import org.junit.Before;
63 import org.junit.Test;
64
65 public class NoteMapMergerTest extends RepositoryTestCase {
66 private TestRepository<Repository> tr;
67
68 private ObjectReader reader;
69
70 private ObjectInserter inserter;
71
72 private NoteMap noRoot;
73
74 private NoteMap empty;
75
76 private NoteMap map_a;
77
78 private NoteMap map_a_b;
79
80 private RevBlob noteAId;
81
82 private String noteAContent;
83
84 private RevBlob noteABlob;
85
86 private RevBlob noteBId;
87
88 private String noteBContent;
89
90 private RevBlob noteBBlob;
91
92 private RevCommit sampleTree_a;
93
94 private RevCommit sampleTree_a_b;
95
96 @Override
97 @Before
98 public void setUp() throws Exception {
99 super.setUp();
100 tr = new TestRepository<>(db);
101 reader = db.newObjectReader();
102 inserter = db.newObjectInserter();
103
104 noRoot = NoteMap.newMap(null, reader);
105 empty = NoteMap.newEmptyMap();
106
107 noteAId = tr.blob("a");
108 noteAContent = "noteAContent";
109 noteABlob = tr.blob(noteAContent);
110 sampleTree_a = tr.commit()
111 .add(noteAId.name(), noteABlob)
112 .create();
113 tr.parseBody(sampleTree_a);
114 map_a = NoteMap.read(reader, sampleTree_a);
115
116 noteBId = tr.blob("b");
117 noteBContent = "noteBContent";
118 noteBBlob = tr.blob(noteBContent);
119 sampleTree_a_b = tr.commit()
120 .add(noteAId.name(), noteABlob)
121 .add(noteBId.name(), noteBBlob)
122 .create();
123 tr.parseBody(sampleTree_a_b);
124 map_a_b = NoteMap.read(reader, sampleTree_a_b);
125 }
126
127 @Override
128 @After
129 public void tearDown() throws Exception {
130 reader.close();
131 inserter.close();
132 super.tearDown();
133 }
134
135 @Test
136 public void testNoChange() throws IOException {
137 NoteMapMerger merger = new NoteMapMerger(db, null, null);
138 NoteMap result;
139
140 assertEquals(0, countNotes(merger.merge(noRoot, noRoot, noRoot)));
141 assertEquals(0, countNotes(merger.merge(empty, empty, empty)));
142
143 result = merger.merge(map_a, map_a, map_a);
144 assertEquals(1, countNotes(result));
145 assertEquals(noteABlob, result.get(noteAId));
146 }
147
148 @Test
149 public void testOursEqualsTheirs() throws Exception {
150 NoteMapMerger merger = new NoteMapMerger(db, null, null);
151 NoteMap result;
152
153 assertEquals(0, countNotes(merger.merge(empty, noRoot, noRoot)));
154 assertEquals(0, countNotes(merger.merge(map_a, noRoot, noRoot)));
155
156 assertEquals(0, countNotes(merger.merge(noRoot, empty, empty)));
157 assertEquals(0, countNotes(merger.merge(map_a, empty, empty)));
158
159 result = merger.merge(noRoot, map_a, map_a);
160 assertEquals(1, countNotes(result));
161 assertEquals(noteABlob, result.get(noteAId));
162
163 result = merger.merge(empty, map_a, map_a);
164 assertEquals(1, countNotes(result));
165 assertEquals(noteABlob, result.get(noteAId));
166
167 result = merger.merge(map_a_b, map_a, map_a);
168 assertEquals(1, countNotes(result));
169 assertEquals(noteABlob, result.get(noteAId));
170
171 result = merger.merge(map_a, map_a_b, map_a_b);
172 assertEquals(2, countNotes(result));
173 assertEquals(noteABlob, result.get(noteAId));
174 assertEquals(noteBBlob, result.get(noteBId));
175 }
176
177 @Test
178 public void testBaseEqualsOurs() throws Exception {
179 NoteMapMerger merger = new NoteMapMerger(db, null, null);
180 NoteMap result;
181
182 assertEquals(0, countNotes(merger.merge(noRoot, noRoot, empty)));
183 result = merger.merge(noRoot, noRoot, map_a);
184 assertEquals(1, countNotes(result));
185 assertEquals(noteABlob, result.get(noteAId));
186
187 assertEquals(0, countNotes(merger.merge(empty, empty, noRoot)));
188 result = merger.merge(empty, empty, map_a);
189 assertEquals(1, countNotes(result));
190 assertEquals(noteABlob, result.get(noteAId));
191
192 assertEquals(0, countNotes(merger.merge(map_a, map_a, noRoot)));
193 assertEquals(0, countNotes(merger.merge(map_a, map_a, empty)));
194 result = merger.merge(map_a, map_a, map_a_b);
195 assertEquals(2, countNotes(result));
196 assertEquals(noteABlob, result.get(noteAId));
197 assertEquals(noteBBlob, result.get(noteBId));
198 }
199
200 @Test
201 public void testBaseEqualsTheirs() throws Exception {
202 NoteMapMerger merger = new NoteMapMerger(db, null, null);
203 NoteMap result;
204
205 assertEquals(0, countNotes(merger.merge(noRoot, empty, noRoot)));
206 result = merger.merge(noRoot, map_a, noRoot);
207 assertEquals(1, countNotes(result));
208 assertEquals(noteABlob, result.get(noteAId));
209
210 assertEquals(0, countNotes(merger.merge(empty, noRoot, empty)));
211 result = merger.merge(empty, map_a, empty);
212 assertEquals(1, countNotes(result));
213 assertEquals(noteABlob, result.get(noteAId));
214
215 assertEquals(0, countNotes(merger.merge(map_a, noRoot, map_a)));
216 assertEquals(0, countNotes(merger.merge(map_a, empty, map_a)));
217 result = merger.merge(map_a, map_a_b, map_a);
218 assertEquals(2, countNotes(result));
219 assertEquals(noteABlob, result.get(noteAId));
220 assertEquals(noteBBlob, result.get(noteBId));
221 }
222
223 @Test
224 public void testAddDifferentNotes() throws Exception {
225 NoteMapMerger merger = new NoteMapMerger(db, null, null);
226 NoteMap result;
227
228 NoteMap map_a_c = NoteMap.read(reader, sampleTree_a);
229 RevBlob noteCId = tr.blob("c");
230 RevBlob noteCBlob = tr.blob("noteCContent");
231 map_a_c.set(noteCId, noteCBlob);
232 map_a_c.writeTree(inserter);
233
234 result = merger.merge(map_a, map_a_b, map_a_c);
235 assertEquals(3, countNotes(result));
236 assertEquals(noteABlob, result.get(noteAId));
237 assertEquals(noteBBlob, result.get(noteBId));
238 assertEquals(noteCBlob, result.get(noteCId));
239 }
240
241 @Test
242 public void testAddSameNoteDifferentContent() throws Exception {
243 NoteMapMerger merger = new NoteMapMerger(db, new DefaultNoteMerger(),
244 null);
245 NoteMap result;
246
247 NoteMap map_a_b1 = NoteMap.read(reader, sampleTree_a);
248 String noteBContent1 = noteBContent + "change";
249 RevBlob noteBBlob1 = tr.blob(noteBContent1);
250 map_a_b1.set(noteBId, noteBBlob1);
251 map_a_b1.writeTree(inserter);
252
253 result = merger.merge(map_a, map_a_b, map_a_b1);
254 assertEquals(2, countNotes(result));
255 assertEquals(noteABlob, result.get(noteAId));
256 assertEquals(tr.blob(noteBContent + noteBContent1), result.get(noteBId));
257 }
258
259 @Test
260 public void testEditSameNoteDifferentContent() throws Exception {
261 NoteMapMerger merger = new NoteMapMerger(db, new DefaultNoteMerger(),
262 null);
263 NoteMap result;
264
265 NoteMap map_a1 = NoteMap.read(reader, sampleTree_a);
266 String noteAContent1 = noteAContent + "change1";
267 RevBlob noteABlob1 = tr.blob(noteAContent1);
268 map_a1.set(noteAId, noteABlob1);
269 map_a1.writeTree(inserter);
270
271 NoteMap map_a2 = NoteMap.read(reader, sampleTree_a);
272 String noteAContent2 = noteAContent + "change2";
273 RevBlob noteABlob2 = tr.blob(noteAContent2);
274 map_a2.set(noteAId, noteABlob2);
275 map_a2.writeTree(inserter);
276
277 result = merger.merge(map_a, map_a1, map_a2);
278 assertEquals(1, countNotes(result));
279 assertEquals(tr.blob(noteAContent1 + noteAContent2),
280 result.get(noteAId));
281 }
282
283 @Test
284 public void testEditDifferentNotes() throws Exception {
285 NoteMapMerger merger = new NoteMapMerger(db, null, null);
286 NoteMap result;
287
288 NoteMap map_a1_b = NoteMap.read(reader, sampleTree_a_b);
289 String noteAContent1 = noteAContent + "change";
290 RevBlob noteABlob1 = tr.blob(noteAContent1);
291 map_a1_b.set(noteAId, noteABlob1);
292 map_a1_b.writeTree(inserter);
293
294 NoteMap map_a_b1 = NoteMap.read(reader, sampleTree_a_b);
295 String noteBContent1 = noteBContent + "change";
296 RevBlob noteBBlob1 = tr.blob(noteBContent1);
297 map_a_b1.set(noteBId, noteBBlob1);
298 map_a_b1.writeTree(inserter);
299
300 result = merger.merge(map_a_b, map_a1_b, map_a_b1);
301 assertEquals(2, countNotes(result));
302 assertEquals(noteABlob1, result.get(noteAId));
303 assertEquals(noteBBlob1, result.get(noteBId));
304 }
305
306 @Test
307 public void testDeleteDifferentNotes() throws Exception {
308 NoteMapMerger merger = new NoteMapMerger(db, null, null);
309
310 NoteMap map_b = NoteMap.read(reader, sampleTree_a_b);
311 map_b.set(noteAId, null);
312 map_b.writeTree(inserter);
313
314 assertEquals(0, countNotes(merger.merge(map_a_b, map_a, map_b)));
315 }
316
317 @Test
318 public void testEditDeleteConflict() throws Exception {
319 NoteMapMerger merger = new NoteMapMerger(db, new DefaultNoteMerger(),
320 null);
321 NoteMap result;
322
323 NoteMap map_a_b1 = NoteMap.read(reader, sampleTree_a_b);
324 String noteBContent1 = noteBContent + "change";
325 RevBlob noteBBlob1 = tr.blob(noteBContent1);
326 map_a_b1.set(noteBId, noteBBlob1);
327 map_a_b1.writeTree(inserter);
328
329 result = merger.merge(map_a_b, map_a_b1, map_a);
330 assertEquals(2, countNotes(result));
331 assertEquals(noteABlob, result.get(noteAId));
332 assertEquals(noteBBlob1, result.get(noteBId));
333 }
334
335 @Test
336 public void testLargeTreesWithoutConflict() throws Exception {
337 NoteMapMerger merger = new NoteMapMerger(db, null, null);
338 NoteMap map1 = createLargeNoteMap("note_1_", "content_1_", 300, 0);
339 NoteMap map2 = createLargeNoteMap("note_2_", "content_2_", 300, 0);
340
341 NoteMap result = merger.merge(empty, map1, map2);
342 assertEquals(600, countNotes(result));
343
344 assertEquals(tr.blob("content_1_59"), result.get(tr.blob("note_1_59")));
345 assertEquals(tr.blob("content_2_10"), result.get(tr.blob("note_2_10")));
346 assertEquals(tr.blob("content_2_99"), result.get(tr.blob("note_2_99")));
347 }
348
349 @Test
350 public void testLargeTreesWithConflict() throws Exception {
351 NoteMapMerger merger = new NoteMapMerger(db, new DefaultNoteMerger(),
352 null);
353 NoteMap largeTree1 = createLargeNoteMap("note_1_", "content_1_", 300, 0);
354 NoteMap largeTree2 = createLargeNoteMap("note_1_", "content_2_", 300, 0);
355
356 NoteMap result = merger.merge(empty, largeTree1, largeTree2);
357 assertEquals(300, countNotes(result));
358
359 assertEquals(tr.blob("content_1_59content_2_59"),
360 result.get(tr.blob("note_1_59")));
361 assertEquals(tr.blob("content_1_10content_2_10"),
362 result.get(tr.blob("note_1_10")));
363 assertEquals(tr.blob("content_1_99content_2_99"),
364 result.get(tr.blob("note_1_99")));
365 }
366
367 private NoteMap createLargeNoteMap(String noteNamePrefix,
368 String noteContentPrefix, int notesCount, int firstIndex)
369 throws Exception {
370 NoteMap result = NoteMap.newEmptyMap();
371 for (int i = 0; i < notesCount; i++) {
372 result.set(tr.blob(noteNamePrefix + (firstIndex + i)),
373 tr.blob(noteContentPrefix + (firstIndex + i)));
374 }
375 result.writeTree(inserter);
376 return result;
377 }
378
379 @Test
380 public void testFanoutAndLeafWithoutConflict() throws Exception {
381 NoteMapMerger merger = new NoteMapMerger(db, null, null);
382
383 NoteMap largeTree = createLargeNoteMap("note_1_", "content_1_", 300, 0);
384 NoteMap result = merger.merge(map_a, map_a_b, largeTree);
385 assertEquals(301, countNotes(result));
386 }
387
388 @Test
389 public void testFanoutAndLeafWitConflict() throws Exception {
390 NoteMapMerger merger = new NoteMapMerger(db, new DefaultNoteMerger(),
391 null);
392
393 NoteMap largeTree_b1 = createLargeNoteMap("note_1_", "content_1_", 300,
394 0);
395 String noteBContent1 = noteBContent + "change";
396 largeTree_b1.set(noteBId, tr.blob(noteBContent1));
397 largeTree_b1.writeTree(inserter);
398
399 NoteMap result = merger.merge(map_a, map_a_b, largeTree_b1);
400 assertEquals(301, countNotes(result));
401 assertEquals(tr.blob(noteBContent + noteBContent1), result.get(noteBId));
402 }
403
404 @Test
405 public void testCollapseFanoutAfterMerge() throws Exception {
406 NoteMapMerger merger = new NoteMapMerger(db, null, null);
407
408 NoteMap largeTree = createLargeNoteMap("note_", "content_", 257, 0);
409 assertTrue(largeTree.getRoot() instanceof FanoutBucket);
410 NoteMap deleteFirstHundredNotes = createLargeNoteMap("note_", "content_", 157,
411 100);
412 NoteMap deleteLastHundredNotes = createLargeNoteMap("note_",
413 "content_", 157, 0);
414 NoteMap result = merger.merge(largeTree, deleteFirstHundredNotes,
415 deleteLastHundredNotes);
416 assertEquals(57, countNotes(result));
417 assertTrue(result.getRoot() instanceof LeafBucket);
418 }
419
420 @Test
421 public void testNonNotesWithoutNonNoteConflict() throws Exception {
422 NoteMapMerger merger = new NoteMapMerger(db, null,
423 MergeStrategy.RESOLVE);
424 RevCommit treeWithNonNotes =
425 tr.commit()
426 .add(noteAId.name(), noteABlob)
427 .add("a.txt", tr.blob("content of a.txt"))
428 .create();
429 tr.parseBody(treeWithNonNotes);
430 NoteMap base = NoteMap.read(reader, treeWithNonNotes);
431
432 treeWithNonNotes =
433 tr.commit()
434 .add(noteAId.name(), noteABlob)
435 .add("a.txt", tr.blob("content of a.txt"))
436 .add("b.txt", tr.blob("content of b.txt"))
437 .create();
438 tr.parseBody(treeWithNonNotes);
439 NoteMap ours = NoteMap.read(reader, treeWithNonNotes);
440
441 treeWithNonNotes =
442 tr.commit()
443 .add(noteAId.name(), noteABlob)
444 .add("a.txt", tr.blob("content of a.txt"))
445 .add("c.txt", tr.blob("content of c.txt"))
446 .create();
447 tr.parseBody(treeWithNonNotes);
448 NoteMap theirs = NoteMap.read(reader, treeWithNonNotes);
449
450 NoteMap result = merger.merge(base, ours, theirs);
451 assertEquals(3, countNonNotes(result));
452 }
453
454 @Test
455 public void testNonNotesWithNonNoteConflict() throws Exception {
456 NoteMapMerger merger = new NoteMapMerger(db, null,
457 MergeStrategy.RESOLVE);
458 RevCommit treeWithNonNotes =
459 tr.commit()
460 .add(noteAId.name(), noteABlob)
461 .add("a.txt", tr.blob("content of a.txt"))
462 .create();
463 tr.parseBody(treeWithNonNotes);
464 NoteMap base = NoteMap.read(reader, treeWithNonNotes);
465
466 treeWithNonNotes =
467 tr.commit()
468 .add(noteAId.name(), noteABlob)
469 .add("a.txt", tr.blob("change 1"))
470 .create();
471 tr.parseBody(treeWithNonNotes);
472 NoteMap ours = NoteMap.read(reader, treeWithNonNotes);
473
474 treeWithNonNotes =
475 tr.commit()
476 .add(noteAId.name(), noteABlob)
477 .add("a.txt", tr.blob("change 2"))
478 .create();
479 tr.parseBody(treeWithNonNotes);
480 NoteMap theirs = NoteMap.read(reader, treeWithNonNotes);
481
482 try {
483 merger.merge(base, ours, theirs);
484 fail("NotesMergeConflictException was expected");
485 } catch (NotesMergeConflictException e) {
486
487 }
488 }
489
490 private static int countNotes(NoteMap map) {
491 int c = 0;
492 Iterator<Note> it = map.iterator();
493 while (it.hasNext()) {
494 it.next();
495 c++;
496 }
497 return c;
498 }
499
500 private static int countNonNotes(NoteMap map) {
501 int c = 0;
502 NonNoteEntry nonNotes = map.getRoot().nonNotes;
503 while (nonNotes != null) {
504 c++;
505 nonNotes = nonNotes.next;
506 }
507 return c;
508 }
509 }