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.assertFalse;
48 import static org.junit.Assert.assertNotNull;
49 import static org.junit.Assert.assertNotSame;
50 import static org.junit.Assert.assertNull;
51 import static org.junit.Assert.assertSame;
52 import static org.junit.Assert.assertTrue;
53
54 import java.io.IOException;
55 import java.util.Iterator;
56
57 import org.eclipse.jgit.junit.RepositoryTestCase;
58 import org.eclipse.jgit.junit.TestRepository;
59 import org.eclipse.jgit.lib.CommitBuilder;
60 import org.eclipse.jgit.lib.Constants;
61 import org.eclipse.jgit.lib.MutableObjectId;
62 import org.eclipse.jgit.lib.ObjectInserter;
63 import org.eclipse.jgit.lib.ObjectReader;
64 import org.eclipse.jgit.lib.Repository;
65 import org.eclipse.jgit.revwalk.RevBlob;
66 import org.eclipse.jgit.revwalk.RevCommit;
67 import org.eclipse.jgit.revwalk.RevTree;
68 import org.eclipse.jgit.treewalk.TreeWalk;
69 import org.eclipse.jgit.util.RawParseUtils;
70 import org.junit.After;
71 import org.junit.Before;
72 import org.junit.Test;
73
74 public class NoteMapTest extends RepositoryTestCase {
75 private TestRepository<Repository> tr;
76
77 private ObjectReader reader;
78
79 private ObjectInserter inserter;
80
81 @Override
82 @Before
83 public void setUp() throws Exception {
84 super.setUp();
85
86 tr = new TestRepository<Repository>(db);
87 reader = db.newObjectReader();
88 inserter = db.newObjectInserter();
89 }
90
91 @Override
92 @After
93 public void tearDown() throws Exception {
94 reader.close();
95 inserter.close();
96 super.tearDown();
97 }
98
99 @Test
100 public void testReadFlatTwoNotes() throws Exception {
101 RevBlob a = tr.blob("a");
102 RevBlob b = tr.blob("b");
103 RevBlob data1 = tr.blob("data1");
104 RevBlob data2 = tr.blob("data2");
105
106 RevCommit r = tr.commit()
107 .add(a.name(), data1)
108 .add(b.name(), data2)
109 .create();
110 tr.parseBody(r);
111
112 NoteMap map = NoteMap.read(reader, r);
113 assertNotNull("have map", map);
114
115 assertTrue("has note for a", map.contains(a));
116 assertTrue("has note for b", map.contains(b));
117 assertEquals(data1, map.get(a));
118 assertEquals(data2, map.get(b));
119
120 assertFalse("no note for data1", map.contains(data1));
121 assertNull("no note for data1", map.get(data1));
122 }
123
124 @Test
125 public void testReadFanout2_38() throws Exception {
126 RevBlob a = tr.blob("a");
127 RevBlob b = tr.blob("b");
128 RevBlob data1 = tr.blob("data1");
129 RevBlob data2 = tr.blob("data2");
130
131 RevCommit r = tr.commit()
132 .add(fanout(2, a.name()), data1)
133 .add(fanout(2, b.name()), data2)
134 .create();
135 tr.parseBody(r);
136
137 NoteMap map = NoteMap.read(reader, r);
138 assertNotNull("have map", map);
139
140 assertTrue("has note for a", map.contains(a));
141 assertTrue("has note for b", map.contains(b));
142 assertEquals(data1, map.get(a));
143 assertEquals(data2, map.get(b));
144
145 assertFalse("no note for data1", map.contains(data1));
146 assertNull("no note for data1", map.get(data1));
147 }
148
149 @Test
150 public void testReadFanout2_2_36() throws Exception {
151 RevBlob a = tr.blob("a");
152 RevBlob b = tr.blob("b");
153 RevBlob data1 = tr.blob("data1");
154 RevBlob data2 = tr.blob("data2");
155
156 RevCommit r = tr.commit()
157 .add(fanout(4, a.name()), data1)
158 .add(fanout(4, b.name()), data2)
159 .create();
160 tr.parseBody(r);
161
162 NoteMap map = NoteMap.read(reader, r);
163 assertNotNull("have map", map);
164
165 assertTrue("has note for a", map.contains(a));
166 assertTrue("has note for b", map.contains(b));
167 assertEquals(data1, map.get(a));
168 assertEquals(data2, map.get(b));
169
170 assertFalse("no note for data1", map.contains(data1));
171 assertNull("no note for data1", map.get(data1));
172 }
173
174 @Test
175 public void testReadFullyFannedOut() throws Exception {
176 RevBlob a = tr.blob("a");
177 RevBlob b = tr.blob("b");
178 RevBlob data1 = tr.blob("data1");
179 RevBlob data2 = tr.blob("data2");
180
181 RevCommit r = tr.commit()
182 .add(fanout(38, a.name()), data1)
183 .add(fanout(38, b.name()), data2)
184 .create();
185 tr.parseBody(r);
186
187 NoteMap map = NoteMap.read(reader, r);
188 assertNotNull("have map", map);
189
190 assertTrue("has note for a", map.contains(a));
191 assertTrue("has note for b", map.contains(b));
192 assertEquals(data1, map.get(a));
193 assertEquals(data2, map.get(b));
194
195 assertFalse("no note for data1", map.contains(data1));
196 assertNull("no note for data1", map.get(data1));
197 }
198
199 @Test
200 public void testGetCachedBytes() throws Exception {
201 final String exp = "this is test data";
202 RevBlob a = tr.blob("a");
203 RevBlob data = tr.blob(exp);
204
205 RevCommit r = tr.commit()
206 .add(a.name(), data)
207 .create();
208 tr.parseBody(r);
209
210 NoteMap map = NoteMap.read(reader, r);
211 byte[] act = map.getCachedBytes(a, exp.length() * 4);
212 assertNotNull("has data for a", act);
213 assertEquals(exp, RawParseUtils.decode(act));
214 }
215
216 @Test
217 public void testWriteUnchangedFlat() throws Exception {
218 RevBlob a = tr.blob("a");
219 RevBlob b = tr.blob("b");
220 RevBlob data1 = tr.blob("data1");
221 RevBlob data2 = tr.blob("data2");
222
223 RevCommit r = tr.commit()
224 .add(a.name(), data1)
225 .add(b.name(), data2)
226 .add(".gitignore", "")
227 .add("zoo-animals.txt", "")
228 .create();
229 tr.parseBody(r);
230
231 NoteMap map = NoteMap.read(reader, r);
232 assertTrue("has note for a", map.contains(a));
233 assertTrue("has note for b", map.contains(b));
234
235 RevCommit n = commitNoteMap(map);
236 assertNotSame("is new commit", r, n);
237 assertSame("same tree", r.getTree(), n.getTree());
238 }
239
240 @Test
241 public void testWriteUnchangedFanout2_38() throws Exception {
242 RevBlob a = tr.blob("a");
243 RevBlob b = tr.blob("b");
244 RevBlob data1 = tr.blob("data1");
245 RevBlob data2 = tr.blob("data2");
246
247 RevCommit r = tr.commit()
248 .add(fanout(2, a.name()), data1)
249 .add(fanout(2, b.name()), data2)
250 .add(".gitignore", "")
251 .add("zoo-animals.txt", "")
252 .create();
253 tr.parseBody(r);
254
255 NoteMap map = NoteMap.read(reader, r);
256 assertTrue("has note for a", map.contains(a));
257 assertTrue("has note for b", map.contains(b));
258
259
260 RevCommit n = commitNoteMap(map);
261 assertNotSame("is new commit", r, n);
262 assertSame("same tree", r.getTree(), n.getTree());
263
264
265 map = NoteMap.read(reader, r);
266 n = commitNoteMap(map);
267 assertNotSame("is new commit", r, n);
268 assertSame("same tree", r.getTree(), n.getTree());
269 }
270
271 @Test
272 public void testCreateFromEmpty() throws Exception {
273 RevBlob a = tr.blob("a");
274 RevBlob b = tr.blob("b");
275 RevBlob data1 = tr.blob("data1");
276 RevBlob data2 = tr.blob("data2");
277
278 NoteMap map = NoteMap.newEmptyMap();
279 assertFalse("no a", map.contains(a));
280 assertFalse("no b", map.contains(b));
281
282 map.set(a, data1);
283 map.set(b, data2);
284
285 assertEquals(data1, map.get(a));
286 assertEquals(data2, map.get(b));
287
288 map.remove(a);
289 map.remove(b);
290
291 assertFalse("no a", map.contains(a));
292 assertFalse("no b", map.contains(b));
293
294 map.set(a, "data1", inserter);
295 assertEquals(data1, map.get(a));
296
297 map.set(a, null, inserter);
298 assertFalse("no a", map.contains(a));
299 }
300
301 @Test
302 public void testEditFlat() throws Exception {
303 RevBlob a = tr.blob("a");
304 RevBlob b = tr.blob("b");
305 RevBlob data1 = tr.blob("data1");
306 RevBlob data2 = tr.blob("data2");
307
308 RevCommit r = tr.commit()
309 .add(a.name(), data1)
310 .add(b.name(), data2)
311 .add(".gitignore", "")
312 .add("zoo-animals.txt", b)
313 .create();
314 tr.parseBody(r);
315
316 NoteMap map = NoteMap.read(reader, r);
317 map.set(a, data2);
318 map.set(b, null);
319 map.set(data1, b);
320 map.set(data2, null);
321
322 assertEquals(data2, map.get(a));
323 assertEquals(b, map.get(data1));
324 assertFalse("no b", map.contains(b));
325 assertFalse("no data2", map.contains(data2));
326
327 MutableObjectId id = new MutableObjectId();
328 for (int p = 42; p > 0; p--) {
329 id.setByte(1, p);
330 map.set(id, data1);
331 }
332
333 for (int p = 42; p > 0; p--) {
334 id.setByte(1, p);
335 assertTrue("contains " + id, map.contains(id));
336 }
337
338 RevCommit n = commitNoteMap(map);
339 map = NoteMap.read(reader, n);
340 assertEquals(data2, map.get(a));
341 assertEquals(b, map.get(data1));
342 assertFalse("no b", map.contains(b));
343 assertFalse("no data2", map.contains(data2));
344 assertEquals(b, TreeWalk
345 .forPath(reader, "zoo-animals.txt", n.getTree()).getObjectId(0));
346 }
347
348 @Test
349 public void testEditFanout2_38() throws Exception {
350 RevBlob a = tr.blob("a");
351 RevBlob b = tr.blob("b");
352 RevBlob data1 = tr.blob("data1");
353 RevBlob data2 = tr.blob("data2");
354
355 RevCommit r = tr.commit()
356 .add(fanout(2, a.name()), data1)
357 .add(fanout(2, b.name()), data2)
358 .add(".gitignore", "")
359 .add("zoo-animals.txt", b)
360 .create();
361 tr.parseBody(r);
362
363 NoteMap map = NoteMap.read(reader, r);
364 map.set(a, data2);
365 map.set(b, null);
366 map.set(data1, b);
367 map.set(data2, null);
368
369 assertEquals(data2, map.get(a));
370 assertEquals(b, map.get(data1));
371 assertFalse("no b", map.contains(b));
372 assertFalse("no data2", map.contains(data2));
373 RevCommit n = commitNoteMap(map);
374
375 map.set(a, null);
376 map.set(data1, null);
377 assertFalse("no a", map.contains(a));
378 assertFalse("no data1", map.contains(data1));
379
380 map = NoteMap.read(reader, n);
381 assertEquals(data2, map.get(a));
382 assertEquals(b, map.get(data1));
383 assertFalse("no b", map.contains(b));
384 assertFalse("no data2", map.contains(data2));
385 assertEquals(b, TreeWalk
386 .forPath(reader, "zoo-animals.txt", n.getTree()).getObjectId(0));
387 }
388
389 @Test
390 public void testLeafSplitsWhenFull() throws Exception {
391 RevBlob data1 = tr.blob("data1");
392 MutableObjectId idBuf = new MutableObjectId();
393
394 RevCommit r = tr.commit()
395 .add(data1.name(), data1)
396 .create();
397 tr.parseBody(r);
398
399 NoteMap map = NoteMap.read(reader, r);
400 for (int i = 0; i < 254; i++) {
401 idBuf.setByte(Constants.OBJECT_ID_LENGTH - 1, i);
402 map.set(idBuf, data1);
403 }
404
405 RevCommit n = commitNoteMap(map);
406 TreeWalk tw = new TreeWalk(reader);
407 tw.reset(n.getTree());
408 while (tw.next())
409 assertFalse("no fan-out subtree", tw.isSubtree());
410
411 for (int i = 254; i < 256; i++) {
412 idBuf.setByte(Constants.OBJECT_ID_LENGTH - 1, i);
413 map.set(idBuf, data1);
414 }
415 idBuf.setByte(Constants.OBJECT_ID_LENGTH - 2, 1);
416 map.set(idBuf, data1);
417 n = commitNoteMap(map);
418
419
420 String path = fanout(38, idBuf.name());
421 tw = TreeWalk.forPath(reader, path, n.getTree());
422 assertNotNull("has " + path, tw);
423
424
425 path = fanout(2, data1.name());
426 tw = TreeWalk.forPath(reader, path, n.getTree());
427 assertNotNull("has " + path, tw);
428 }
429
430 @Test
431 public void testRemoveDeletesTreeFanout2_38() throws Exception {
432 RevBlob a = tr.blob("a");
433 RevBlob data1 = tr.blob("data1");
434 RevTree empty = tr.tree();
435
436 RevCommit r = tr.commit()
437 .add(fanout(2, a.name()), data1)
438 .create();
439 tr.parseBody(r);
440
441 NoteMap map = NoteMap.read(reader, r);
442 map.set(a, null);
443
444 RevCommit n = commitNoteMap(map);
445 assertEquals("empty tree", empty, n.getTree());
446 }
447
448 public void testIteratorEmptyMap() {
449 Iterator<Note> it = NoteMap.newEmptyMap().iterator();
450 assertFalse(it.hasNext());
451 }
452
453 public void testIteratorFlatTree() throws Exception {
454 RevBlob a = tr.blob("a");
455 RevBlob b = tr.blob("b");
456 RevBlob data1 = tr.blob("data1");
457 RevBlob data2 = tr.blob("data2");
458 RevBlob nonNote = tr.blob("non note");
459
460 RevCommit r = tr.commit()
461 .add(a.name(), data1)
462 .add(b.name(), data2)
463 .add("nonNote", nonNote)
464 .create();
465 tr.parseBody(r);
466
467 Iterator it = NoteMap.read(reader, r).iterator();
468 assertEquals(2, count(it));
469 }
470
471 public void testIteratorFanoutTree2_38() throws Exception {
472 RevBlob a = tr.blob("a");
473 RevBlob b = tr.blob("b");
474 RevBlob data1 = tr.blob("data1");
475 RevBlob data2 = tr.blob("data2");
476 RevBlob nonNote = tr.blob("non note");
477
478 RevCommit r = tr.commit()
479 .add(fanout(2, a.name()), data1)
480 .add(fanout(2, b.name()), data2)
481 .add("nonNote", nonNote)
482 .create();
483 tr.parseBody(r);
484
485 Iterator it = NoteMap.read(reader, r).iterator();
486 assertEquals(2, count(it));
487 }
488
489 public void testIteratorFanoutTree2_2_36() throws Exception {
490 RevBlob a = tr.blob("a");
491 RevBlob b = tr.blob("b");
492 RevBlob data1 = tr.blob("data1");
493 RevBlob data2 = tr.blob("data2");
494 RevBlob nonNote = tr.blob("non note");
495
496 RevCommit r = tr.commit()
497 .add(fanout(4, a.name()), data1)
498 .add(fanout(4, b.name()), data2)
499 .add("nonNote", nonNote)
500 .create();
501 tr.parseBody(r);
502
503 Iterator it = NoteMap.read(reader, r).iterator();
504 assertEquals(2, count(it));
505 }
506
507 public void testIteratorFullyFannedOut() throws Exception {
508 RevBlob a = tr.blob("a");
509 RevBlob b = tr.blob("b");
510 RevBlob data1 = tr.blob("data1");
511 RevBlob data2 = tr.blob("data2");
512 RevBlob nonNote = tr.blob("non note");
513
514 RevCommit r = tr.commit()
515 .add(fanout(38, a.name()), data1)
516 .add(fanout(38, b.name()), data2)
517 .add("nonNote", nonNote)
518 .create();
519 tr.parseBody(r);
520
521 Iterator it = NoteMap.read(reader, r).iterator();
522 assertEquals(2, count(it));
523 }
524
525 public void testShorteningNoteRefName() throws Exception {
526 String expectedShortName = "review";
527 String noteRefName = Constants.R_NOTES + expectedShortName;
528 assertEquals(expectedShortName, NoteMap.shortenRefName(noteRefName));
529 String nonNoteRefName = Constants.R_HEADS + expectedShortName;
530 assertEquals(nonNoteRefName, NoteMap.shortenRefName(expectedShortName));
531 }
532
533 private RevCommit commitNoteMap(NoteMap map) throws IOException {
534 tr.tick(600);
535
536 CommitBuilder builder = new CommitBuilder();
537 builder.setTreeId(map.writeTree(inserter));
538 tr.setAuthorAndCommitter(builder);
539 return tr.getRevWalk().parseCommit(inserter.insert(builder));
540 }
541
542 private static String fanout(int prefix, String name) {
543 StringBuilder r = new StringBuilder();
544 int i = 0;
545 for (; i < prefix && i < name.length(); i += 2) {
546 if (i != 0)
547 r.append('/');
548 r.append(name.charAt(i + 0));
549 r.append(name.charAt(i + 1));
550 }
551 if (i < name.length()) {
552 if (i != 0)
553 r.append('/');
554 r.append(name.substring(i));
555 }
556 return r.toString();
557 }
558
559 private static int count(Iterator it) {
560 int c = 0;
561 while (it.hasNext()) {
562 c++;
563 it.next();
564 }
565 return c;
566 }
567 }