blob: f6698356d26493519873744d31ea94406ba83de0 [file] [log] [blame]
package org.hamcrest.collection;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
import static org.hamcrest.core.IsEqual.equalTo;
public class IsIterableContainingInRelativeOrder<E> extends TypeSafeDiagnosingMatcher<Iterable<? extends E>> {
private final List<Matcher<? super E>> matchers;
public IsIterableContainingInRelativeOrder(List<Matcher<? super E>> matchers) {
this.matchers = matchers;
}
@Override
protected boolean matchesSafely(Iterable<? extends E> iterable, Description mismatchDescription) {
MatchSeriesInRelativeOrder<E> matchSeriesInRelativeOrder = new MatchSeriesInRelativeOrder<E>(matchers, mismatchDescription);
matchSeriesInRelativeOrder.processItems(iterable);
return matchSeriesInRelativeOrder.isFinished();
}
public void describeTo(Description description) {
description.appendText("iterable containing ").appendList("[", ", ", "]", matchers).appendText(" in relative order");
}
private static class MatchSeriesInRelativeOrder<F> {
public final List<Matcher<? super F>> matchers;
private final Description mismatchDescription;
private int nextMatchIx = 0;
private F lastMatchedItem = null;
public MatchSeriesInRelativeOrder(List<Matcher<? super F>> matchers, Description mismatchDescription) {
this.mismatchDescription = mismatchDescription;
if (matchers.isEmpty()) {
throw new IllegalArgumentException("Should specify at least one expected element");
}
this.matchers = matchers;
}
public void processItems(Iterable<? extends F> iterable) {
for (F item : iterable) {
if (nextMatchIx < matchers.size()) {
Matcher<? super F> matcher = matchers.get(nextMatchIx);
if (matcher.matches(item)) {
lastMatchedItem = item;
nextMatchIx++;
}
}
}
}
public boolean isFinished() {
if (nextMatchIx < matchers.size()) {
mismatchDescription.appendDescriptionOf(matchers.get(nextMatchIx)).appendText(" was not found");
if (lastMatchedItem != null) {
mismatchDescription.appendText(" after ").appendValue(lastMatchedItem);
}
return false;
}
return true;
}
}
/**
* Creates a matcher for {@link Iterable}s that matches when a single pass over the
* examined {@link Iterable} yields a series of items, that contains items logically equal to the
* corresponding item in the specified items, in the same relative order
* For example:
* <pre>assertThat(Arrays.asList("a", "b", "c", "d", "e"), containsInRelativeOrder("b", "d"))</pre>
*
* @param items
* the items that must be contained within items provided by an examined {@link Iterable} in the same relative order
*/
public static <E> Matcher<Iterable<? extends E>> containsInRelativeOrder(E... items) {
List<Matcher<? super E>> matchers = new ArrayList<Matcher<? super E>>();
for (E item : items) {
matchers.add(equalTo(item));
}
return containsInRelativeOrder(matchers);
}
/**
* Creates a matcher for {@link Iterable}s that matches when a single pass over the
* examined {@link Iterable} yields a series of items, that each satisfying the corresponding
* matcher in the specified matchers, in the same relative order.
* For example:
* <pre>assertThat(Arrays.asList("a", "b", "c", "d", "e"), containsInRelativeOrder(equalTo("b"), equalTo("d")))</pre>
*
* @param itemMatchers
* the matchers that must be satisfied by the items provided by an examined {@link Iterable} in the same relative order
*/
public static <E> Matcher<Iterable<? extends E>> containsInRelativeOrder(Matcher<? super E>... itemMatchers) {
return containsInRelativeOrder((List) asList(itemMatchers));
}
/**
* Creates a matcher for {@link Iterable}s that matches when a single pass over the
* examined {@link Iterable} yields a series of items, that contains items satisfying the corresponding
* matcher in the specified list of matchers, in the same relative order.
* For example:
* <pre>assertThat(Arrays.asList("a", "b", "c", "d", "e"), contains(Arrays.asList(equalTo("b"), equalTo("d"))))</pre>
*
* @param itemMatchers
* a list of matchers, each of which must be satisfied by the items provided by
* an examined {@link Iterable} in the same relative order
*/
public static <E> Matcher<Iterable<? extends E>> containsInRelativeOrder(List<Matcher<? super E>> itemMatchers) {
return new IsIterableContainingInRelativeOrder<E>(itemMatchers);
}
}