• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.hamcrest.collection;
2 
3 import org.hamcrest.Description;
4 import org.hamcrest.Matcher;
5 import org.hamcrest.TypeSafeDiagnosingMatcher;
6 
7 import java.util.ArrayList;
8 import java.util.List;
9 
10 import static java.util.Arrays.asList;
11 import static org.hamcrest.core.IsEqual.equalTo;
12 
13 public class IsIterableContainingInRelativeOrder<E> extends TypeSafeDiagnosingMatcher<Iterable<? extends E>> {
14     private final List<Matcher<? super E>> matchers;
15 
IsIterableContainingInRelativeOrder(List<Matcher<? super E>> matchers)16     public IsIterableContainingInRelativeOrder(List<Matcher<? super E>> matchers) {
17         this.matchers = matchers;
18     }
19 
20     @Override
matchesSafely(Iterable<? extends E> iterable, Description mismatchDescription)21     protected boolean matchesSafely(Iterable<? extends E> iterable, Description mismatchDescription) {
22         MatchSeriesInRelativeOrder<E> matchSeriesInRelativeOrder = new MatchSeriesInRelativeOrder<E>(matchers, mismatchDescription);
23         matchSeriesInRelativeOrder.processItems(iterable);
24         return matchSeriesInRelativeOrder.isFinished();
25     }
26 
describeTo(Description description)27     public void describeTo(Description description) {
28         description.appendText("iterable containing ").appendList("[", ", ", "]", matchers).appendText(" in relative order");
29     }
30 
31     private static class MatchSeriesInRelativeOrder<F> {
32         public final List<Matcher<? super F>> matchers;
33         private final Description mismatchDescription;
34         private int nextMatchIx = 0;
35         private F lastMatchedItem = null;
36 
MatchSeriesInRelativeOrder(List<Matcher<? super F>> matchers, Description mismatchDescription)37         public MatchSeriesInRelativeOrder(List<Matcher<? super F>> matchers, Description mismatchDescription) {
38             this.mismatchDescription = mismatchDescription;
39             if (matchers.isEmpty()) {
40                 throw new IllegalArgumentException("Should specify at least one expected element");
41             }
42             this.matchers = matchers;
43         }
44 
processItems(Iterable<? extends F> iterable)45         public void processItems(Iterable<? extends F> iterable) {
46             for (F item : iterable) {
47                 if (nextMatchIx < matchers.size()) {
48                     Matcher<? super F> matcher = matchers.get(nextMatchIx);
49                     if (matcher.matches(item)) {
50                         lastMatchedItem = item;
51                         nextMatchIx++;
52                     }
53                 }
54             }
55         }
56 
isFinished()57         public boolean isFinished() {
58             if (nextMatchIx < matchers.size()) {
59                 mismatchDescription.appendDescriptionOf(matchers.get(nextMatchIx)).appendText(" was not found");
60                 if (lastMatchedItem != null) {
61                     mismatchDescription.appendText(" after ").appendValue(lastMatchedItem);
62                 }
63                 return false;
64             }
65             return true;
66         }
67 
68     }
69 
70     /**
71      * Creates a matcher for {@link Iterable}s that matches when a single pass over the
72      * examined {@link Iterable} yields a series of items, that contains items logically equal to the
73      * corresponding item in the specified items, in the same relative order
74      * For example:
75      * <pre>assertThat(Arrays.asList("a", "b", "c", "d", "e"), containsInRelativeOrder("b", "d"))</pre>
76      *
77      * @param items
78      *     the items that must be contained within items provided by an examined {@link Iterable} in the same relative order
79      */
containsInRelativeOrder(E... items)80     public static <E> Matcher<Iterable<? extends E>> containsInRelativeOrder(E... items) {
81         List<Matcher<? super E>> matchers = new ArrayList<Matcher<? super E>>();
82         for (E item : items) {
83             matchers.add(equalTo(item));
84         }
85 
86         return containsInRelativeOrder(matchers);
87     }
88 
89     /**
90      * Creates a matcher for {@link Iterable}s that matches when a single pass over the
91      * examined {@link Iterable} yields a series of items, that each satisfying the corresponding
92      * matcher in the specified matchers, in the same relative order.
93      * For example:
94      * <pre>assertThat(Arrays.asList("a", "b", "c", "d", "e"), containsInRelativeOrder(equalTo("b"), equalTo("d")))</pre>
95      *
96      * @param itemMatchers
97      *     the matchers that must be satisfied by the items provided by an examined {@link Iterable} in the same relative order
98      */
containsInRelativeOrder(Matcher<? super E>.... itemMatchers)99     public static <E> Matcher<Iterable<? extends E>> containsInRelativeOrder(Matcher<? super E>... itemMatchers) {
100         return containsInRelativeOrder((List) asList(itemMatchers));
101     }
102 
103     /**
104      * Creates a matcher for {@link Iterable}s that matches when a single pass over the
105      * examined {@link Iterable} yields a series of items, that contains items satisfying the corresponding
106      * matcher in the specified list of matchers, in the same relative order.
107      * For example:
108      * <pre>assertThat(Arrays.asList("a", "b", "c", "d", "e"), contains(Arrays.asList(equalTo("b"), equalTo("d"))))</pre>
109      *
110      * @param itemMatchers
111      *     a list of matchers, each of which must be satisfied by the items provided by
112      *     an examined {@link Iterable} in the same relative order
113      */
containsInRelativeOrder(List<Matcher<? super E>> itemMatchers)114     public static <E> Matcher<Iterable<? extends E>> containsInRelativeOrder(List<Matcher<? super E>> itemMatchers) {
115         return new IsIterableContainingInRelativeOrder<E>(itemMatchers);
116     }
117 }
118