diff test/org/tmatesoft/hg/test/TestBlame.java @ 546:cd78e8b9d7bc

File annotate test. Refactored FileAnnotation as standalone class, introduced LineInspector to make line offset calc code shared
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 18 Feb 2013 19:19:48 +0100
parents 15b406c7cd9d
children ab21ac7dd833
line wrap: on
line diff
--- a/test/org/tmatesoft/hg/test/TestBlame.java	Fri Feb 15 22:15:13 2013 +0100
+++ b/test/org/tmatesoft/hg/test/TestBlame.java	Mon Feb 18 19:19:48 2013 +0100
@@ -16,12 +16,13 @@
  */
 package org.tmatesoft.hg.test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.util.Arrays;
-import java.util.LinkedList;
 import java.util.regex.Pattern;
 
 import org.junit.Assert;
@@ -31,8 +32,8 @@
 import org.tmatesoft.hg.internal.AnnotateFacility.ChangeBlock;
 import org.tmatesoft.hg.internal.AnnotateFacility.DeleteBlock;
 import org.tmatesoft.hg.internal.AnnotateFacility.EqualBlock;
+import org.tmatesoft.hg.internal.AnnotateFacility.LineDescriptor;
 import org.tmatesoft.hg.internal.IntMap;
-import org.tmatesoft.hg.internal.IntVector;
 import org.tmatesoft.hg.repo.HgDataFile;
 import org.tmatesoft.hg.repo.HgLookup;
 import org.tmatesoft.hg.repo.HgRepository;
@@ -66,22 +67,25 @@
 	public void testFileAnnotate() throws Exception {
 		HgRepository repo = new HgLookup().detectFromWorkingDir();
 		final String fname = "src/org/tmatesoft/hg/internal/PatchGenerator.java";
-		final int checkChangeset = 539;
+		final int[] checkChangesets = new int[] { 539 , 536, 531 };
 		HgDataFile df = repo.getFileNode(fname);
 		AnnotateFacility af = new AnnotateFacility();
-		System.out.println("536 -> 539");
-		af.annotateChange(df, checkChangeset, new DiffOutInspector(System.out));
-		System.out.println("531 -> 536");
-		af.annotateChange(df, 536, new DiffOutInspector(System.out));
-		System.out.println(" -1 -> 531");
-		af.annotateChange(df, 531, new DiffOutInspector(System.out));
+		FileAnnotateInspector fa = new FileAnnotateInspector();
+		for (int cs : checkChangesets) {
+			af.annotateChange(df, cs, new FileAnnotation(fa));
+		}
 		
-		FileAnnotation fa = new FileAnnotation();
-		af.annotateChange(df, checkChangeset, fa);
-		af.annotateChange(df, 536, fa);
-		af.annotateChange(df, 531, fa);
+		OutputParser.Stub op = new OutputParser.Stub();
+		ExecHelper eh = new ExecHelper(op, null);
+		eh.run("hg", "annotate", "-r", String.valueOf(checkChangesets[0]), fname);
+		
+		String[] hgAnnotateLines = splitLines(op.result());
+		assertTrue("[sanity]", hgAnnotateLines.length > 0);
+		assertEquals("Number of lines reported by native annotate and our impl", hgAnnotateLines.length, fa.lineRevisions.length);
+
 		for (int i = 0; i < fa.lineRevisions.length; i++) {
-			System.out.printf("%3d: %d\n", fa.lineRevisions[i], i+1);
+			int hgAnnotateRevIndex = Integer.parseInt(hgAnnotateLines[i].substring(0, hgAnnotateLines[i].indexOf(':')));
+			assertEquals(String.format("Revision mismatch for line %d", i+1), hgAnnotateRevIndex, fa.lineRevisions[i]);
 		}
 	}
 	
@@ -110,7 +114,19 @@
 		return rv;
 	}
 	
