// Copyright 2004-2014 Jim Voris // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package org.apache.commons.jrcs.diff.myers; import org.apache.commons.jrcs.diff.AddDelta; import org.apache.commons.jrcs.diff.ChangeDelta; import org.apache.commons.jrcs.diff.DeleteDelta; import org.apache.commons.jrcs.diff.Delta; import org.apache.commons.jrcs.diff.Diff; import org.apache.commons.jrcs.diff.DiffAlgorithm; import org.apache.commons.jrcs.diff.DifferentiationFailedException; import org.apache.commons.jrcs.diff.PatchFailedException; import org.apache.commons.jrcs.diff.Revision; import org.apache.commons.jrcs.diff.RevisionVisitor; import org.apache.commons.jrcs.diff.SimpleDiff; import org.junit.Test; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import static org.junit.Assert.*; public class MyersDiffTest { static final int LARGE=2*1024; private DiffAlgorithm algorithm = new MyersDiff(); Object[] empty; Object[] original; Object[] rev1; Object[] rev2; @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() throws Exception { empty = new Object[] {}; original = new String[] { "[1] one", "[2] two", "[3] three", "[4] four", "[5] five", "[6] six", "[7] seven", "[8] eight", "[9] nine" }; // lines 3 and 9 deleted rev1 = new String[] { "[1] one", "[2] two", "[4] four", "[5] five", "[6] six", "[7] seven", "[8] eight", }; // lines 7 and 8 changed, 9 deleted rev2 = new String[] { "[1] one", "[2] two", "[3] three", "[4] four", "[5] five", "[6] six", "[7] seven revised", "[8] eight revised", }; } @After public void tearDown() { } @Test public void testCompare() { assertTrue(!Diff.compare(original, empty)); assertTrue(!Diff.compare(empty, original)); assertTrue(Diff.compare(empty, empty)); assertTrue(Diff.compare(original, original)); } @Test public void testEmptySequences() throws DifferentiationFailedException { String[] emptyOrig = {}; String[] emptyRev = {}; Revision revision = Diff.diff(emptyOrig, emptyRev, algorithm); assertEquals("revision size is not zero", 0, revision.size()); } @Test public void testOriginalEmpty() throws DifferentiationFailedException { String[] emptyOrig = {}; String[] rev = {"1", "2", "3"}; Revision revision = Diff.diff(emptyOrig, rev, algorithm); assertEquals("revision size should be one", 1, revision.size()); assertTrue(revision.getDelta(0) instanceof AddDelta); } @Test public void testRevisedEmpty() throws DifferentiationFailedException { String[] orig = {"1", "2", "3"}; String[] emptyRev = {}; Revision revision = Diff.diff(orig, emptyRev, algorithm); assertEquals("revision size should be one", 1, revision.size()); assertTrue(revision.getDelta(0) instanceof DeleteDelta); } @Test public void testDeleteAll() throws DifferentiationFailedException, PatchFailedException { Revision revision = Diff.diff(original, empty, algorithm); assertEquals(1, revision.size()); assertEquals(DeleteDelta.class, revision.getDelta(0).getClass()); assertTrue(Diff.compare(revision.patch(original), empty)); } @Test public void testTwoDeletes() throws DifferentiationFailedException, PatchFailedException { Revision revision = Diff.diff(original, rev1, algorithm); assertEquals(2, revision.size()); assertEquals(DeleteDelta.class, revision.getDelta(0).getClass()); assertEquals(DeleteDelta.class, revision.getDelta(1).getClass()); assertTrue(Diff.compare(revision.patch(original), rev1)); assertEquals("3d2" + Diff.NL + "< [3] three" + Diff.NL + "9d7" + Diff.NL + "< [9] nine" + Diff.NL , revision.toString()); } @Test public void testChangeAtTheEnd() throws DifferentiationFailedException, PatchFailedException { Revision revision = Diff.diff(original, rev2, algorithm); assertEquals(1, revision.size()); assertEquals(ChangeDelta.class, revision.getDelta(0).getClass()); assertTrue(Diff.compare(revision.patch(original), rev2)); assertEquals("d7 3" + Diff.NL + "a9 2" + Diff.NL + "[7] seven revised" + Diff.NL + "[8] eight revised" + Diff.NL, revision.toRCSString()); } @Test public void testPatchFailed() throws DifferentiationFailedException { try { Revision revision = Diff.diff(original, rev2, algorithm); assertTrue(!Diff.compare(revision.patch(rev1), rev2)); fail("PatchFailedException not thrown"); } catch (PatchFailedException e) { } } @Test public void testPreviouslyFailedShuffle() throws DifferentiationFailedException, PatchFailedException { Object[] orig = new String[] { "[1] one", "[2] two", "[3] three", "[4] four", "[5] five", "[6] six" }; Object[] rev = new String[] { "[3] three", "[1] one", "[5] five", "[2] two", "[6] six", "[4] four" }; Revision revision = Diff.diff(orig, rev, algorithm); Object[] patched = revision.patch(orig); assertTrue(Diff.compare(patched, rev)); } @Test public void testEdit5() throws DifferentiationFailedException, PatchFailedException { Object[] orig = new String[] { "[1] one", "[2] two", "[3] three", "[4] four", "[5] five", "[6] six" }; Object[] rev = new String[] { "one revised", "two revised", "[2] two", "[3] three", "five revised", "six revised", "[5] five" }; Revision revision = Diff.diff(orig, rev, algorithm); Object[] patched = revision.patch(orig); assertTrue(Diff.compare(patched, rev)); } @Test public void testShuffle() throws DifferentiationFailedException, PatchFailedException { Object[] orig = new String[] { "[1] one", "[2] two", "[3] three", "[4] four", "[5] five", "[6] six" }; for (int seed = 0; seed < 10; seed++) { Object[] shuffle = Diff.shuffle(orig); Revision revision = Diff.diff(orig, shuffle, algorithm); Object[] patched = revision.patch(orig); if (!Diff.compare(patched, shuffle)) { fail("iter " + seed + " revisions differ after patch"); } } } @Test public void testRandomEdit() throws DifferentiationFailedException, PatchFailedException { Object[] orig = original; for (int seed = 0; seed < 10; seed++) { Object[] random = Diff.randomEdit(orig, seed); Revision revision = Diff.diff(orig, random, algorithm); Object[] patched = revision.patch(orig); if (!Diff.compare(patched, random)) { fail("iter " + seed + " revisions differ after patch"); } orig = random; } } @Test public void testVisitor() { Object[] orig = new String[] { "[1] one", "[2] two", "[3] three", "[4] four", "[5] five", "[6] six" }; Object[] rev = new String[] { "[1] one", "[2] two revised", "[3] three", "[4] four revised", "[5] five", "[6] six" }; class Visitor implements RevisionVisitor { StringBuffer sb = new StringBuffer(); @Override public void visit(Revision revision) { sb.append("visited Revision\n"); } @Override public void visit(DeleteDelta delta) { visit( (Delta) delta); } @Override public void visit(ChangeDelta delta) { visit( (Delta) delta); } @Override public void visit(AddDelta delta) { visit( (Delta) delta); } public void visit(Delta delta) { sb.append(delta.getRevised()); sb.append("\n"); } @Override public String toString() { return sb.toString(); } } Visitor visitor = new Visitor(); try { Diff.diff(orig, rev, algorithm).accept(visitor); assertEquals(visitor.toString(), "visited Revision\n" + "[2] two revised\n" + "[4] four revised\n"); } catch (Exception e) { fail(e.toString()); } } @Test public void testAlternativeAlgorithm() throws DifferentiationFailedException, PatchFailedException { Revision revision = Diff.diff(original, rev2, new SimpleDiff()); assertEquals(1, revision.size()); assertEquals(ChangeDelta.class, revision.getDelta(0).getClass()); assertTrue(Diff.compare(revision.patch(original), rev2)); assertEquals("d7 3" + Diff.NL + "a9 2" + Diff.NL + "[7] seven revised" + Diff.NL + "[8] eight revised" + Diff.NL, revision.toRCSString()); } @Test public void testLargeShuffles() throws DifferentiationFailedException, PatchFailedException { Object[] orig = Diff.randomSequence(LARGE); for (int seed = 0; seed < 3; seed++) { Object[] rev = Diff.shuffle(orig); Revision revision = Diff.diff(orig, rev, algorithm); Object[] patched = revision.patch(orig); if (!Diff.compare(patched, rev)) { fail("iter " + seed + " revisions differ after patch"); } orig = rev; } } @Test public void testLargeShuffleEdits() throws DifferentiationFailedException, PatchFailedException { Object[] orig = Diff.randomSequence(LARGE); for (int seed = 0; seed < 3; seed++) { Object[] rev = Diff.randomEdit(orig, seed); Revision revision = Diff.diff(orig, rev, algorithm); Object[] patched = revision.patch(orig); if (!Diff.compare(patched, rev)) { fail("iter " + seed + " revisions differ after patch"); } } } @Test public void testLargeAllEdited() throws DifferentiationFailedException, PatchFailedException { Object[] orig = Diff.randomSequence(LARGE); Object[] rev = Diff.editAll(orig); Revision revision = Diff.diff(orig, rev, algorithm); Object[] patched = revision.patch(orig); if (!Diff.compare(patched, rev)) { fail("revisions differ after patch"); } } }