1package org.hamcrest.core;
2
3import org.hamcrest.Description;
4import org.hamcrest.Matcher;
5import org.hamcrest.TypeSafeDiagnosingMatcher;
6
7import java.util.ArrayList;
8
9public class CombinableMatcher<T> extends TypeSafeDiagnosingMatcher<T> {
10  private final Matcher<? super T> matcher;
11
12  public CombinableMatcher(Matcher<? super T> matcher) {
13    this.matcher = matcher;
14  }
15
16  @Override
17  protected boolean matchesSafely(T item, Description mismatch) {
18    if (!matcher.matches(item)) {
19      matcher.describeMismatch(item, mismatch);
20      return false;
21    }
22    return true;
23  }
24
25  @Override
26  public void describeTo(Description description) {
27    description.appendDescriptionOf(matcher);
28  }
29
30  public CombinableMatcher<T> and(Matcher<? super T> other) {
31    return new CombinableMatcher<T>(new AllOf<T>(templatedListWith(other)));
32  }
33
34  public CombinableMatcher<T> or(Matcher<? super T> other) {
35    return new CombinableMatcher<T>(new AnyOf<T>(templatedListWith(other)));
36  }
37
38  private ArrayList<Matcher<? super T>> templatedListWith(Matcher<? super T> other) {
39    ArrayList<Matcher<? super T>> matchers = new ArrayList<Matcher<? super T>>();
40    matchers.add(matcher);
41    matchers.add(other);
42    return matchers;
43  }
44
45  /**
46   * Creates a matcher that matches when both of the specified matchers match the examined object.
47   * For example:
48   * <pre>assertThat("fab", both(containsString("a")).and(containsString("b")))</pre>
49   */
50  public static <LHS> CombinableBothMatcher<LHS> both(Matcher<? super LHS> matcher) {
51    return new CombinableBothMatcher<LHS>(matcher);
52  }
53
54  public static final class CombinableBothMatcher<X> {
55    private final Matcher<? super X> first;
56    public CombinableBothMatcher(Matcher<? super X> matcher) {
57        this.first = matcher;
58    }
59    public CombinableMatcher<X> and(Matcher<? super X> other) {
60      return new CombinableMatcher<X>(first).and(other);
61    }
62  }
63
64  /**
65   * Creates a matcher that matches when either of the specified matchers match the examined object.
66   * For example:
67   * <pre>assertThat("fan", either(containsString("a")).or(containsString("b")))</pre>
68   */
69  public static <LHS> CombinableEitherMatcher<LHS> either(Matcher<? super LHS> matcher) {
70    return new CombinableEitherMatcher<LHS>(matcher);
71  }
72
73  public static final class CombinableEitherMatcher<X> {
74    private final Matcher<? super X> first;
75    public CombinableEitherMatcher(Matcher<? super X> matcher) {
76        this.first = matcher;
77    }
78    public CombinableMatcher<X> or(Matcher<? super X> other) {
79      return new CombinableMatcher<X>(first).or(other);
80    }
81  }
82}
83