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 }