1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.api;
11
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertNull;
15 import static org.junit.Assert.assertTrue;
16
17 import java.io.File;
18
19 import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
20 import org.eclipse.jgit.api.ResetCommand.ResetType;
21 import org.eclipse.jgit.blame.BlameResult;
22 import org.eclipse.jgit.diff.RawTextComparator;
23 import org.eclipse.jgit.junit.RepositoryTestCase;
24 import org.eclipse.jgit.lib.ConfigConstants;
25 import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
26 import org.eclipse.jgit.revwalk.RevCommit;
27 import org.eclipse.jgit.storage.file.FileBasedConfig;
28 import org.junit.Test;
29
30
31
32
33 public class BlameCommandTest extends RepositoryTestCase {
34
35 private static String join(String... lines) {
36 StringBuilder joined = new StringBuilder();
37 for (String line : lines)
38 joined.append(line).append('\n');
39 return joined.toString();
40 }
41
42 @Test
43 public void testSingleRevision() throws Exception {
44 try (Git git = new Git(db)) {
45 String[] content = new String[] { "first", "second", "third" };
46
47 writeTrashFile("file.txt", join(content));
48 git.add().addFilepattern("file.txt").call();
49 RevCommit commit = git.commit().setMessage("create file").call();
50
51 BlameCommand command = new BlameCommand(db);
52 command.setFilePath("file.txt");
53 BlameResult lines = command.call();
54 assertNotNull(lines);
55 assertEquals(3, lines.getResultContents().size());
56
57 for (int i = 0; i < 3; i++) {
58 assertEquals(commit, lines.getSourceCommit(i));
59 assertEquals(i, lines.getSourceLine(i));
60 }
61 }
62 }
63
64 @Test
65 public void testTwoRevisions() throws Exception {
66 try (Git git = new Git(db)) {
67 String[] content1 = new String[] { "first", "second" };
68 writeTrashFile("file.txt", join(content1));
69 git.add().addFilepattern("file.txt").call();
70 RevCommit commit1 = git.commit().setMessage("create file").call();
71
72 String[] content2 = new String[] { "first", "second", "third" };
73 writeTrashFile("file.txt", join(content2));
74 git.add().addFilepattern("file.txt").call();
75 RevCommit commit2 = git.commit().setMessage("create file").call();
76
77 BlameCommand command = new BlameCommand(db);
78 command.setFilePath("file.txt");
79 BlameResult lines = command.call();
80 assertEquals(3, lines.getResultContents().size());
81
82 assertEquals(commit1, lines.getSourceCommit(0));
83 assertEquals(0, lines.getSourceLine(0));
84
85 assertEquals(commit1, lines.getSourceCommit(1));
86 assertEquals(1, lines.getSourceLine(1));
87
88 assertEquals(commit2, lines.getSourceCommit(2));
89 assertEquals(2, lines.getSourceLine(2));
90 }
91 }
92
93 @Test
94 public void testRename() throws Exception {
95 testRename("file1.txt", "file2.txt");
96 }
97
98 @Test
99 public void testRenameInSubDir() throws Exception {
100 testRename("subdir/file1.txt", "subdir/file2.txt");
101 }
102
103 @Test
104 public void testMoveToOtherDir() throws Exception {
105 testRename("subdir/file1.txt", "otherdir/file1.txt");
106 }
107
108 private void testRename(String sourcePath, String destPath)
109 throws Exception {
110 try (Git git = new Git(db)) {
111 String[] content1 = new String[] { "a", "b", "c" };
112 writeTrashFile(sourcePath, join(content1));
113 git.add().addFilepattern(sourcePath).call();
114 RevCommit commit1 = git.commit().setMessage("create file").call();
115
116 writeTrashFile(destPath, join(content1));
117 git.add().addFilepattern(destPath).call();
118 git.rm().addFilepattern(sourcePath).call();
119 git.commit().setMessage("moving file").call();
120
121 String[] content2 = new String[] { "a", "b", "c2" };
122 writeTrashFile(destPath, join(content2));
123 git.add().addFilepattern(destPath).call();
124 RevCommit commit3 = git.commit().setMessage("editing file").call();
125
126 BlameCommand command = new BlameCommand(db);
127 command.setFollowFileRenames(true);
128 command.setFilePath(destPath);
129 BlameResult lines = command.call();
130
131 assertEquals(commit1, lines.getSourceCommit(0));
132 assertEquals(0, lines.getSourceLine(0));
133 assertEquals(sourcePath, lines.getSourcePath(0));
134
135 assertEquals(commit1, lines.getSourceCommit(1));
136 assertEquals(1, lines.getSourceLine(1));
137 assertEquals(sourcePath, lines.getSourcePath(1));
138
139 assertEquals(commit3, lines.getSourceCommit(2));
140 assertEquals(2, lines.getSourceLine(2));
141 assertEquals(destPath, lines.getSourcePath(2));
142 }
143 }
144
145 @Test
146 public void testTwoRenames() throws Exception {
147 try (Git git = new Git(db)) {
148
149 String[] content1 = new String[] { "a" };
150 writeTrashFile("file.txt", join(content1));
151 git.add().addFilepattern("file.txt").call();
152 RevCommit commit1 = git.commit().setMessage("create file").call();
153
154
155 writeTrashFile("file1.txt", join(content1));
156 git.add().addFilepattern("file1.txt").call();
157 git.rm().addFilepattern("file.txt").call();
158 git.commit().setMessage("moving file").call();
159
160
161 String[] content2 = new String[] { "a", "b" };
162 writeTrashFile("file1.txt", join(content2));
163 git.add().addFilepattern("file1.txt").call();
164 RevCommit commit3 = git.commit().setMessage("editing file").call();
165
166
167 writeTrashFile("file2.txt", join(content2));
168 git.add().addFilepattern("file2.txt").call();
169 git.rm().addFilepattern("file1.txt").call();
170 git.commit().setMessage("moving file again").call();
171
172 BlameCommand command = new BlameCommand(db);
173 command.setFollowFileRenames(true);
174 command.setFilePath("file2.txt");
175 BlameResult lines = command.call();
176
177 assertEquals(commit1, lines.getSourceCommit(0));
178 assertEquals(0, lines.getSourceLine(0));
179 assertEquals("file.txt", lines.getSourcePath(0));
180
181 assertEquals(commit3, lines.getSourceCommit(1));
182 assertEquals(1, lines.getSourceLine(1));
183 assertEquals("file1.txt", lines.getSourcePath(1));
184 }
185 }
186
187 @Test
188 public void testDeleteTrailingLines() throws Exception {
189 try (Git git = new Git(db)) {
190 String[] content1 = new String[] { "a", "b", "c", "d" };
191 String[] content2 = new String[] { "a", "b" };
192
193 writeTrashFile("file.txt", join(content2));
194 git.add().addFilepattern("file.txt").call();
195 RevCommit commit1 = git.commit().setMessage("create file").call();
196
197 writeTrashFile("file.txt", join(content1));
198 git.add().addFilepattern("file.txt").call();
199 git.commit().setMessage("edit file").call();
200
201 writeTrashFile("file.txt", join(content2));
202 git.add().addFilepattern("file.txt").call();
203 git.commit().setMessage("edit file").call();
204
205 BlameCommand command = new BlameCommand(db);
206
207 command.setFilePath("file.txt");
208 BlameResult lines = command.call();
209 assertEquals(content2.length, lines.getResultContents().size());
210
211 assertEquals(commit1, lines.getSourceCommit(0));
212 assertEquals(commit1, lines.getSourceCommit(1));
213
214 assertEquals(0, lines.getSourceLine(0));
215 assertEquals(1, lines.getSourceLine(1));
216 }
217 }
218
219 @Test
220 public void testDeleteMiddleLines() throws Exception {
221 try (Git git = new Git(db)) {
222 String[] content1 = new String[] { "a", "b", "c", "d", "e" };
223 String[] content2 = new String[] { "a", "c", "e" };
224
225 writeTrashFile("file.txt", join(content2));
226 git.add().addFilepattern("file.txt").call();
227 RevCommit commit1 = git.commit().setMessage("edit file").call();
228
229 writeTrashFile("file.txt", join(content1));
230 git.add().addFilepattern("file.txt").call();
231 git.commit().setMessage("edit file").call();
232
233 writeTrashFile("file.txt", join(content2));
234 git.add().addFilepattern("file.txt").call();
235 git.commit().setMessage("edit file").call();
236
237 BlameCommand command = new BlameCommand(db);
238
239 command.setFilePath("file.txt");
240 BlameResult lines = command.call();
241 assertEquals(content2.length, lines.getResultContents().size());
242
243 assertEquals(commit1, lines.getSourceCommit(0));
244 assertEquals(0, lines.getSourceLine(0));
245
246 assertEquals(commit1, lines.getSourceCommit(1));
247 assertEquals(1, lines.getSourceLine(1));
248
249 assertEquals(commit1, lines.getSourceCommit(2));
250 assertEquals(2, lines.getSourceLine(2));
251 }
252 }
253
254 @Test
255 public void testEditAllLines() throws Exception {
256 try (Git git = new Git(db)) {
257 String[] content1 = new String[] { "a", "1" };
258 String[] content2 = new String[] { "b", "2" };
259
260 writeTrashFile("file.txt", join(content1));
261 git.add().addFilepattern("file.txt").call();
262 git.commit().setMessage("edit file").call();
263
264 writeTrashFile("file.txt", join(content2));
265 git.add().addFilepattern("file.txt").call();
266 RevCommit commit2 = git.commit().setMessage("create file").call();
267
268 BlameCommand command = new BlameCommand(db);
269
270 command.setFilePath("file.txt");
271 BlameResult lines = command.call();
272 assertEquals(content2.length, lines.getResultContents().size());
273 assertEquals(commit2, lines.getSourceCommit(0));
274 assertEquals(commit2, lines.getSourceCommit(1));
275 }
276 }
277
278 @Test
279 public void testMiddleClearAllLines() throws Exception {
280 try (Git git = new Git(db)) {
281 String[] content1 = new String[] { "a", "b", "c" };
282
283 writeTrashFile("file.txt", join(content1));
284 git.add().addFilepattern("file.txt").call();
285 git.commit().setMessage("edit file").call();
286
287 writeTrashFile("file.txt", "");
288 git.add().addFilepattern("file.txt").call();
289 git.commit().setMessage("create file").call();
290
291 writeTrashFile("file.txt", join(content1));
292 git.add().addFilepattern("file.txt").call();
293 RevCommit commit3 = git.commit().setMessage("edit file").call();
294
295 BlameCommand command = new BlameCommand(db);
296
297 command.setFilePath("file.txt");
298 BlameResult lines = command.call();
299 assertEquals(content1.length, lines.getResultContents().size());
300 assertEquals(commit3, lines.getSourceCommit(0));
301 assertEquals(commit3, lines.getSourceCommit(1));
302 assertEquals(commit3, lines.getSourceCommit(2));
303 }
304 }
305
306 @Test
307 public void testCoreAutoCrlf1() throws Exception {
308 testCoreAutoCrlf(AutoCRLF.INPUT, AutoCRLF.FALSE);
309 }
310
311 @Test
312 public void testCoreAutoCrlf2() throws Exception {
313 testCoreAutoCrlf(AutoCRLF.FALSE, AutoCRLF.FALSE);
314 }
315
316 @Test
317 public void testCoreAutoCrlf3() throws Exception {
318 testCoreAutoCrlf(AutoCRLF.INPUT, AutoCRLF.INPUT);
319 }
320
321 @Test
322 public void testCoreAutoCrlf4() throws Exception {
323 testCoreAutoCrlf(AutoCRLF.FALSE, AutoCRLF.INPUT);
324 }
325
326 @Test
327 public void testCoreAutoCrlf5() throws Exception {
328 testCoreAutoCrlf(AutoCRLF.INPUT, AutoCRLF.TRUE);
329 }
330
331 private void testCoreAutoCrlf(AutoCRLF modeForCommitting,
332 AutoCRLF modeForReset) throws Exception {
333 try (Git git = new Git(db)) {
334 FileBasedConfig config = db.getConfig();
335 config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
336 ConfigConstants.CONFIG_KEY_AUTOCRLF, modeForCommitting);
337 config.save();
338
339 String joinedCrlf = "a\r\nb\r\nc\r\n";
340 File trashFile = writeTrashFile("file.txt", joinedCrlf);
341 git.add().addFilepattern("file.txt").call();
342 RevCommit commit = git.commit().setMessage("create file").call();
343
344
345 trashFile.delete();
346 config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
347 ConfigConstants.CONFIG_KEY_AUTOCRLF, modeForReset);
348 config.save();
349 git.reset().setMode(ResetType.HARD).call();
350
351 BlameCommand command = new BlameCommand(db);
352 command.setFilePath("file.txt");
353 BlameResult lines = command.call();
354
355 assertEquals(3, lines.getResultContents().size());
356 assertEquals(commit, lines.getSourceCommit(0));
357 assertEquals(commit, lines.getSourceCommit(1));
358 assertEquals(commit, lines.getSourceCommit(2));
359 }
360 }
361
362 @Test
363 public void testConflictingMerge1() throws Exception {
364 try (Git git = new Git(db)) {
365 RevCommit base = commitFile("file.txt", join("0", "1", "2", "3", "4"),
366 "master");
367
368 git.checkout().setName("side").setCreateBranch(true)
369 .setStartPoint(base).call();
370 RevCommit side = commitFile("file.txt",
371 join("0", "1 side", "2", "3 on side", "4"), "side");
372
373 commitFile("file.txt", join("0", "1", "2"), "master");
374
375 checkoutBranch("refs/heads/master");
376 git.merge().include(side).call();
377
378
379
380 RevCommit merge = commitFile("file.txt",
381 join("0", "1 side", "2", "3 resolved", "4"), "master");
382
383 BlameCommand command = new BlameCommand(db);
384 command.setFilePath("file.txt");
385 BlameResult lines = command.call();
386
387 assertEquals(5, lines.getResultContents().size());
388 assertEquals(base, lines.getSourceCommit(0));
389 assertEquals(side, lines.getSourceCommit(1));
390 assertEquals(base, lines.getSourceCommit(2));
391 assertEquals(merge, lines.getSourceCommit(3));
392 assertEquals(base, lines.getSourceCommit(4));
393 }
394 }
395
396
397
398 @Test
399 public void testConflictingMerge2() throws Exception {
400 try (Git git = new Git(db)) {
401 RevCommit base = commitFile("file.txt", join("0", "1", "2", "3", "4"),
402 "master");
403
404 commitFile("file.txt", join("0", "1", "2"), "master");
405
406 git.checkout().setName("side").setCreateBranch(true)
407 .setStartPoint(base).call();
408 RevCommit side = commitFile("file.txt",
409 join("0", "1 side", "2", "3 on side", "4"), "side");
410
411 checkoutBranch("refs/heads/master");
412 git.merge().include(side).call();
413
414
415
416 RevCommit merge = commitFile("file.txt",
417 join("0", "1 side", "2", "3 resolved", "4"), "master");
418
419 BlameCommand command = new BlameCommand(db);
420 command.setFilePath("file.txt");
421 BlameResult lines = command.call();
422
423 assertEquals(5, lines.getResultContents().size());
424 assertEquals(base, lines.getSourceCommit(0));
425 assertEquals(side, lines.getSourceCommit(1));
426 assertEquals(base, lines.getSourceCommit(2));
427 assertEquals(merge, lines.getSourceCommit(3));
428 assertEquals(base, lines.getSourceCommit(4));
429 }
430 }
431
432 @Test
433 public void testUnresolvedMergeConflict() throws Exception {
434 try (Git git = new Git(db)) {
435 RevCommit base = commitFile("file.txt", "Origin\n", "master");
436
437 RevCommit master = commitFile("file.txt",
438 "Change on master branch\n", "master");
439
440 git.checkout().setName("side").setCreateBranch(true)
441 .setStartPoint(base).call();
442 RevCommit side = commitFile("file.txt",
443 "Conflicting change on side\n", "side");
444
445 checkoutBranch("refs/heads/master");
446 MergeResult result = git.merge().include(side).call();
447
448
449 assertTrue("Expected a conflict",
450 result.getConflicts().containsKey("file.txt"));
451
452 BlameCommand command = new BlameCommand(db);
453 command.setFilePath("file.txt");
454 BlameResult lines = command.call();
455
456 assertEquals(5, lines.getResultContents().size());
457 assertNull(lines.getSourceCommit(0));
458 assertEquals(master, lines.getSourceCommit(1));
459 assertNull(lines.getSourceCommit(2));
460 assertEquals(side, lines.getSourceCommit(3));
461 assertNull(lines.getSourceCommit(4));
462 }
463 }
464
465 @Test
466 public void testWhitespaceMerge() throws Exception {
467 try (Git git = new Git(db)) {
468 RevCommit base = commitFile("file.txt", join("0", "1", "2"), "master");
469 RevCommit side = commitFile("file.txt", join("0", "1", " 2 side "),
470 "side");
471
472 checkoutBranch("refs/heads/master");
473 git.merge().setFastForward(FastForwardMode.NO_FF).include(side).call();
474
475
476
477 writeTrashFile("file.txt", join("0", "1", "2 side"));
478 RevCommit merge = git.commit().setAll(true).setMessage("merge")
479 .setAmend(true)
480 .call();
481
482 BlameCommand command = new BlameCommand(db);
483 command.setFilePath("file.txt")
484 .setTextComparator(RawTextComparator.WS_IGNORE_ALL)
485 .setStartCommit(merge.getId());
486 BlameResult lines = command.call();
487
488 assertEquals(3, lines.getResultContents().size());
489 assertEquals(base, lines.getSourceCommit(0));
490 assertEquals(base, lines.getSourceCommit(1));
491 assertEquals(side, lines.getSourceCommit(2));
492 }
493 }
494
495 @Test
496 public void testBlameWithNulByteInHistory() throws Exception {
497 try (Git git = new Git(db)) {
498 String[] content1 = { "First line", "Another line" };
499 writeTrashFile("file.txt", join(content1));
500 git.add().addFilepattern("file.txt").call();
501 RevCommit c1 = git.commit().setMessage("create file").call();
502
503 String[] content2 = { "First line", "Second line with NUL >\000<",
504 "Another line" };
505 assertTrue("Content should contain a NUL byte",
506 content2[1].indexOf(0) > 0);
507 writeTrashFile("file.txt", join(content2));
508 git.add().addFilepattern("file.txt").call();
509 git.commit().setMessage("add line with NUL").call();
510
511 String[] content3 = { "First line", "Second line with NUL >\000<",
512 "Third line" };
513 writeTrashFile("file.txt", join(content3));
514 git.add().addFilepattern("file.txt").call();
515 RevCommit c3 = git.commit().setMessage("change third line").call();
516
517 String[] content4 = { "First line", "Second line with NUL >\\000<",
518 "Third line" };
519 assertTrue("Content should not contain a NUL byte",
520 content4[1].indexOf(0) < 0);
521 writeTrashFile("file.txt", join(content4));
522 git.add().addFilepattern("file.txt").call();
523 RevCommit c4 = git.commit().setMessage("fix NUL line").call();
524
525 BlameResult lines = git.blame().setFilePath("file.txt").call();
526 assertEquals(3, lines.getResultContents().size());
527 assertEquals(c1, lines.getSourceCommit(0));
528 assertEquals(c4, lines.getSourceCommit(1));
529 assertEquals(c3, lines.getSourceCommit(2));
530 }
531 }
532
533 @Test
534 public void testBlameWithNulByteInTopRevision() throws Exception {
535 try (Git git = new Git(db)) {
536 String[] content1 = { "First line", "Another line" };
537 writeTrashFile("file.txt", join(content1));
538 git.add().addFilepattern("file.txt").call();
539 RevCommit c1 = git.commit().setMessage("create file").call();
540
541 String[] content2 = { "First line", "Second line with NUL >\000<",
542 "Another line" };
543 assertTrue("Content should contain a NUL byte",
544 content2[1].indexOf(0) > 0);
545 writeTrashFile("file.txt", join(content2));
546 git.add().addFilepattern("file.txt").call();
547 RevCommit c2 = git.commit().setMessage("add line with NUL").call();
548
549 String[] content3 = { "First line", "Second line with NUL >\000<",
550 "Third line" };
551 writeTrashFile("file.txt", join(content3));
552 git.add().addFilepattern("file.txt").call();
553 RevCommit c3 = git.commit().setMessage("change third line").call();
554
555 BlameResult lines = git.blame().setFilePath("file.txt").call();
556 assertEquals(3, lines.getResultContents().size());
557 assertEquals(c1, lines.getSourceCommit(0));
558 assertEquals(c2, lines.getSourceCommit(1));
559 assertEquals(c3, lines.getSourceCommit(2));
560 }
561 }
562
563 }