001package org.hamcrest.core;
002
003import org.hamcrest.*;
004
005import java.util.ArrayList;
006
007public class CombinableMatcher<T> extends TypeSafeDiagnosingMatcher<T> {
008  private final Matcher<? super T> matcher;
009
010  public CombinableMatcher(Matcher<? super T> matcher) {
011    this.matcher = matcher;
012  }
013
014  @Override
015  protected boolean matchesSafely(T item, Description mismatch) {
016    if (!matcher.matches(item)) {
017      matcher.describeMismatch(item, mismatch);
018      return false;
019    }
020    return true;
021  }
022
023  @Override
024  public void describeTo(Description description) {
025    description.appendDescriptionOf(matcher);
026  }
027
028  public CombinableMatcher<T> and(Matcher<? super T> other) {
029    return new CombinableMatcher<T>(new AllOf<T>(templatedListWith(other)));
030  }
031
032  public CombinableMatcher<T> or(Matcher<? super T> other) {
033    return new CombinableMatcher<T>(new AnyOf<T>(templatedListWith(other)));
034  }
035
036  private ArrayList<Matcher<? super T>> templatedListWith(Matcher<? super T> other) {
037    ArrayList<Matcher<? super T>> matchers = new ArrayList<Matcher<? super T>>();
038    matchers.add(matcher);
039    matchers.add(other);
040    return matchers;
041  }
042
043  /**
044   * Creates a matcher that matches when both of the specified matchers match the examined object.
045   * <p/>
046   * For example:
047   * <pre>assertThat("fab", both(containsString("a")).and(containsString("b")))</pre>
048   */
049  @Factory
050  public static <LHS> CombinableBothMatcher<LHS> both(Matcher<? super LHS> matcher) {
051    return new CombinableBothMatcher<LHS>(matcher);
052  }
053  
054  public static final class CombinableBothMatcher<X> {
055    private final Matcher<? super X> first;
056    public CombinableBothMatcher(Matcher<? super X> matcher) {
057        this.first = matcher;
058    }
059    public CombinableMatcher<X> and(Matcher<? super X> other) {
060      return new CombinableMatcher<X>(first).and(other);
061    }
062  }
063
064  /**
065   * Creates a matcher that matches when either of the specified matchers match the examined object.
066   * <p/>
067   * For example:
068   * <pre>assertThat("fan", either(containsString("a")).and(containsString("b")))</pre>
069   */
070  @Factory
071  public static <LHS> CombinableEitherMatcher<LHS> either(Matcher<? super LHS> matcher) {
072    return new CombinableEitherMatcher<LHS>(matcher);
073  }
074  
075  public static final class CombinableEitherMatcher<X> {
076    private final Matcher<? super X> first;
077    public CombinableEitherMatcher(Matcher<? super X> matcher) {
078        this.first = matcher;
079    }
080    public CombinableMatcher<X> or(Matcher<? super X> other) {
081      return new CombinableMatcher<X>(first).or(other);
082    }
083  }
084}