Mercurial > hg4j
comparison test/org/tmatesoft/hg/test/TestBlame.java @ 570:36853bb80a35
Tests for HgAnnotateCommand with follow/no-follow option
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 11 Apr 2013 16:07:17 +0200 |
parents | 8ed4f4f4f0a6 |
children | e49f9d9513fa |
comparison
equal
deleted
inserted
replaced
569:c4fd1037bc6f | 570:36853bb80a35 |
---|---|
20 import static org.junit.Assert.assertTrue; | 20 import static org.junit.Assert.assertTrue; |
21 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; | 21 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; |
22 import static org.tmatesoft.hg.repo.HgRepository.TIP; | 22 import static org.tmatesoft.hg.repo.HgRepository.TIP; |
23 | 23 |
24 import java.io.ByteArrayOutputStream; | 24 import java.io.ByteArrayOutputStream; |
25 import java.io.IOException; | 25 import java.io.File; |
26 import java.io.PrintStream; | 26 import java.io.PrintStream; |
27 import java.util.ArrayList; | |
27 import java.util.Arrays; | 28 import java.util.Arrays; |
28 import java.util.LinkedHashSet; | 29 import java.util.LinkedHashSet; |
29 import java.util.LinkedList; | 30 import java.util.LinkedList; |
31 import java.util.List; | |
30 import java.util.ListIterator; | 32 import java.util.ListIterator; |
31 import java.util.regex.Matcher; | 33 import java.util.regex.Matcher; |
32 import java.util.regex.Pattern; | 34 import java.util.regex.Pattern; |
33 | 35 |
34 import org.junit.Assert; | 36 import org.junit.Assert; |
35 import org.junit.Rule; | 37 import org.junit.Rule; |
36 import org.junit.Test; | 38 import org.junit.Test; |
39 import org.tmatesoft.hg.core.HgAnnotateCommand; | |
40 import org.tmatesoft.hg.core.HgAnnotateCommand.LineInfo; | |
37 import org.tmatesoft.hg.core.HgCallbackTargetException; | 41 import org.tmatesoft.hg.core.HgCallbackTargetException; |
38 import org.tmatesoft.hg.core.HgIterateDirection; | 42 import org.tmatesoft.hg.core.HgIterateDirection; |
43 import org.tmatesoft.hg.core.HgRepoFacade; | |
39 import org.tmatesoft.hg.internal.FileAnnotation; | 44 import org.tmatesoft.hg.internal.FileAnnotation; |
40 import org.tmatesoft.hg.internal.FileAnnotation.LineDescriptor; | 45 import org.tmatesoft.hg.internal.FileAnnotation.LineDescriptor; |
41 import org.tmatesoft.hg.internal.FileAnnotation.LineInspector; | 46 import org.tmatesoft.hg.internal.FileAnnotation.LineInspector; |
42 import org.tmatesoft.hg.internal.IntVector; | 47 import org.tmatesoft.hg.internal.IntVector; |
43 import org.tmatesoft.hg.repo.HgBlameFacility; | 48 import org.tmatesoft.hg.repo.HgBlameFacility; |
48 import org.tmatesoft.hg.repo.HgBlameFacility.DeleteBlock; | 53 import org.tmatesoft.hg.repo.HgBlameFacility.DeleteBlock; |
49 import org.tmatesoft.hg.repo.HgBlameFacility.EqualBlock; | 54 import org.tmatesoft.hg.repo.HgBlameFacility.EqualBlock; |
50 import org.tmatesoft.hg.repo.HgDataFile; | 55 import org.tmatesoft.hg.repo.HgDataFile; |
51 import org.tmatesoft.hg.repo.HgLookup; | 56 import org.tmatesoft.hg.repo.HgLookup; |
52 import org.tmatesoft.hg.repo.HgRepository; | 57 import org.tmatesoft.hg.repo.HgRepository; |
58 import org.tmatesoft.hg.util.Path; | |
53 | 59 |
54 /** | 60 /** |
55 * | 61 * |
56 * @author Artem Tikhomirov | 62 * @author Artem Tikhomirov |
57 * @author TMate Software Ltd. | 63 * @author TMate Software Ltd. |
58 */ | 64 */ |
59 public class TestBlame { | 65 public class TestBlame { |
60 | 66 |
61 @Rule | 67 @Rule |
62 public ErrorCollectorExt errorCollector = new ErrorCollectorExt(); | 68 public ErrorCollectorExt errorCollector = new ErrorCollectorExt(); |
63 private ExecHelper eh; | |
64 | 69 |
65 | 70 |
66 @Test | 71 @Test |
67 public void testSingleParentBlame() throws Exception { | 72 public void testSingleParentBlame() throws Exception { |
68 HgRepository repo = new HgLookup().detectFromWorkingDir(); | 73 HgRepository repo = new HgLookup().detectFromWorkingDir(); |
83 @Test | 88 @Test |
84 public void testFileLineAnnotate1() throws Exception { | 89 public void testFileLineAnnotate1() throws Exception { |
85 HgRepository repo = new HgLookup().detectFromWorkingDir(); | 90 HgRepository repo = new HgLookup().detectFromWorkingDir(); |
86 final String fname = "src/org/tmatesoft/hg/internal/PatchGenerator.java"; | 91 final String fname = "src/org/tmatesoft/hg/internal/PatchGenerator.java"; |
87 HgDataFile df = repo.getFileNode(fname); | 92 HgDataFile df = repo.getFileNode(fname); |
88 OutputParser.Stub op = new OutputParser.Stub(); | 93 AnnotateRunner ar = new AnnotateRunner(df.getPath(), null); |
89 eh = new ExecHelper(op, null); | 94 |
90 | 95 for (int cs : new int[] { 539, 541 /*, TIP */}) { |
91 for (int startChangeset : new int[] { 539, 541 /*, TIP */}) { | 96 ar.run(cs, false); |
92 doLineAnnotateTest(df, startChangeset, op); | 97 FileAnnotateInspector fa = new FileAnnotateInspector(); |
93 } | 98 FileAnnotation.annotate(df, cs, fa); |
94 } | 99 doAnnotateLineCheck(cs, ar.getLines(), Arrays.asList(fa.lineRevisions), Arrays.asList(fa.lines)); |
95 | |
96 private void doLineAnnotateTest(HgDataFile df, int cs, OutputParser.Stub op) throws HgCallbackTargetException, InterruptedException, IOException { | |
97 FileAnnotateInspector fa = new FileAnnotateInspector(); | |
98 FileAnnotation.annotate(df, cs, fa); | |
99 | |
100 op.reset(); | |
101 eh.run("hg", "annotate", "--no-follow", "-r", cs == TIP ? "tip" : String.valueOf(cs), df.getPath().toString()); | |
102 | |
103 String[] hgAnnotateLines = splitLines(op.result()); | |
104 assertTrue("[sanity]", hgAnnotateLines.length > 0); | |
105 assertEquals("Number of lines reported by native annotate and our impl", hgAnnotateLines.length, fa.lineRevisions.length); | |
106 | |
107 for (int i = 0; i < fa.lineRevisions.length; i++) { | |
108 int hgAnnotateRevIndex = Integer.parseInt(hgAnnotateLines[i].substring(0, hgAnnotateLines[i].indexOf(':')).trim()); | |
109 errorCollector.assertEquals(String.format("Revision mismatch for line %d (annotating rev: %d)", i+1, cs), hgAnnotateRevIndex, fa.lineRevisions[i]); | |
110 String hgAnnotateLine = hgAnnotateLines[i].substring(hgAnnotateLines[i].indexOf(':') + 1); | |
111 String apiLine = fa.line(i).trim(); | |
112 errorCollector.assertEquals(hgAnnotateLine.trim(), apiLine); | |
113 } | 100 } |
114 } | 101 } |
115 | 102 |
116 @Test | 103 @Test |
117 public void testFileLineAnnotate2() throws Exception { | 104 public void testFileLineAnnotate2() throws Exception { |
118 HgRepository repo = Configuration.get().find("test-annotate"); | 105 HgRepository repo = Configuration.get().find("test-annotate"); |
119 HgDataFile df = repo.getFileNode("file1"); | 106 HgDataFile df = repo.getFileNode("file1"); |
120 OutputParser.Stub op = new OutputParser.Stub(); | 107 AnnotateRunner ar = new AnnotateRunner(df.getPath(), repo.getWorkingDir()); |
121 eh = new ExecHelper(op, repo.getWorkingDir()); | 108 |
122 for (int cs : new int[] { 4, 6 /*, 8 see below*/, TIP}) { | 109 for (int cs : new int[] { 4, 6 /*, 8 see below*/, TIP}) { |
123 doLineAnnotateTest(df, cs, op); | 110 ar.run(cs, false); |
111 FileAnnotateInspector fa = new FileAnnotateInspector(); | |
112 FileAnnotation.annotate(df, cs, fa); | |
113 doAnnotateLineCheck(cs, ar.getLines(), Arrays.asList(fa.lineRevisions), Arrays.asList(fa.lines)); | |
124 } | 114 } |
125 /*`hg annotate -r 8` and HgBlameFacility give different result | 115 /*`hg annotate -r 8` and HgBlameFacility give different result |
126 * for "r0, line 5" line, which was deleted in rev2 and restored back in | 116 * for "r0, line 5" line, which was deleted in rev2 and restored back in |
127 * rev4 (both in default branch), while branch with r3 and r6 kept the line intact. | 117 * rev4 (both in default branch), while branch with r3 and r6 kept the line intact. |
128 * HgBlame reports rev4 for the line, `hg annotate` gives original, rev0. | 118 * HgBlame reports rev4 for the line, `hg annotate` gives original, rev0. |
193 } | 183 } |
194 } | 184 } |
195 } | 185 } |
196 errorCollector.assertTrue(String.format("Annotate API reported excessive diff: %s ", apiResult.toString()), apiResult.isEmpty()); | 186 errorCollector.assertTrue(String.format("Annotate API reported excessive diff: %s ", apiResult.toString()), apiResult.isEmpty()); |
197 } | 187 } |
188 | |
189 @Test | |
190 public void testAnnotateCmdFollowNoFollow() throws Exception { | |
191 HgRepoFacade hgRepoFacade = new HgRepoFacade(); | |
192 HgRepository repo = Configuration.get().find("test-annotate2"); | |
193 hgRepoFacade.init(repo); | |
194 HgAnnotateCommand cmd = hgRepoFacade.createAnnotateCommand(); | |
195 final Path fname = Path.create("file1b.txt"); | |
196 final int changeset = TIP; | |
197 AnnotateInspector ai = new AnnotateInspector(); | |
198 | |
199 cmd.changeset(changeset); | |
200 // follow | |
201 cmd.file(fname); | |
202 cmd.execute(ai); | |
203 AnnotateRunner ar = new AnnotateRunner(fname, repo.getWorkingDir()); | |
204 ar.run(changeset, true); | |
205 doAnnotateLineCheck(changeset, ar.getLines(), ai.changesets, ai.lines); | |
206 | |
207 // no follow | |
208 cmd.file(fname, false); | |
209 ai = new AnnotateInspector(); | |
210 cmd.execute(ai); | |
211 ar.run(changeset, false); | |
212 doAnnotateLineCheck(changeset, ar.getLines(), ai.changesets, ai.lines); | |
213 } | |
214 | |
215 private void doAnnotateLineCheck(int cs, String[] hgAnnotateLines, List<Integer> cmdChangesets, List<String> cmdLines) { | |
216 assertTrue("[sanity]", hgAnnotateLines.length > 0); | |
217 assertEquals("Number of lines reported by native annotate and our impl", hgAnnotateLines.length, cmdLines.size()); | |
218 | |
219 for (int i = 0; i < cmdChangesets.size(); i++) { | |
220 int hgAnnotateRevIndex = Integer.parseInt(hgAnnotateLines[i].substring(0, hgAnnotateLines[i].indexOf(':')).trim()); | |
221 errorCollector.assertEquals(String.format("Revision mismatch for line %d (annotating rev: %d)", i+1, cs), hgAnnotateRevIndex, cmdChangesets.get(i)); | |
222 String hgAnnotateLine = hgAnnotateLines[i].substring(hgAnnotateLines[i].indexOf(':') + 1); | |
223 String apiLine = cmdLines.get(i).trim(); | |
224 errorCollector.assertEquals(hgAnnotateLine.trim(), apiLine); | |
225 } | |
226 } | |
227 | |
228 // FIXME HgWorkingCopyStatusCollector (and HgStatusCollector), with their ancestors (rev 59/69) have examples | |
229 // of *incorrect* assignment of common lines (like "}") - our impl doesn't process common lines in any special way | |
230 // while original diff lib does. Would be nice to behave as close to original, as possible. | |
198 | 231 |
199 private static String[] splitLines(CharSequence seq) { | 232 private static String[] splitLines(CharSequence seq) { |
200 int lineCount = 0; | 233 int lineCount = 0; |
201 for (int i = 0, x = seq.length(); i < x; i++) { | 234 for (int i = 0, x = seq.length(); i < x; i++) { |
202 if (seq.charAt(i) == '\n') { | 235 if (seq.charAt(i) == '\n') { |
296 public static void main(String[] args) throws Throwable { | 329 public static void main(String[] args) throws Throwable { |
297 // System.out.println(Arrays.equals(new String[0], splitLines(""))); | 330 // System.out.println(Arrays.equals(new String[0], splitLines(""))); |
298 // System.out.println(Arrays.equals(new String[] { "abc" }, splitLines("abc"))); | 331 // System.out.println(Arrays.equals(new String[] { "abc" }, splitLines("abc"))); |
299 // System.out.println(Arrays.equals(new String[] { "a", "bc" }, splitLines("a\nbc"))); | 332 // System.out.println(Arrays.equals(new String[] { "a", "bc" }, splitLines("a\nbc"))); |
300 // System.out.println(Arrays.equals(new String[] { "a", "bc" }, splitLines("a\nbc\n"))); | 333 // System.out.println(Arrays.equals(new String[] { "a", "bc" }, splitLines("a\nbc\n"))); |
301 new TestBlame().ccc(); | 334 TestBlame tt = new TestBlame(); |
335 tt.ccc(); | |
302 } | 336 } |
303 | 337 |
304 private static class DiffOutInspector implements HgBlameFacility.Inspector { | 338 private static class DiffOutInspector implements HgBlameFacility.Inspector { |
305 private final PrintStream out; | 339 private final PrintStream out; |
306 private boolean dumpRevs; | 340 private boolean dumpRevs; |
388 } while (lineStart < seq.length()); | 422 } while (lineStart < seq.length()); |
389 } | 423 } |
390 } | 424 } |
391 | 425 |
392 private static class FileAnnotateInspector implements LineInspector { | 426 private static class FileAnnotateInspector implements LineInspector { |
393 private int[] lineRevisions; | 427 private Integer[] lineRevisions; |
394 private String[] lines; | 428 private String[] lines; |
395 | 429 |
396 FileAnnotateInspector() { | 430 FileAnnotateInspector() { |
397 } | 431 } |
398 | 432 |
399 public void line(int lineNumber, int changesetRevIndex, BlockData lineContent, LineDescriptor ld) { | 433 public void line(int lineNumber, int changesetRevIndex, BlockData lineContent, LineDescriptor ld) { |
400 if (lineRevisions == null) { | 434 if (lineRevisions == null) { |
401 lineRevisions = new int [ld.totalLines()]; | 435 lineRevisions = new Integer[ld.totalLines()]; |
402 Arrays.fill(lineRevisions, NO_REVISION); | 436 Arrays.fill(lineRevisions, NO_REVISION); |
403 lines = new String[ld.totalLines()]; | 437 lines = new String[ld.totalLines()]; |
404 } | 438 } |
405 lineRevisions[lineNumber] = changesetRevIndex; | 439 lineRevisions[lineNumber] = changesetRevIndex; |
406 lines[lineNumber] = new String(lineContent.asArray()); | 440 lines[lineNumber] = new String(lineContent.asArray()); |
449 String content = new String(lines.asArray()); | 483 String content = new String(lines.asArray()); |
450 System.out.printf("%3d:%s:[%d..%d):\n%s", cset, marker, first, first+length, content); | 484 System.out.printf("%3d:%s:[%d..%d):\n%s", cset, marker, first, first+length, content); |
451 } | 485 } |
452 } | 486 } |
453 } | 487 } |
488 | |
489 static class AnnotateInspector implements HgAnnotateCommand.Inspector { | |
490 private int lineNumber = 1; | |
491 public final ArrayList<String> lines = new ArrayList<String>(); | |
492 public final ArrayList<Integer> changesets = new ArrayList<Integer>(); | |
493 | |
494 public void next(LineInfo lineInfo) throws HgCallbackTargetException { | |
495 Assert.assertEquals(lineInfo.getLineNumber(), lineNumber); | |
496 lineNumber++; | |
497 lines.add(new String(lineInfo.getContent())); | |
498 changesets.add(lineInfo.getChangesetIndex()); | |
499 } | |
500 } | |
501 | |
502 private static class AnnotateRunner { | |
503 private final ExecHelper eh; | |
504 private final OutputParser.Stub op; | |
505 private final Path file; | |
506 | |
507 public AnnotateRunner(Path filePath, File repoDir) { | |
508 file = filePath; | |
509 op = new OutputParser.Stub(); | |
510 eh = new ExecHelper(op, repoDir); | |
511 } | |
512 | |
513 public void run(int cset, boolean follow) throws Exception { | |
514 op.reset(); | |
515 ArrayList<String> args = new ArrayList<String>(); | |
516 args.add("hg"); | |
517 args.add("annotate"); | |
518 args.add("-r"); | |
519 args.add(cset == TIP ? "tip" : String.valueOf(cset)); | |
520 if (!follow) { | |
521 args.add("--no-follow"); | |
522 } | |
523 args.add(file.toString()); | |
524 eh.run(args); | |
525 } | |
526 | |
527 public String[] getLines() { | |
528 return splitLines(op.result()); | |
529 } | |
530 } | |
454 } | 531 } |