001 package org.hamcrest.core;
002
003 import static org.hamcrest.core.AllOf.allOf;
004 import static org.hamcrest.core.IsEqual.equalTo;
005
006 import java.util.ArrayList;
007 import java.util.List;
008
009 import org.hamcrest.Description;
010 import org.hamcrest.Factory;
011 import org.hamcrest.Matcher;
012 import org.hamcrest.TypeSafeDiagnosingMatcher;
013
014 public class IsCollectionContaining<T> extends TypeSafeDiagnosingMatcher<Iterable<? super T>> {
015 private final Matcher<? super T> elementMatcher;
016
017 public IsCollectionContaining(Matcher<? super T> elementMatcher) {
018 this.elementMatcher = elementMatcher;
019 }
020
021 @Override
022 protected boolean matchesSafely(Iterable<? super T> collection, Description mismatchDescription) {
023 boolean isPastFirst = false;
024 for (Object item : collection) {
025 if (elementMatcher.matches(item)){
026 return true;
027 }
028 if (isPastFirst) {
029 mismatchDescription.appendText(", ");
030 }
031 elementMatcher.describeMismatch(item, mismatchDescription);
032 isPastFirst = true;
033 }
034 return false;
035 }
036
037 @Override
038 public void describeTo(Description description) {
039 description
040 .appendText("a collection containing ")
041 .appendDescriptionOf(elementMatcher);
042 }
043
044
045 /**
046 * Creates a matcher for {@link Iterable}s that only matches when a single pass over the
047 * examined {@link Iterable} yields at least one item that is matched by the specified
048 * <code>itemMatcher</code>. Whilst matching, the traversal of the examined {@link Iterable}
049 * will stop as soon as a matching item is found.
050 * <p/>
051 * For example:
052 * <pre>assertThat(Arrays.asList("foo", "bar"), hasItem(startsWith("ba")))</pre>
053 *
054 * @param itemMatcher
055 * the matcher to apply to items provided by the examined {@link Iterable}
056 */
057 @Factory
058 public static <T> Matcher<Iterable<? super T>> hasItem(Matcher<? super T> itemMatcher) {
059 return new IsCollectionContaining<T>(itemMatcher);
060 }
061
062 /**
063 * Creates a matcher for {@link Iterable}s that only matches when a single pass over the
064 * examined {@link Iterable} yields at least one item that is equal to the specified
065 * <code>item</code>. Whilst matching, the traversal of the examined {@link Iterable}
066 * will stop as soon as a matching item is found.
067 * <p/>
068 * For example:
069 * <pre>assertThat(Arrays.asList("foo", "bar"), hasItem("bar"))</pre>
070 *
071 * @param item
072 * the item to compare against the items provided by the examined {@link Iterable}
073 */
074 @Factory
075 public static <T> Matcher<Iterable<? super T>> hasItem(T item) {
076 // Doesn't forward to hasItem() method so compiler can sort out generics.
077 return new IsCollectionContaining<T>(equalTo(item));
078 }
079
080 /**
081 * Creates a matcher for {@link Iterable}s that matches when consecutive passes over the
082 * examined {@link Iterable} yield at least one item that is matched by the corresponding
083 * matcher from the specified <code>itemMatchers</code>. Whilst matching, each traversal of
084 * the examined {@link Iterable} will stop as soon as a matching item is found.
085 * <p/>
086 * For example:
087 * <pre>assertThat(Arrays.asList("foo", "bar", "baz"), hasItems(endsWith("z"), endsWith("o")))</pre>
088 *
089 * @param itemMatchers
090 * the matchers to apply to items provided by the examined {@link Iterable}
091 */
092 @Factory
093 public static <T> Matcher<Iterable<T>> hasItems(Matcher<? super T>... itemMatchers) {
094 List<Matcher<? super Iterable<T>>> all = new ArrayList<Matcher<? super Iterable<T>>>(itemMatchers.length);
095
096 for (Matcher<? super T> elementMatcher : itemMatchers) {
097 // Doesn't forward to hasItem() method so compiler can sort out generics.
098 all.add(new IsCollectionContaining<T>(elementMatcher));
099 }
100
101 return allOf(all);
102 }
103
104 /**
105 * Creates a matcher for {@link Iterable}s that matches when consecutive passes over the
106 * examined {@link Iterable} yield at least one item that is equal to the corresponding
107 * item from the specified <code>items</code>. Whilst matching, each traversal of the
108 * examined {@link Iterable} will stop as soon as a matching item is found.
109 * <p/>
110 * For example:
111 * <pre>assertThat(Arrays.asList("foo", "bar", "baz"), hasItems("baz", "foo"))</pre>
112 *
113 * @param items
114 * the items to compare against the items provided by the examined {@link Iterable}
115 */
116 @Factory
117 public static <T> Matcher<Iterable<T>> hasItems(T... items) {
118 List<Matcher<? super Iterable<T>>> all = new ArrayList<Matcher<? super Iterable<T>>>(items.length);
119 for (T element : items) {
120 all.add(hasItem(element));
121 }
122
123 return allOf(all);
124 }
125
126 }