Mercurial > hg4j
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; + } + } }