Marek Turski
Marek Turski

Reputation: 33

Hamcrest IsNot matcher together with a wrapped custom matcher - describeMismatch doesn't work as expected

Recently I've made a custom matcher for the jaxb generated element and came upon this scenario:

Preconditions:

When assertion fails, in result I have:

Expected: not myMatchersDescribeToDescription
but: isNotCoreMatcherDescribeMismatchDescription

Digging in the code of org.hamcrest.core.IsNot class I can see that describeTo is implemented properly (ie. delegates gathering of description to a wrapped matcher), but describeMismatch is not overriden hence the BaseMatcher's version is used.

Imho it's a faulty behavior, because mismatch should be taken from the wrapped matcher as well. What do you think, guys?

Upvotes: 2

Views: 633

Answers (2)

crazystick
crazystick

Reputation: 610

I don't know why this was voted down. I agree it is faulty behaviour. Seems similar to this issue

You can fix it only by creating your own custom "notD" matcher, its a copy of the IsNot matcher adding the Override for describeMismatch:

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;

import static org.hamcrest.core.IsEqual.equalTo;


/**
 * Calculates the logical negation of a matcher.
 */
public class IsNotDescribing<T> extends BaseMatcher<T>  {
    private final Matcher<T> matcher;

    public IsNotDescribing(Matcher<T> matcher) {
        this.matcher = matcher;
    }

    @Override
    public boolean matches(Object arg) {
        return !matcher.matches(arg);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("not ").appendDescriptionOf(matcher);
    }

    // use the matcher to describe its mismatch
    @Override
    public void describeMismatch(Object item, Description description) {
        matcher.describeMismatch(item, description);
    }

    @Factory
    public static <T> Matcher<T> notD(Matcher<T> matcher) {
        return new IsNotDescribing<T>(matcher);
    }

    @Factory
    public static <T> Matcher<T> notD(T value) {
        return notD(equalTo(value));
    }
}

Upvotes: 1

John B
John B

Reputation: 32969

Where are you getting that describeMismatch should be overloaded in a Matcher? The Matcher interface specifies match and describeTo (via SelfDescribing). Hence the Hamcrest framework does not attempt to get the description of the actual object via the Matcher, just the description of the Matcher itself.

Upvotes: 1

Related Questions