package org.hamcrest;

import org.hamcrest.core.IsEqual;
import org.junit.jupiter.api.Test;

import static org.hamcrest.test.MatcherAssertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

public final class FeatureMatcherTest {

    private final FeatureMatcher<Thingy, String> resultMatcher = resultMatcher();

    @Test public void
    matchesPartOfAnObject() {
        assertMatches("feature", resultMatcher, new Thingy("bar"));
        assertDescription("Thingy with result \"bar\"", resultMatcher);
    }

    @Test public void
    mismatchesPartOfAnObject() {
        assertMismatchDescription("result mismatch-description", resultMatcher, new Thingy("foo"));
    }

    @Test public void
    doesNotThrowNullPointerException() {
        assertMismatchDescription("was null", resultMatcher, null);
    }

    @Test public void
    doesNotThrowClassCastException() {
        resultMatcher.matches(new ShouldNotMatch());
        StringDescription mismatchDescription = new StringDescription();
        resultMatcher.describeMismatch(new ShouldNotMatch(), mismatchDescription);
        assertEquals("was ShouldNotMatch <ShouldNotMatch>", mismatchDescription.toString());
    }

    public static class Match extends IsEqual<String> {
        public Match(String equalArg) { super(equalArg); }
        @Override public void describeMismatch(Object item, Description description) {
            description.appendText("mismatch-description");
        }
    }

    public static class Thingy {
        private final String result;

        public Thingy(String result) {
            this.result = result;
        }

        public String getResult() {
            return result;
        }
    }

    public static class ShouldNotMatch {
        @Override public String toString() { return "ShouldNotMatch"; }
    }

    private static FeatureMatcher<Thingy, String> resultMatcher() {
        return new FeatureMatcher<Thingy, String>(new Match("bar"), "Thingy with result", "result") {
            @Override
            public String featureValueOf(Thingy actual) {
                return actual.getResult();
            }
        };
    }

}
