diff --git a/common/src/test/java/com/jeesite/test/diff/diff_match_patch.java b/common/src/main/java/com/jeesite/common/text/DiffMatchPatch.java similarity index 100% rename from common/src/test/java/com/jeesite/test/diff/diff_match_patch.java rename to common/src/main/java/com/jeesite/common/text/DiffMatchPatch.java diff --git a/common/src/main/java/com/jeesite/common/text/DiffMatchPatchTest.java b/common/src/main/java/com/jeesite/common/text/DiffMatchPatchTest.java new file mode 100644 index 00000000..57baafed --- /dev/null +++ b/common/src/main/java/com/jeesite/common/text/DiffMatchPatchTest.java @@ -0,0 +1,956 @@ +/* + * Test harness for diff_match_patch.java + * + * Copyright 2006 Google Inc. + * http://code.google.com/p/google-diff-match-patch/ + * + * 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 com.jeesite.common.text; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import com.jeesite.common.io.FileUtils; +import com.jeesite.common.text.DiffMatchPatch.Diff; +import com.jeesite.common.text.DiffMatchPatch.LinesToCharsResult; +import com.jeesite.common.text.DiffMatchPatch.Patch; + +import junit.framework.Assert; + +@SuppressWarnings("deprecation") +public class DiffMatchPatchTest { + + private DiffMatchPatch dmp; + private DiffMatchPatch.Operation DELETE = DiffMatchPatch.Operation.DELETE; + private DiffMatchPatch.Operation EQUAL = DiffMatchPatch.Operation.EQUAL; + private DiffMatchPatch.Operation INSERT = DiffMatchPatch.Operation.INSERT; + + public DiffMatchPatchTest() { + // Create an instance of the diff_match_patch object. + dmp = new DiffMatchPatch(); + } + + + // DIFF TEST FUNCTIONS + + public void testDiffCommonPrefix() { + // Detect any common prefix. + assertEquals("diff_commonPrefix: Null case.", 0, dmp.diff_commonPrefix("abc", "xyz")); + + assertEquals("diff_commonPrefix: Non-null case.", 4, dmp.diff_commonPrefix("1234abcdef", "1234xyz")); + + assertEquals("diff_commonPrefix: Whole case.", 4, dmp.diff_commonPrefix("1234", "1234xyz")); + } + + public void testDiffCommonSuffix() { + // Detect any common suffix. + assertEquals("diff_commonSuffix: Null case.", 0, dmp.diff_commonSuffix("abc", "xyz")); + + assertEquals("diff_commonSuffix: Non-null case.", 4, dmp.diff_commonSuffix("abcdef1234", "xyz1234")); + + assertEquals("diff_commonSuffix: Whole case.", 4, dmp.diff_commonSuffix("1234", "xyz1234")); + } + + public void testDiffCommonOverlap() { + // Detect any suffix/prefix overlap. + assertEquals("diff_commonOverlap: Null case.", 0, dmp.diff_commonOverlap("", "abcd")); + + assertEquals("diff_commonOverlap: Whole case.", 3, dmp.diff_commonOverlap("abc", "abcd")); + + assertEquals("diff_commonOverlap: No overlap.", 0, dmp.diff_commonOverlap("123456", "abcd")); + + assertEquals("diff_commonOverlap: Overlap.", 3, dmp.diff_commonOverlap("123456xxx", "xxxabcd")); + + // Some overly clever languages (C#) may treat ligatures as equal to their + // component letters. E.g. U+FB01 == 'fi' + assertEquals("diff_commonOverlap: Unicode.", 0, dmp.diff_commonOverlap("fi", "\ufb01i")); + } + + public void testDiffHalfmatch() { + // Detect a halfmatch. + dmp.Diff_Timeout = 1; + assertNull("diff_halfMatch: No match #1.", dmp.diff_halfMatch("1234567890", "abcdef")); + + assertNull("diff_halfMatch: No match #2.", dmp.diff_halfMatch("12345", "23")); + + assertArrayEquals("diff_halfMatch: Single Match #1.", new String[]{"12", "90", "a", "z", "345678"}, dmp.diff_halfMatch("1234567890", "a345678z")); + + assertArrayEquals("diff_halfMatch: Single Match #2.", new String[]{"a", "z", "12", "90", "345678"}, dmp.diff_halfMatch("a345678z", "1234567890")); + + assertArrayEquals("diff_halfMatch: Single Match #3.", new String[]{"abc", "z", "1234", "0", "56789"}, dmp.diff_halfMatch("abc56789z", "1234567890")); + + assertArrayEquals("diff_halfMatch: Single Match #4.", new String[]{"a", "xyz", "1", "7890", "23456"}, dmp.diff_halfMatch("a23456xyz", "1234567890")); + + assertArrayEquals("diff_halfMatch: Multiple Matches #1.", new String[]{"12123", "123121", "a", "z", "1234123451234"}, dmp.diff_halfMatch("121231234123451234123121", "a1234123451234z")); + + assertArrayEquals("diff_halfMatch: Multiple Matches #2.", new String[]{"", "-=-=-=-=-=", "x", "", "x-=-=-=-=-=-=-="}, dmp.diff_halfMatch("x-=-=-=-=-=-=-=-=-=-=-=-=", "xx-=-=-=-=-=-=-=")); + + assertArrayEquals("diff_halfMatch: Multiple Matches #3.", new String[]{"-=-=-=-=-=", "", "", "y", "-=-=-=-=-=-=-=y"}, dmp.diff_halfMatch("-=-=-=-=-=-=-=-=-=-=-=-=y", "-=-=-=-=-=-=-=yy")); + + // Optimal diff would be -q+x=H-i+e=lloHe+Hu=llo-Hew+y not -qHillo+x=HelloHe-w+Hulloy + assertArrayEquals("diff_halfMatch: Non-optimal halfmatch.", new String[]{"qHillo", "w", "x", "Hulloy", "HelloHe"}, dmp.diff_halfMatch("qHilloHelloHew", "xHelloHeHulloy")); + + dmp.Diff_Timeout = 0; + assertNull("diff_halfMatch: Optimal no halfmatch.", dmp.diff_halfMatch("qHilloHelloHew", "xHelloHeHulloy")); + } + + public void testDiffLinesToChars() { + // Convert lines down to characters. + ArrayList tmpVector = new ArrayList(); + tmpVector.add(""); + tmpVector.add("alpha\n"); + tmpVector.add("beta\n"); + assertLinesToCharsResultEquals("diff_linesToChars: Shared lines.", new LinesToCharsResult("\u0001\u0002\u0001", "\u0002\u0001\u0002", tmpVector), dmp.diff_linesToChars("alpha\nbeta\nalpha\n", "beta\nalpha\nbeta\n")); + + tmpVector.clear(); + tmpVector.add(""); + tmpVector.add("alpha\r\n"); + tmpVector.add("beta\r\n"); + tmpVector.add("\r\n"); + assertLinesToCharsResultEquals("diff_linesToChars: Empty string and blank lines.", new LinesToCharsResult("", "\u0001\u0002\u0003\u0003", tmpVector), dmp.diff_linesToChars("", "alpha\r\nbeta\r\n\r\n\r\n")); + + tmpVector.clear(); + tmpVector.add(""); + tmpVector.add("a"); + tmpVector.add("b"); + assertLinesToCharsResultEquals("diff_linesToChars: No linebreaks.", new LinesToCharsResult("\u0001", "\u0002", tmpVector), dmp.diff_linesToChars("a", "b")); + + // More than 256 to reveal any 8-bit limitations. + int n = 300; + tmpVector.clear(); + StringBuilder lineList = new StringBuilder(); + StringBuilder charList = new StringBuilder(); + for (int x = 1; x < n + 1; x++) { + tmpVector.add(x + "\n"); + lineList.append(x + "\n"); + charList.append(String.valueOf((char) x)); + } + assertEquals(n, tmpVector.size()); + String lines = lineList.toString(); + String chars = charList.toString(); + assertEquals(n, chars.length()); + tmpVector.add(0, ""); + assertLinesToCharsResultEquals("diff_linesToChars: More than 256.", new LinesToCharsResult(chars, "", tmpVector), dmp.diff_linesToChars(lines, "")); + } + + public void testDiffCharsToLines() { + // First check that Diff equality works. + assertTrue("diff_charsToLines: Equality #1.", new Diff(EQUAL, "a").equals(new Diff(EQUAL, "a"))); + + assertEquals("diff_charsToLines: Equality #2.", new Diff(EQUAL, "a"), new Diff(EQUAL, "a")); + + // Convert chars up to lines. + LinkedList diffs = diffList(new Diff(EQUAL, "\u0001\u0002\u0001"), new Diff(INSERT, "\u0002\u0001\u0002")); + ArrayList tmpVector = new ArrayList(); + tmpVector.add(""); + tmpVector.add("alpha\n"); + tmpVector.add("beta\n"); + dmp.diff_charsToLines(diffs, tmpVector); + assertEquals("diff_charsToLines: Shared lines.", diffList(new Diff(EQUAL, "alpha\nbeta\nalpha\n"), new Diff(INSERT, "beta\nalpha\nbeta\n")), diffs); + + // More than 256 to reveal any 8-bit limitations. + int n = 300; + tmpVector.clear(); + StringBuilder lineList = new StringBuilder(); + StringBuilder charList = new StringBuilder(); + for (int x = 1; x < n + 1; x++) { + tmpVector.add(x + "\n"); + lineList.append(x + "\n"); + charList.append(String.valueOf((char) x)); + } + assertEquals(n, tmpVector.size()); + String lines = lineList.toString(); + String chars = charList.toString(); + assertEquals(n, chars.length()); + tmpVector.add(0, ""); + diffs = diffList(new Diff(DELETE, chars)); + dmp.diff_charsToLines(diffs, tmpVector); + assertEquals("diff_charsToLines: More than 256.", diffList(new Diff(DELETE, lines)), diffs); + } + + public void testDiffCleanupMerge() { + // Cleanup a messy diff. + LinkedList diffs = diffList(); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Null case.", diffList(), diffs); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(DELETE, "b"), new Diff(INSERT, "c")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: No change case.", diffList(new Diff(EQUAL, "a"), new Diff(DELETE, "b"), new Diff(INSERT, "c")), diffs); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(EQUAL, "b"), new Diff(EQUAL, "c")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Merge equalities.", diffList(new Diff(EQUAL, "abc")), diffs); + + diffs = diffList(new Diff(DELETE, "a"), new Diff(DELETE, "b"), new Diff(DELETE, "c")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Merge deletions.", diffList(new Diff(DELETE, "abc")), diffs); + + diffs = diffList(new Diff(INSERT, "a"), new Diff(INSERT, "b"), new Diff(INSERT, "c")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Merge insertions.", diffList(new Diff(INSERT, "abc")), diffs); + + diffs = diffList(new Diff(DELETE, "a"), new Diff(INSERT, "b"), new Diff(DELETE, "c"), new Diff(INSERT, "d"), new Diff(EQUAL, "e"), new Diff(EQUAL, "f")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Merge interweave.", diffList(new Diff(DELETE, "ac"), new Diff(INSERT, "bd"), new Diff(EQUAL, "ef")), diffs); + + diffs = diffList(new Diff(DELETE, "a"), new Diff(INSERT, "abc"), new Diff(DELETE, "dc")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Prefix and suffix detection.", diffList(new Diff(EQUAL, "a"), new Diff(DELETE, "d"), new Diff(INSERT, "b"), new Diff(EQUAL, "c")), diffs); + + diffs = diffList(new Diff(EQUAL, "x"), new Diff(DELETE, "a"), new Diff(INSERT, "abc"), new Diff(DELETE, "dc"), new Diff(EQUAL, "y")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Prefix and suffix detection with equalities.", diffList(new Diff(EQUAL, "xa"), new Diff(DELETE, "d"), new Diff(INSERT, "b"), new Diff(EQUAL, "cy")), diffs); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(INSERT, "ba"), new Diff(EQUAL, "c")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Slide edit left.", diffList(new Diff(INSERT, "ab"), new Diff(EQUAL, "ac")), diffs); + + diffs = diffList(new Diff(EQUAL, "c"), new Diff(INSERT, "ab"), new Diff(EQUAL, "a")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Slide edit right.", diffList(new Diff(EQUAL, "ca"), new Diff(INSERT, "ba")), diffs); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(DELETE, "b"), new Diff(EQUAL, "c"), new Diff(DELETE, "ac"), new Diff(EQUAL, "x")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Slide edit left recursive.", diffList(new Diff(DELETE, "abc"), new Diff(EQUAL, "acx")), diffs); + + diffs = diffList(new Diff(EQUAL, "x"), new Diff(DELETE, "ca"), new Diff(EQUAL, "c"), new Diff(DELETE, "b"), new Diff(EQUAL, "a")); + dmp.diff_cleanupMerge(diffs); + assertEquals("diff_cleanupMerge: Slide edit right recursive.", diffList(new Diff(EQUAL, "xca"), new Diff(DELETE, "cba")), diffs); + } + + public void testDiffCleanupSemanticLossless() { + // Slide diffs to match logical boundaries. + LinkedList diffs = diffList(); + dmp.diff_cleanupSemanticLossless(diffs); + assertEquals("diff_cleanupSemanticLossless: Null case.", diffList(), diffs); + + diffs = diffList(new Diff(EQUAL, "AAA\r\n\r\nBBB"), new Diff(INSERT, "\r\nDDD\r\n\r\nBBB"), new Diff(EQUAL, "\r\nEEE")); + dmp.diff_cleanupSemanticLossless(diffs); + assertEquals("diff_cleanupSemanticLossless: Blank lines.", diffList(new Diff(EQUAL, "AAA\r\n\r\n"), new Diff(INSERT, "BBB\r\nDDD\r\n\r\n"), new Diff(EQUAL, "BBB\r\nEEE")), diffs); + + diffs = diffList(new Diff(EQUAL, "AAA\r\nBBB"), new Diff(INSERT, " DDD\r\nBBB"), new Diff(EQUAL, " EEE")); + dmp.diff_cleanupSemanticLossless(diffs); + assertEquals("diff_cleanupSemanticLossless: Line boundaries.", diffList(new Diff(EQUAL, "AAA\r\n"), new Diff(INSERT, "BBB DDD\r\n"), new Diff(EQUAL, "BBB EEE")), diffs); + + diffs = diffList(new Diff(EQUAL, "The c"), new Diff(INSERT, "ow and the c"), new Diff(EQUAL, "at.")); + dmp.diff_cleanupSemanticLossless(diffs); + assertEquals("diff_cleanupSemanticLossless: Word boundaries.", diffList(new Diff(EQUAL, "The "), new Diff(INSERT, "cow and the "), new Diff(EQUAL, "cat.")), diffs); + + diffs = diffList(new Diff(EQUAL, "The-c"), new Diff(INSERT, "ow-and-the-c"), new Diff(EQUAL, "at.")); + dmp.diff_cleanupSemanticLossless(diffs); + assertEquals("diff_cleanupSemanticLossless: Alphanumeric boundaries.", diffList(new Diff(EQUAL, "The-"), new Diff(INSERT, "cow-and-the-"), new Diff(EQUAL, "cat.")), diffs); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(DELETE, "a"), new Diff(EQUAL, "ax")); + dmp.diff_cleanupSemanticLossless(diffs); + assertEquals("diff_cleanupSemanticLossless: Hitting the start.", diffList(new Diff(DELETE, "a"), new Diff(EQUAL, "aax")), diffs); + + diffs = diffList(new Diff(EQUAL, "xa"), new Diff(DELETE, "a"), new Diff(EQUAL, "a")); + dmp.diff_cleanupSemanticLossless(diffs); + assertEquals("diff_cleanupSemanticLossless: Hitting the end.", diffList(new Diff(EQUAL, "xaa"), new Diff(DELETE, "a")), diffs); + + diffs = diffList(new Diff(EQUAL, "The xxx. The "), new Diff(INSERT, "zzz. The "), new Diff(EQUAL, "yyy.")); + dmp.diff_cleanupSemanticLossless(diffs); + assertEquals("diff_cleanupSemanticLossless: Sentence boundaries.", diffList(new Diff(EQUAL, "The xxx."), new Diff(INSERT, " The zzz."), new Diff(EQUAL, " The yyy.")), diffs); + } + + public void testDiffCleanupSemantic() { + // Cleanup semantically trivial equalities. + LinkedList diffs = diffList(); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: Null case.", diffList(), diffs); + + diffs = diffList(new Diff(DELETE, "ab"), new Diff(INSERT, "cd"), new Diff(EQUAL, "12"), new Diff(DELETE, "e")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: No elimination #1.", diffList(new Diff(DELETE, "ab"), new Diff(INSERT, "cd"), new Diff(EQUAL, "12"), new Diff(DELETE, "e")), diffs); + + diffs = diffList(new Diff(DELETE, "abc"), new Diff(INSERT, "ABC"), new Diff(EQUAL, "1234"), new Diff(DELETE, "wxyz")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: No elimination #2.", diffList(new Diff(DELETE, "abc"), new Diff(INSERT, "ABC"), new Diff(EQUAL, "1234"), new Diff(DELETE, "wxyz")), diffs); + + diffs = diffList(new Diff(DELETE, "a"), new Diff(EQUAL, "b"), new Diff(DELETE, "c")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: Simple elimination.", diffList(new Diff(DELETE, "abc"), new Diff(INSERT, "b")), diffs); + + diffs = diffList(new Diff(DELETE, "ab"), new Diff(EQUAL, "cd"), new Diff(DELETE, "e"), new Diff(EQUAL, "f"), new Diff(INSERT, "g")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: Backpass elimination.", diffList(new Diff(DELETE, "abcdef"), new Diff(INSERT, "cdfg")), diffs); + + diffs = diffList(new Diff(INSERT, "1"), new Diff(EQUAL, "A"), new Diff(DELETE, "B"), new Diff(INSERT, "2"), new Diff(EQUAL, "_"), new Diff(INSERT, "1"), new Diff(EQUAL, "A"), new Diff(DELETE, "B"), new Diff(INSERT, "2")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: Multiple elimination.", diffList(new Diff(DELETE, "AB_AB"), new Diff(INSERT, "1A2_1A2")), diffs); + + diffs = diffList(new Diff(EQUAL, "The c"), new Diff(DELETE, "ow and the c"), new Diff(EQUAL, "at.")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: Word boundaries.", diffList(new Diff(EQUAL, "The "), new Diff(DELETE, "cow and the "), new Diff(EQUAL, "cat.")), diffs); + + diffs = diffList(new Diff(DELETE, "abcxx"), new Diff(INSERT, "xxdef")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: No overlap elimination.", diffList(new Diff(DELETE, "abcxx"), new Diff(INSERT, "xxdef")), diffs); + + diffs = diffList(new Diff(DELETE, "abcxxx"), new Diff(INSERT, "xxxdef")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: Overlap elimination.", diffList(new Diff(DELETE, "abc"), new Diff(EQUAL, "xxx"), new Diff(INSERT, "def")), diffs); + + diffs = diffList(new Diff(DELETE, "xxxabc"), new Diff(INSERT, "defxxx")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: Reverse overlap elimination.", diffList(new Diff(INSERT, "def"), new Diff(EQUAL, "xxx"), new Diff(DELETE, "abc")), diffs); + + diffs = diffList(new Diff(DELETE, "abcd1212"), new Diff(INSERT, "1212efghi"), new Diff(EQUAL, "----"), new Diff(DELETE, "A3"), new Diff(INSERT, "3BC")); + dmp.diff_cleanupSemantic(diffs); + assertEquals("diff_cleanupSemantic: Two overlap eliminations.", diffList(new Diff(DELETE, "abcd"), new Diff(EQUAL, "1212"), new Diff(INSERT, "efghi"), new Diff(EQUAL, "----"), new Diff(DELETE, "A"), new Diff(EQUAL, "3"), new Diff(INSERT, "BC")), diffs); + } + + public void testDiffCleanupEfficiency() { + // Cleanup operationally trivial equalities. + dmp.Diff_EditCost = 4; + LinkedList diffs = diffList(); + dmp.diff_cleanupEfficiency(diffs); + assertEquals("diff_cleanupEfficiency: Null case.", diffList(), diffs); + System.out.println(dmp.diff_prettyHtml(diffs)); + + diffs = diffList(new Diff(DELETE, "ab"), new Diff(INSERT, "12"), new Diff(EQUAL, "wxyz"), new Diff(DELETE, "cd"), new Diff(INSERT, "34")); + dmp.diff_cleanupEfficiency(diffs); + assertEquals("diff_cleanupEfficiency: No elimination.", diffList(new Diff(DELETE, "ab"), new Diff(INSERT, "12"), new Diff(EQUAL, "wxyz"), new Diff(DELETE, "cd"), new Diff(INSERT, "34")), diffs); + System.out.println(dmp.diff_prettyHtml(diffs)); + + diffs = diffList(new Diff(DELETE, "ab"), new Diff(INSERT, "12"), new Diff(EQUAL, "xyz"), new Diff(DELETE, "cd"), new Diff(INSERT, "34")); + dmp.diff_cleanupEfficiency(diffs); + assertEquals("diff_cleanupEfficiency: Four-edit elimination.", diffList(new Diff(DELETE, "abxyzcd"), new Diff(INSERT, "12xyz34")), diffs); + System.out.println(dmp.diff_prettyHtml(diffs)); + + diffs = diffList(new Diff(INSERT, "12"), new Diff(EQUAL, "x"), new Diff(DELETE, "cd"), new Diff(INSERT, "34")); + dmp.diff_cleanupEfficiency(diffs); + assertEquals("diff_cleanupEfficiency: Three-edit elimination.", diffList(new Diff(DELETE, "xcd"), new Diff(INSERT, "12x34")), diffs); + System.out.println(dmp.diff_prettyHtml(diffs)); + + diffs = diffList(new Diff(DELETE, "ab"), new Diff(INSERT, "12"), new Diff(EQUAL, "xy"), new Diff(INSERT, "34"), new Diff(EQUAL, "z"), new Diff(DELETE, "cd"), new Diff(INSERT, "56")); + dmp.diff_cleanupEfficiency(diffs); + assertEquals("diff_cleanupEfficiency: Backpass elimination.", diffList(new Diff(DELETE, "abxyzcd"), new Diff(INSERT, "12xy34z56")), diffs); + System.out.println(dmp.diff_prettyHtml(diffs)); + + dmp.Diff_EditCost = 5; + diffs = diffList(new Diff(DELETE, "ab"), new Diff(INSERT, "12"), new Diff(EQUAL, "wxyz"), new Diff(DELETE, "cd"), new Diff(INSERT, "34")); + dmp.diff_cleanupEfficiency(diffs); + assertEquals("diff_cleanupEfficiency: High cost elimination.", diffList(new Diff(DELETE, "abwxyzcd"), new Diff(INSERT, "12wxyz34")), diffs); + dmp.Diff_EditCost = 4; + } + + public void testDiffPrettyHtml() { + // Pretty print. + LinkedList diffs = diffList(new Diff(EQUAL, "a\n"), new Diff(DELETE, "b"), new Diff(INSERT, "c&d")); + assertEquals("diff_prettyHtml:", "
<B>b</B>c&d", dmp.diff_prettyHtml(diffs)); + } + + public void testDiffText() { + // Compute the source and destination texts. + LinkedList diffs = diffList(new Diff(EQUAL, "jump"), new Diff(DELETE, "s"), new Diff(INSERT, "ed"), new Diff(EQUAL, " over "), new Diff(DELETE, "the"), new Diff(INSERT, "a"), new Diff(EQUAL, " lazy")); + assertEquals("diff_text1:", "jumps over the lazy", dmp.diff_text1(diffs)); + assertEquals("diff_text2:", "jumped over a lazy", dmp.diff_text2(diffs)); + } + + public void testDiffDelta() { + // Convert a diff into delta string. + LinkedList diffs = diffList(new Diff(EQUAL, "jump"), new Diff(DELETE, "s"), new Diff(INSERT, "ed"), new Diff(EQUAL, " over "), new Diff(DELETE, "the"), new Diff(INSERT, "a"), new Diff(EQUAL, " lazy"), new Diff(INSERT, "old dog")); + String text1 = dmp.diff_text1(diffs); + assertEquals("diff_text1: Base text.", "jumps over the lazy", text1); + + String delta = dmp.diff_toDelta(diffs); + assertEquals("diff_toDelta:", "=4\t-1\t+ed\t=6\t-3\t+a\t=5\t+old dog", delta); + + // Convert delta string into a diff. + assertEquals("diff_fromDelta: Normal.", diffs, dmp.diff_fromDelta(text1, delta)); + + // Generates error (19 < 20). + try { + dmp.diff_fromDelta(text1 + "x", delta); + fail("diff_fromDelta: Too long."); + } catch (IllegalArgumentException ex) { + // Exception expected. + } + + // Generates error (19 > 18). + try { + dmp.diff_fromDelta(text1.substring(1), delta); + fail("diff_fromDelta: Too short."); + } catch (IllegalArgumentException ex) { + // Exception expected. + } + + // Generates error (%c3%xy invalid Unicode). + try { + dmp.diff_fromDelta("", "+%c3%xy"); + fail("diff_fromDelta: Invalid character."); + } catch (IllegalArgumentException ex) { + // Exception expected. + } + + // Test deltas with special characters. + diffs = diffList(new Diff(EQUAL, "\u0680 \000 \t %"), new Diff(DELETE, "\u0681 \001 \n ^"), new Diff(INSERT, "\u0682 \002 \\ |")); + text1 = dmp.diff_text1(diffs); + assertEquals("diff_text1: Unicode text.", "\u0680 \000 \t %\u0681 \001 \n ^", text1); + + delta = dmp.diff_toDelta(diffs); + assertEquals("diff_toDelta: Unicode.", "=7\t-7\t+%DA%82 %02 %5C %7C", delta); + + assertEquals("diff_fromDelta: Unicode.", diffs, dmp.diff_fromDelta(text1, delta)); + + // Verify pool of unchanged characters. + diffs = diffList(new Diff(INSERT, "A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; / ? : @ & = + $ , # ")); + String text2 = dmp.diff_text2(diffs); + assertEquals("diff_text2: Unchanged characters.", "A-Z a-z 0-9 - _ . ! ~ * \' ( ) ; / ? : @ & = + $ , # ", text2); + + delta = dmp.diff_toDelta(diffs); + assertEquals("diff_toDelta: Unchanged characters.", "+A-Z a-z 0-9 - _ . ! ~ * \' ( ) ; / ? : @ & = + $ , # ", delta); + + // Convert delta string into a diff. + assertEquals("diff_fromDelta: Unchanged characters.", diffs, dmp.diff_fromDelta("", delta)); + } + + public void testDiffXIndex() { + // Translate a location in text1 to text2. + LinkedList diffs = diffList(new Diff(DELETE, "a"), new Diff(INSERT, "1234"), new Diff(EQUAL, "xyz")); + assertEquals("diff_xIndex: Translation on equality.", 5, dmp.diff_xIndex(diffs, 2)); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(DELETE, "1234"), new Diff(EQUAL, "xyz")); + assertEquals("diff_xIndex: Translation on deletion.", 1, dmp.diff_xIndex(diffs, 3)); + } + + public void testDiffLevenshtein() { + LinkedList diffs = diffList(new Diff(DELETE, "abc"), new Diff(INSERT, "1234"), new Diff(EQUAL, "xyz")); + assertEquals("Levenshtein with trailing equality.", 4, dmp.diff_levenshtein(diffs)); + + diffs = diffList(new Diff(EQUAL, "xyz"), new Diff(DELETE, "abc"), new Diff(INSERT, "1234")); + assertEquals("Levenshtein with leading equality.", 4, dmp.diff_levenshtein(diffs)); + + diffs = diffList(new Diff(DELETE, "abc"), new Diff(EQUAL, "xyz"), new Diff(INSERT, "1234")); + assertEquals("Levenshtein with middle equality.", 7, dmp.diff_levenshtein(diffs)); + } + + public void testDiffBisect() { + // Normal. + String a = "cat"; + String b = "map"; + // Since the resulting diff hasn't been normalized, it would be ok if + // the insertion and deletion pairs are swapped. + // If the order changes, tweak this test as required. + LinkedList diffs = diffList(new Diff(DELETE, "c"), new Diff(INSERT, "m"), new Diff(EQUAL, "a"), new Diff(DELETE, "t"), new Diff(INSERT, "p")); + assertEquals("diff_bisect: Normal.", diffs, dmp.diff_bisect(a, b, Long.MAX_VALUE)); + + // Timeout. + diffs = diffList(new Diff(DELETE, "cat"), new Diff(INSERT, "map")); + assertEquals("diff_bisect: Timeout.", diffs, dmp.diff_bisect(a, b, 0)); + } + + public void testDiffMain() { + // Perform a trivial diff. + LinkedList diffs = diffList(); + assertEquals("diff_main: Null case.", diffs, dmp.diff_main("", "", false)); + + diffs = diffList(new Diff(EQUAL, "abc")); + assertEquals("diff_main: Equality.", diffs, dmp.diff_main("abc", "abc", false)); + + diffs = diffList(new Diff(EQUAL, "ab"), new Diff(INSERT, "123"), new Diff(EQUAL, "c")); + assertEquals("diff_main: Simple insertion.", diffs, dmp.diff_main("abc", "ab123c", false)); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(DELETE, "123"), new Diff(EQUAL, "bc")); + assertEquals("diff_main: Simple deletion.", diffs, dmp.diff_main("a123bc", "abc", false)); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(INSERT, "123"), new Diff(EQUAL, "b"), new Diff(INSERT, "456"), new Diff(EQUAL, "c")); + assertEquals("diff_main: Two insertions.", diffs, dmp.diff_main("abc", "a123b456c", false)); + + diffs = diffList(new Diff(EQUAL, "a"), new Diff(DELETE, "123"), new Diff(EQUAL, "b"), new Diff(DELETE, "456"), new Diff(EQUAL, "c")); + assertEquals("diff_main: Two deletions.", diffs, dmp.diff_main("a123b456c", "abc", false)); + + // Perform a real diff. + // Switch off the timeout. + dmp.Diff_Timeout = 0; + diffs = diffList(new Diff(DELETE, "a"), new Diff(INSERT, "b")); + assertEquals("diff_main: Simple case #1.", diffs, dmp.diff_main("a", "b", false)); + + diffs = diffList(new Diff(DELETE, "Apple"), new Diff(INSERT, "Banana"), new Diff(EQUAL, "s are a"), new Diff(INSERT, "lso"), new Diff(EQUAL, " fruit.")); + assertEquals("diff_main: Simple case #2.", diffs, dmp.diff_main("Apples are a fruit.", "Bananas are also fruit.", false)); + + diffs = diffList(new Diff(DELETE, "a"), new Diff(INSERT, "\u0680"), new Diff(EQUAL, "x"), new Diff(DELETE, "\t"), new Diff(INSERT, "\000")); + assertEquals("diff_main: Simple case #3.", diffs, dmp.diff_main("ax\t", "\u0680x\000", false)); + + diffs = diffList(new Diff(DELETE, "1"), new Diff(EQUAL, "a"), new Diff(DELETE, "y"), new Diff(EQUAL, "b"), new Diff(DELETE, "2"), new Diff(INSERT, "xab")); + assertEquals("diff_main: Overlap #1.", diffs, dmp.diff_main("1ayb2", "abxab", false)); + + diffs = diffList(new Diff(INSERT, "xaxcx"), new Diff(EQUAL, "abc"), new Diff(DELETE, "y")); + assertEquals("diff_main: Overlap #2.", diffs, dmp.diff_main("abcy", "xaxcxabc", false)); + + diffs = diffList(new Diff(DELETE, "ABCD"), new Diff(EQUAL, "a"), new Diff(DELETE, "="), new Diff(INSERT, "-"), new Diff(EQUAL, "bcd"), new Diff(DELETE, "="), new Diff(INSERT, "-"), new Diff(EQUAL, "efghijklmnopqrs"), new Diff(DELETE, "EFGHIJKLMNOefg")); + assertEquals("diff_main: Overlap #3.", diffs, dmp.diff_main("ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg", "a-bcd-efghijklmnopqrs", false)); + + diffs = diffList(new Diff(INSERT, " "), new Diff(EQUAL, "a"), new Diff(INSERT, "nd"), new Diff(EQUAL, " [[Pennsylvania]]"), new Diff(DELETE, " and [[New")); + assertEquals("diff_main: Large equality.", diffs, dmp.diff_main("a [[Pennsylvania]] and [[New", " and [[Pennsylvania]]", false)); + + dmp.Diff_Timeout = 0.1f; // 100ms + String a = "`Twas brillig, and the slithy toves\nDid gyre and gimble in the wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.\n"; + String b = "I am the very model of a modern major general,\nI've information vegetable, animal, and mineral,\nI know the kings of England, and I quote the fights historical,\nFrom Marathon to Waterloo, in order categorical.\n"; + // Increase the text lengths by 1024 times to ensure a timeout. + for (int x = 0; x < 10; x++) { + a = a + a; + b = b + b; + } + long startTime = System.currentTimeMillis(); + dmp.diff_main(a, b); + long endTime = System.currentTimeMillis(); + // Test that we took at least the timeout period. + assertTrue("diff_main: Timeout min.", dmp.Diff_Timeout * 1000 <= endTime - startTime); + // Test that we didn't take forever (be forgiving). + // Theoretically this test could fail very occasionally if the + // OS task swaps or locks up for a second at the wrong moment. + assertTrue("diff_main: Timeout max.", dmp.Diff_Timeout * 1000 * 2 > endTime - startTime); + dmp.Diff_Timeout = 0; + + // Test the linemode speedup. + // Must be long to pass the 100 char cutoff. + a = "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n"; + b = "abcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\n"; + assertEquals("diff_main: Simple line-mode.", dmp.diff_main(a, b, true), dmp.diff_main(a, b, false)); + + a = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; + b = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"; + assertEquals("diff_main: Single line-mode.", dmp.diff_main(a, b, true), dmp.diff_main(a, b, false)); + + a = "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n"; + b = "abcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n"; + String[] texts_linemode = diff_rebuildtexts(dmp.diff_main(a, b, true)); + String[] texts_textmode = diff_rebuildtexts(dmp.diff_main(a, b, false)); + assertArrayEquals("diff_main: Overlap line-mode.", texts_textmode, texts_linemode); + + // Test null inputs. + try { + dmp.diff_main(null, null); + fail("diff_main: Null inputs."); + } catch (IllegalArgumentException ex) { + // Error expected. + } + } + + + // MATCH TEST FUNCTIONS + + + public void testMatchAlphabet() { + // Initialise the bitmasks for Bitap. + Map bitmask; + bitmask = new HashMap(); + bitmask.put('a', 4); bitmask.put('b', 2); bitmask.put('c', 1); + assertEquals("match_alphabet: Unique.", bitmask, dmp.match_alphabet("abc")); + + bitmask = new HashMap(); + bitmask.put('a', 37); bitmask.put('b', 18); bitmask.put('c', 8); + assertEquals("match_alphabet: Duplicates.", bitmask, dmp.match_alphabet("abcaba")); + } + + public void testMatchBitap() { + // Bitap algorithm. + dmp.Match_Distance = 100; + dmp.Match_Threshold = 0.5f; + assertEquals("match_bitap: Exact match #1.", 5, dmp.match_bitap("abcdefghijk", "fgh", 5)); + + assertEquals("match_bitap: Exact match #2.", 5, dmp.match_bitap("abcdefghijk", "fgh", 0)); + + assertEquals("match_bitap: Fuzzy match #1.", 4, dmp.match_bitap("abcdefghijk", "efxhi", 0)); + + assertEquals("match_bitap: Fuzzy match #2.", 2, dmp.match_bitap("abcdefghijk", "cdefxyhijk", 5)); + + assertEquals("match_bitap: Fuzzy match #3.", -1, dmp.match_bitap("abcdefghijk", "bxy", 1)); + + assertEquals("match_bitap: Overflow.", 2, dmp.match_bitap("123456789xx0", "3456789x0", 2)); + + assertEquals("match_bitap: Before start match.", 0, dmp.match_bitap("abcdef", "xxabc", 4)); + + assertEquals("match_bitap: Beyond end match.", 3, dmp.match_bitap("abcdef", "defyy", 4)); + + assertEquals("match_bitap: Oversized pattern.", 0, dmp.match_bitap("abcdef", "xabcdefy", 0)); + + dmp.Match_Threshold = 0.4f; + assertEquals("match_bitap: Threshold #1.", 4, dmp.match_bitap("abcdefghijk", "efxyhi", 1)); + + dmp.Match_Threshold = 0.3f; + assertEquals("match_bitap: Threshold #2.", -1, dmp.match_bitap("abcdefghijk", "efxyhi", 1)); + + dmp.Match_Threshold = 0.0f; + assertEquals("match_bitap: Threshold #3.", 1, dmp.match_bitap("abcdefghijk", "bcdef", 1)); + + dmp.Match_Threshold = 0.5f; + assertEquals("match_bitap: Multiple select #1.", 0, dmp.match_bitap("abcdexyzabcde", "abccde", 3)); + + assertEquals("match_bitap: Multiple select #2.", 8, dmp.match_bitap("abcdexyzabcde", "abccde", 5)); + + dmp.Match_Distance = 10; // Strict location. + assertEquals("match_bitap: Distance test #1.", -1, dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdefg", 24)); + + assertEquals("match_bitap: Distance test #2.", 0, dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdxxefg", 1)); + + dmp.Match_Distance = 1000; // Loose location. + assertEquals("match_bitap: Distance test #3.", 0, dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdefg", 24)); + } + + public void testMatchMain() { + // Full match. + assertEquals("match_main: Equality.", 0, dmp.match_main("abcdef", "abcdef", 1000)); + + assertEquals("match_main: Null text.", -1, dmp.match_main("", "abcdef", 1)); + + assertEquals("match_main: Null pattern.", 3, dmp.match_main("abcdef", "", 3)); + + assertEquals("match_main: Exact match.", 3, dmp.match_main("abcdef", "de", 3)); + + assertEquals("match_main: Beyond end match.", 3, dmp.match_main("abcdef", "defy", 4)); + + assertEquals("match_main: Oversized pattern.", 0, dmp.match_main("abcdef", "abcdefy", 0)); + + dmp.Match_Threshold = 0.7f; + assertEquals("match_main: Complex match.", 4, dmp.match_main("I am the very model of a modern major general.", " that berry ", 5)); + dmp.Match_Threshold = 0.5f; + + // Test null inputs. + try { + dmp.match_main(null, null, 0); + fail("match_main: Null inputs."); + } catch (IllegalArgumentException ex) { + // Error expected. + } + } + + + // PATCH TEST FUNCTIONS + + + public void testPatchObj() { + // Patch Object. + Patch p = new Patch(); + p.start1 = 20; + p.start2 = 21; + p.length1 = 18; + p.length2 = 17; + p.diffs = diffList(new Diff(EQUAL, "jump"), new Diff(DELETE, "s"), new Diff(INSERT, "ed"), new Diff(EQUAL, " over "), new Diff(DELETE, "the"), new Diff(INSERT, "a"), new Diff(EQUAL, "\nlaz")); + String strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n %0Alaz\n"; + assertEquals("Patch: toString.", strp, p.toString()); + } + + public void testPatchFromText() { + assertTrue("patch_fromText: #0.", dmp.patch_fromText("").isEmpty()); + + String strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n %0Alaz\n"; + assertEquals("patch_fromText: #1.", strp, dmp.patch_fromText(strp).get(0).toString()); + + assertEquals("patch_fromText: #2.", "@@ -1 +1 @@\n-a\n+b\n", dmp.patch_fromText("@@ -1 +1 @@\n-a\n+b\n").get(0).toString()); + + assertEquals("patch_fromText: #3.", "@@ -1,3 +0,0 @@\n-abc\n", dmp.patch_fromText("@@ -1,3 +0,0 @@\n-abc\n").get(0).toString()); + + assertEquals("patch_fromText: #4.", "@@ -0,0 +1,3 @@\n+abc\n", dmp.patch_fromText("@@ -0,0 +1,3 @@\n+abc\n").get(0).toString()); + + // Generates error. + try { + dmp.patch_fromText("Bad\nPatch\n"); + fail("patch_fromText: #5."); + } catch (IllegalArgumentException ex) { + // Exception expected. + } + } + + public void testPatchToText() { + String strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n laz\n"; + List patches; + patches = dmp.patch_fromText(strp); + assertEquals("patch_toText: Single.", strp, dmp.patch_toText(patches)); + + strp = "@@ -1,9 +1,9 @@\n-f\n+F\n oo+fooba\n@@ -7,9 +7,9 @@\n obar\n-,\n+.\n tes\n"; + patches = dmp.patch_fromText(strp); + assertEquals("patch_toText: Dual.", strp, dmp.patch_toText(patches)); + } + + public void testPatchAddContext() { + dmp.Patch_Margin = 4; + Patch p; + p = dmp.patch_fromText("@@ -21,4 +21,10 @@\n-jump\n+somersault\n").get(0); + dmp.patch_addContext(p, "The quick brown fox jumps over the lazy dog."); + assertEquals("patch_addContext: Simple case.", "@@ -17,12 +17,18 @@\n fox \n-jump\n+somersault\n s ov\n", p.toString()); + + p = dmp.patch_fromText("@@ -21,4 +21,10 @@\n-jump\n+somersault\n").get(0); + dmp.patch_addContext(p, "The quick brown fox jumps."); + assertEquals("patch_addContext: Not enough trailing context.", "@@ -17,10 +17,16 @@\n fox \n-jump\n+somersault\n s.\n", p.toString()); + + p = dmp.patch_fromText("@@ -3 +3,2 @@\n-e\n+at\n").get(0); + dmp.patch_addContext(p, "The quick brown fox jumps."); + assertEquals("patch_addContext: Not enough leading context.", "@@ -1,7 +1,8 @@\n Th\n-e\n+at\n qui\n", p.toString()); + + p = dmp.patch_fromText("@@ -3 +3,2 @@\n-e\n+at\n").get(0); + dmp.patch_addContext(p, "The quick brown fox jumps. The quick brown fox crashes."); + assertEquals("patch_addContext: Ambiguity.", "@@ -1,27 +1,28 @@\n Th\n-e\n+at\n quick brown fox jumps. \n", p.toString()); + } + + public void testPatchMake() { + LinkedList patches; + patches = dmp.patch_make("", ""); + assertEquals("patch_make: Null case.", "", dmp.patch_toText(patches)); + + String text1 = "The quick brown fox jumps over the lazy dog."; + String text2 = "That quick brown fox jumped over a lazy dog."; + String expectedPatch = "@@ -1,8 +1,7 @@\n Th\n-at\n+e\n qui\n@@ -21,17 +21,18 @@\n jump\n-ed\n+s\n over \n-a\n+the\n laz\n"; + // The second patch must be "-21,17 +21,18", not "-22,17 +21,18" due to rolling context. + patches = dmp.patch_make(text2, text1); + assertEquals("patch_make: Text2+Text1 inputs.", expectedPatch, dmp.patch_toText(patches)); + + expectedPatch = "@@ -1,11 +1,12 @@\n Th\n-e\n+at\n quick b\n@@ -22,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n laz\n"; + patches = dmp.patch_make(text1, text2); + assertEquals("patch_make: Text1+Text2 inputs.", expectedPatch, dmp.patch_toText(patches)); + + LinkedList diffs = dmp.diff_main(text1, text2, false); + patches = dmp.patch_make(diffs); + assertEquals("patch_make: Diff input.", expectedPatch, dmp.patch_toText(patches)); + + patches = dmp.patch_make(text1, diffs); + assertEquals("patch_make: Text1+Diff inputs.", expectedPatch, dmp.patch_toText(patches)); + + patches = dmp.patch_make("`1234567890-=[]\\;',./", "~!@#$%^&*()_+{}|:\"<>?"); + assertEquals("patch_toText: Character encoding.", "@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;',./\n+~!@#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n", dmp.patch_toText(patches)); + + diffs = diffList(new Diff(DELETE, "`1234567890-=[]\\;',./"), new Diff(INSERT, "~!@#$%^&*()_+{}|:\"<>?")); + assertEquals("patch_fromText: Character decoding.", diffs, dmp.patch_fromText("@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;',./\n+~!@#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n").get(0).diffs); + + text1 = ""; + for (int x = 0; x < 100; x++) { + text1 += "abcdef"; + } + text2 = text1 + "123"; + expectedPatch = "@@ -573,28 +573,31 @@\n cdefabcdefabcdefabcdefabcdef\n+123\n"; + patches = dmp.patch_make(text1, text2); + assertEquals("patch_make: Long string with repeats.", expectedPatch, dmp.patch_toText(patches)); + + // Test null inputs. + try { + dmp.patch_make(null); + fail("patch_make: Null inputs."); + } catch (IllegalArgumentException ex) { + // Error expected. + } + } + + public void testPatchSplitMax() { + // Assumes that Match_MaxBits is 32. + LinkedList patches; + patches = dmp.patch_make("abcdefghijklmnopqrstuvwxyz01234567890", "XabXcdXefXghXijXklXmnXopXqrXstXuvXwxXyzX01X23X45X67X89X0"); + dmp.patch_splitMax(patches); + assertEquals("patch_splitMax: #1.", "@@ -1,32 +1,46 @@\n+X\n ab\n+X\n cd\n+X\n ef\n+X\n gh\n+X\n ij\n+X\n kl\n+X\n mn\n+X\n op\n+X\n qr\n+X\n st\n+X\n uv\n+X\n wx\n+X\n yz\n+X\n 012345\n@@ -25,13 +39,18 @@\n zX01\n+X\n 23\n+X\n 45\n+X\n 67\n+X\n 89\n+X\n 0\n", dmp.patch_toText(patches)); + + patches = dmp.patch_make("abcdef1234567890123456789012345678901234567890123456789012345678901234567890uvwxyz", "abcdefuvwxyz"); + String oldToText = dmp.patch_toText(patches); + dmp.patch_splitMax(patches); + assertEquals("patch_splitMax: #2.", oldToText, dmp.patch_toText(patches)); + + patches = dmp.patch_make("1234567890123456789012345678901234567890123456789012345678901234567890", "abc"); + dmp.patch_splitMax(patches); + assertEquals("patch_splitMax: #3.", "@@ -1,32 +1,4 @@\n-1234567890123456789012345678\n 9012\n@@ -29,32 +1,4 @@\n-9012345678901234567890123456\n 7890\n@@ -57,14 +1,3 @@\n-78901234567890\n+abc\n", dmp.patch_toText(patches)); + + patches = dmp.patch_make("abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1", "abcdefghij , h : 1 , t : 1 abcdefghij , h : 1 , t : 1 abcdefghij , h : 0 , t : 1"); + dmp.patch_splitMax(patches); + assertEquals("patch_splitMax: #4.", "@@ -2,32 +2,32 @@\n bcdefghij , h : \n-0\n+1\n , t : 1 abcdef\n@@ -29,32 +29,32 @@\n bcdefghij , h : \n-0\n+1\n , t : 1 abcdef\n", dmp.patch_toText(patches)); + } + + public void testPatchAddPadding() { + LinkedList patches; + patches = dmp.patch_make("", "test"); + assertEquals("patch_addPadding: Both edges full.", "@@ -0,0 +1,4 @@\n+test\n", dmp.patch_toText(patches)); + dmp.patch_addPadding(patches); + assertEquals("patch_addPadding: Both edges full.", "@@ -1,8 +1,12 @@\n %01%02%03%04\n+test\n %01%02%03%04\n", dmp.patch_toText(patches)); + + patches = dmp.patch_make("XY", "XtestY"); + assertEquals("patch_addPadding: Both edges partial.", "@@ -1,2 +1,6 @@\n X\n+test\n Y\n", dmp.patch_toText(patches)); + dmp.patch_addPadding(patches); + assertEquals("patch_addPadding: Both edges partial.", "@@ -2,8 +2,12 @@\n %02%03%04X\n+test\n Y%01%02%03\n", dmp.patch_toText(patches)); + + patches = dmp.patch_make("XXXXYYYY", "XXXXtestYYYY"); + assertEquals("patch_addPadding: Both edges none.", "@@ -1,8 +1,12 @@\n XXXX\n+test\n YYYY\n", dmp.patch_toText(patches)); + dmp.patch_addPadding(patches); + assertEquals("patch_addPadding: Both edges none.", "@@ -5,8 +5,12 @@\n XXXX\n+test\n YYYY\n", dmp.patch_toText(patches)); + } + + public void testPatchApply() { + dmp.Match_Distance = 1000; + dmp.Match_Threshold = 0.5f; + dmp.Patch_DeleteThreshold = 0.5f; + LinkedList patches; + patches = dmp.patch_make("", ""); + Object[] results = dmp.patch_apply(patches, "Hello world."); + boolean[] boolArray = (boolean[]) results[1]; + String resultStr = results[0] + "\t" + boolArray.length; + assertEquals("patch_apply: Null case.", "Hello world.\t0", resultStr); + + patches = dmp.patch_make("The quick brown fox jumps over the lazy dog.", "That quick brown fox jumped over a lazy dog."); + results = dmp.patch_apply(patches, "The quick brown fox jumps over the lazy dog."); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0] + "\t" + boolArray[1]; + assertEquals("patch_apply: Exact match.", "That quick brown fox jumped over a lazy dog.\ttrue\ttrue", resultStr); + + results = dmp.patch_apply(patches, "The quick red rabbit jumps over the tired tiger."); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0] + "\t" + boolArray[1]; + assertEquals("patch_apply: Partial match.", "That quick red rabbit jumped over a tired tiger.\ttrue\ttrue", resultStr); + + results = dmp.patch_apply(patches, "I am the very model of a modern major general."); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0] + "\t" + boolArray[1]; + assertEquals("patch_apply: Failed match.", "I am the very model of a modern major general.\tfalse\tfalse", resultStr); + + patches = dmp.patch_make("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy"); + results = dmp.patch_apply(patches, "x123456789012345678901234567890-----++++++++++-----123456789012345678901234567890y"); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0] + "\t" + boolArray[1]; + assertEquals("patch_apply: Big delete, small change.", "xabcy\ttrue\ttrue", resultStr); + + patches = dmp.patch_make("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy"); + results = dmp.patch_apply(patches, "x12345678901234567890---------------++++++++++---------------12345678901234567890y"); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0] + "\t" + boolArray[1]; + assertEquals("patch_apply: Big delete, big change 1.", "xabc12345678901234567890---------------++++++++++---------------12345678901234567890y\tfalse\ttrue", resultStr); + + dmp.Patch_DeleteThreshold = 0.6f; + patches = dmp.patch_make("x1234567890123456789012345678901234567890123456789012345678901234567890y", "xabcy"); + results = dmp.patch_apply(patches, "x12345678901234567890---------------++++++++++---------------12345678901234567890y"); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0] + "\t" + boolArray[1]; + assertEquals("patch_apply: Big delete, big change 2.", "xabcy\ttrue\ttrue", resultStr); + dmp.Patch_DeleteThreshold = 0.5f; + + // Compensate for failed patch. + dmp.Match_Threshold = 0.0f; + dmp.Match_Distance = 0; + patches = dmp.patch_make("abcdefghijklmnopqrstuvwxyz--------------------1234567890", "abcXXXXXXXXXXdefghijklmnopqrstuvwxyz--------------------1234567YYYYYYYYYY890"); + results = dmp.patch_apply(patches, "ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567890"); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0] + "\t" + boolArray[1]; + assertEquals("patch_apply: Compensate for failed patch.", "ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567YYYYYYYYYY890\tfalse\ttrue", resultStr); + dmp.Match_Threshold = 0.5f; + dmp.Match_Distance = 1000; + + patches = dmp.patch_make("", "test"); + String patchStr = dmp.patch_toText(patches); + dmp.patch_apply(patches, ""); + assertEquals("patch_apply: No side effects.", patchStr, dmp.patch_toText(patches)); + + patches = dmp.patch_make("The quick brown fox jumps over the lazy dog.", "Woof"); + patchStr = dmp.patch_toText(patches); + dmp.patch_apply(patches, "The quick brown fox jumps over the lazy dog."); + assertEquals("patch_apply: No side effects with major delete.", patchStr, dmp.patch_toText(patches)); + + patches = dmp.patch_make("", "test"); + results = dmp.patch_apply(patches, ""); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0]; + assertEquals("patch_apply: Edge exact match.", "test\ttrue", resultStr); + + patches = dmp.patch_make("XY", "XtestY"); + results = dmp.patch_apply(patches, "XY"); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0]; + assertEquals("patch_apply: Near edge exact match.", "XtestY\ttrue", resultStr); + + patches = dmp.patch_make("y", "y123"); + results = dmp.patch_apply(patches, "x"); + boolArray = (boolean[]) results[1]; + resultStr = results[0] + "\t" + boolArray[0]; + assertEquals("patch_apply: Edge partial match.", "x123\ttrue", resultStr); + } + + private void assertArrayEquals(String error_msg, Object[] a, Object[] b) { + List list_a = Arrays.asList(a); + List list_b = Arrays.asList(b); + assertEquals(error_msg, list_a, list_b); + } + + private void assertLinesToCharsResultEquals(String error_msg, + LinesToCharsResult a, LinesToCharsResult b) { + assertEquals(error_msg, a.chars1, b.chars1); + assertEquals(error_msg, a.chars2, b.chars2); + assertEquals(error_msg, a.lineArray, b.lineArray); + } + + // Construct the two texts which made up the diff originally. + private static String[] diff_rebuildtexts(LinkedList diffs) { + String[] text = {"", ""}; + for (Diff myDiff : diffs) { + if (myDiff.operation != DiffMatchPatch.Operation.INSERT) { + text[0] += myDiff.text; + } + if (myDiff.operation != DiffMatchPatch.Operation.DELETE) { + text[1] += myDiff.text; + } + } + return text; + } + + // Private function for quickly building lists of diffs. + private static LinkedList diffList(Diff... diffs) { + LinkedList myDiffList = new LinkedList(); + for (Diff myDiff : diffs) { + myDiffList.add(myDiff); + } + return myDiffList; + } + + private static void assertNull(String message, Object object) { + Assert.assertNull(message, object); + } + + private static void assertEquals(String message, Object expected, Object actual) { + Assert.assertEquals(message, expected, actual); + } + + private static void assertEquals(String message, String expected, String actual) { + Assert.assertEquals(message, expected, actual); + } + + private static void assertTrue(String message, boolean condition) { + Assert.assertTrue(message, condition); + } + + private static void assertEquals(Object expected, Object actual) { + Assert.assertEquals(expected, actual); + } + + private static void fail(String message) { + Assert.fail(message); + } + + public static void main(String[] args) { + +// DiffMatchPatchTest d = new DiffMatchPatchTest(); +// d.testDiffCleanupEfficiency(); +// d.testDiffPrettyHtml(); + + String text1 = "花一样的你,花一样的我,花一样的年华,花一样的世界,花一样的未来。"; + String text2 = "花样的你,花一样的年华,花一样的我,花一样的未来,花一样的世界。"; + + DiffMatchPatch dmp = new DiffMatchPatch(); + + LinkedList diffs = dmp.diff_main(text1, text2); + String result = dmp.diff_prettyHtml(diffs); + + FileUtils.writeToFile("x:\\test.html", result, false); + System.out.println(result); + + } + +} diff --git a/common/src/test/java/com/jeesite/test/diff/diff_match_patch_test.java b/common/src/test/java/com/jeesite/test/diff/DiffMatchPatchTest.java similarity index 100% rename from common/src/test/java/com/jeesite/test/diff/diff_match_patch_test.java rename to common/src/test/java/com/jeesite/test/diff/DiffMatchPatchTest.java diff --git a/common/src/test/java/com/jeesite/test/diff/Speedtest.java b/common/src/test/java/com/jeesite/test/diff/Speedtest.java deleted file mode 100644 index 80891b9a..00000000 --- a/common/src/test/java/com/jeesite/test/diff/Speedtest.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2010 Google Inc. All Rights Reserved. - -/** - * Diff Speed Test - * - * Compile from google3/third_party/diff_match_patch/java with: - * javac name/fraser/neil/plaintext/Speedtest.java name/fraser/neil/plaintext/diff_match_patch.java - * Execute with: - * java name/fraser/neil/plaintext/Speedtest - * - * @author fraser@google.com (Neil Fraser) - */ - -package com.jeesite.test.diff; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; - -public class Speedtest { - - public static void main(String args[]) { - String text1 = readFile("name/fraser/neil/plaintext/Speedtest1.txt"); - String text2 = readFile("name/fraser/neil/plaintext/Speedtest2.txt"); - - diff_match_patch dmp = new diff_match_patch(); - dmp.Diff_Timeout = 0; - - // Execute one reverse diff as a warmup. - dmp.diff_main(text2, text1, false); - System.gc(); - - long start_time = System.currentTimeMillis(); - dmp.diff_main(text1, text2, false); - long end_time = System.currentTimeMillis(); - System.out.printf("Elapsed time: %f\n", ((end_time - start_time) / 1000.0)); - } - - private static String readFile(String filename) { - // Read a file from disk and return the text contents. - StringBuffer strbuf = new StringBuffer(); - try { - FileReader input = new FileReader(filename); - BufferedReader bufRead = new BufferedReader(input); - String line = bufRead.readLine(); - while (line != null) { - strbuf.append(line); - strbuf.append('\n'); - line = bufRead.readLine(); - } - - bufRead.close(); - - } catch (IOException e) { - e.printStackTrace(); - } - return strbuf.toString(); - } -} diff --git a/common/src/test/java/com/jeesite/test/diff/Speedtest1.txt b/common/src/test/java/com/jeesite/test/diff/Speedtest1.txt deleted file mode 100644 index 54b438fd..00000000 --- a/common/src/test/java/com/jeesite/test/diff/Speedtest1.txt +++ /dev/null @@ -1,230 +0,0 @@ -This is a '''list of newspapers published by [[Journal Register Company]]'''. - -The company owns daily and weekly newspapers, other print media properties and newspaper-affiliated local Websites in the [[U.S.]] states of [[Connecticut]], [[Michigan]], [[New York]], [[Ohio]] and [[Pennsylvania]], organized in six geographic "clusters":[http://www.journalregister.com/newspapers.html Journal Register Company: Our Newspapers], accessed February 10, 2008. - -== Capital-Saratoga == -Three dailies, associated weeklies and [[pennysaver]]s in greater [[Albany, New York]]; also [http://www.capitalcentral.com capitalcentral.com] and [http://www.jobsinnewyork.com JobsInNewYork.com]. - -* ''The Oneida Daily Dispatch'' {{WS|oneidadispatch.com}} of [[Oneida, New York]] -* ''[[The Record (Troy)|The Record]]'' {{WS|troyrecord.com}} of [[Troy, New York]] -* ''[[The Saratogian]]'' {{WS|saratogian.com}} of [[Saratoga Springs, New York]] -* Weeklies: -** ''Community News'' {{WS|cnweekly.com}} weekly of [[Clifton Park, New York]] -** ''Rome Observer'' of [[Rome, New York]] -** ''Life & Times of Utica'' of [[Utica, New York]] - -== Connecticut == -Five dailies, associated weeklies and [[pennysaver]]s in the state of [[Connecticut]]; also [http://www.ctcentral.com CTcentral.com], [http://www.ctcarsandtrucks.com CTCarsAndTrucks.com] and [http://www.jobsinct.com JobsInCT.com]. - -* ''The Middletown Press'' {{WS|middletownpress.com}} of [[Middletown, Connecticut|Middletown]] -* ''[[New Haven Register]]'' {{WS|newhavenregister.com}} of [[New Haven, Connecticut|New Haven]] -* ''The Register Citizen'' {{WS|registercitizen.com}} of [[Torrington, Connecticut|Torrington]] - -* [[New Haven Register#Competitors|Elm City Newspapers]] {{WS|ctcentral.com}} -** ''The Advertiser'' of [[East Haven, Connecticut|East Haven]] -** ''Hamden Chronicle'' of [[Hamden, Connecticut|Hamden]] -** ''Milford Weekly'' of [[Milford, Connecticut|Milford]] -** ''The Orange Bulletin'' of [[Orange, Connecticut|Orange]] -** ''The Post'' of [[North Haven, Connecticut|North Haven]] -** ''Shelton Weekly'' of [[Shelton, Connecticut|Shelton]] -** ''The Stratford Bard'' of [[Stratford, Connecticut|Stratford]] -** ''Wallingford Voice'' of [[Wallingford, Connecticut|Wallingford]] -** ''West Haven News'' of [[West Haven, Connecticut|West Haven]] -* Housatonic Publications -** ''The New Milford Times'' {{WS|newmilfordtimes.com}} of [[New Milford, Connecticut|New Milford]] -** ''The Brookfield Journal'' of [[Brookfield, Connecticut|Brookfield]] -** ''The Kent Good Times Dispatch'' of [[Kent, Connecticut|Kent]] -** ''The Bethel Beacon'' of [[Bethel, Connecticut|Bethel]] -** ''The Litchfield Enquirer'' of [[Litchfield, Connecticut|Litchfield]] -** ''Litchfield County Times'' of [[Litchfield, Connecticut|Litchfield]] -* Imprint Newspapers {{WS|imprintnewspapers.com}} -** ''West Hartford News'' of [[West Hartford, Connecticut|West Hartford]] -** ''Windsor Journal'' of [[Windsor, Connecticut|Windsor]] -** ''Windsor Locks Journal'' of [[Windsor Locks, Connecticut|Windsor Locks]] -** ''Avon Post'' of [[Avon, Connecticut|Avon]] -** ''Farmington Post'' of [[Farmington, Connecticut|Farmington]] -** ''Simsbury Post'' of [[Simsbury, Connecticut|Simsbury]] -** ''Tri-Town Post'' of [[Burlington, Connecticut|Burlington]], [[Canton, Connecticut|Canton]] and [[Harwinton, Connecticut|Harwinton]] -* Minuteman Publications -** ''[[Fairfield Minuteman]]'' of [[Fairfield, Connecticut|Fairfield]] -** ''The Westport Minuteman'' {{WS|westportminuteman.com}} of [[Westport, Connecticut|Westport]] -* Shoreline Newspapers weeklies: -** ''Branford Review'' of [[Branford, Connecticut|Branford]] -** ''Clinton Recorder'' of [[Clinton, Connecticut|Clinton]] -** ''The Dolphin'' of [[Naval Submarine Base New London]] in [[New London, Connecticut|New London]] -** ''Main Street News'' {{WS|ctmainstreetnews.com}} of [[Essex, Connecticut|Essex]] -** ''Pictorial Gazette'' of [[Old Saybrook, Connecticut|Old Saybrook]] -** ''Regional Express'' of [[Colchester, Connecticut|Colchester]] -** ''Regional Standard'' of [[Colchester, Connecticut|Colchester]] -** ''Shoreline Times'' {{WS|shorelinetimes.com}} of [[Guilford, Connecticut|Guilford]] -** ''Shore View East'' of [[Madison, Connecticut|Madison]] -** ''Shore View West'' of [[Guilford, Connecticut|Guilford]] -* Other weeklies: -** ''Registro'' {{WS|registroct.com}} of [[New Haven, Connecticut|New Haven]] -** ''Thomaston Express'' {{WS|thomastownexpress.com}} of [[Thomaston, Connecticut|Thomaston]] -** ''Foothills Traders'' {{WS|foothillstrader.com}} of Torrington, Bristol, Canton - -== Michigan == -Four dailies, associated weeklies and [[pennysaver]]s in the state of [[Michigan]]; also [http://www.micentralhomes.com MIcentralhomes.com] and [http://www.micentralautos.com MIcentralautos.com] -* ''[[Oakland Press]]'' {{WS|theoaklandpress.com}} of [[Oakland, Michigan|Oakland]] -* ''Daily Tribune'' {{WS|dailytribune.com}} of [[Royal Oak, Michigan|Royal Oak]] -* ''Macomb Daily'' {{WS|macombdaily.com}} of [[Mt. Clemens, Michigan|Mt. Clemens]] -* ''[[Morning Sun]]'' {{WS|themorningsun.com}} of [[Mount Pleasant, Michigan|Mount Pleasant]] -* Heritage Newspapers {{WS|heritage.com}} -** ''Belleville View'' -** ''Ile Camera'' -** ''Monroe Guardian'' -** ''Ypsilanti Courier'' -** ''News-Herald'' -** ''Press & Guide'' -** ''Chelsea Standard & Dexter Leader'' -** ''Manchester Enterprise'' -** ''Milan News-Leader'' -** ''Saline Reporter'' -* Independent Newspapers {{WS|sourcenewspapers.com}} -** ''Advisor'' -** ''Source'' -* Morning Star {{WS|morningstarpublishing.com}} -** ''Alma Reminder'' -** ''Alpena Star'' -** ''Antrim County News'' -** ''Carson City Reminder'' -** ''The Leader & Kalkaskian'' -** ''Ogemaw/Oscoda County Star'' -** ''Petoskey/Charlevoix Star'' -** ''Presque Isle Star'' -** ''Preview Community Weekly'' -** ''Roscommon County Star'' -** ''St. Johns Reminder'' -** ''Straits Area Star'' -** ''The (Edmore) Advertiser'' -* Voice Newspapers {{WS|voicenews.com}} -** ''Armada Times'' -** ''Bay Voice'' -** ''Blue Water Voice'' -** ''Downriver Voice'' -** ''Macomb Township Voice'' -** ''North Macomb Voice'' -** ''Weekend Voice'' -** ''Suburban Lifestyles'' {{WS|suburbanlifestyles.com}} - -== Mid-Hudson == -One daily, associated magazines in the [[Hudson River Valley]] of [[New York]]; also [http://www.midhudsoncentral.com MidHudsonCentral.com] and [http://www.jobsinnewyork.com JobsInNewYork.com]. - -* ''[[Daily Freeman]]'' {{WS|dailyfreeman.com}} of [[Kingston, New York]] - -== Ohio == -Two dailies, associated magazines and three shared Websites, all in the state of [[Ohio]]: [http://www.allaroundcleveland.com AllAroundCleveland.com], [http://www.allaroundclevelandcars.com AllAroundClevelandCars.com] and [http://www.allaroundclevelandjobs.com AllAroundClevelandJobs.com]. - -* ''[[The News-Herald (Ohio)|The News-Herald]]'' {{WS|news-herald.com}} of [[Willoughby, Ohio|Willoughby]] -* ''[[The Morning Journal]]'' {{WS|morningjournal.com}} of [[Lorain, Ohio|Lorain]] - -== Philadelphia area == -Seven dailies and associated weeklies and magazines in [[Pennsylvania]] and [[New Jersey]], and associated Websites: [http://www.allaroundphilly.com AllAroundPhilly.com], [http://www.jobsinnj.com JobsInNJ.com], [http://www.jobsinpa.com JobsInPA.com], and [http://www.phillycarsearch.com PhillyCarSearch.com]. - -* ''The Daily Local'' {{WS|dailylocal.com}} of [[West Chester, Pennsylvania|West Chester]] -* ''[[Delaware County Daily and Sunday Times]] {{WS|delcotimes.com}} of Primos -* ''[[The Mercury (Pennsylvania)|The Mercury]]'' {{WS|pottstownmercury.com}} of [[Pottstown, Pennsylvania|Pottstown]] -* ''The Phoenix'' {{WS|phoenixvillenews.com}} of [[Phoenixville, Pennsylvania|Phoenixville]] -* ''[[The Reporter (Lansdale)|The Reporter]]'' {{WS|thereporteronline.com}} of [[Lansdale, Pennsylvania|Lansdale]] -* ''The Times Herald'' {{WS|timesherald.com}} of [[Norristown, Pennsylvania|Norristown]] -* ''[[The Trentonian]]'' {{WS|trentonian.com}} of [[Trenton, New Jersey]] - -* Weeklies -** ''El Latino Expreso'' of [[Trenton, New Jersey]] -** ''La Voz'' of [[Norristown, Pennsylvania]] -** ''The Village News'' of [[Downingtown, Pennsylvania]] -** ''The Times Record'' of [[Kennett Square, Pennsylvania]] -** ''The Tri-County Record'' {{WS|tricountyrecord.com}} of [[Morgantown, Pennsylvania]] -** ''News of Delaware County'' {{WS|newsofdelawarecounty.com}}of [[Havertown, Pennsylvania]] -** ''Main Line Times'' {{WS|mainlinetimes.com}}of [[Ardmore, Pennsylvania]] -** ''Penny Pincher'' of [[Pottstown, Pennsylvania]] -** ''Town Talk'' {{WS|towntalknews.com}} of [[Ridley, Pennsylvania]] -* Chesapeake Publishing {{WS|pa8newsgroup.com}} -** ''Solanco Sun Ledger'' of [[Quarryville, Pennsylvania]] -** ''Columbia Ledger'' of [[Columbia, Pennsylvania]] -** ''Coatesville Ledger'' of [[Downingtown, Pennsylvania]] -** ''Parkesburg Post Ledger'' of [[Quarryville, Pennsylvania]] -** ''Downingtown Ledger'' of [[Downingtown, Pennsylvania]] -** ''The Kennett Paper'' of [[Kennett Square, Pennsylvania]] -** ''Avon Grove Sun'' of [[West Grove, Pennsylvania]] -** ''Oxford Tribune'' of [[Oxford, Pennsylvania]] -** ''Elizabethtown Chronicle'' of [[Elizabethtown, Pennsylvania]] -** ''Donegal Ledger'' of [[Donegal, Pennsylvania]] -** ''Chadds Ford Post'' of [[Chadds Ford, Pennsylvania]] -** ''The Central Record'' of [[Medford, New Jersey]] -** ''Maple Shade Progress'' of [[Maple Shade, New Jersey]] -* Intercounty Newspapers {{WS|buckslocalnews.com}} -** ''The Review'' of Roxborough, Pennsylvania -** ''The Recorder'' of [[Conshohocken, Pennsylvania]] -** ''The Leader'' of [[Mount Airy, Pennsylvania|Mount Airy]] and West Oak Lake, Pennsylvania -** ''The Pennington Post'' of [[Pennington, New Jersey]] -** ''The Bristol Pilot'' of [[Bristol, Pennsylvania]] -** ''Yardley News'' of [[Yardley, Pennsylvania]] -** ''New Hope Gazette'' of [[New Hope, Pennsylvania]] -** ''Doylestown Patriot'' of [[Doylestown, Pennsylvania]] -** ''Newtown Advance'' of [[Newtown, Pennsylvania]] -** ''The Plain Dealer'' of [[Williamstown, New Jersey]] -** ''News Report'' of [[Sewell, New Jersey]] -** ''Record Breeze'' of [[Berlin, New Jersey]] -** ''Newsweekly'' of [[Moorestown, New Jersey]] -** ''Haddon Herald'' of [[Haddonfield, New Jersey]] -** ''New Egypt Press'' of [[New Egypt, New Jersey]] -** ''Community News'' of [[Pemberton, New Jersey]] -** ''Plymouth Meeting Journal'' of [[Plymouth Meeting, Pennsylvania]] -** ''Lafayette Hill Journal'' of [[Lafayette Hill, Pennsylvania]] -* Montgomery Newspapers {{WS|montgomerynews.com}} -** ''Ambler Gazette'' of [[Ambler, Pennsylvania]] -** ''Central Bucks Life'' of [[Bucks County, Pennsylvania]] -** ''The Colonial'' of [[Plymouth Meeting, Pennsylvania]] -** ''Glenside News'' of [[Glenside, Pennsylvania]] -** ''The Globe'' of [[Lower Moreland Township, Pennsylvania]] -** ''Main Line Life'' of [[Ardmore, Pennsylvania]] -** ''Montgomery Life'' of [[Fort Washington, Pennsylvania]] -** ''North Penn Life'' of [[Lansdale, Pennsylvania]] -** ''Perkasie News Herald'' of [[Perkasie, Pennsylvania]] -** ''Public Spirit'' of [[Hatboro, Pennsylvania]] -** ''Souderton Independent'' of [[Souderton, Pennsylvania]] -** ''Springfield Sun'' of [[Springfield, Pennsylvania]] -** ''Spring-Ford Reporter'' of [[Royersford, Pennsylvania]] -** ''Times Chronicle'' of [[Jenkintown, Pennsylvania]] -** ''Valley Item'' of [[Perkiomenville, Pennsylvania]] -** ''Willow Grove Guide'' of [[Willow Grove, Pennsylvania]] -* News Gleaner Publications (closed December 2008) {{WS|newsgleaner.com}} -** ''Life Newspapers'' of [[Philadelphia, Pennsylvania]] -* Suburban Publications -** ''The Suburban & Wayne Times'' {{WS|waynesuburban.com}} of [[Wayne, Pennsylvania]] -** ''The Suburban Advertiser'' of [[Exton, Pennsylvania]] -** ''The King of Prussia Courier'' of [[King of Prussia, Pennsylvania]] -* Press Newspapers {{WS|countypressonline.com}} -** ''County Press'' of [[Newtown Square, Pennsylvania]] -** ''Garnet Valley Press'' of [[Glen Mills, Pennsylvania]] -** ''Haverford Press'' of [[Newtown Square, Pennsylvania]] (closed January 2009) -** ''Hometown Press'' of [[Glen Mills, Pennsylvania]] (closed January 2009) -** ''Media Press'' of [[Newtown Square, Pennsylvania]] (closed January 2009) -** ''Springfield Press'' of [[Springfield, Pennsylvania]] -* Berks-Mont Newspapers {{WS|berksmontnews.com}} -** ''The Boyertown Area Times'' of [[Boyertown, Pennsylvania]] -** ''The Kutztown Area Patriot'' of [[Kutztown, Pennsylvania]] -** ''The Hamburg Area Item'' of [[Hamburg, Pennsylvania]] -** ''The Southern Berks News'' of [[Exeter Township, Berks County, Pennsylvania]] -** ''The Free Press'' of [[Quakertown, Pennsylvania]] -** ''The Saucon News'' of [[Quakertown, Pennsylvania]] -** ''Westside Weekly'' of [[Reading, Pennsylvania]] - -* Magazines -** ''Bucks Co. Town & Country Living'' -** ''Chester Co. Town & Country Living'' -** ''Montomgery Co. Town & Country Living'' -** ''Garden State Town & Country Living'' -** ''Montgomery Homes'' -** ''Philadelphia Golfer'' -** ''Parents Express'' -** ''Art Matters'' - -{{JRC}} - -==References== - - -[[Category:Journal Register publications|*]] diff --git a/common/src/test/java/com/jeesite/test/diff/Speedtest2.txt b/common/src/test/java/com/jeesite/test/diff/Speedtest2.txt deleted file mode 100644 index 8f25a80f..00000000 --- a/common/src/test/java/com/jeesite/test/diff/Speedtest2.txt +++ /dev/null @@ -1,188 +0,0 @@ -This is a '''list of newspapers published by [[Journal Register Company]]'''. - -The company owns daily and weekly newspapers, other print media properties and newspaper-affiliated local Websites in the [[U.S.]] states of [[Connecticut]], [[Michigan]], [[New York]], [[Ohio]], [[Pennsylvania]] and [[New Jersey]], organized in six geographic "clusters":[http://www.journalregister.com/publications.html Journal Register Company: Our Publications], accessed April 21, 2010. - -== Capital-Saratoga == -Three dailies, associated weeklies and [[pennysaver]]s in greater [[Albany, New York]]; also [http://www.capitalcentral.com capitalcentral.com] and [http://www.jobsinnewyork.com JobsInNewYork.com]. - -* ''The Oneida Daily Dispatch'' {{WS|oneidadispatch.com}} of [[Oneida, New York]] -* ''[[The Record (Troy)|The Record]]'' {{WS|troyrecord.com}} of [[Troy, New York]] -* ''[[The Saratogian]]'' {{WS|saratogian.com}} of [[Saratoga Springs, New York]] -* Weeklies: -** ''Community News'' {{WS|cnweekly.com}} weekly of [[Clifton Park, New York]] -** ''Rome Observer'' {{WS|romeobserver.com}} of [[Rome, New York]] -** ''WG Life '' {{WS|saratogian.com/wglife/}} of [[Wilton, New York]] -** ''Ballston Spa Life '' {{WS|saratogian.com/bspalife}} of [[Ballston Spa, New York]] -** ''Greenbush Life'' {{WS|troyrecord.com/greenbush}} of [[Troy, New York]] -** ''Latham Life'' {{WS|troyrecord.com/latham}} of [[Latham, New York]] -** ''River Life'' {{WS|troyrecord.com/river}} of [[Troy, New York]] - -== Connecticut == -Three dailies, associated weeklies and [[pennysaver]]s in the state of [[Connecticut]]; also [http://www.ctcentral.com CTcentral.com], [http://www.ctcarsandtrucks.com CTCarsAndTrucks.com] and [http://www.jobsinct.com JobsInCT.com]. - -* ''The Middletown Press'' {{WS|middletownpress.com}} of [[Middletown, Connecticut|Middletown]] -* ''[[New Haven Register]]'' {{WS|newhavenregister.com}} of [[New Haven, Connecticut|New Haven]] -* ''The Register Citizen'' {{WS|registercitizen.com}} of [[Torrington, Connecticut|Torrington]] - -* Housatonic Publications -** ''The Housatonic Times'' {{WS|housatonictimes.com}} of [[New Milford, Connecticut|New Milford]] -** ''Litchfield County Times'' {{WS|countytimes.com}} of [[Litchfield, Connecticut|Litchfield]] - -* Minuteman Publications -** ''[[Fairfield Minuteman]]'' {{WS|fairfieldminuteman.com}}of [[Fairfield, Connecticut|Fairfield]] -** ''The Westport Minuteman'' {{WS|westportminuteman.com}} of [[Westport, Connecticut|Westport]] - -* Shoreline Newspapers -** ''The Dolphin'' {{WS|dolphin-news.com}} of [[Naval Submarine Base New London]] in [[New London, Connecticut|New London]] -** ''Shoreline Times'' {{WS|shorelinetimes.com}} of [[Guilford, Connecticut|Guilford]] - -* Foothills Media Group {{WS|foothillsmediagroup.com}} -** ''Thomaston Express'' {{WS|thomastonexpress.com}} of [[Thomaston, Connecticut|Thomaston]] -** ''Good News About Torrington'' {{WS|goodnewsabouttorrington.com}} of [[Torrington, Connecticut|Torrington]] -** ''Granby News'' {{WS|foothillsmediagroup.com/granby}} of [[Granby, Connecticut|Granby]] -** ''Canton News'' {{WS|foothillsmediagroup.com/canton}} of [[Canton, Connecticut|Canton]] -** ''Avon News'' {{WS|foothillsmediagroup.com/avon}} of [[Avon, Connecticut|Avon]] -** ''Simsbury News'' {{WS|foothillsmediagroup.com/simsbury}} of [[Simsbury, Connecticut|Simsbury]] -** ''Litchfield News'' {{WS|foothillsmediagroup.com/litchfield}} of [[Litchfield, Connecticut|Litchfield]] -** ''Foothills Trader'' {{WS|foothillstrader.com}} of Torrington, Bristol, Canton - -* Other weeklies -** ''The Milford-Orange Bulletin'' {{WS|ctbulletin.com}} of [[Orange, Connecticut|Orange]] -** ''The Post-Chronicle'' {{WS|ctpostchronicle.com}} of [[North Haven, Connecticut|North Haven]] -** ''West Hartford News'' {{WS|westhartfordnews.com}} of [[West Hartford, Connecticut|West Hartford]] - -* Magazines -** ''The Connecticut Bride'' {{WS|connecticutmag.com}} -** ''Connecticut Magazine'' {{WS|theconnecticutbride.com}} -** ''Passport Magazine'' {{WS|passport-mag.com}} - -== Michigan == -Four dailies, associated weeklies and [[pennysaver]]s in the state of [[Michigan]]; also [http://www.micentralhomes.com MIcentralhomes.com] and [http://www.micentralautos.com MIcentralautos.com] -* ''[[Oakland Press]]'' {{WS|theoaklandpress.com}} of [[Oakland, Michigan|Oakland]] -* ''Daily Tribune'' {{WS|dailytribune.com}} of [[Royal Oak, Michigan|Royal Oak]] -* ''Macomb Daily'' {{WS|macombdaily.com}} of [[Mt. Clemens, Michigan|Mt. Clemens]] -* ''[[Morning Sun]]'' {{WS|themorningsun.com}} of [[Mount Pleasant, Michigan|Mount Pleasant]] - -* Heritage Newspapers {{WS|heritage.com}} -** ''Belleville View'' {{WS|bellevilleview.com}} -** ''Ile Camera'' {{WS|thenewsherald.com/ile_camera}} -** ''Monroe Guardian'' {{WS|monreguardian.com}} -** ''Ypsilanti Courier'' {{WS|ypsilanticourier.com}} -** ''News-Herald'' {{WS|thenewsherald.com}} -** ''Press & Guide'' {{WS|pressandguide.com}} -** ''Chelsea Standard & Dexter Leader'' {{WS|chelseastandard.com}} -** ''Manchester Enterprise'' {{WS|manchesterguardian.com}} -** ''Milan News-Leader'' {{WS|milannews.com}} -** ''Saline Reporter'' {{WS|salinereporter.com}} -* Independent Newspapers -** ''Advisor'' {{WS|sourcenewspapers.com}} -** ''Source'' {{WS|sourcenewspapers.com}} -* Morning Star {{WS|morningstarpublishing.com}} -** ''The Leader & Kalkaskian'' {{WS|leaderandkalkaskian.com}} -** ''Grand Traverse Insider'' {{WS|grandtraverseinsider.com}} -** ''Alma Reminder'' -** ''Alpena Star'' -** ''Ogemaw/Oscoda County Star'' -** ''Presque Isle Star'' -** ''St. Johns Reminder'' - -* Voice Newspapers {{WS|voicenews.com}} -** ''Armada Times'' -** ''Bay Voice'' -** ''Blue Water Voice'' -** ''Downriver Voice'' -** ''Macomb Township Voice'' -** ''North Macomb Voice'' -** ''Weekend Voice'' - -== Mid-Hudson == -One daily, associated magazines in the [[Hudson River Valley]] of [[New York]]; also [http://www.midhudsoncentral.com MidHudsonCentral.com] and [http://www.jobsinnewyork.com JobsInNewYork.com]. - -* ''[[Daily Freeman]]'' {{WS|dailyfreeman.com}} of [[Kingston, New York]] -* ''Las Noticias'' {{WS|lasnoticiasny.com}} of [[Kingston, New York]] - -== Ohio == -Two dailies, associated magazines and three shared Websites, all in the state of [[Ohio]]: [http://www.allaroundcleveland.com AllAroundCleveland.com], [http://www.allaroundclevelandcars.com AllAroundClevelandCars.com] and [http://www.allaroundclevelandjobs.com AllAroundClevelandJobs.com]. - -* ''[[The News-Herald (Ohio)|The News-Herald]]'' {{WS|news-herald.com}} of [[Willoughby, Ohio|Willoughby]] -* ''[[The Morning Journal]]'' {{WS|morningjournal.com}} of [[Lorain, Ohio|Lorain]] -* ''El Latino Expreso'' {{WS|lorainlatino.com}} of [[Lorain, Ohio|Lorain]] - -== Philadelphia area == -Seven dailies and associated weeklies and magazines in [[Pennsylvania]] and [[New Jersey]], and associated Websites: [http://www.allaroundphilly.com AllAroundPhilly.com], [http://www.jobsinnj.com JobsInNJ.com], [http://www.jobsinpa.com JobsInPA.com], and [http://www.phillycarsearch.com PhillyCarSearch.com]. - -* ''[[The Daily Local News]]'' {{WS|dailylocal.com}} of [[West Chester, Pennsylvania|West Chester]] -* ''[[Delaware County Daily and Sunday Times]] {{WS|delcotimes.com}} of Primos [[Upper Darby Township, Pennsylvania]] -* ''[[The Mercury (Pennsylvania)|The Mercury]]'' {{WS|pottstownmercury.com}} of [[Pottstown, Pennsylvania|Pottstown]] -* ''[[The Reporter (Lansdale)|The Reporter]]'' {{WS|thereporteronline.com}} of [[Lansdale, Pennsylvania|Lansdale]] -* ''The Times Herald'' {{WS|timesherald.com}} of [[Norristown, Pennsylvania|Norristown]] -* ''[[The Trentonian]]'' {{WS|trentonian.com}} of [[Trenton, New Jersey]] - -* Weeklies -* ''The Phoenix'' {{WS|phoenixvillenews.com}} of [[Phoenixville, Pennsylvania]] -** ''El Latino Expreso'' {{WS|njexpreso.com}} of [[Trenton, New Jersey]] -** ''La Voz'' {{WS|lavozpa.com}} of [[Norristown, Pennsylvania]] -** ''The Tri County Record'' {{WS|tricountyrecord.com}} of [[Morgantown, Pennsylvania]] -** ''Penny Pincher'' {{WS|pennypincherpa.com}}of [[Pottstown, Pennsylvania]] - -* Chesapeake Publishing {{WS|southernchestercountyweeklies.com}} -** ''The Kennett Paper'' {{WS|kennettpaper.com}} of [[Kennett Square, Pennsylvania]] -** ''Avon Grove Sun'' {{WS|avongrovesun.com}} of [[West Grove, Pennsylvania]] -** ''The Central Record'' {{WS|medfordcentralrecord.com}} of [[Medford, New Jersey]] -** ''Maple Shade Progress'' {{WS|mapleshadeprogress.com}} of [[Maple Shade, New Jersey]] - -* Intercounty Newspapers {{WS|buckslocalnews.com}} {{WS|southjerseylocalnews.com}} -** ''The Pennington Post'' {{WS|penningtonpost.com}} of [[Pennington, New Jersey]] -** ''The Bristol Pilot'' {{WS|bristolpilot.com}} of [[Bristol, Pennsylvania]] -** ''Yardley News'' {{WS|yardleynews.com}} of [[Yardley, Pennsylvania]] -** ''Advance of Bucks County'' {{WS|advanceofbucks.com}} of [[Newtown, Pennsylvania]] -** ''Record Breeze'' {{WS|recordbreeze.com}} of [[Berlin, New Jersey]] -** ''Community News'' {{WS|sjcommunitynews.com}} of [[Pemberton, New Jersey]] - -* Montgomery Newspapers {{WS|montgomerynews.com}} -** ''Ambler Gazette'' {{WS|amblergazette.com}} of [[Ambler, Pennsylvania]] -** ''The Colonial'' {{WS|colonialnews.com}} of [[Plymouth Meeting, Pennsylvania]] -** ''Glenside News'' {{WS|glensidenews.com}} of [[Glenside, Pennsylvania]] -** ''The Globe'' {{WS|globenewspaper.com}} of [[Lower Moreland Township, Pennsylvania]] -** ''Montgomery Life'' {{WS|montgomerylife.com}} of [[Fort Washington, Pennsylvania]] -** ''North Penn Life'' {{WS|northpennlife.com}} of [[Lansdale, Pennsylvania]] -** ''Perkasie News Herald'' {{WS|perkasienewsherald.com}} of [[Perkasie, Pennsylvania]] -** ''Public Spirit'' {{WS|thepublicspirit.com}} of [[Hatboro, Pennsylvania]] -** ''Souderton Independent'' {{WS|soudertonindependent.com}} of [[Souderton, Pennsylvania]] -** ''Springfield Sun'' {{WS|springfieldsun.com}} of [[Springfield, Pennsylvania]] -** ''Spring-Ford Reporter'' {{WS|springfordreporter.com}} of [[Royersford, Pennsylvania]] -** ''Times Chronicle'' {{WS|thetimeschronicle.com}} of [[Jenkintown, Pennsylvania]] -** ''Valley Item'' {{WS|valleyitem.com}} of [[Perkiomenville, Pennsylvania]] -** ''Willow Grove Guide'' {{WS|willowgroveguide.com}} of [[Willow Grove, Pennsylvania]] -** ''The Review'' {{WS|roxreview.com}} of [[Roxborough, Philadelphia, Pennsylvania]] - -* Main Line Media News {{WS|mainlinemedianews.com}} -** ''Main Line Times'' {{WS|mainlinetimes.com}} of [[Ardmore, Pennsylvania]] -** ''Main Line Life'' {{WS|mainlinelife.com}} of [[Ardmore, Pennsylvania]] -** ''The King of Prussia Courier'' {{WS|kingofprussiacourier.com}} of [[King of Prussia, Pennsylvania]] - -* Delaware County News Network {{WS|delconewsnetwork.com}} -** ''News of Delaware County'' {{WS|newsofdelawarecounty.com}} of [[Havertown, Pennsylvania]] -** ''County Press'' {{WS|countypressonline.com}} of [[Newtown Square, Pennsylvania]] -** ''Garnet Valley Press'' {{WS|countypressonline.com}} of [[Glen Mills, Pennsylvania]] -** ''Springfield Press'' {{WS|countypressonline.com}} of [[Springfield, Pennsylvania]] -** ''Town Talk'' {{WS|towntalknews.com}} of [[Ridley, Pennsylvania]] - -* Berks-Mont Newspapers {{WS|berksmontnews.com}} -** ''The Boyertown Area Times'' {{WS|berksmontnews.com/boyertown_area_times}} of [[Boyertown, Pennsylvania]] -** ''The Kutztown Area Patriot'' {{WS|berksmontnews.com/kutztown_area_patriot}} of [[Kutztown, Pennsylvania]] -** ''The Hamburg Area Item'' {{WS|berksmontnews.com/hamburg_area_item}} of [[Hamburg, Pennsylvania]] -** ''The Southern Berks News'' {{WS|berksmontnews.com/southern_berks_news}} of [[Exeter Township, Berks County, Pennsylvania]] -** ''Community Connection'' {{WS|berksmontnews.com/community_connection}} of [[Boyertown, Pennsylvania]] - -* Magazines -** ''Bucks Co. Town & Country Living'' {{WS|buckscountymagazine.com}} -** ''Parents Express'' {{WS|parents-express.com}} -** ''Real Men, Rednecks'' {{WS|realmenredneck.com}} - -{{JRC}} - -==References== - - -[[Category:Journal Register publications|*]]