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 }