Mercurial > hg4j
diff test/org/tmatesoft/hg/test/TestDiffHelper.java @ 551:4ea0351ca878
Better (precise) name for diff facility, tests
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 20 Feb 2013 18:19:52 +0100 |
parents | |
children | 8ed4f4f4f0a6 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/org/tmatesoft/hg/test/TestDiffHelper.java Wed Feb 20 18:19:52 2013 +0100 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2013 TMate Software Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@hg4j.com + */ +package org.tmatesoft.hg.test; + +import static org.junit.Assert.*; +import static org.tmatesoft.hg.internal.DiffHelper.LineSequence.newlines; + +import org.junit.Test; +import org.tmatesoft.hg.internal.DiffHelper; +import org.tmatesoft.hg.internal.DiffHelper.ChunkSequence; +import org.tmatesoft.hg.internal.DiffHelper.LineSequence; +import org.tmatesoft.hg.internal.IntVector; + +/** + * Testing DiffHelper (foundation for facilities like commit and annotate) directly + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class TestDiffHelper { + + @Test + public void testSimple() { + DiffHelper<LineSequence> diffHelper = new DiffHelper<LineSequence>(); + MatchCollector<LineSequence> mc; DeltaCollector dc; + + // single change + diffHelper.init(newlines("hello\nabc".getBytes()), newlines("hello\nworld".getBytes())); + diffHelper.findMatchingBlocks(mc = new MatchCollector<LineSequence>()); + assertEquals(1, mc.matchCount()); + assertTrue(mc.originLineMatched(0)); + assertTrue(mc.targetLineMatched(0)); + assertFalse(mc.originLineMatched(1)); + assertFalse(mc.targetLineMatched(1)); + diffHelper.findMatchingBlocks(dc = new DeltaCollector()); + assertEquals(1, dc.unchangedCount()); + assertEquals(1, dc.deletedCount()); + assertEquals(1, dc.addedCount()); + + // boundary case, additions to an empty origin + diffHelper.init(newlines("".getBytes()), newlines("hello\nworld".getBytes())); + diffHelper.findMatchingBlocks(mc = new MatchCollector<LineSequence>()); + assertEquals(0, mc.matchCount()); + diffHelper.findMatchingBlocks(dc = new DeltaCollector()); + assertEquals(0, dc.unchangedCount()); + assertEquals(0, dc.deletedCount()); + assertEquals(1, dc.addedCount()); // two lines added, but 1 range + + // boundary case, complete deletion + diffHelper.init(newlines("hello\nworld".getBytes()), newlines("".getBytes())); + diffHelper.findMatchingBlocks(mc = new MatchCollector<LineSequence>()); + assertEquals(0, mc.matchCount()); + diffHelper.findMatchingBlocks(dc = new DeltaCollector()); + assertEquals(0, dc.unchangedCount()); + assertEquals(1, dc.deletedCount()); + assertEquals(0, dc.addedCount()); + + // regular case, few changes + String s1 = "line 1\nline 2\r\nline 3\n\nline 1\nline 2"; + String s2 = "abc\ncdef\r\nline 2\r\nline 3\nline 2"; + diffHelper.init(newlines(s1.getBytes()), newlines(s2.getBytes())); + diffHelper.findMatchingBlocks(mc = new MatchCollector<LineSequence>()); + assertEquals(2, mc.matchCount()); + assertFalse(mc.originLineMatched(0)); + assertTrue(mc.originLineMatched(1)); + assertTrue(mc.originLineMatched(2)); + assertFalse(mc.originLineMatched(3)); + assertFalse(mc.originLineMatched(4)); + assertTrue(mc.originLineMatched(5)); + assertFalse(mc.targetLineMatched(0)); + assertFalse(mc.targetLineMatched(1)); + assertTrue(mc.targetLineMatched(2)); + assertTrue(mc.targetLineMatched(3)); + assertTrue(mc.targetLineMatched(4)); + diffHelper.findMatchingBlocks(dc = new DeltaCollector()); + assertEquals(2, dc.unchangedCount()); // 3 lines but 2 ranges + assertEquals(2, dc.deletedCount()); + assertEquals(1, dc.addedCount()); + assertTrue(dc.deletedLine(0)); + assertTrue(dc.deletedLine(3)); + assertTrue(dc.deletedLine(4)); + assertTrue(dc.addedLine(0)); + assertTrue(dc.addedLine(1)); + } + + @Test + public void testOtherSequence() { + class CharSequence implements DiffHelper.ChunkSequence<Character> { + private final char[] chunks; + + CharSequence(String s) { + chunks = s.toCharArray(); + } + public Character chunk(int index) { + return chunks[index]; + } + public int chunkCount() { + return chunks.length; + } + } + DiffHelper<CharSequence> diff = new DiffHelper<CharSequence>(); + diff.init(new CharSequence("abcefg"), new CharSequence("bcdegh")); + MatchCollector<CharSequence> mc; + diff.findMatchingBlocks(mc = new MatchCollector<CharSequence>()); + assertEquals(3, mc.matchCount()); // bc, e, g + } + + // range is comprised of 3 values, range length always last, range start comes at index o (either 0 or 1) + static boolean includes(IntVector ranges, int o, int ln) { + assert ranges.size() % 3 == 0; + for (int i = 2; i < ranges.size(); o += 3, i+=3) { + int rangeStart = ranges.get(o); + if (rangeStart > ln) { + return false; + } + int rangeLen = ranges.get(i); + if (rangeStart + rangeLen > ln) { + return true; + } + } + return false; + } + + static class MatchCollector<T extends ChunkSequence<?>> implements DiffHelper.MatchInspector<T> { + private IntVector matched = new IntVector(10 * 3, 5 * 3); + + public void begin(T s1, T s2) { + } + + public void match(int startSeq1, int startSeq2, int matchLength) { + matched.add(startSeq1, startSeq2, matchLength); + } + + public void end() { + } + + int matchCount() { + return matched.size() / 3; + } + + // true if zero-based line matches any "same" block in the origin + boolean originLineMatched(int ln) { + return includes(matched, 0, ln); + } + + boolean targetLineMatched(int ln) { + return includes(matched, 1, ln); + } + } + + static class DeltaCollector extends DiffHelper.DeltaInspector<LineSequence> { + private IntVector added, deleted, same; + public DeltaCollector() { + final int x = 10 * 3, y = 5 * 3; + added = new IntVector(x, y); + deleted = new IntVector(x, y); + same = new IntVector(x, y); + } + @Override + protected void added(int s1InsertPoint, int s2From, int s2To) { + // TODO Auto-generated method stub + added.add(s1InsertPoint, s2From, s2To - s2From); + } + @Override + protected void changed(int s1From, int s1To, int s2From, int s2To) { + deleted(s2From, s1From, s1To); + added(s1From, s2From, s2To); + } + @Override + protected void deleted(int s2DeletePoint, int s1From, int s1To) { + deleted.add(s2DeletePoint, s1From, s1To - s1From); + } + @Override + protected void unchanged(int s1From, int s2From, int length) { + same.add(s1From, s2From, length); + } + + int unchangedCount() { + return same.size() / 3; + } + + int addedCount() { + return added.size() / 3; + } + + int deletedCount() { + return deleted.size() / 3; + } + boolean addedLine(int ln) { + return includes(added, 1, ln); + } + boolean deletedLine(int ln) { + return includes(deleted, 1, ln); + } + } +}