package com.googlecode.totallylazy.matchers;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.Sequences;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import java.util.Iterator;
import static com.googlecode.totallylazy.Sequences.sequence;
import static com.googlecode.totallylazy.matchers.Matchers.are;
public class IterableMatcher<T> extends TypeSafeMatcher<Iterable<T>> {
private final Sequence<Matcher<? super T>> expected;
private boolean shouldBeSameSize;
private IterableMatcher(Iterable<? extends Matcher<? super T>> expected, boolean shouldBeSameSize) {
this.expected = sequence(expected);
this.shouldBeSameSize = shouldBeSameSize;
}
@SuppressWarnings("unchecked")
public static Matcher<Iterable> hasSize(final Number size) {
return new HasSizeMatcher(size);
}
public static <T> Matcher<Iterable<T>> isEmpty(Class<T> aClass) {
return IterableMatcher.<T>isEmpty();
}
public static <T> Matcher<Iterable<T>> isEmpty() {
return IterableMatcher.<T>hasExactly(Sequences.<T>empty());
}
public static <T> Matcher<Iterable<T>> hasExactly(final T first) {
return hasExactly(sequence(first));
}
public static <T> Matcher<Iterable<T>> hasExactly(final T first, final T second) {
return hasExactly(sequence(first, second));
}
public static <T> Matcher<Iterable<T>> hasExactly(final T first, final T second, final T third) {
return hasExactly(sequence(first, second, third));
}
public static <T> Matcher<Iterable<T>> hasExactly(final T first, final T second, final T third, final T fourth) {
return hasExactly(sequence(first, second, third, fourth));
}
public static <T> Matcher<Iterable<T>> hasExactly(final T first, final T second, final T third, final T fourth, final T fifth) {
return hasExactly(sequence(first, second, third, fourth, fifth));
}
@SafeVarargs
public static <T> Matcher<Iterable<T>> hasExactly(final T... items) {
return hasExactly(sequence(items));
}
public static <T> Matcher<Iterable<T>> hasExactly(Iterable<T> expected) {
return new IterableMatcher<T>(are(expected), true);
}
public static <T> Matcher<Iterable<T>> hasExactlyMatching(Iterable<? extends Matcher<? super T>> expected) {
return new IterableMatcher<T>(expected, true);
}
@SafeVarargs
public static <T> Matcher<Iterable<T>> startsWith(T... items) {
return startsWith(sequence(items));
}
public static <T> Matcher<Iterable<T>> startsWith(Iterable<T> expected) {
Iterable<? extends Matcher<T>> are = are(expected);
return new IterableMatcher<T>(are, false);
}
@Override
public boolean matchesSafely(Iterable<T> actual) {
Iterator<Matcher<? super T>> e = this.expected.iterator();
Iterator<T> a = actual.iterator();
while(e.hasNext()){
if(!a.hasNext()){
return false;
}
if(!e.next().matches(a.next())){
return false;
}
}
if(shouldBeSameSize && a.hasNext()){
return false;
}
return true;
}
public void describeTo(Description description) {
description.appendValue("An iterable with values matching: ");
description.appendValue(expected);
}
}