1package org.hamcrest;
2
3/**
4 * A Condition implements part of a multi-step match. We sometimes need to write matchers
5 * that have a sequence of steps, where each step depends on the result of the previous
6 * step and we can stop processing as soon as a step fails. These classes provide
7 * infrastructure for writing such a sequence.
8 *
9 * Based on https://github.com/npryce/maybe-java
10 * @author Steve Freeman 2012 http://www.hamcrest.com
11 */
12
13public abstract class Condition<T> {
14    public static final NotMatched<Object> NOT_MATCHED = new NotMatched<Object>();
15
16    public interface Step<I, O> {
17        Condition<O> apply(I value, Description mismatch);
18    }
19
20    private Condition() { }
21
22    public abstract boolean matching(Matcher<T> match, String message);
23    public abstract <U> Condition<U> and(Step<? super T, U> mapping);
24
25    public final boolean matching(Matcher<T> match) { return matching(match, ""); }
26    public final <U> Condition<U> then(Step<? super T, U> mapping) { return and(mapping); }
27
28    @SuppressWarnings("unchecked")
29    public static <T> Condition<T> notMatched() {
30        return (Condition<T>) NOT_MATCHED;
31    }
32
33    public static <T> Condition<T> matched(final T theValue, final Description mismatch) {
34        return new Matched<T>(theValue, mismatch);
35    }
36
37    private static final class Matched<T> extends Condition<T> {
38        private final T theValue;
39        private final Description mismatch;
40
41        private Matched(T theValue, Description mismatch) {
42            this.theValue = theValue;
43            this.mismatch = mismatch;
44        }
45
46        @Override
47        public boolean matching(Matcher<T> matcher, String message) {
48            if (matcher.matches(theValue)) {
49                return true;
50            }
51            mismatch.appendText(message);
52            matcher.describeMismatch(theValue, mismatch);
53            return false;
54        }
55
56        @Override
57        public <U> Condition<U> and(Step<? super T, U> next) {
58            return next.apply(theValue, mismatch);
59        }
60    }
61
62    private static final class NotMatched<T> extends Condition<T> {
63        @Override public boolean matching(Matcher<T> match, String message) { return false; }
64
65        @Override public <U> Condition<U> and(Step<? super T, U> mapping) {
66            return notMatched();
67        }
68    }
69}
70