View Javadoc
1   /*
2    * Copyright (C) 2010, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.diff;
45  
46  import static org.junit.Assert.assertEquals;
47  import static org.junit.Assert.assertSame;
48  import static org.junit.Assert.assertTrue;
49  import static org.junit.Assert.fail;
50  
51  import java.util.Arrays;
52  import java.util.List;
53  
54  import org.eclipse.jgit.diff.DiffEntry.ChangeType;
55  import org.eclipse.jgit.junit.RepositoryTestCase;
56  import org.eclipse.jgit.junit.TestRepository;
57  import org.eclipse.jgit.lib.AbbreviatedObjectId;
58  import org.eclipse.jgit.lib.FileMode;
59  import org.eclipse.jgit.lib.ObjectId;
60  import org.eclipse.jgit.lib.Repository;
61  import org.junit.Before;
62  import org.junit.Test;
63  
64  public class RenameDetectorTest extends RepositoryTestCase {
65  	private static final String PATH_A = "src/A";
66  	private static final String PATH_B = "src/B";
67  	private static final String PATH_H = "src/H";
68  	private static final String PATH_Q = "src/Q";
69  
70  	private RenameDetector rd;
71  
72  	private TestRepository<Repository> testDb;
73  
74  	@Override
75  	@Before
76  	public void setUp() throws Exception {
77  		super.setUp();
78  		testDb = new TestRepository<>(db);
79  		rd = new RenameDetector(db);
80  	}
81  
82  	@Test
83  	public void testExactRename_OneRename() throws Exception {
84  		ObjectId foo = blob("foo");
85  
86  		DiffEntry a = DiffEntry.add(PATH_A, foo);
87  		DiffEntry b = DiffEntry.delete(PATH_Q, foo);
88  
89  		rd.add(a);
90  		rd.add(b);
91  
92  		List<DiffEntry> entries = rd.compute();
93  		assertEquals(1, entries.size());
94  		assertRename(b, a, 100, entries.get(0));
95  	}
96  
97  	@Test
98  	public void testExactRename_DifferentObjects() throws Exception {
99  		ObjectId foo = blob("foo");
100 		ObjectId bar = blob("bar");
101 
102 		DiffEntry a = DiffEntry.add(PATH_A, foo);
103 		DiffEntry h = DiffEntry.add(PATH_H, foo);
104 		DiffEntry q = DiffEntry.delete(PATH_Q, bar);
105 
106 		rd.add(a);
107 		rd.add(h);
108 		rd.add(q);
109 
110 		List<DiffEntry> entries = rd.compute();
111 		assertEquals(3, entries.size());
112 		assertSame(a, entries.get(0));
113 		assertSame(h, entries.get(1));
114 		assertSame(q, entries.get(2));
115 	}
116 
117 	@Test
118 	public void testExactRename_OneRenameOneModify() throws Exception {
119 		ObjectId foo = blob("foo");
120 		ObjectId bar = blob("bar");
121 
122 		DiffEntry a = DiffEntry.add(PATH_A, foo);
123 		DiffEntry b = DiffEntry.delete(PATH_Q, foo);
124 
125 		DiffEntry c = DiffEntry.modify(PATH_H);
126 		c.newId = c.oldId = AbbreviatedObjectId.fromObjectId(bar);
127 
128 		rd.add(a);
129 		rd.add(b);
130 		rd.add(c);
131 
132 		List<DiffEntry> entries = rd.compute();
133 		assertEquals(2, entries.size());
134 		assertRename(b, a, 100, entries.get(0));
135 		assertSame(c, entries.get(1));
136 	}
137 
138 	@Test
139 	public void testExactRename_ManyRenames() throws Exception {
140 		ObjectId foo = blob("foo");
141 		ObjectId bar = blob("bar");
142 
143 		DiffEntry a = DiffEntry.add(PATH_A, foo);
144 		DiffEntry b = DiffEntry.delete(PATH_Q, foo);
145 
146 		DiffEntry c = DiffEntry.add(PATH_H, bar);
147 		DiffEntry d = DiffEntry.delete(PATH_B, bar);
148 
149 		rd.add(a);
150 		rd.add(b);
151 		rd.add(c);
152 		rd.add(d);
153 
154 		List<DiffEntry> entries = rd.compute();
155 		assertEquals(2, entries.size());
156 		assertRename(b, a, 100, entries.get(0));
157 		assertRename(d, c, 100, entries.get(1));
158 	}
159 
160 	@Test
161 	public void testExactRename_MultipleIdenticalDeletes() throws Exception {
162 		ObjectId foo = blob("foo");
163 
164 		DiffEntry a = DiffEntry.delete(PATH_A, foo);
165 		DiffEntry b = DiffEntry.delete(PATH_B, foo);
166 
167 		DiffEntry c = DiffEntry.delete(PATH_H, foo);
168 		DiffEntry d = DiffEntry.add(PATH_Q, foo);
169 
170 		rd.add(a);
171 		rd.add(b);
172 		rd.add(c);
173 		rd.add(d);
174 
175 		// Pairs the add with the first delete added
176 		List<DiffEntry> entries = rd.compute();
177 		assertEquals(3, entries.size());
178 		assertEquals(b, entries.get(0));
179 		assertEquals(c, entries.get(1));
180 		assertRename(a, d, 100, entries.get(2));
181 	}
182 
183 	@Test
184 	public void testExactRename_PathBreaksTie() throws Exception {
185 		ObjectId foo = blob("foo");
186 
187 		DiffEntry a = DiffEntry.add("src/com/foo/a.java", foo);
188 		DiffEntry b = DiffEntry.delete("src/com/foo/b.java", foo);
189 
190 		DiffEntry c = DiffEntry.add("c.txt", foo);
191 		DiffEntry d = DiffEntry.delete("d.txt", foo);
192 		DiffEntry e = DiffEntry.add("the_e_file.txt", foo);
193 
194 		// Add out of order to avoid first-match succeeding
195 		rd.add(a);
196 		rd.add(d);
197 		rd.add(e);
198 		rd.add(b);
199 		rd.add(c);
200 
201 		List<DiffEntry> entries = rd.compute();
202 		assertEquals(3, entries.size());
203 		assertRename(d, c, 100, entries.get(0));
204 		assertRename(b, a, 100, entries.get(1));
205 		assertCopy(d, e, 100, entries.get(2));
206 	}
207 
208 	@Test
209 	public void testExactRename_OneDeleteManyAdds() throws Exception {
210 		ObjectId foo = blob("foo");
211 
212 		DiffEntry a = DiffEntry.add("src/com/foo/a.java", foo);
213 		DiffEntry b = DiffEntry.add("src/com/foo/b.java", foo);
214 		DiffEntry c = DiffEntry.add("c.txt", foo);
215 
216 		DiffEntry d = DiffEntry.delete("d.txt", foo);
217 
218 		rd.add(a);
219 		rd.add(b);
220 		rd.add(c);
221 		rd.add(d);
222 
223 		List<DiffEntry> entries = rd.compute();
224 		assertEquals(3, entries.size());
225 		assertRename(d, c, 100, entries.get(0));
226 		assertCopy(d, a, 100, entries.get(1));
227 		assertCopy(d, b, 100, entries.get(2));
228 	}
229 
230 	@Test
231 	public void testExactRename_UnstagedFile() throws Exception {
232 		ObjectId aId = blob("foo");
233 		DiffEntry a = DiffEntry.delete(PATH_A, aId);
234 		DiffEntry b = DiffEntry.add(PATH_B, aId);
235 
236 		rd.addAll(Arrays.asList(a, b));
237 		List<DiffEntry> entries = rd.compute();
238 
239 		assertEquals(1, entries.size());
240 		assertRename(a, b, 100, entries.get(0));
241 	}
242 
243 	@Test
244 	public void testInexactRename_OnePair() throws Exception {
245 		ObjectId aId = blob("foo\nbar\nbaz\nblarg\n");
246 		ObjectId bId = blob("foo\nbar\nbaz\nblah\n");
247 
248 		DiffEntry a = DiffEntry.add(PATH_A, aId);
249 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
250 
251 		rd.add(a);
252 		rd.add(b);
253 
254 		List<DiffEntry> entries = rd.compute();
255 		assertEquals(1, entries.size());
256 		assertRename(b, a, 66, entries.get(0));
257 	}
258 
259 	@Test
260 	public void testInexactRename_OneRenameTwoUnrelatedFiles() throws Exception {
261 		ObjectId aId = blob("foo\nbar\nbaz\nblarg\n");
262 		ObjectId bId = blob("foo\nbar\nbaz\nblah\n");
263 		DiffEntry a = DiffEntry.add(PATH_A, aId);
264 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
265 
266 		ObjectId cId = blob("some\nsort\nof\ntext\n");
267 		ObjectId dId = blob("completely\nunrelated\ntext\n");
268 		DiffEntry c = DiffEntry.add(PATH_B, cId);
269 		DiffEntry d = DiffEntry.delete(PATH_H, dId);
270 
271 		rd.add(a);
272 		rd.add(b);
273 		rd.add(c);
274 		rd.add(d);
275 
276 		List<DiffEntry> entries = rd.compute();
277 		assertEquals(3, entries.size());
278 		assertRename(b, a, 66, entries.get(0));
279 		assertSame(c, entries.get(1));
280 		assertSame(d, entries.get(2));
281 	}
282 
283 	@Test
284 	public void testInexactRename_LastByteDifferent() throws Exception {
285 		ObjectId aId = blob("foo\nbar\na");
286 		ObjectId bId = blob("foo\nbar\nb");
287 
288 		DiffEntry a = DiffEntry.add(PATH_A, aId);
289 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
290 
291 		rd.add(a);
292 		rd.add(b);
293 
294 		List<DiffEntry> entries = rd.compute();
295 		assertEquals(1, entries.size());
296 		assertRename(b, a, 88, entries.get(0));
297 	}
298 
299 	@Test
300 	public void testInexactRename_NewlinesOnly() throws Exception {
301 		ObjectId aId = blob("\n\n\n");
302 		ObjectId bId = blob("\n\n\n\n");
303 
304 		DiffEntry a = DiffEntry.add(PATH_A, aId);
305 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
306 
307 		rd.add(a);
308 		rd.add(b);
309 
310 		List<DiffEntry> entries = rd.compute();
311 		assertEquals(1, entries.size());
312 		assertRename(b, a, 74, entries.get(0));
313 	}
314 
315 	@Test
316 	public void testInexactRename_SameContentMultipleTimes() throws Exception {
317 		ObjectId aId = blob("a\na\na\na\n");
318 		ObjectId bId = blob("a\na\na\n");
319 
320 		DiffEntry a = DiffEntry.add(PATH_A, aId);
321 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
322 
323 		rd.add(a);
324 		rd.add(b);
325 
326 		List<DiffEntry> entries = rd.compute();
327 		assertEquals(1, entries.size());
328 		assertRename(b, a, 74, entries.get(0));
329 	}
330 
331 	@Test
332 	public void testInexactRenames_OnePair2() throws Exception {
333 		ObjectId aId = blob("ab\nab\nab\nac\nad\nae\n");
334 		ObjectId bId = blob("ac\nab\nab\nab\naa\na0\na1\n");
335 
336 		DiffEntry a = DiffEntry.add(PATH_A, aId);
337 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
338 
339 		rd.add(a);
340 		rd.add(b);
341 		rd.setRenameScore(50);
342 
343 		List<DiffEntry> entries = rd.compute();
344 		assertEquals(1, entries.size());
345 		assertRename(b, a, 57, entries.get(0));
346 	}
347 
348 	@Test
349 	public void testNoRenames_SingleByteFiles() throws Exception {
350 		ObjectId aId = blob("a");
351 		ObjectId bId = blob("b");
352 
353 		DiffEntry a = DiffEntry.add(PATH_A, aId);
354 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
355 
356 		rd.add(a);
357 		rd.add(b);
358 
359 		List<DiffEntry> entries = rd.compute();
360 		assertEquals(2, entries.size());
361 		assertSame(a, entries.get(0));
362 		assertSame(b, entries.get(1));
363 	}
364 
365 	@Test
366 	public void testNoRenames_EmptyFile1() throws Exception {
367 		ObjectId aId = blob("");
368 		DiffEntry a = DiffEntry.add(PATH_A, aId);
369 
370 		rd.add(a);
371 
372 		List<DiffEntry> entries = rd.compute();
373 		assertEquals(1, entries.size());
374 		assertSame(a, entries.get(0));
375 	}
376 
377 	@Test
378 	public void testNoRenames_EmptyFile2() throws Exception {
379 		ObjectId aId = blob("");
380 		ObjectId bId = blob("blah");
381 
382 		DiffEntry a = DiffEntry.add(PATH_A, aId);
383 		DiffEntry b = DiffEntry.delete(PATH_Q, bId);
384 
385 		rd.add(a);
386 		rd.add(b);
387 
388 		List<DiffEntry> entries = rd.compute();
389 		assertEquals(2, entries.size());
390 		assertSame(a, entries.get(0));
391 		assertSame(b, entries.get(1));
392 	}
393 
394 	@Test
395 	public void testNoRenames_SymlinkAndFile() throws Exception {
396 		ObjectId aId = blob("src/dest");
397 
398 		DiffEntry a = DiffEntry.add(PATH_A, aId);
399 		DiffEntry b = DiffEntry.delete(PATH_Q, aId);
400 		b.oldMode = FileMode.SYMLINK;
401 
402 		rd.add(a);
403 		rd.add(b);
404 
405 		List<DiffEntry> entries = rd.compute();
406 		assertEquals(2, entries.size());
407 		assertSame(a, entries.get(0));
408 		assertSame(b, entries.get(1));
409 	}
410 
411 	@Test
412 	public void testNoRenames_GitlinkAndFile() throws Exception {
413 		ObjectId aId = blob("src/dest");
414 
415 		DiffEntry a = DiffEntry.add(PATH_A, aId);
416 		DiffEntry b = DiffEntry.delete(PATH_Q, aId);
417 		b.oldMode = FileMode.GITLINK;
418 
419 		rd.add(a);
420 		rd.add(b);
421 
422 		List<DiffEntry> entries = rd.compute();
423 		assertEquals(2, entries.size());
424 		assertSame(a, entries.get(0));
425 		assertSame(b, entries.get(1));
426 	}
427 
428 	@Test
429 	public void testNoRenames_SymlinkAndFileSamePath() throws Exception {
430 		ObjectId aId = blob("src/dest");
431 
432 		DiffEntry a = DiffEntry.delete(PATH_A, aId);
433 		DiffEntry b = DiffEntry.add(PATH_A, aId);
434 		a.oldMode = FileMode.SYMLINK;
435 
436 		rd.add(a);
437 		rd.add(b);
438 
439 		// Deletes should be first
440 		List<DiffEntry> entries = rd.compute();
441 		assertEquals(2, entries.size());
442 		assertSame(a, entries.get(0));
443 		assertSame(b, entries.get(1));
444 	}
445 
446 	@Test
447 	public void testNoRenames_UntrackedFile() throws Exception {
448 		ObjectId aId = blob("foo");
449 		ObjectId bId = ObjectId
450 				.fromString("3049eb6eee7e1318f4e78e799bf33f1e54af9cbf");
451 
452 		DiffEntry a = DiffEntry.delete(PATH_A, aId);
453 		DiffEntry b = DiffEntry.add(PATH_B, bId);
454 
455 		rd.addAll(Arrays.asList(a, b));
456 		List<DiffEntry> entries = rd.compute();
457 
458 		assertEquals(2, entries.size());
459 		assertSame(a, entries.get(0));
460 		assertSame(b, entries.get(1));
461 	}
462 
463 	@Test
464 	public void testBreakModify_BreakAll() 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(101);
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_BreakNone() throws Exception {
487 		ObjectId aId = blob("foo");
488 		ObjectId bId = blob("bar");
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(-1);
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_BreakBelowScore() 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 		DiffEntry a = DiffEntry.add(PATH_B, aId);
517 
518 		rd.add(a);
519 		rd.add(m);
520 
521 		rd.setBreakScore(20); // Should break the modify
522 
523 		List<DiffEntry> entries = rd.compute();
524 		assertEquals(2, entries.size());
525 		assertAdd(PATH_A, bId, FileMode.REGULAR_FILE, entries.get(0));
526 		assertRename(DiffEntry.breakModify(m).get(0), a, 100, entries.get(1));
527 	}
528 
529 	@Test
530 	public void testBreakModify_DontBreakAboveScore() throws Exception {
531 		ObjectId aId = blob("blah\nblah\nfoo");
532 		ObjectId bId = blob("blah\nblah\nbar");
533 
534 		DiffEntry m = DiffEntry.modify(PATH_A);
535 		m.oldId = AbbreviatedObjectId.fromObjectId(aId);
536 		m.newId = AbbreviatedObjectId.fromObjectId(bId);
537 
538 		DiffEntry a = DiffEntry.add(PATH_B, aId);
539 
540 		rd.add(a);
541 		rd.add(m);
542 
543 		rd.setBreakScore(20); // Should not break the modify
544 
545 		List<DiffEntry> entries = rd.compute();
546 		assertEquals(2, entries.size());
547 		assertSame(m, entries.get(0));
548 		assertSame(a, entries.get(1));
549 	}
550 
551 	@Test
552 	public void testBreakModify_RejoinIfUnpaired() throws Exception {
553 		ObjectId aId = blob("foo");
554 		ObjectId bId = blob("bar");
555 
556 		DiffEntry m = DiffEntry.modify(PATH_A);
557 		m.oldId = AbbreviatedObjectId.fromObjectId(aId);
558 		m.newId = AbbreviatedObjectId.fromObjectId(bId);
559 
560 		rd.add(m);
561 
562 		rd.setBreakScore(101); // Ensure m is broken apart
563 
564 		List<DiffEntry> entries = rd.compute();
565 		assertEquals(1, entries.size());
566 
567 		DiffEntry modify = entries.get(0);
568 		assertEquals(m.oldPath, modify.oldPath);
569 		assertEquals(m.oldId, modify.oldId);
570 		assertEquals(m.oldMode, modify.oldMode);
571 		assertEquals(m.newPath, modify.newPath);
572 		assertEquals(m.newId, modify.newId);
573 		assertEquals(m.newMode, modify.newMode);
574 		assertEquals(m.changeType, modify.changeType);
575 		assertEquals(0, modify.score);
576 	}
577 
578 	@Test
579 	public void testSetRenameScore_IllegalArgs() throws Exception {
580 		try {
581 			rd.setRenameScore(-1);
582 			fail();
583 		} catch (IllegalArgumentException e) {
584 			// pass
585 		}
586 
587 		try {
588 			rd.setRenameScore(101);
589 			fail();
590 		} catch (IllegalArgumentException e) {
591 			// pass
592 		}
593 	}
594 
595 	@Test
596 	public void testRenameLimit() throws Exception {
597 		ObjectId aId = blob("foo\nbar\nbaz\nblarg\n");
598 		ObjectId bId = blob("foo\nbar\nbaz\nblah\n");
599 		DiffEntry a = DiffEntry.add(PATH_A, aId);
600 		DiffEntry b = DiffEntry.delete(PATH_B, bId);
601 
602 		ObjectId cId = blob("a\nb\nc\nd\n");
603 		ObjectId dId = blob("a\nb\nc\n");
604 		DiffEntry c = DiffEntry.add(PATH_H, cId);
605 		DiffEntry d = DiffEntry.delete(PATH_Q, dId);
606 
607 		rd.add(a);
608 		rd.add(b);
609 		rd.add(c);
610 		rd.add(d);
611 
612 		rd.setRenameLimit(1);
613 
614 		assertTrue(rd.isOverRenameLimit());
615 
616 		List<DiffEntry> entries = rd.compute();
617 		assertEquals(4, entries.size());
618 		assertSame(a, entries.get(0));
619 		assertSame(b, entries.get(1));
620 		assertSame(c, entries.get(2));
621 		assertSame(d, entries.get(3));
622 	}
623 
624 	private ObjectId blob(String content) throws Exception {
625 		return testDb.blob(content).copy();
626 	}
627 
628 	private static void assertRename(DiffEntry o, DiffEntry n, int score,
629 			DiffEntry rename) {
630 		assertEquals(ChangeType.RENAME, rename.getChangeType());
631 
632 		assertEquals(o.getOldPath(), rename.getOldPath());
633 		assertEquals(n.getNewPath(), rename.getNewPath());
634 
635 		assertEquals(o.getOldMode(), rename.getOldMode());
636 		assertEquals(n.getNewMode(), rename.getNewMode());
637 
638 		assertEquals(o.getOldId(), rename.getOldId());
639 		assertEquals(n.getNewId(), rename.getNewId());
640 
641 		assertEquals(score, rename.getScore());
642 	}
643 
644 	private static void assertCopy(DiffEntry o, DiffEntry n, int score,
645 			DiffEntry copy) {
646 		assertEquals(ChangeType.COPY, copy.getChangeType());
647 
648 		assertEquals(o.getOldPath(), copy.getOldPath());
649 		assertEquals(n.getNewPath(), copy.getNewPath());
650 
651 		assertEquals(o.getOldMode(), copy.getOldMode());
652 		assertEquals(n.getNewMode(), copy.getNewMode());
653 
654 		assertEquals(o.getOldId(), copy.getOldId());
655 		assertEquals(n.getNewId(), copy.getNewId());
656 
657 		assertEquals(score, copy.getScore());
658 	}
659 
660 	private static void assertAdd(String newName, ObjectId newId,
661 			FileMode newMode, DiffEntry add) {
662 		assertEquals(DiffEntry.DEV_NULL, add.oldPath);
663 		assertEquals(DiffEntry.A_ZERO, add.oldId);
664 		assertEquals(FileMode.MISSING, add.oldMode);
665 		assertEquals(ChangeType.ADD, add.changeType);
666 		assertEquals(newName, add.newPath);
667 		assertEquals(AbbreviatedObjectId.fromObjectId(newId), add.newId);
668 		assertEquals(newMode, add.newMode);
669 	}
670 }