From 9b0f9fa20f3ff3a47ccd77a1d4ead7da7ddf558e Mon Sep 17 00:00:00 2001 From: "Olivier B. OURA" Date: Sun, 17 Jan 2021 08:31:55 +0000 Subject: [PATCH] Remove all MatcherOf ctors except last one #165 --- .../llorllale/cactoos/matchers/EndsWith.java | 8 +-- .../cactoos/matchers/HasContent.java | 19 ++++-- .../llorllale/cactoos/matchers/HasString.java | 9 +-- .../llorllale/cactoos/matchers/IsNumber.java | 27 ++++++-- .../llorllale/cactoos/matchers/IsText.java | 8 +-- .../llorllale/cactoos/matchers/MatcherOf.java | 60 ------------------ .../cactoos/matchers/MatchesRegex.java | 8 +-- .../cactoos/matchers/StartsWith.java | 8 +-- .../cactoos/matchers/TextMatcher.java | 50 ++++++++++----- .../cactoos/matchers/HasContentTest.java | 7 ++- .../cactoos/matchers/MatcherOfTest.java | 61 +++++++------------ .../cactoos/matchers/TextMatcherTest.java | 43 +++++++++++++ 12 files changed, 155 insertions(+), 153 deletions(-) diff --git a/src/main/java/org/llorllale/cactoos/matchers/EndsWith.java b/src/main/java/org/llorllale/cactoos/matchers/EndsWith.java index 21303b7b..06496b4a 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/EndsWith.java +++ b/src/main/java/org/llorllale/cactoos/matchers/EndsWith.java @@ -51,11 +51,9 @@ public EndsWith(final String suffix) { public EndsWith(final Text text) { super( new TextMatcher( - new MatcherOf<>( - (String act) -> act.endsWith(text.asString()), - text - ), - "Text ending with " + text, + (act, txt) -> act.endsWith(txt), + "Text ending with" ) ); } diff --git a/src/main/java/org/llorllale/cactoos/matchers/HasContent.java b/src/main/java/org/llorllale/cactoos/matchers/HasContent.java index cbabeffa..4f51440b 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/HasContent.java +++ b/src/main/java/org/llorllale/cactoos/matchers/HasContent.java @@ -28,6 +28,7 @@ import org.cactoos.Input; import org.cactoos.Text; +import org.cactoos.text.FormattedText; import org.cactoos.text.TextOf; import org.hamcrest.Matcher; @@ -54,11 +55,20 @@ public HasContent(final String text) { /** * Ctor. * @param text The text to match against + * @todo #165:30min We need an InputMatcher similar to {@link TextMatcher} that would + * be in charge of caching the value of the {@link Input} so that it is ready only once + * per invocation of the {@link Matcher}. */ public HasContent(final Text text) { this( new MatcherOf<>( - (String input) -> text.asString().equals(input), text + input -> text.asString().equals(input), + desc -> desc.appendText( + new FormattedText("\"%s\"", text).asString() + ), + (act, desc) -> desc + .appendText("has content ") + .appendValue(act) ) ); } @@ -74,9 +84,10 @@ public HasContent(final Matcher mtr) { desc -> desc .appendText("has content ") .appendDescriptionOf(mtr), - (input, desc) -> desc - .appendText("has content ") - .appendValue(new TextOf(input).asString()) + (input, desc) -> mtr.describeMismatch( + new TextOf(input).toString(), + desc + ) ) ); } diff --git a/src/main/java/org/llorllale/cactoos/matchers/HasString.java b/src/main/java/org/llorllale/cactoos/matchers/HasString.java index a0c779e3..aa10ed3c 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/HasString.java +++ b/src/main/java/org/llorllale/cactoos/matchers/HasString.java @@ -51,13 +51,10 @@ public HasString(final String text) { public HasString(final Text text) { super( new TextMatcher( - new MatcherOf<>( - (String actual) -> actual.contains(text.asString()), - text - ), - "Text with " + text, + (act, txt) -> act.contains(txt), + "Text with" ) ); } - } diff --git a/src/main/java/org/llorllale/cactoos/matchers/IsNumber.java b/src/main/java/org/llorllale/cactoos/matchers/IsNumber.java index 691b3aa7..7494ff25 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/IsNumber.java +++ b/src/main/java/org/llorllale/cactoos/matchers/IsNumber.java @@ -35,19 +35,34 @@ */ public final class IsNumber extends MatcherEnvelope { + /** + * Comparator of numbers. + */ + private static final Comparator FNC = + Comparator + .comparing(Number::doubleValue) + .thenComparing(Number::intValue) + .thenComparing(Number::longValue) + .thenComparing(Number::floatValue); + /** * Ctor. * @param expected The expected value + * @todo #165:30min Introduce a ComparatorMatcher that encapsulates comparison logic here. + * It would only take a {@code Comparator} and an expected X for example. */ public IsNumber(final Number expected) { super( new MatcherOf<>( - expected, - Comparator - .comparing(Number::doubleValue) - .thenComparing(Number::intValue) - .thenComparing(Number::longValue) - .thenComparing(Number::floatValue) + actual -> IsNumber.FNC.compare(actual, expected) == 0, + desc -> desc.appendText("equals ").appendValue(expected), + (actual, desc) -> desc + .appendText("comparator returns ") + .appendValue(IsNumber.FNC.compare(actual, expected)) + .appendText(" when ") + .appendValue(expected) + .appendText(" compared to ") + .appendValue(actual) ) ); } diff --git a/src/main/java/org/llorllale/cactoos/matchers/IsText.java b/src/main/java/org/llorllale/cactoos/matchers/IsText.java index d7af9777..975beda0 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/IsText.java +++ b/src/main/java/org/llorllale/cactoos/matchers/IsText.java @@ -51,11 +51,9 @@ public IsText(final String text) { public IsText(final Text text) { super( new TextMatcher( - new MatcherOf<>( - (String actual) -> actual.equals(text.asString()), - text - ), - "Text with value " + text, + (act, txt) -> act.equals(txt), + "Text with value" ) ); } diff --git a/src/main/java/org/llorllale/cactoos/matchers/MatcherOf.java b/src/main/java/org/llorllale/cactoos/matchers/MatcherOf.java index e4e72051..413d51d6 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/MatcherOf.java +++ b/src/main/java/org/llorllale/cactoos/matchers/MatcherOf.java @@ -26,17 +26,12 @@ */ package org.llorllale.cactoos.matchers; -import java.util.Comparator; import org.cactoos.BiProc; import org.cactoos.Func; import org.cactoos.Proc; -import org.cactoos.Text; -import org.cactoos.func.FuncOf; import org.cactoos.func.UncheckedFunc; import org.cactoos.proc.UncheckedBiProc; import org.cactoos.proc.UncheckedProc; -import org.cactoos.text.FormattedText; -import org.cactoos.text.UncheckedText; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; @@ -47,9 +42,6 @@ * * @param Type of object to match * @since 0.12 - * @todo #135:30min Remove all constructors except the last one so that - * every matcher implemented using MatcherOf take care of properly - * describe itself and the mismatch. */ public final class MatcherOf extends TypeSafeMatcher { @@ -69,37 +61,6 @@ public final class MatcherOf extends TypeSafeMatcher { */ private final BiProc mismatch; - /** - * Ctor. - * @param proc The func - */ - public MatcherOf(final Proc proc) { - this(new FuncOf<>(proc, true)); - } - - /** - * Ctor. - * @param fnc The func - */ - public MatcherOf(final Func fnc) { - this(fnc, new UncheckedText(fnc.toString())); - } - - /** - * Ctor. - * @param fnc The func - * @param description The description - */ - public MatcherOf(final Func fnc, final Text description) { - this( - fnc, - desc -> desc.appendText( - new FormattedText("\"%s\"", description).asString() - ), - (actual, desc) -> desc.appendValue(actual) - ); - } - /** * Ctor. * @param match Matches an actual object with expected one @@ -117,27 +78,6 @@ public MatcherOf( this.mismatch = mismatch; } - /** - * Ctor. - * @param expected Expected value. - * @param comp Comparator. - */ - public MatcherOf(final T expected, final Comparator comp) { - this( - (T x) -> comp.compare(x, expected) == 0, - (Description desc) -> desc - .appendText("equals ") - .appendValue(expected), - (T actual, Description desc) -> desc - .appendText("comparator returns ") - .appendValue(comp.compare(actual, expected)) - .appendText(" when ") - .appendValue(expected) - .appendText(" compared to ") - .appendValue(actual) - ); - } - @Override public void describeTo(final Description desc) { new UncheckedProc<>(this.description).exec(desc); diff --git a/src/main/java/org/llorllale/cactoos/matchers/MatchesRegex.java b/src/main/java/org/llorllale/cactoos/matchers/MatchesRegex.java index aead613f..c4e320b4 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/MatchesRegex.java +++ b/src/main/java/org/llorllale/cactoos/matchers/MatchesRegex.java @@ -51,11 +51,9 @@ public MatchesRegex(final String regex) { public MatchesRegex(final Text regex) { super( new TextMatcher( - new MatcherOf<>( - (String act) -> act.matches(regex.asString()), - regex - ), - "Text matches " + regex, + (act, txt) -> act.matches(txt), + "Text matches" ) ); } diff --git a/src/main/java/org/llorllale/cactoos/matchers/StartsWith.java b/src/main/java/org/llorllale/cactoos/matchers/StartsWith.java index 39f28b32..ab69fac3 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/StartsWith.java +++ b/src/main/java/org/llorllale/cactoos/matchers/StartsWith.java @@ -51,11 +51,9 @@ public StartsWith(final String prefix) { public StartsWith(final Text text) { super( new TextMatcher( - new MatcherOf<>( - (String act) -> act.startsWith(text.asString()), - text - ), - "Text starting with " + text, + (act, txt) -> act.startsWith(txt), + "Text starting with" ) ); } diff --git a/src/main/java/org/llorllale/cactoos/matchers/TextMatcher.java b/src/main/java/org/llorllale/cactoos/matchers/TextMatcher.java index 0a68eef8..33b0509a 100644 --- a/src/main/java/org/llorllale/cactoos/matchers/TextMatcher.java +++ b/src/main/java/org/llorllale/cactoos/matchers/TextMatcher.java @@ -26,7 +26,9 @@ */ package org.llorllale.cactoos.matchers; +import org.cactoos.BiFunc; import org.cactoos.Text; +import org.cactoos.text.FormattedText; import org.cactoos.text.UncheckedText; import org.hamcrest.Description; import org.hamcrest.Matcher; @@ -45,11 +47,6 @@ public final class TextMatcher extends TypeSafeDiagnosingMatcher { */ private final Matcher matcher; - /** - * The description of the matcher's expected text. - */ - private final String expected; - /** * The description of the matcher's actual text. */ @@ -57,39 +54,60 @@ public final class TextMatcher extends TypeSafeDiagnosingMatcher { /** * Ctor. - * @param mtchr The matcher to test. + * @param text The text to match against. + * @param func Function that compares actual to expected value. * @param expected The description of the matcher's expected text. */ public TextMatcher( - final Matcher mtchr, final String expected + final Text text, + final BiFunc func, + final String expected ) { - this(mtchr, expected, "Text is "); + this( + new MatcherOf<>( + act -> func.apply(act, text.asString()), + desc -> desc.appendText( + new FormattedText("%s \"%s\"", expected, text).asString() + ), + (act, desc) -> desc.appendValue(act) + ) + ); + } + + /** + * Ctor. + * @param mtchr The matcher to test. + */ + public TextMatcher(final Matcher mtchr) { + this(mtchr, "Text is "); } /** * Ctor. * @param mtchr The matcher to test. - * @param expected The description of the matcher's expected text. * @param actual The description of the matcher's actual text. */ - public TextMatcher( - final Matcher mtchr, final String expected, final String actual - ) { + public TextMatcher(final Matcher mtchr, final String actual) { super(); this.matcher = mtchr; - this.expected = expected; this.actual = actual; } @Override public void describeTo(final Description desc) { - desc.appendText(this.expected).appendDescriptionOf(this.matcher); + desc.appendDescriptionOf(this.matcher); } @Override protected boolean matchesSafely(final Text text, final Description desc) { final String txt = new UncheckedText(text).asString(); - desc.appendText(this.actual).appendValue(txt); - return this.matcher.matches(txt); + final boolean matches = this.matcher.matches(txt); + desc.appendText(this.actual); + if (matches) { + desc.appendValue(txt); + } else { + this.matcher.describeMismatch(txt, desc); + } + return matches; } } diff --git a/src/test/java/org/llorllale/cactoos/matchers/HasContentTest.java b/src/test/java/org/llorllale/cactoos/matchers/HasContentTest.java index 3503ceaa..33cd6088 100644 --- a/src/test/java/org/llorllale/cactoos/matchers/HasContentTest.java +++ b/src/test/java/org/llorllale/cactoos/matchers/HasContentTest.java @@ -30,7 +30,6 @@ import org.hamcrest.Description; import org.hamcrest.StringDescription; import org.hamcrest.core.IsEqual; -import org.hamcrest.core.IsNot; import org.junit.jupiter.api.Test; /** @@ -56,7 +55,11 @@ void mismatchInputContent() { new Assertion<>( "does not match input with different contents", new HasContent("hello"), - new IsNot<>(new Matches<>(new InputOf("world"))) + new Mismatches<>( + new InputOf("world"), + "has content \"hello\"", + "has content \"world\"" + ) ).affirm(); } diff --git a/src/test/java/org/llorllale/cactoos/matchers/MatcherOfTest.java b/src/test/java/org/llorllale/cactoos/matchers/MatcherOfTest.java index 56940253..d25dc4d6 100644 --- a/src/test/java/org/llorllale/cactoos/matchers/MatcherOfTest.java +++ b/src/test/java/org/llorllale/cactoos/matchers/MatcherOfTest.java @@ -26,9 +26,9 @@ */ package org.llorllale.cactoos.matchers; -import java.util.Comparator; import org.cactoos.text.Joined; -import org.cactoos.text.TextOf; +import org.hamcrest.StringDescription; +import org.hamcrest.core.IsEqual; import org.junit.jupiter.api.Test; /** @@ -38,13 +38,18 @@ * @checkstyle MagicNumberCheck (500 lines) * @checkstyle ClassDataAbstractionCouplingCheck (500 lines) */ +@SuppressWarnings("PMD.AvoidDuplicateLiterals") final class MatcherOfTest { @Test void matchesFunc() { new Assertion<>( "matches when arg satisfies the predicate", - new MatcherOf<>(x -> x > 5), + new MatcherOf<>( + x -> x > 5, + desc -> desc.appendText("Must be > 5"), + (actual, desc) -> desc.appendValue(actual) + ), new Matches<>(10) ).affirm(); } @@ -54,26 +59,18 @@ void mismatchesFunc() { new Assertion<>( "mismatches when arg does not satisfy the predicate", new MatcherOf<>( - x -> x > 5, - new TextOf("Must be > 5") + x -> x > 7, + desc -> desc.appendText("\"Must be > 7\""), + (actual, desc) -> desc.appendValue(actual) ), new Mismatches<>( 1, - "\"Must be > 5\"", + "\"Must be > 7\"", "<1>" ) ).affirm(); } - @Test - void matcherOfProcMatchesAnyArguments() { - new Assertion<>( - "matches any arguments when constructed from a Proc", - new MatcherOf<>(String::trim), - new Matches<>("a") - ).affirm(); - } - @Test void mismatches() { final Integer expected = 42; @@ -94,31 +91,17 @@ void mismatches() { } @Test - void matchesByComparator() { + void describesMismatchSafely() { + final StringDescription dsc = new StringDescription(); + new MatcherOf( + x -> x.equals("hello"), + desc -> desc.appendText("hello"), + (act, desc) -> desc.appendText(act) + ).describeMismatchSafely("world", dsc); new Assertion<>( - "matches when comparator returns 0", - new MatcherOf<>( - 10, - Comparator.comparingInt(x -> Math.abs(x.intValue())) - ), - new Matches<>(-10) - ).affirm(); - } - - @Test - void mismatchesByComparator() { - new Assertion<>( - "mismatches when arg does not satisfy comparator", - new MatcherOf<>( - 123, - Comparator.comparingInt(x -> Math.abs(x.intValue())) - ), - new Mismatches<>( - 1234, - "equals <123>", - "comparator returns <1> when <123> compared to <1234>" - ) + "describes mismatch safely", + dsc.toString(), + new IsEqual<>("world") ).affirm(); } - } diff --git a/src/test/java/org/llorllale/cactoos/matchers/TextMatcherTest.java b/src/test/java/org/llorllale/cactoos/matchers/TextMatcherTest.java index 3a577da9..ae93d912 100644 --- a/src/test/java/org/llorllale/cactoos/matchers/TextMatcherTest.java +++ b/src/test/java/org/llorllale/cactoos/matchers/TextMatcherTest.java @@ -36,7 +36,9 @@ * * @since 1.0.0 * @checkstyle JavadocTypeCheck (500 lines) + * @checkstyle ClassDataAbstractionCouplingCheck (500 lines) */ +@SuppressWarnings("PMD.AvoidDuplicateLiterals") final class TextMatcherTest { @Test void matchesAReadOnceInput() { @@ -50,4 +52,45 @@ void matchesAReadOnceInput() { new Matches<>(new TextOf(new StringReader(input))) ).affirm(); } + + @Test + void mismatches() { + new Assertion<>( + "mismatches text without the prefix", + new TextMatcher( + new TextOf("!"), + (act, txt) -> act.startsWith(txt), + "Text starting with" + ), + new Mismatches<>( + new TextOf("The sentence."), + "Text starting with \"!\"", + "Text is \"The sentence.\"" + ) + ).affirm(); + } + + @Test + void matchesFromMatcher() { + new Assertion<>( + "must match with matcher", + new TextMatcher( + new IsBlank() + ), + new Matches<>(new TextOf("")) + ).affirm(); + } + + @Test + void matchesFromFunc() { + new Assertion<>( + "must match with function", + new TextMatcher( + new TextOf("I am"), + (act, txt) -> act.startsWith(txt), + "Text starts with" + ), + new Matches<>(new TextOf("I am happy.")) + ).affirm(); + } }