View Javadoc
1   /*
2    * Copyright (C) 2010, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.diff;
12  
13  import static org.junit.Assert.assertEquals;
14  import static org.junit.Assert.assertSame;
15  import static org.junit.Assert.assertTrue;
16  import static org.junit.Assert.fail;
17  
18  import java.util.Arrays;
19  import java.util.List;
20  
21  import org.eclipse.jgit.lib.AbbreviatedObjectId;
22  import org.eclipse.jgit.lib.FileMode;
23  import org.eclipse.jgit.lib.ObjectId;
24  import org.junit.Before;
25  import org.junit.Test;
26  
27  public class RenameDetectorTest extends AbstractRenameDetectionTestCase {
28  
29  	private RenameDetector rd;
30  
31  	@Override
32  	@Before
33  	public void setUp() throws Exception {
34  		super.setUp();
35  		rd = new RenameDetector(db);
36  	}
37  
38  	@Test
39  	public void testExactRename_OneRename() throws Exception {
40  		ObjectId foo = blob("foo");
41  
42  		DiffEntry a = DiffEntry.add(PATH_A, foo);
43  		DiffEntry b = DiffEntry.delete(PATH_Q, foo);
44  
45  		rd.add(a);
46  		rd.add(b);
47  
48  		List<DiffEntry> entries = rd.compute();
49  		assertEquals(1, entries.size());
50  		assertRename(b, a, 100, entries.get(0));
51  	}
52  
53  	@Test
54  	public void testExactRename_DifferentObjects() throws Exception {
55  		ObjectId foo = blob("foo");
56  		ObjectId bar = blob("bar");
57  
58  		DiffEntry a = DiffEntry.add(PATH_A, foo);
59  		DiffEntry h = DiffEntry.add(PATH_H, foo);
60  		DiffEntry q = DiffEntry.delete(PATH_Q, bar);
61  
62  		rd.add(a);
63  		rd.add(h);
64  		rd.add(q);
65  
66  		List<DiffEntry> entries = rd.compute();
67  		assertEquals(3, entries.size());
68  		assertSame(a, entries.get(0));
69  		assertSame(h, entries.get(1));
70  		assertSame(q, entries.get(2));
71  	}
72  
73  	@Test
74  	public void testExactRename_OneRenameOneModify() throws Exception {
75  		ObjectId foo = blob("foo");
76  		ObjectId bar = blob("bar");
77  
78  		DiffEntry a = DiffEntry.add(PATH_A, foo);
79  		DiffEntry b = DiffEntry.delete(PATH_Q, foo);
80  
81  		DiffEntry c = DiffEntry.modify(PATH_H);
82  		c.newId = c.oldId = AbbreviatedObjectId.fromObjectId(bar);
83  
84  		rd.add(a);
85  		rd.add(b);
86  		rd.add(c);
87  
88  		List<DiffEntry> entries = rd.compute();
89  		assertEquals(2, entries.size());
90  		assertRename(b, a, 100, entries.get(0));
91  		assertSame(c, entries.get(1));
92  	}
93  
94  	@Test
95  	public void testExactRename_ManyRenames() throws Exception {
96  		ObjectId foo = blob("foo");
97  		ObjectId bar = blob("bar");
98  
99  		DiffEntry a = DiffEntry.add(PATH_A, foo);
100 		DiffEntry b = DiffEntry.delete(PATH_Q, foo);
101 
102 		DiffEntry c = DiffEntry.add(PATH_H, bar);
103 		DiffEntry d = DiffEntry.delete(PATH_B, bar);
104 
105 		rd.add(a);
106 		rd.add(b);
107 		rd.add(c);
108 		rd.add(d);
109 
110 		List<DiffEntry> entries = rd.compute();
111 		assertEquals(2, entries.size());
112 		assertRename(b, a, 100, entries.get(0));
113 		assertRename(d, c, 100, entries.get(1));
114 	}
115 
116 	@Test
117 	public void testExactRename_MultipleIdenticalDeletes() throws Exception {
118 		ObjectId foo = blob("foo");
119 
120 		DiffEntry a = DiffEntry.delete(PATH_A, foo);
121 		DiffEntry b = DiffEntry.delete(PATH_B, foo);
122 
123 		DiffEntry c = DiffEntry.delete(PATH_H, foo);
124 		DiffEntry d = DiffEntry.add(PATH_Q, foo);
125 
126 		rd.add(a);
127 		rd.add(b);
128 		rd.add(c);
129 		rd.add(d);
130 
131 		// Pairs the add with the first delete added
132 		List<DiffEntry> entries = rd.compute();
133 		assertEquals(3, entries.size());
134 		assertEquals(b, entries.get(0));
135 		assertEquals(c, entries.get(1));
136 		assertRename(a, d, 100, entries.get(2));
137 	}
138 
139 	@Test
140 	public void testExactRename_PathBreaksTie() throws Exception {
141 		ObjectId foo = blob("foo");
142 
143 		DiffEntry a = DiffEntry.add("src/com/foo/a.java", foo);
144 		DiffEntry b = DiffEntry.delete("src/com/foo/b.java", foo);
145 
146 		DiffEntry c = DiffEntry.add("c.txt", foo);
147 		DiffEntry d = DiffEntry.delete("d.txt", foo);
148 		DiffEntry e = DiffEntry.add("the_e_file.txt", foo);
149 
150 		// Add out of order to avoid first-match succeeding
151 		rd.add(a);
152 		rd.add(d);
153 		rd.add(e);
154 		rd.add(b);
155 		rd.add(c);
156 
157 		List<DiffEntry> entries = rd.compute();
158 		assertEquals(3, entries.size());
159 		assertRename(d, c, 100, entries.get(0));
160 		assertRename(b, a, 100, entries.get(1));
161 		assertCopy(d, e, 100, entries.get(2));
162 	}
163 
164 	@Test
165 	public void testExactRename_OneDeleteManyAdds() throws Exception {
166 		ObjectId foo = blob("foo");
167 
168 		DiffEntry a = DiffEntry.add("src/com/foo/a.java", foo);
169 		DiffEntry b = DiffEntry.add("src/com/foo/b.java", foo);
170 		DiffEntry c = DiffEntry.add("c.txt", foo);
171 
172 		DiffEntry d = DiffEntry.delete("d.txt", foo);
173 
174 		rd.add(a);
175 		rd.add(b);
176 		rd.add(c);
177 		rd.add(d);
178 
179 		List<DiffEntry> entries = rd.compute();
180 		assertEquals(3, entries.size());
181 		assertRename(d, c, 100, entries.get(0));
182 		assertCopy(d, a, 100, entries.get(1));
183 		assertCopy(d, b, 100, entries.get(2));
184 	}
185 
186 	@Test
187 	public void testExactRename_UnstagedFile() throws Exception {
188 		ObjectId aId = blob("foo");
189 		DiffEntry a = DiffEntry.delete(PATH_A, aId);
190 		DiffEntry b = DiffEntry.add(PATH_B, aId);
191 
192 		rd.addAll(Arrays.asList(a, b));
193 		List<DiffEntry> entries = rd.compute();
194 
195 		assertEquals(1, entries.size());
196 		assertRename(a, b, 100, entries.get(0));
197 	}
198 
199 	@Test
200 	public void testInexactRename_OnePair() throws Exception {
201 		ObjectId aId = blob("foo\nbar\nbaz\nblarg\n");
202 		ObjectId bId = blob("foo\nbar\nbaz\nblah\n");
203 
204 		DiffEntry a = DiffEntry.add(PATH_A, aId);
205 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
206 
207 		rd.add(a);
208 		rd.add(b);
209 
210 		List<DiffEntry> entries = rd.compute();
211 		assertEquals(1, entries.size());
212 		assertRename(b, a, 66, entries.get(0));
213 	}
214 
215 	@Test
216 	public void testInexactRename_OneRenameTwoUnrelatedFiles() throws Exception {
217 		ObjectId aId = blob("foo\nbar\nbaz\nblarg\n");
218 		ObjectId bId = blob("foo\nbar\nbaz\nblah\n");
219 		DiffEntry a = DiffEntry.add(PATH_A, aId);
220 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
221 
222 		ObjectId cId = blob("some\nsort\nof\ntext\n");
223 		ObjectId dId = blob("completely\nunrelated\ntext\n");
224 		DiffEntry c = DiffEntry.add(PATH_B, cId);
225 		DiffEntry d = DiffEntry.delete(PATH_H, dId);
226 
227 		rd.add(a);
228 		rd.add(b);
229 		rd.add(c);
230 		rd.add(d);
231 
232 		List<DiffEntry> entries = rd.compute();
233 		assertEquals(3, entries.size());
234 		assertRename(b, a, 66, entries.get(0));
235 		assertSame(c, entries.get(1));
236 		assertSame(d, entries.get(2));
237 	}
238 
239 	@Test
240 	public void testInexactRename_LastByteDifferent() throws Exception {
241 		ObjectId aId = blob("foo\nbar\na");
242 		ObjectId bId = blob("foo\nbar\nb");
243 
244 		DiffEntry a = DiffEntry.add(PATH_A, aId);
245 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
246 
247 		rd.add(a);
248 		rd.add(b);
249 
250 		List<DiffEntry> entries = rd.compute();
251 		assertEquals(1, entries.size());
252 		assertRename(b, a, 88, entries.get(0));
253 	}
254 
255 	@Test
256 	public void testInexactRename_NewlinesOnly() throws Exception {
257 		ObjectId aId = blob("\n\n\n");
258 		ObjectId bId = blob("\n\n\n\n");
259 
260 		DiffEntry a = DiffEntry.add(PATH_A, aId);
261 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
262 
263 		rd.add(a);
264 		rd.add(b);
265 
266 		List<DiffEntry> entries = rd.compute();
267 		assertEquals(1, entries.size());
268 		assertRename(b, a, 74, entries.get(0));
269 	}
270 
271 	@Test
272 	public void testInexactRename_SameContentMultipleTimes() throws Exception {
273 		ObjectId aId = blob("a\na\na\na\n");
274 		ObjectId bId = blob("a\na\na\n");
275 
276 		DiffEntry a = DiffEntry.add(PATH_A, aId);
277 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
278 
279 		rd.add(a);
280 		rd.add(b);
281 
282 		List<DiffEntry> entries = rd.compute();
283 		assertEquals(1, entries.size());
284 		assertRename(b, a, 74, entries.get(0));
285 	}
286 
287 	@Test
288 	public void testInexactRenames_OnePair2() throws Exception {
289 		ObjectId aId = blob("ab\nab\nab\nac\nad\nae\n");
290 		ObjectId bId = blob("ac\nab\nab\nab\naa\na0\na1\n");
291 
292 		DiffEntry a = DiffEntry.add(PATH_A, aId);
293 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
294 
295 		rd.add(a);
296 		rd.add(b);
297 		rd.setRenameScore(50);
298 
299 		List<DiffEntry> entries = rd.compute();
300 		assertEquals(1, entries.size());
301 		assertRename(b, a, 57, entries.get(0));
302 	}
303 
304 	@Test
305 	public void testNoRenames_SingleByteFiles() throws Exception {
306 		ObjectId aId = blob("a");
307 		ObjectId bId = blob("b");
308 
309 		DiffEntry a = DiffEntry.add(PATH_A, aId);
310 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
311 
312 		rd.add(a);
313 		rd.add(b);
314 
315 		List<DiffEntry> entries = rd.compute();
316 		assertEquals(2, entries.size());
317 		assertSame(a, entries.get(0));
318 		assertSame(b, entries.get(1));
319 	}
320 
321 	@Test
322 	public void testNoRenames_EmptyFile1() throws Exception {
323 		ObjectId aId = blob("");
324 		DiffEntry a = DiffEntry.add(PATH_A, aId);
325 
326 		rd.add(a);
327 
328 		List<DiffEntry> entries = rd.compute();
329 		assertEquals(1, entries.size());
330 		assertSame(a, entries.get(0));
331 	}
332 
333 	@Test
334 	public void testNoRenames_EmptyFile2() throws Exception {
335 		ObjectId aId = blob("");
336 		ObjectId bId = blob("blah");
337 
338 		DiffEntry a = DiffEntry.add(PATH_A, aId);
339 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
340 
341 		rd.add(a);
342 		rd.add(b);
343 
344 		List<DiffEntry> entries = rd.compute();
345 		assertEquals(2, entries.size());
346 		assertSame(a, entries.get(0));
347 		assertSame(b, entries.get(1));
348 	}
349 
350 	@Test
351 	public void testNoRenames_SymlinkAndFile() throws Exception {
352 		ObjectId aId = blob("src/dest");
353 
354 		DiffEntry a = DiffEntry.add(PATH_A, aId);
355 		DiffEntry b = DiffEntry.delete(PATH_Q, aId);
356 		b.oldMode = FileMode.SYMLINK;
357 
358 		rd.add(a);
359 		rd.add(b);
360 
361 		List<DiffEntry> entries = rd.compute();
362 		assertEquals(2, entries.size());
363 		assertSame(a, entries.get(0));
364 		assertSame(b, entries.get(1));
365 	}
366 
367 	@Test
368 	public void testNoRenames_GitlinkAndFile() throws Exception {
369 		ObjectId aId = blob("src/dest");
370 
371 		DiffEntry a = DiffEntry.add(PATH_A, aId);
372 		DiffEntry b = DiffEntry.delete(PATH_Q, aId);
373 		b.oldMode = FileMode.GITLINK;
374 
375 		rd.add(a);
376 		rd.add(b);
377 
378 		List<DiffEntry> entries = rd.compute();
379 		assertEquals(2, entries.size());
380 		assertSame(a, entries.get(0));
381 		assertSame(b, entries.get(1));
382 	}
383 
384 	@Test
385 	public void testNoRenames_SymlinkAndFileSamePath() throws Exception {
386 		ObjectId aId = blob("src/dest");
387 
388 		DiffEntry a = DiffEntry.delete(PATH_A, aId);
389 		DiffEntry b = DiffEntry.add(PATH_A, aId);
390 		a.oldMode = FileMode.SYMLINK;
391 
392 		rd.add(a);
393 		rd.add(b);
394 
395 		// Deletes should be first
396 		List<DiffEntry> entries = rd.compute();
397 		assertEquals(2, entries.size());
398 		assertSame(a, entries.get(0));
399 		assertSame(b, entries.get(1));
400 	}
401 
402 	@Test
403 	public void testNoRenames_UntrackedFile() throws Exception {
404 		ObjectId aId = blob("foo");
405 		ObjectId bId = ObjectId
406 				.fromString("3049eb6eee7e1318f4e78e799bf33f1e54af9cbf");
407 
408 		DiffEntry a = DiffEntry.delete(PATH_A, aId);
409 		DiffEntry b = DiffEntry.add(PATH_B, bId);
410 
411 		rd.addAll(Arrays.asList(a, b));
412 		List<DiffEntry> entries = rd.compute();
413 
414 		assertEquals(2, entries.size());
415 		assertSame(a, entries.get(0));
416 		assertSame(b, entries.get(1));
417 	}
418 
419 	@Test
420 	public void testBreakModify_BreakAll() throws Exception {
421 		ObjectId aId = blob("foo");
422 		ObjectId bId = blob("bar");
423 
424 		DiffEntry m = DiffEntry.modify(PATH_A);
425 		m.oldId = AbbreviatedObjectId.fromObjectId(aId);
426 		m.newId = AbbreviatedObjectId.fromObjectId(bId);
427 
428 		DiffEntry a = DiffEntry.add(PATH_B, aId);
429 
430 		rd.add(a);
431 		rd.add(m);
432 
433 		rd.setBreakScore(101);
434 
435 		List<DiffEntry> entries = rd.compute();
436 		assertEquals(2, entries.size());
437 		assertAdd(PATH_A, bId, FileMode.REGULAR_FILE, entries.get(0));
438 		assertRename(DiffEntry.breakModify(m).get(0), a, 100, entries.get(1));
439 	}
440 
441 	@Test
442 	public void testBreakModify_BreakNone() throws Exception {
443 		ObjectId aId = blob("foo");
444 		ObjectId bId = blob("bar");
445 
446 		DiffEntry m = DiffEntry.modify(PATH_A);
447 		m.oldId = AbbreviatedObjectId.fromObjectId(aId);
448 		m.newId = AbbreviatedObjectId.fromObjectId(bId);
449 
450 		DiffEntry a = DiffEntry.add(PATH_B, aId);
451 
452 		rd.add(a);
453 		rd.add(m);
454 
455 		rd.setBreakScore(-1);
456 
457 		List<DiffEntry> entries = rd.compute();
458 		assertEquals(2, entries.size());
459 		assertSame(m, entries.get(0));
460 		assertSame(a, entries.get(1));
461 	}
462 
463 	@Test
464 	public void testBreakModify_BreakBelowScore() throws Exception {
465 		ObjectId aId = blob("foo");
466 		ObjectId bId = blob("bar");
467 
468 		DiffEntry m = DiffEntry.modify(PATH_A);
469 		m.oldId = AbbreviatedObjectId.fromObjectId(aId);
470 		m.newId = AbbreviatedObjectId.fromObjectId(bId);
471 
472 		DiffEntry a = DiffEntry.add(PATH_B, aId);
473 
474 		rd.add(a);
475 		rd.add(m);
476 
477 		rd.setBreakScore(20); // Should break the modify
478 
479 		List<DiffEntry> entries = rd.compute();
480 		assertEquals(2, entries.size());
481 		assertAdd(PATH_A, bId, FileMode.REGULAR_FILE, entries.get(0));
482 		assertRename(DiffEntry.breakModify(m).get(0), a, 100, entries.get(1));
483 	}
484 
485 	@Test
486 	public void testBreakModify_DontBreakAboveScore() throws Exception {
487 		ObjectId aId = blob("blah\nblah\nfoo");
488 		ObjectId bId = blob("blah\nblah\nbar");
489 
490 		DiffEntry m = DiffEntry.modify(PATH_A);
491 		m.oldId = AbbreviatedObjectId.fromObjectId(aId);
492 		m.newId = AbbreviatedObjectId.fromObjectId(bId);
493 
494 		DiffEntry a = DiffEntry.add(PATH_B, aId);
495 
496 		rd.add(a);
497 		rd.add(m);
498 
499 		rd.setBreakScore(20); // Should not break the modify
500 
501 		List<DiffEntry> entries = rd.compute();
502 		assertEquals(2, entries.size());
503 		assertSame(m, entries.get(0));
504 		assertSame(a, entries.get(1));
505 	}
506 
507 	@Test
508 	public void testBreakModify_RejoinIfUnpaired() throws Exception {
509 		ObjectId aId = blob("foo");
510 		ObjectId bId = blob("bar");
511 
512 		DiffEntry m = DiffEntry.modify(PATH_A);
513 		m.oldId = AbbreviatedObjectId.fromObjectId(aId);
514 		m.newId = AbbreviatedObjectId.fromObjectId(bId);
515 
516 		rd.add(m);
517 
518 		rd.setBreakScore(101); // Ensure m is broken apart
519 
520 		List<DiffEntry> entries = rd.compute();
521 		assertEquals(1, entries.size());
522 
523 		DiffEntry modify = entries.get(0);
524 		assertEquals(m.oldPath, modify.oldPath);
525 		assertEquals(m.oldId, modify.oldId);
526 		assertEquals(m.oldMode, modify.oldMode);
527 		assertEquals(m.newPath, modify.newPath);
528 		assertEquals(m.newId, modify.newId);
529 		assertEquals(m.newMode, modify.newMode);
530 		assertEquals(m.changeType, modify.changeType);
531 		assertEquals(0, modify.score);
532 	}
533 
534 	@Test
535 	public void testExactRename_LargeFile() throws Exception {
536 		ObjectId aId = blob("blah\nblah\nfoo"); // size = 14
537 
538 		DiffEntry a = DiffEntry.add(PATH_A, aId);
539 		DiffEntry b = DiffEntry.delete(PATH_Q, aId);
540 
541 		rd.add(a);
542 		rd.add(b);
543 
544 		// Exact renames are identified for large files
545 		rd.setBigFileThreshold(10);
546 		List<DiffEntry> entries = rd.compute();
547 		assertEquals(1, entries.size());
548 		assertRename(b, a, 100, entries.get(0));
549 	}
550 
551 	@Test
552 	public void testInexactRename_LargeFile() throws Exception {
553 		ObjectId aId = blob("blah\nblah\nfoo"); // size = 14
554 		ObjectId bId = blob("bla\nblah\nfoo"); // size = 13
555 
556 		DiffEntry a = DiffEntry.add(PATH_A, aId);
557 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
558 
559 		rd.add(a);
560 		rd.add(b);
561 
562 		rd.setBigFileThreshold(10);
563 
564 		// Inexact renames are not detected for large files
565 		List<DiffEntry> entries = rd.compute();
566 		assertEquals(2, entries.size());
567 		assertAdd(PATH_A, aId, FileMode.REGULAR_FILE, entries.get(0));
568 		assertDelete(PATH_Q, bId, FileMode.REGULAR_FILE, entries.get(1));
569 	}
570 
571 	@Test
572 	public void testExactRenameForBinaryFile_isIdentified() throws Exception {
573 		ObjectId aId = blob("a\nb\nc\n\0\0\0\0d\n");
574 
575 		DiffEntry a = DiffEntry.add(PATH_A, aId);
576 		DiffEntry b = DiffEntry.delete(PATH_Q, aId);
577 
578 		rd.add(a);
579 		rd.add(b);
580 
581 		List<DiffEntry> entries = rd.compute();
582 		assertEquals(1, entries.size());
583 		assertRename(b, a, 100, entries.get(0));
584 	}
585 
586 	@Test
587 	public void testInexactRenameForBinaryFile_identifiedByDefault() throws Exception {
588 		ObjectId aId = blob("a\nb\nc\n\0\0\0\0d\n");
589 		ObjectId bId = blob("a\nb\nc\n\0\0\0d\n");
590 
591 		DiffEntry a = DiffEntry.add(PATH_A, aId);
592 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
593 
594 		rd.add(a);
595 		rd.add(b);
596 		rd.setRenameScore(40);
597 
598 		List<DiffEntry> entries = rd.compute();
599 		assertEquals(1, entries.size());
600 		assertRename(b, a, 50, entries.get(0));
601 	}
602 
603 	@Test
604 	public void testInexactRenameForBinaryFile_notIdentifiedIfSkipParameterSet() throws Exception {
605 		ObjectId aId = blob("a\nb\nc\n\0\0\0\0d\n");
606 		ObjectId bId = blob("a\nb\nc\n\0\0\0d\n");
607 
608 		DiffEntry a = DiffEntry.add(PATH_A, aId);
609 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
610 
611 		rd.add(a);
612 		rd.add(b);
613 		rd.setRenameScore(40);
614 		rd.setSkipContentRenamesForBinaryFiles(true);
615 
616 		List<DiffEntry> entries = rd.compute();
617 		assertEquals(2, entries.size());
618 		assertAdd(PATH_A, aId, FileMode.REGULAR_FILE, entries.get(0));
619 		assertDelete(PATH_Q, bId, FileMode.REGULAR_FILE, entries.get(1));
620 	}
621 
622 	@Test
623 	public void testSetRenameScore_IllegalArgs() throws Exception {
624 		try {
625 			rd.setRenameScore(-1);
626 			fail();
627 		} catch (IllegalArgumentException e) {
628 			// pass
629 		}
630 
631 		try {
632 			rd.setRenameScore(101);
633 			fail();
634 		} catch (IllegalArgumentException e) {
635 			// pass
636 		}
637 	}
638 
639 	@Test
640 	public void testRenameLimit() throws Exception {
641 		ObjectId aId = blob("foo\nbar\nbaz\nblarg\n");
642 		ObjectId bId = blob("foo\nbar\nbaz\nblah\n");
643 		DiffEntry a = DiffEntry.add(PATH_A, aId);
644 		DiffEntry b = DiffEntry.delete(PATH_B, bId);
645 
646 		ObjectId cId = blob("a\nb\nc\nd\n");
647 		ObjectId dId = blob("a\nb\nc\n");
648 		DiffEntry c = DiffEntry.add(PATH_H, cId);
649 		DiffEntry d = DiffEntry.delete(PATH_Q, dId);
650 
651 		rd.add(a);
652 		rd.add(b);
653 		rd.add(c);
654 		rd.add(d);
655 
656 		rd.setRenameLimit(1);
657 
658 		assertTrue(rd.isOverRenameLimit());
659 
660 		List<DiffEntry> entries = rd.compute();
661 		assertEquals(4, entries.size());
662 		assertSame(a, entries.get(0));
663 		assertSame(b, entries.get(1));
664 		assertSame(c, entries.get(2));
665 		assertSame(d, entries.get(3));
666 	}
667 }