    001    package org.hamcrest;
    002
    003    /**
    004     * A Condition implements part of a multi-step match. We sometimes need to write matchers
    005     * that have a sequence of steps, where each step depends on the result of the previous
    006     * step and we can stop processing as soon as a step fails. These classes provide
    007     * infrastructure for writing such a sequence.
    008     *
    009     * Based on https://github.com/npryce/maybe-java
    010     * @author Steve Freeman 2012 http://www.hamcrest.com
    011     */
    012
    013    public abstract class Condition<T> {
    014        public static final NotMatched<Object> NOT_MATCHED = new NotMatched<Object>();
    015
    016        public interface Step<I, O> {
    017            Condition<O> apply(I value, Description mismatch);
    018        }
    019
    020        private Condition() { }
    021
    022        public abstract boolean matching(Matcher<T> match, String message);
    023        public abstract <U> Condition<U> and(Step<? super T, U> mapping);
    024
    025        public final boolean matching(Matcher<T> match) { return matching(match, ""); }
    026        public final <U> Condition<U> then(Step<? super T, U> mapping) { return and(mapping); }
    027
    028        @SuppressWarnings("unchecked")
    029        public static <T> Condition<T> notMatched() {
    030            return (Condition<T>) NOT_MATCHED;
    031        }
    032
    033        public static <T> Condition<T> matched(final T theValue, final Description mismatch) {
    034            return new Matched<T>(theValue, mismatch);
    035        }
    036
    037        private static final class Matched<T> extends Condition<T> {
    038            private final T theValue;
    039            private final Description mismatch;
    040
    041            private Matched(T theValue, Description mismatch) {
    042                this.theValue = theValue;
    043                this.mismatch = mismatch;
    044            }
    045
    046            @Override
    047            public boolean matching(Matcher<T> matcher, String message) {
    048                if (matcher.matches(theValue)) {
    049                    return true;
    050                }
    051                mismatch.appendText(message);
    052                matcher.describeMismatch(theValue, mismatch);
    053                return false;
    054            }
    055
    056            @Override
    057            public <U> Condition<U> and(Step<? super T, U> next) {
    058                return next.apply(theValue, mismatch);
    059            }
    060        }
    061
    062        private static final class NotMatched<T> extends Condition<T> {
    063            @Override public boolean matching(Matcher<T> match, String message) { return false; }
    064
    065            @Override public <U> Condition<U> and(Step<? super T, U> mapping) {
    066                return notMatched();
    067            }
    068        }
    069    }