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    }