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    }