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 }