Mercurial > hg4j
comparison test/org/tmatesoft/hg/test/TestBlame.java @ 545:15b406c7cd9d
First round of annotate file is functional
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 15 Feb 2013 22:15:13 +0100 |
parents | 7f5998a9619d |
children | cd78e8b9d7bc |
comparison
equal
deleted
inserted
replaced
544:7f5998a9619d | 545:15b406c7cd9d |
---|---|
14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
16 */ | 16 */ |
17 package org.tmatesoft.hg.test; | 17 package org.tmatesoft.hg.test; |
18 | 18 |
19 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; | |
20 | |
19 import java.io.ByteArrayOutputStream; | 21 import java.io.ByteArrayOutputStream; |
20 import java.io.PrintStream; | 22 import java.io.PrintStream; |
21 import java.util.Arrays; | 23 import java.util.Arrays; |
24 import java.util.LinkedList; | |
22 import java.util.regex.Pattern; | 25 import java.util.regex.Pattern; |
23 | 26 |
24 import org.junit.Assert; | 27 import org.junit.Assert; |
25 import org.junit.Test; | 28 import org.junit.Test; |
26 import org.tmatesoft.hg.internal.AnnotateFacility; | 29 import org.tmatesoft.hg.internal.AnnotateFacility; |
27 import org.tmatesoft.hg.internal.AnnotateFacility.AddBlock; | 30 import org.tmatesoft.hg.internal.AnnotateFacility.AddBlock; |
28 import org.tmatesoft.hg.internal.AnnotateFacility.Block; | |
29 import org.tmatesoft.hg.internal.AnnotateFacility.ChangeBlock; | 31 import org.tmatesoft.hg.internal.AnnotateFacility.ChangeBlock; |
30 import org.tmatesoft.hg.internal.AnnotateFacility.DeleteBlock; | 32 import org.tmatesoft.hg.internal.AnnotateFacility.DeleteBlock; |
33 import org.tmatesoft.hg.internal.AnnotateFacility.EqualBlock; | |
31 import org.tmatesoft.hg.internal.IntMap; | 34 import org.tmatesoft.hg.internal.IntMap; |
35 import org.tmatesoft.hg.internal.IntVector; | |
32 import org.tmatesoft.hg.repo.HgDataFile; | 36 import org.tmatesoft.hg.repo.HgDataFile; |
33 import org.tmatesoft.hg.repo.HgLookup; | 37 import org.tmatesoft.hg.repo.HgLookup; |
34 import org.tmatesoft.hg.repo.HgRepository; | 38 import org.tmatesoft.hg.repo.HgRepository; |
35 | 39 |
36 /** | 40 /** |
56 String[] apiResult = splitLines(bos.toString()); | 60 String[] apiResult = splitLines(bos.toString()); |
57 String[] expected = splitLines(gp.result()); | 61 String[] expected = splitLines(gp.result()); |
58 Assert.assertArrayEquals(expected, apiResult); | 62 Assert.assertArrayEquals(expected, apiResult); |
59 } | 63 } |
60 | 64 |
65 @Test | |
66 public void testFileAnnotate() throws Exception { | |
67 HgRepository repo = new HgLookup().detectFromWorkingDir(); | |
68 final String fname = "src/org/tmatesoft/hg/internal/PatchGenerator.java"; | |
69 final int checkChangeset = 539; | |
70 HgDataFile df = repo.getFileNode(fname); | |
71 AnnotateFacility af = new AnnotateFacility(); | |
72 System.out.println("536 -> 539"); | |
73 af.annotateChange(df, checkChangeset, new DiffOutInspector(System.out)); | |
74 System.out.println("531 -> 536"); | |
75 af.annotateChange(df, 536, new DiffOutInspector(System.out)); | |
76 System.out.println(" -1 -> 531"); | |
77 af.annotateChange(df, 531, new DiffOutInspector(System.out)); | |
78 | |
79 FileAnnotation fa = new FileAnnotation(); | |
80 af.annotateChange(df, checkChangeset, fa); | |
81 af.annotateChange(df, 536, fa); | |
82 af.annotateChange(df, 531, fa); | |
83 for (int i = 0; i < fa.lineRevisions.length; i++) { | |
84 System.out.printf("%3d: %d\n", fa.lineRevisions[i], i+1); | |
85 } | |
86 } | |
87 | |
61 private static String[] splitLines(CharSequence seq) { | 88 private static String[] splitLines(CharSequence seq) { |
62 int lineCount = 0; | 89 int lineCount = 0; |
63 for (int i = 0, x = seq.length(); i < x; i++) { | 90 for (int i = 0, x = seq.length(); i < x; i++) { |
64 if (seq.charAt(i) == '\n') { | 91 if (seq.charAt(i) == '\n') { |
65 lineCount++; | 92 lineCount++; |
99 } | 126 } |
100 } | 127 } |
101 } | 128 } |
102 | 129 |
103 public static void main(String[] args) throws Exception { | 130 public static void main(String[] args) throws Exception { |
104 System.out.println(Arrays.equals(new String[0], splitLines(""))); | 131 // System.out.println(Arrays.equals(new String[0], splitLines(""))); |
105 System.out.println(Arrays.equals(new String[] { "abc" }, splitLines("abc"))); | 132 // System.out.println(Arrays.equals(new String[] { "abc" }, splitLines("abc"))); |
106 new TestBlame().testSingleParentBlame(); | 133 // System.out.println(Arrays.equals(new String[] { "a", "bc" }, splitLines("a\nbc"))); |
134 // System.out.println(Arrays.equals(new String[] { "a", "bc" }, splitLines("a\nbc\n"))); | |
135 new TestBlame().testFileAnnotate(); | |
107 } | 136 } |
108 | 137 |
109 static class DiffOutInspector implements AnnotateFacility.Inspector { | 138 static class DiffOutInspector implements AnnotateFacility.Inspector { |
110 private final PrintStream out; | 139 private final PrintStream out; |
111 | 140 |
112 DiffOutInspector(PrintStream ps) { | 141 DiffOutInspector(PrintStream ps) { |
113 out = ps; | 142 out = ps; |
114 } | 143 } |
115 | 144 |
116 public void same(Block block) { | 145 public void same(EqualBlock block) { |
117 // nothing | 146 // nothing |
118 } | 147 } |
119 | 148 |
120 public void deleted(DeleteBlock block) { | 149 public void deleted(DeleteBlock block) { |
121 out.printf("@@ -%d,%d +%d,0 @@\n", block.firstRemovedLine() + 1, block.totalRemovedLines(), block.removedAt()); | 150 out.printf("@@ -%d,%d +%d,0 @@\n", block.firstRemovedLine() + 1, block.totalRemovedLines(), block.removedAt()); |
169 } | 198 } |
170 lineStart = ++lineEnd; | 199 lineStart = ++lineEnd; |
171 } while (lineStart < seq.length()); | 200 } while (lineStart < seq.length()); |
172 } | 201 } |
173 } | 202 } |
203 | |
204 private static class FileAnnotation implements AnnotateFacility.InspectorEx { | |
205 private int[] lineRevisions; | |
206 private LinkedList<DeleteBlock> deleted = new LinkedList<DeleteBlock>(); | |
207 private LinkedList<DeleteBlock> newDeleted = new LinkedList<DeleteBlock>(); | |
208 // keeps <startSeq1, startSeq2, len> of equal blocks | |
209 // XXX smth like IntSliceVector to access triples (or slices of any size, in fact) | |
210 // with easy indexing, e.g. #get(sliceIndex, indexWithinSlice) | |
211 // and vect.get(7,2) instead of vect.get(7*SIZEOF_SLICE+2) | |
212 private IntVector identical = new IntVector(20*3, 2*3); | |
213 private IntVector newIdentical = new IntVector(20*3, 2*3); | |
214 | |
215 public FileAnnotation() { | |
216 } | |
217 | |
218 public void start(int originLineCount, int targetLineCount) { | |
219 if (lineRevisions == null) { | |
220 lineRevisions = new int [targetLineCount]; | |
221 Arrays.fill(lineRevisions, NO_REVISION); | |
222 } | |
223 } | |
224 | |
225 // private static void ppp(IntVector v) { | |
226 // for (int i = 0; i < v.size(); i+= 3) { | |
227 // int len = v.get(i+2); | |
228 // System.out.printf("[%d..%d) == [%d..%d); ", v.get(i), v.get(i) + len, v.get(i+1), v.get(i+1) + len); | |
229 // } | |
230 // System.out.println(); | |
231 // } | |
232 | |
233 public void done() { | |
234 if (identical.size() > 0) { | |
235 // update line numbers of the intermediate target to point to ultimate target's line numbers | |
236 IntVector v = new IntVector(identical.size(), 2*3); | |
237 for (int i = 0; i < newIdentical.size(); i+= 3) { | |
238 int originLine = newIdentical.get(i); | |
239 int targetLine = newIdentical.get(i+1); | |
240 int length = newIdentical.get(i+2); | |
241 int startTargetLine = -1, startOriginLine = -1, c = 0; | |
242 for (int j = 0; j < length; j++) { | |
243 int lnInFinal = mapLineIndex(targetLine + j); | |
244 if (lnInFinal == -1 || (startTargetLine != -1 && lnInFinal != startTargetLine + c)) { | |
245 // the line is not among "same" in ultimate origin | |
246 // or belongs to another/next "same" chunk | |
247 if (startOriginLine == -1) { | |
248 continue; | |
249 } | |
250 v.add(startOriginLine); | |
251 v.add(startTargetLine); | |
252 v.add(c); | |
253 c = 0; | |
254 startOriginLine = startTargetLine = -1; | |
255 // fall-through to check if it's not complete miss but a next chunk | |
256 } | |
257 if (lnInFinal != -1) { | |
258 if (startOriginLine == -1) { | |
259 startOriginLine = originLine + j; | |
260 startTargetLine = lnInFinal; | |
261 c = 1; | |
262 } else { | |
263 assert lnInFinal == startTargetLine + c; | |
264 c++; | |
265 } | |
266 } | |
267 } | |
268 if (startOriginLine != -1) { | |
269 assert c > 0; | |
270 v.add(startOriginLine); | |
271 v.add(startTargetLine); | |
272 v.add(c); | |
273 } | |
274 } | |
275 newIdentical.clear(); | |
276 identical = v; | |
277 } else { | |
278 IntVector li = newIdentical; | |
279 newIdentical = identical; | |
280 identical = li; | |
281 } | |
282 LinkedList<DeleteBlock> ld = newDeleted; | |
283 deleted.clear(); | |
284 newDeleted = deleted; | |
285 deleted = ld; | |
286 } | |
287 | |
288 public void same(EqualBlock block) { | |
289 newIdentical.add(block.originStart()); | |
290 newIdentical.add(block.targetStart()); | |
291 newIdentical.add(block.length()); | |
292 } | |
293 | |
294 public void added(AddBlock block) { | |
295 for (int i = 0, ln = block.firstAddedLine(), x = block.totalAddedLines(); i < x; i++, ln++) { | |
296 int lnInFinal = mapLineIndex(ln); | |
297 if (lnInFinal != -1 && historyUnknown(lnInFinal)) { | |
298 lineRevisions[lnInFinal] = block.targetChangesetIndex(); | |
299 } | |
300 } | |
301 } | |
302 | |
303 public void changed(ChangeBlock block) { | |
304 deleted(block); | |
305 added(block); | |
306 } | |
307 | |
308 public void deleted(DeleteBlock block) { | |
309 newDeleted.add(block); | |
310 } | |
311 | |
312 private boolean historyUnknown(int lineNumber) { | |
313 return lineRevisions[lineNumber] == NO_REVISION; | |
314 } | |
315 | |
316 private boolean isDeleted(int line) { | |
317 for (DeleteBlock b : deleted) { | |
318 if (b.firstRemovedLine() > line) { | |
319 break; | |
320 } | |
321 // line >= b.firstRemovedLine | |
322 if (b.firstRemovedLine() + b.totalRemovedLines() > line) { | |
323 return true; | |
324 } | |
325 } | |
326 return false; | |
327 } | |
328 | |
329 // map target lines to the lines of the revision being annotated (the one that came first) | |
330 private int mapLineIndex(int ln) { | |
331 if (isDeleted(ln)) { | |
332 return -1; | |
333 } | |
334 if (identical.isEmpty()) { | |
335 return ln; | |
336 } | |
337 for (int i = 0; i < identical.size(); i += 3) { | |
338 final int originStart = identical.get(i); | |
339 if (originStart > ln) { | |
340 assert false; | |
341 return -1; | |
342 } | |
343 // ln >= b.originStart | |
344 final int length = identical.get(i+2); | |
345 if (originStart + length > ln) { | |
346 int targetStart = identical.get(i+1); | |
347 return targetStart + (ln - originStart); | |
348 } | |
349 } | |
350 assert false; | |
351 return -1; | |
352 } | |
353 } | |
174 } | 354 } |