-	private void leftovers() {
+	private void leftovers() throws Exception {
+		HgRepository repo = new HgLookup().detectFromWorkingDir();
+		final String fname = "src/org/tmatesoft/hg/internal/PatchGenerator.java";
+		final int checkChangeset = 539;
+		HgDataFile df = repo.getFileNode(fname);
+		AnnotateFacility af = new AnnotateFacility();
+		System.out.println("536 -> 539");
+		af.annotateChange(df, checkChangeset, new DiffOutInspector(System.out));
+		System.out.println("531 -> 536");
+		af.annotateChange(df, 536, new DiffOutInspector(System.out));
+		System.out.println(" -1 -> 531");
+		af.annotateChange(df, 531, new DiffOutInspector(System.out));
+
 		IntMap<String> linesOld = new IntMap<String>(100), linesNew = new IntMap<String>(100);
 		System.out.println("Changes to old revision:");
 		for (int i = linesOld.firstKey(), x = linesOld.lastKey(); i < x; i++) {
@@ -135,7 +151,7 @@
 		new TestBlame().testFileAnnotate();
 	}
 
-	static class DiffOutInspector implements AnnotateFacility.Inspector {
+	static class DiffOutInspector implements AnnotateFacility.BlockInspector {
 		private final PrintStream out;
 		
 		DiffOutInspector(PrintStream ps) {
@@ -201,154 +217,19 @@
 		}
 	}
 
-	private static class FileAnnotation implements AnnotateFacility.InspectorEx {
+	private static class FileAnnotateInspector implements AnnotateFacility.LineInspector {
 		private int[] lineRevisions;
-		private LinkedList<DeleteBlock> deleted = new LinkedList<DeleteBlock>();
-		private LinkedList<DeleteBlock> newDeleted = new LinkedList<DeleteBlock>();
-		// keeps <startSeq1, startSeq2, len> of equal blocks
-		// XXX smth like IntSliceVector to access triples (or slices of any size, in fact)
-		// with easy indexing, e.g. #get(sliceIndex, indexWithinSlice)
-		// and vect.get(7,2) instead of vect.get(7*SIZEOF_SLICE+2)
-		private IntVector identical = new IntVector(20*3, 2*3);
-		private IntVector newIdentical = new IntVector(20*3, 2*3);
 		
-		public FileAnnotation() {
+		FileAnnotateInspector() {
 		}
 		
-		public void start(int originLineCount, int targetLineCount) {
+		public void line(int lineNumber, int changesetRevIndex, LineDescriptor ld) {
 			if (lineRevisions == null) {
-				lineRevisions = new int [targetLineCount];
+				lineRevisions = new int [ld.totalLines()];
 				Arrays.fill(lineRevisions, NO_REVISION);
 			}
-		}
-
-//		private static void ppp(IntVector v) {
-//			for (int i = 0; i < v.size(); i+= 3) {
-//				int len = v.get(i+2);
-//				System.out.printf("[%d..%d) == [%d..%d);  ", v.get(i), v.get(i) + len, v.get(i+1), v.get(i+1) + len);
-//			}
-//			System.out.println();
-//		}
-
-		public void done() {
-			if (identical.size() > 0) {
-				// update line numbers of the intermediate target to point to ultimate target's line numbers
-				IntVector v = new IntVector(identical.size(), 2*3);
-				for (int i = 0; i < newIdentical.size(); i+= 3) {
-					int originLine = newIdentical.get(i);
-					int targetLine = newIdentical.get(i+1);
-					int length = newIdentical.get(i+2);
-					int startTargetLine = -1, startOriginLine = -1, c = 0;
-					for (int j = 0; j < length; j++) {
-						int lnInFinal = mapLineIndex(targetLine + j);
-						if (lnInFinal == -1 || (startTargetLine != -1 && lnInFinal != startTargetLine + c)) {
-							// the line is not among "same" in ultimate origin
-							// or belongs to another/next "same" chunk 
-							if (startOriginLine == -1) {
-								continue;
-							}
-							v.add(startOriginLine);
-							v.add(startTargetLine);
-							v.add(c);
-							c = 0;
-							startOriginLine = startTargetLine = -1;
-							// fall-through to check if it's not complete miss but a next chunk
-						}
-						if (lnInFinal != -1) {
-							if (startOriginLine == -1) {
-								startOriginLine = originLine + j;
-								startTargetLine = lnInFinal;
-								c = 1;
-							} else {
-								assert lnInFinal == startTargetLine + c;
-								c++;
-							}
-						}
-					}
-					if (startOriginLine != -1) {
-						assert c > 0;
-						v.add(startOriginLine);
-						v.add(startTargetLine);
-						v.add(c);
-					}
-				}
-				newIdentical.clear();
-				identical = v;
-			} else {
-				IntVector li = newIdentical;
-				newIdentical = identical;
-				identical = li;
-			}
-			LinkedList<DeleteBlock> ld = newDeleted;
-			deleted.clear();
-			newDeleted = deleted;
-			deleted = ld;
-		}
-		
-		public void same(EqualBlock block) {
-			newIdentical.add(block.originStart());
-			newIdentical.add(block.targetStart());
-			newIdentical.add(block.length());
-		}
-
-		public void added(AddBlock block) {
-			for (int i = 0, ln = block.firstAddedLine(), x = block.totalAddedLines(); i < x; i++, ln++) {
-				int lnInFinal = mapLineIndex(ln);
-				if (lnInFinal != -1 && historyUnknown(lnInFinal)) {
-					lineRevisions[lnInFinal] = block.targetChangesetIndex();
-				}
-			}
-		}
-
-		public void changed(ChangeBlock block) {
-			deleted(block);
-			added(block);
-		}
-
-		public void deleted(DeleteBlock block) {
-			newDeleted.add(block);
-		}
-		
-		private boolean historyUnknown(int lineNumber) {
-			return lineRevisions[lineNumber] == NO_REVISION;
-		}
-
-		private boolean isDeleted(int line) {
-			for (DeleteBlock b : deleted) {
-				if (b.firstRemovedLine() > line) {
-					break;
-				}
-				// line >= b.firstRemovedLine
-				if (b.firstRemovedLine() + b.totalRemovedLines() > line) {
-					return true;
-				}
-			}
-			return false;
-		}
-
-		// map target lines to the lines of the revision being annotated (the one that came first)
-		private int mapLineIndex(int ln) {
-			if (isDeleted(ln)) {
-				return -1;
-			}
-			if (identical.isEmpty()) {
-				return ln;
-			}
-			for (int i = 0; i < identical.size(); i += 3) {
-				final int originStart = identical.get(i);
-				if (originStart > ln) {
-					assert false;
-					return -1;
-				}
-				// ln >= b.originStart
-				final int length = identical.get(i+2);
-				if (originStart + length > ln) {
-					int targetStart = identical.get(i+1);
-					return targetStart + (ln - originStart);
-				}
-			}
-			assert false;
-			return -1;
+			lineRevisions[lineNumber] = changesetRevIndex;
 		}
 	}
+
 }