From aa1a15aa6735af30cbc1e90a32b479fd3daed111 Mon Sep 17 00:00:00 2001 From: night-gale Date: Sun, 25 Apr 2021 08:59:08 +0800 Subject: [PATCH] Added equalToWithDiff for comparing strings and output diff message --- hamcrest/hamcrest.gradle | 1 + .../src/main/java/org/hamcrest/Matchers.java | 13 +++ .../org/hamcrest/text/IsEqualWithDiff.java | 92 +++++++++++++++++++ .../hamcrest/text/IsEqualWithDiffTest.java | 41 +++++++++ 4 files changed, 147 insertions(+) create mode 100644 hamcrest/src/main/java/org/hamcrest/text/IsEqualWithDiff.java create mode 100644 hamcrest/src/test/java/org/hamcrest/text/IsEqualWithDiffTest.java diff --git a/hamcrest/hamcrest.gradle b/hamcrest/hamcrest.gradle index 749b7255..63b3118a 100644 --- a/hamcrest/hamcrest.gradle +++ b/hamcrest/hamcrest.gradle @@ -6,6 +6,7 @@ dependencies { testImplementation(group: 'junit', name: 'junit', version: '4.13') { transitive = false } + implementation "io.github.java-diff-utils:java-diff-utils:4.5" } jar { diff --git a/hamcrest/src/main/java/org/hamcrest/Matchers.java b/hamcrest/src/main/java/org/hamcrest/Matchers.java index d4f543ea..a5ff649e 100644 --- a/hamcrest/src/main/java/org/hamcrest/Matchers.java +++ b/hamcrest/src/main/java/org/hamcrest/Matchers.java @@ -1372,6 +1372,19 @@ public static Matcher equalToIgnoringCase(java.lang.String exp return org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase(expectedString); } + /** + * Creates a matcher of {@link String} that matches when the examined string is equal to + * the specified expectedString, with markdown style diff message when mismatch + * For example: + *
assertThat("Foo", equalToWithDiff("FOO"))
+ * + * @param expectedString + * the expected value of matched strings + */ + public static Matcher equalToWithDiff(java.lang.String expectedString) { + return org.hamcrest.text.IsEqualWithDiff.equalToWithDiff(expectedString); + } + /** * @deprecated {@link #equalToCompressingWhiteSpace(String)} * @param expectedString diff --git a/hamcrest/src/main/java/org/hamcrest/text/IsEqualWithDiff.java b/hamcrest/src/main/java/org/hamcrest/text/IsEqualWithDiff.java new file mode 100644 index 00000000..4d914170 --- /dev/null +++ b/hamcrest/src/main/java/org/hamcrest/text/IsEqualWithDiff.java @@ -0,0 +1,92 @@ +package org.hamcrest.text; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import com.github.difflib.text.DiffRowGenerator; +import com.github.difflib.algorithm.DiffException; +import com.github.difflib.text.DiffRow; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +public class IsEqualWithDiff extends TypeSafeMatcher { + private final String string; + + public IsEqualWithDiff(String string) { + if (string == null) { + throw new IllegalArgumentException("Non-null value required"); + } + this.string = string; + } + + @Override + public boolean matchesSafely(String item) { + return string.equals(item); + } + + @Override + public void describeMismatchSafely(String item, Description mismatchDescription) { + mismatchDescription.appendText("Diff: \n\t"); + List expected = Arrays.asList(string.split("\n")); + List actual = Arrays.asList(item.split("\n")); + + DiffRowGenerator generator = DiffRowGenerator.create() + .showInlineDiffs(true) + .mergeOriginalRevised(true) + .reportLinesUnchanged(false) + .inlineDiffByWord(true) + .oldTag(new Function() { + @Override + public String apply(Boolean aBoolean) { + return "~"; + } + }) + .newTag(new Function() { + @Override + public String apply(Boolean aBoolean) { + return "**"; + } + }) + .build(); + List rows = null; + try { + rows = generator.generateDiffRows( + actual, + expected + ); + } catch (DiffException e) { + e.printStackTrace(); + } + + for (int ii = 0; ii < rows.size(); ii++) { + if (rows.get(ii).getTag() == DiffRow.Tag.CHANGE) + { + mismatchDescription.appendText(String.format("At line %d: ", ii)); + mismatchDescription.appendText(rows.get(ii).getOldLine()).appendText("\n\t"); + } + } + } + + @Override + public void describeTo(Description description) { + description.appendText("a string equal to ") + .appendValue(string) + .appendText(" with diff when mismatch"); + } + + /** + * Creates a matcher of {@link String} that matches when the examined string is equal to + * the specified expectedString, with markdown style diff output message when mismatch. + * For example: + *
assertThat("Foo", equalToIgnoringCase("FOO"))
+ * + * @param expectedString + * the expected value of matched strings + */ + public static Matcher equalToWithDiff(String expectedString) { + return new IsEqualWithDiff(expectedString); + } +} diff --git a/hamcrest/src/test/java/org/hamcrest/text/IsEqualWithDiffTest.java b/hamcrest/src/test/java/org/hamcrest/text/IsEqualWithDiffTest.java new file mode 100644 index 00000000..5358bcc0 --- /dev/null +++ b/hamcrest/src/test/java/org/hamcrest/text/IsEqualWithDiffTest.java @@ -0,0 +1,41 @@ +package org.hamcrest.text; + +import org.hamcrest.Matcher; + +import org.hamcrest.Description; +import org.hamcrest.StringDescription; +import org.junit.Test; + +import static org.hamcrest.AbstractMatcherTest.assertMatches; +import static org.hamcrest.text.IsEqualWithDiff.equalToWithDiff; + + +public class IsEqualWithDiffTest { + /* + Test the correctness of diff message + */ + @Test public void + testMismatchesWithCorrectDiffMessage() { + final String actual = "This is first see you, bye\nhbha"; + final Description expectedDescription = new StringDescription() + .appendText("Diff: \n\t") + .appendText("At line 0: This is first ~see~**hello** ~you~**world**, bye\n\t") + .appendText("At line 1: ~hbha~**haha**\n\t"); + Description actualDescription = new StringDescription(); + final Matcher matcher = equalToWithDiff("This is first hello world, bye\nhaha"); + matcher.describeMismatch(actual, actualDescription); + + assertMatches(equalToWithDiff(expectedDescription.toString()), actualDescription.toString()); + } + + /* + Test the correctness of Matcher itself + */ + @Test public void + testMatcherCorrectness() { + final String actual = "This is first see you, bye\nhbha"; + final String expected = "This is first see you, bye\nhbha"; + + assertMatches(equalToWithDiff(expected), actual); + } +}