diff 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
line wrap: on
line diff
--- a/test/org/tmatesoft/hg/test/TestBlame.java	Fri Feb 15 16:48:54 2013 +0100
+++ b/test/org/tmatesoft/hg/test/TestBlame.java	Fri Feb 15 22:15:13 2013 +0100
@@ -16,19 +16,23 @@
  */
 package org.tmatesoft.hg.test;
 
+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;
 import org.junit.Test;
 import org.tmatesoft.hg.internal.AnnotateFacility;
 import org.tmatesoft.hg.internal.AnnotateFacility.AddBlock;
-import org.tmatesoft.hg.internal.AnnotateFacility.Block;
 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.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;
@@ -58,6 +62,29 @@
 		Assert.assertArrayEquals(expected, apiResult);
 	}
 	
+	@Test
+	public void testFileAnnotate() 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));
+		
+		FileAnnotation fa = new FileAnnotation();
+		af.annotateChange(df, checkChangeset, fa);
+		af.annotateChange(df, 536, fa);
+		af.annotateChange(df, 531, fa);
+		for (int i = 0; i < fa.lineRevisions.length; i++) {
+			System.out.printf("%3d: %d\n", fa.lineRevisions[i], i+1);
+		}
+	}
+	
 	private static String[] splitLines(CharSequence seq) {
 		int lineCount = 0;
 		for (int i = 0, x = seq.length(); i < x; i++) {
@@ -101,9 +128,11 @@
 	}
 	
 	public static void main(String[] args) throws Exception {
-		System.out.println(Arrays.equals(new String[0], splitLines("")));
-		System.out.println(Arrays.equals(new String[] { "abc" }, splitLines("abc")));
-		new TestBlame().testSingleParentBlame();
+//		System.out.println(Arrays.equals(new String[0], splitLines("")));
+//		System.out.println(Arrays.equals(new String[] { "abc" }, splitLines("abc")));
+//		System.out.println(Arrays.equals(new String[] { "a", "bc" }, splitLines("a\nbc")));
+//		System.out.println(Arrays.equals(new String[] { "a", "bc" }, splitLines("a\nbc\n")));
+		new TestBlame().testFileAnnotate();
 	}
 
 	static class DiffOutInspector implements AnnotateFacility.Inspector {
@@ -113,7 +142,7 @@
 			out = ps;
 		}
 		
-		public void same(Block block) {
+		public void same(EqualBlock block) {
 			// nothing 
 		}
 		
@@ -171,4 +200,155 @@
 			} while (lineStart < seq.length());
 		}
 	}
+
+	private static class FileAnnotation implements AnnotateFacility.InspectorEx {
+		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() {
+		}
+		
+		public void start(int originLineCount, int targetLineCount) {
+			if (lineRevisions == null) {
+				lineRevisions = new int [targetLineCount];
+				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;
+		}
+	}
 }