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