View Javadoc
1   package dev.aherscu.qa.testing.utils;
2   
3   import java.util.Iterator;
4   import java.util.LinkedList;
5   import java.util.List;
6   import java.util.Objects;
7   import java.util.PrimitiveIterator;
8   import java.util.stream.BaseStream;
9   import java.util.stream.DoubleStream;
10  import java.util.stream.IntStream;
11  import java.util.stream.LongStream;
12  import java.util.stream.Stream;
13  
14  import org.hamcrest.Description;
15  import org.hamcrest.Matcher;
16  import org.hamcrest.TypeSafeMatcher;
17  
18  public class StreamMatchers {
19  
20      /**
21       * Matcher for a stream which yields no elements.
22       *
23       * @param <T>
24       *            The type of items
25       * @param <S>
26       *            The type of the BaseStream
27       */
28      public static <T, S extends BaseStream<T, ? extends S>> Matcher<S> yieldsNothing() {
29          return new TypeSafeMatcher<S>() {
30  
31              private Iterator<T> actualIterator;
32  
33              @Override
34              protected boolean matchesSafely(S actual) {
35                  actualIterator = actual.iterator();
36                  return !actualIterator.hasNext();
37              }
38  
39              @Override
40              public void describeTo(Description description) {
41                  description.appendText("A Stream yielding no elements");
42              }
43  
44              @Override
45              protected void describeMismatchSafely(S item,
46                  Description description) {
47                  description.appendText("the Stream started with ")
48                      .appendValue(actualIterator.next());
49                  if (actualIterator.hasNext()) {
50                      description
51                          .appendText(" and will yield even more elements");
52                  } else {
53                      description.appendText(" and is then exhausted");
54                  }
55              }
56          };
57      }
58  
59      /**
60       * Matcher for an empty stream.
61       *
62       * @param <T>
63       *            The type of items
64       * @param <S>
65       *            The type of the BaseStream
66       *
67       * @deprecated name clashes with {@link org.hamcrest.Matchers#empty()}, use
68       *             {@link #yieldsNothing()} instead
69       */
70      @Deprecated
71      public static <T, S extends BaseStream<T, ? extends S>> Matcher<S> empty() {
72          return yieldsNothing();
73      }
74  
75      /**
76       * A matcher for a finite Stream producing the same number of items as the
77       * expected Stream, and producing equal items as expected in the same order.
78       *
79       * For infinite Streams use {@link #startsWith}
80       *
81       * @param expected
82       *            A BaseStream against which to compare
83       * @param <T>
84       *            The type of items produced by each BaseStream
85       * @param <S>
86       *            The type of BaseStream
87       * @see #startsWith
88       * @see #startsWithInt
89       * @see #startsWithLong
90       * @see #startsWithDouble
91       */
92      public static <T, S extends BaseStream<T, ? extends S>> Matcher<S> yieldsSameAs(
93          S expected) {
94          return new BaseStreamMatcher<T, S>() {
95              @Override
96              protected boolean matchesSafely(S actual) {
97                  return remainingItemsEqual(expected.iterator(),
98                      actual.iterator());
99              }
100         };
101     }
102 
103     /**
104      * A matcher for a finite Stream producing the same number of items as the
105      * expected Stream, and producing equal items as expected in the same order.
106      *
107      * @param expected
108      *            A BaseStream against which to compare
109      * @param <T>
110      *            The type of items produced by each BaseStream
111      * @param <S>
112      *            The type of BaseStream
113      *
114      * @deprecated name clashes with
115      *             {@link org.hamcrest.Matchers#equalTo(Object)}, use
116      *             {@link #yieldsSameAs(BaseStream)} instead
117      */
118     @Deprecated
119     public static <T, S extends BaseStream<T, ? extends S>> Matcher<S> equalTo(
120         S expected) {
121         return yieldsSameAs(expected);
122     }
123 
124     /**
125      * A matcher for potentially infinite Streams of objects where the first
126      * limit items from each must be equal
127      *
128      * @param expected
129      *            A Stream to check against
130      * @param limit
131      *            Only check this number of items from actual Stream
132      * @param <T>
133      *            The type of items produced by each Stream
134      * @see #equalTo
135      * @see #startsWithInt
136      * @see #startsWithLong
137      * @see #startsWithDouble
138      */
139     public static <T> Matcher<Stream<T>> startsWith(Stream<T> expected,
140         long limit) {
141         return new BaseStreamMatcher<T, Stream<T>>() {
142             @Override
143             protected boolean matchesSafely(Stream<T> actual) {
144                 return remainingItemsEqual(expected.limit(limit).iterator(),
145                     actual.limit(limit).iterator());
146             }
147         };
148     }
149 
150     /**
151      * A matcher for potentially infinite Streams of primitive doubles where the
152      * first limit items from each must be equal
153      *
154      * @param expected
155      *            A Stream to check against
156      * @param limit
157      *            Only check this number of items from actual Stream
158      * @see #equalTo
159      * @see #startsWith
160      * @see #startsWithInt
161      * @see #startsWithLong
162      */
163     public static Matcher<DoubleStream> startsWith(DoubleStream expected,
164         long limit) {
165         return new BaseStreamMatcher<Double, DoubleStream>() {
166             @Override
167             protected boolean matchesSafely(DoubleStream actual) {
168                 return remainingItemsEqual(expected.limit(limit).iterator(),
169                     actual.limit(limit).iterator());
170             }
171         };
172     }
173 
174     /**
175      * A matcher for potentially infinite Streams of primitive ints where the
176      * first limit items from each must be equal
177      *
178      * @param expected
179      *            A Stream to check against
180      * @param limit
181      *            Only check this number of items from actual Stream
182      * @see #equalTo
183      * @see #startsWith
184      * @see #startsWithLong
185      * @see #startsWithDouble
186      */
187     public static Matcher<IntStream> startsWith(IntStream expected,
188         long limit) {
189         return new BaseStreamMatcher<Integer, IntStream>() {
190             @Override
191             protected boolean matchesSafely(IntStream actual) {
192                 return remainingItemsEqual(expected.limit(limit).iterator(),
193                     actual.limit(limit).iterator());
194             }
195         };
196     }
197 
198     /**
199      * A matcher for potentially infinite Streams of primitive ints where the
200      * first limit items from each must be equal
201      *
202      * @param expected
203      *            A Stream to check against
204      * @param limit
205      *            Only check this number of items from actual Stream
206      * @see #equalTo
207      * @see #startsWith
208      * @see #startsWithInt
209      * @see #startsWithDouble
210      */
211     public static Matcher<LongStream> startsWith(LongStream expected,
212         long limit) {
213         return new BaseStreamMatcher<Long, LongStream>() {
214             @Override
215             protected boolean matchesSafely(LongStream actual) {
216                 return remainingItemsEqual(expected.limit(limit).iterator(),
217                     actual.limit(limit).iterator());
218             }
219         };
220     }
221 
222     private static void describeToStartsAllWith(Description description,
223         long limit, Matcher<?> matcher) {
224         description
225             .appendText("First ")
226             .appendText(Long.toString(limit))
227             .appendText(" to match ")
228             .appendValue(matcher);
229     }
230 
231     /**
232      * A matcher for potentially infinite Streams of objects, the first limit of
233      * which must match the given Matcher
234      *
235      * @param matcher
236      *            A matcher to apply to items produced from the Stream
237      * @param limit
238      *            Only check this number of items from the Stream
239      * @see #allMatch
240      * @see #startsWithAllLong
241      * @see #startsWithAllInt
242      * @see #startsWithAllDouble
243      */
244     public static <T> Matcher<Stream<T>> startsWithAll(Matcher<T> matcher,
245         long limit) {
246         return new StreamAllMatches<T>(matcher) {
247             @Override
248             protected boolean matchesSafely(Stream<T> actual) {
249                 return super.matchesSafely(actual.limit(limit));
250             }
251 
252             @Override
253             public void describeTo(Description description) {
254                 describeToStartsAllWith(description, limit, matcher);
255             }
256         };
257 
258     }
259 
260     /**
261      * A matcher for potentially infinite Streams of primitive longs, the first
262      * limit of which must match the given Matcher
263      *
264      * @param matcher
265      *            A matcher to apply to items produced from the Stream
266      * @param limit
267      *            Only check this number of items from the Stream
268      * @see #allMatchLong
269      * @see #startsWithAll
270      * @see #startsWithAllInt
271      * @see #startsWithAllDouble
272      */
273     public static Matcher<LongStream> startsWithAllLong(Matcher<Long> matcher,
274         long limit) {
275         return new LongStreamAllMatches(matcher) {
276             @Override
277             protected boolean matchesSafely(LongStream actual) {
278                 return super.matchesSafely(actual.limit(limit));
279             }
280 
281             @Override
282             public void describeTo(Description description) {
283                 describeToStartsAllWith(description, limit, matcher);
284             }
285         };
286     }
287 
288     /**
289      * A matcher for potentially infinite Streams of primitive ints, the first
290      * limit of which must match the given Matcher
291      *
292      * @param matcher
293      *            A matcher to apply to items produced from the Stream
294      * @param limit
295      *            Only check this number of items from the Stream
296      * @see #allMatchInt
297      * @see #startsWithAll
298      * @see #startsWithAllLong
299      * @see #startsWithAllDouble
300      */
301     public static Matcher<IntStream> startsWithAllInt(Matcher<Integer> matcher,
302         long limit) {
303         return new IntStreamAllMatches(matcher) {
304             @Override
305             protected boolean matchesSafely(IntStream actual) {
306                 return super.matchesSafely(actual.limit(limit));
307             }
308 
309             @Override
310             public void describeTo(Description description) {
311                 describeToStartsAllWith(description, limit, matcher);
312             }
313         };
314     }
315 
316     /**
317      * A matcher for potentially infinite Streams of primitive doubles, the
318      * first limit of which must match the given Matcher
319      *
320      * @param matcher
321      *            A matcher to apply to items produced from the Stream
322      * @param limit
323      *            Only check this number of items from the Stream
324      * @see #allMatchDouble
325      * @see #startsWithAll
326      * @see #startsWithAllInt
327      * @see #startsWithAllLong
328      */
329     public static Matcher<DoubleStream> startsWithAllDouble(
330         Matcher<Double> matcher, long limit) {
331         return new DoubleStreamAllMatches(matcher) {
332             @Override
333             protected boolean matchesSafely(DoubleStream actual) {
334                 return super.matchesSafely(actual.limit(limit));
335             }
336 
337             @Override
338             public void describeTo(Description description) {
339                 describeToStartsAllWith(description, limit, matcher);
340             }
341         };
342     }
343 
344     private static void describeToStartsAnyWith(Description description,
345         long limit, Matcher<?> matcher) {
346         description
347             .appendText("Any of first ")
348             .appendText(Long.toString(limit))
349             .appendText(" to match ")
350             .appendValue(matcher);
351     }
352 
353     /**
354      * A matcher for potentially infinite Streams of objects, at least one of
355      * the first limit of which must match the given Matcher
356      *
357      * @param matcher
358      *            A matcher to apply to items produced from the Stream
359      * @param limit
360      *            Only check this number of items from the Stream
361      * @see #anyMatch
362      * @see #startsWithAnyInt
363      * @see #startsWithAnyLong
364      * @see #startsWithAnyDouble
365      */
366     public static <T> Matcher<Stream<T>> startsWithAny(Matcher<T> matcher,
367         long limit) {
368         return new StreamAnyMatches<T>(matcher) {
369             @Override
370             protected boolean matchesSafely(Stream<T> actual) {
371                 return super.matchesSafely(actual.limit(limit));
372             }
373 
374             @Override
375             public void describeTo(Description description) {
376                 describeToStartsAnyWith(description, limit, matcher);
377             }
378         };
379     }
380 
381     /**
382      * A matcher for potentially infinite Streams of primitive longs, at least
383      * one of the first limit of which must match the given Matcher
384      *
385      * @param matcher
386      *            A matcher to apply to items produced from the Stream
387      * @param limit
388      *            Only check this number of items from the Stream
389      * @see #anyMatchLong
390      * @see #startsWithAny
391      * @see #startsWithAnyInt
392      * @see #startsWithAnyDouble
393      */
394     public static Matcher<LongStream> startsWithAnyLong(Matcher<Long> matcher,
395         long limit) {
396         return new LongStreamAnyMatches(matcher) {
397             @Override
398             protected boolean matchesSafely(LongStream actual) {
399                 return super.matchesSafely(actual.limit(limit));
400             }
401 
402             @Override
403             public void describeTo(Description description) {
404                 describeToStartsAnyWith(description, limit, matcher);
405             }
406         };
407     }
408 
409     /**
410      * A matcher for potentially infinite Streams of primitive doubles, at least
411      * one of the first limit of which must match the given Matcher
412      *
413      * @param matcher
414      *            A matcher to apply to items produced from the Stream
415      * @param limit
416      *            Only check this number of items from the Stream
417      * @see #anyMatchDouble
418      * @see #startsWithAny
419      * @see #startsWithAnyInt
420      * @see #startsWithAnyLong
421      */
422     public static Matcher<DoubleStream> startsWithAnyDouble(
423         Matcher<Double> matcher, long limit) {
424         return new DoubleStreamAnyMatches(matcher) {
425             @Override
426             protected boolean matchesSafely(DoubleStream actual) {
427                 return super.matchesSafely(actual.limit(limit));
428             }
429 
430             @Override
431             public void describeTo(Description description) {
432                 describeToStartsAnyWith(description, limit, matcher);
433             }
434         };
435     }
436 
437     /**
438      * A matcher for potentially infinite Streams of primitive ints, at least
439      * one of the first limit of which must match the given Matcher
440      *
441      * @param matcher
442      *            A matcher to apply to items produced from the Stream
443      * @param limit
444      *            Only check this number of items from the Stream
445      * @see #anyMatchInt
446      * @see #startsWithAny
447      * @see #startsWithAnyLong
448      * @see #startsWithAnyDouble
449      */
450     public static Matcher<IntStream> startsWithAnyInt(Matcher<Integer> matcher,
451         long limit) {
452         return new IntStreamAnyMatches(matcher) {
453             @Override
454             protected boolean matchesSafely(IntStream actual) {
455                 return super.matchesSafely(actual.limit(limit));
456             }
457 
458             @Override
459             public void describeTo(Description description) {
460                 describeToStartsAnyWith(description, limit, matcher);
461             }
462         };
463     }
464 
465     /**
466      * The BaseStream must produce exactly the given expected items in order,
467      * and no more.
468      *
469      * For infinite BaseStreams see {@link #startsWith(Object...)} or a
470      * primitive stream variant
471      *
472      * @param expectedMatchers
473      *            Matchers for the items that should be produced by the
474      *            BaseStream
475      * @param <T>
476      *            The type of items
477      * @param <S>
478      *            The type of the BaseStream
479      * @see #startsWith(Object...)
480      * @see #startsWithInt(int...)
481      * @see #startsWithLong(long...)
482      * @see #startsWithDouble(double...)
483      */
484     @SafeVarargs
485     public static <T, S extends BaseStream<T, ? extends S>> Matcher<S> yieldsExactly(
486         Matcher<T>... expectedMatchers) {
487         return new BaseMatcherStreamMatcher<T, S>() {
488             @Override
489             protected boolean matchesSafely(S actual) {
490                 return remainingItemsMatch(
491                     new ArrayIterator<>(expectedMatchers), actual.iterator());
492             }
493         };
494     }
495 
496     /**
497      * The BaseStream must produce exactly the given expected items in order,
498      * and no more.
499      *
500      * @param expectedMatchers
501      *            Matchers for the items that should be produced by the
502      *            BaseStream
503      * @param <T>
504      *            The type of items
505      * @param <S>
506      *            The type of the BaseStream
507      *
508      * @deprecated name clashes with
509      *             {@link org.hamcrest.Matchers#contains(Matcher...)}, use
510      *             {@link #yieldsExactly(Matcher...)} instead
511      */
512     @SafeVarargs
513     @Deprecated
514     public static <T, S extends BaseStream<T, ? extends S>> Matcher<S> contains(
515         Matcher<T>... expectedMatchers) {
516         return yieldsExactly(expectedMatchers);
517     }
518 
519     /**
520      * The BaseStream must produce exactly the given expected items in order,
521      * and no more.
522      *
523      * For infinite BaseStreams see {@link #startsWith(Object...)} or a
524      * primitive stream variant
525      *
526      * @param expected
527      *            The items that should be produced by the BaseStream
528      * @param <T>
529      *            The type of items
530      * @param <S>
531      *            The type of the BaseStream
532      * @see #startsWith(Object...)
533      * @see #startsWithInt(int...)
534      * @see #startsWithLong(long...)
535      * @see #startsWithDouble(double...)
536      */
537     @SafeVarargs
538     public static <T, S extends BaseStream<T, ? extends S>> Matcher<S> yieldsExactly(
539         T... expected) {
540         return new BaseStreamMatcher<T, S>() {
541             @Override
542             protected boolean matchesSafely(S actual) {
543                 return remainingItemsEqual(new ArrayIterator<>(expected),
544                     actual.iterator());
545             }
546         };
547     }
548 
549     /**
550      * The BaseStream must produce exactly the given expected items in order,
551      * and no more.
552      *
553      * @param expected
554      *            The items that should be produced by the BaseStream
555      * @param <T>
556      *            The type of items
557      * @param <S>
558      *            The type of the BaseStream
559      *
560      * @deprecated name clashes with
561      *             {@link org.hamcrest.Matchers#contains(Object...)}, use
562      *             {@link #yieldsExactly(Object...)} instead
563      */
564     @SafeVarargs
565     @Deprecated
566     public static <T, S extends BaseStream<T, ? extends S>> Matcher<S> contains(
567         T... expected) {
568         return yieldsExactly(expected);
569     }
570 
571     /**
572      * A matcher for a finite Stream of objects, all of which must match the
573      * given Matcher.
574      *
575      * For infinite Streams see {@link #startsWithAll}
576      *
577      * @param matcher
578      *            A Matcher against which to compare items from the Stream
579      * @param <T>
580      *            The type of items produced by the Stream
581      * @see #startsWithAll
582      * @see #allMatchInt
583      * @see #allMatchLong
584      * @see #allMatchDouble
585      */
586     public static <T> Matcher<Stream<T>> allMatch(Matcher<T> matcher) {
587         return new StreamAllMatches<T>(matcher) {
588             @Override
589             public void describeTo(Description description) {
590                 description.appendText("All to match ").appendValue(matcher);
591             }
592         };
593     }
594 
595     /**
596      * A matcher for a finite Stream of primitive ints, all of which must match
597      * the given Matcher.
598      *
599      * For infinite Streams see {@link #startsWithAllInt}
600      *
601      * @param matcher
602      *            A Matcher against which to compare items from the Stream
603      * @see #startsWithAllInt
604      * @see #allMatch
605      * @see #allMatchLong
606      * @see #allMatchDouble
607      */
608     public static Matcher<IntStream> allMatchInt(Matcher<Integer> matcher) {
609         return new IntStreamAllMatches(matcher) {
610             @Override
611             public void describeTo(Description description) {
612                 description.appendText("All to match ").appendValue(matcher);
613             }
614         };
615     }
616 
617     /**
618      * A matcher for a finite Stream of primitive longs, all of which must match
619      * the given Matcher.
620      *
621      * For infinite Streams see {@link #startsWithAllLong}
622      *
623      * @param matcher
624      *            A Matcher against which to compare items from the Stream
625      * @see #startsWithAllLong
626      * @see #allMatch
627      * @see #allMatchInt
628      * @see #allMatchDouble
629      */
630     public static Matcher<LongStream> allMatchLong(Matcher<Long> matcher) {
631         return new LongStreamAllMatches(matcher) {
632             @Override
633             public void describeTo(Description description) {
634                 description.appendText("All to match ").appendValue(matcher);
635             }
636         };
637     }
638 
639     /**
640      * A matcher for a finite Stream of primitive doubles, all of which must
641      * match the given Matcher.
642      *
643      * For infinite Streams see {@link #startsWithAllDouble}
644      *
645      * @param matcher
646      *            A Matcher against which to compare items from the Stream
647      * @see #startsWithAllDouble
648      * @see #allMatch
649      * @see #allMatchInt
650      * @see #allMatchLong
651      */
652     public static Matcher<DoubleStream> allMatchDouble(
653         Matcher<Double> matcher) {
654         return new DoubleStreamAllMatches(matcher) {
655             @Override
656             public void describeTo(Description description) {
657                 description.appendText("All to match ").appendValue(matcher);
658             }
659         };
660     }
661 
662     /**
663      * A matcher for a finite Stream of objects, at least one of which must
664      * match the given Matcher.
665      *
666      * For infinite Streams see {@link #startsWithAny}
667      *
668      * @param matcher
669      *            A Matcher against which to compare items from the Stream
670      * @param <T>
671      *            The type of items produced by the Stream
672      * @see #startsWithAny
673      * @see #anyMatchInt
674      * @see #anyMatchLong
675      * @see #anyMatchDouble
676      */
677     public static <T> Matcher<Stream<T>> anyMatch(Matcher<T> matcher) {
678         return new StreamAnyMatches<T>(matcher) {
679             @Override
680             public void describeTo(Description description) {
681                 description.appendText("Any to match ").appendValue(matcher);
682             }
683         };
684     }
685 
686     /**
687      * A matcher for a finite Stream of primitive longs, at least one of which
688      * must match the given Matcher.
689      *
690      * For infinite Streams see {@link #startsWithAnyLong}
691      *
692      * @param matcher
693      *            A Matcher against which to compare items from the Stream
694      * @see #startsWithAnyLong
695      * @see #anyMatch
696      * @see #anyMatchInt
697      * @see #anyMatchDouble
698      */
699     public static Matcher<LongStream> anyMatchLong(Matcher<Long> matcher) {
700         return new LongStreamAnyMatches(matcher) {
701             @Override
702             public void describeTo(Description description) {
703                 description.appendText("Any to match ").appendValue(matcher);
704             }
705         };
706     }
707 
708     /**
709      * A matcher for a finite Stream of primitive doubles, at least one of which
710      * must match the given Matcher.
711      *
712      * For infinite Streams see {@link #startsWithAnyDouble}
713      *
714      * @param matcher
715      *            A Matcher against which to compare items from the Stream
716      * @see #startsWithAnyDouble
717      * @see #anyMatch
718      * @see #anyMatchInt
719      * @see #anyMatchDouble
720      */
721     public static Matcher<DoubleStream> anyMatchDouble(
722         Matcher<Double> matcher) {
723         return new DoubleStreamAnyMatches(matcher) {
724             @Override
725             public void describeTo(Description description) {
726                 description.appendText("Any to match ").appendValue(matcher);
727             }
728         };
729     }
730 
731     /**
732      * A matcher for a finite Stream of primitive ints, at least one of which
733      * must match the given Matcher.
734      *
735      * For infinite Streams see {@link #startsWithAnyInt}
736      *
737      * @param matcher
738      *            A Matcher against which to compare items from the Stream
739      * @see #startsWithAnyInt
740      * @see #anyMatch
741      * @see #anyMatchLong
742      * @see #anyMatchDouble
743      */
744 
745     public static Matcher<IntStream> anyMatchInt(Matcher<Integer> matcher) {
746         return new IntStreamAnyMatches(matcher) {
747             @Override
748             public void describeTo(Description description) {
749                 description.appendText("Any to match ").appendValue(matcher);
750             }
751         };
752     }
753 
754     /**
755      * A matcher for a potentially infinite Stream of objects against n expected
756      * items, matching if the first n items produced by the Stream equal the
757      * expected items in order. Whether the Stream would subsequently produce
758      * additional items is irrelevant.
759      *
760      * @param expected
761      *            The expected items produced first by the Stream
762      * @param <T>
763      *            The type of items
764      * @see #contains
765      * @see #startsWithInt
766      * @see #startsWithDouble
767      * @see #startsWithLong
768      */
769 
770     @SafeVarargs
771     public static <T> Matcher<Stream<T>> startsWith(T... expected) {
772         return new BaseStreamMatcher<T, Stream<T>>() {
773             @Override
774             protected boolean matchesSafely(Stream<T> actual) {
775                 return remainingItemsEqual(new ArrayIterator<>(expected),
776                     actual.limit(expected.length).iterator());
777             }
778         };
779     }
780 
781     /**
782      * A matcher for a potentially infinite Stream of primitive doubles against
783      * n expected items, matching if the first n items produced by the Stream
784      * equal the expected items in order. Whether the Stream would subsequently
785      * produce additional items is irrelevant.
786      *
787      * @param expected
788      *            The expected items produced first by the Stream
789      * @see #contains
790      * @see #startsWith
791      * @see #startsWithInt
792      * @see #startsWithLong
793      */
794     public static Matcher<DoubleStream> startsWithDouble(double... expected) {
795         return new BaseStreamMatcher<Double, DoubleStream>() {
796             @Override
797             protected boolean matchesSafely(DoubleStream actual) {
798                 return remainingItemsEqual(new DoubleArrayIterator(expected),
799                     actual.limit(expected.length).iterator());
800             }
801         };
802     }
803 
804     /**
805      * A matcher for a potentially infinite Stream of primitive longs against n
806      * expected items, matching if the first n items produced by the Stream
807      * equal the expected items in order. Whether the Stream would subsequently
808      * produce additional items is irrelevant.
809      *
810      * @param expected
811      *            The expected items produced first by the Stream
812      * @see #contains
813      * @see #startsWith
814      * @see #startsWithInt
815      * @see #startsWithDouble
816      */
817     public static Matcher<LongStream> startsWithLong(long... expected) {
818         return new BaseStreamMatcher<Long, LongStream>() {
819             @Override
820             protected boolean matchesSafely(LongStream actual) {
821                 return remainingItemsEqual(new LongArrayIterator(expected),
822                     actual.limit(expected.length).iterator());
823             }
824         };
825     }
826 
827     /**
828      * A matcher for a potentially infinite Stream of primitive ints against n
829      * expected items, matching if the first n items produced by the Stream
830      * equal the expected items in order. Whether the Stream would subsequently
831      * produce additional items is irrelevant.
832      *
833      * @param expected
834      *            The expected items produced first by the Stream
835      * @see #contains
836      * @see #startsWith
837      * @see #startsWithLong
838      * @see #startsWithDouble
839      */
840     public static Matcher<IntStream> startsWithInt(int... expected) {
841         return new BaseStreamMatcher<Integer, IntStream>() {
842             @Override
843             protected boolean matchesSafely(IntStream actual) {
844                 return remainingItemsEqual(new IntArrayIterator(expected),
845                     actual.limit(expected.length).iterator());
846             }
847         };
848     }
849 
850     private static abstract class BaseStreamMatcher<T, S extends BaseStream<T, ?>>
851         extends TypeSafeMatcher<S> {
852         final List<T> expectedAccumulator = new LinkedList<>();
853         final List<T> actualAccumulator   = new LinkedList<>();
854 
855         @Override
856         public void describeTo(Description description) {
857             describe(description, expectedAccumulator);
858         }
859 
860         @Override
861         protected void describeMismatchSafely(S item, Description description) {
862             describe(description, actualAccumulator);
863         }
864 
865         private void describe(Description description, List<T> values) {
866             description.appendText("Stream of ").appendValueList("[", ",", "]",
867                 values);
868         }
869 
870         boolean remainingItemsEqual(Iterator<T> expectedIterator,
871             Iterator<T> actualIterator) {
872             if (!expectedIterator.hasNext() && !actualIterator.hasNext()) {
873                 return true;
874             }
875             if (expectedIterator.hasNext() && actualIterator.hasNext()) {
876                 T nextExpected = expectedIterator.next();
877                 expectedAccumulator.add(nextExpected);
878                 T nextActual = actualIterator.next();
879                 actualAccumulator.add(nextActual);
880                 if (Objects.equals(nextExpected, nextActual)) {
881                     return remainingItemsEqual(expectedIterator,
882                         actualIterator);
883                 }
884             }
885             expectedIterator.forEachRemaining(expectedAccumulator::add);
886             actualIterator.forEachRemaining(actualAccumulator::add);
887             return false;
888         }
889     }
890 
891     private static abstract class BaseMatcherStreamMatcher<T, S extends BaseStream<T, ?>>
892         extends TypeSafeMatcher<S> {
893         final List<Matcher<T>> expectedAccumulator = new LinkedList<>();
894         final List<T>          actualAccumulator   = new LinkedList<>();
895 
896         @Override
897         protected void describeMismatchSafely(S item, Description description) {
898             description.appendText("Stream of ").appendValueList("[", ",", "]",
899                 actualAccumulator);
900         }
901 
902         @Override
903         public void describeTo(Description description) {
904             description.appendText("Stream of ").appendValueList("[", ",", "]",
905                 expectedAccumulator);
906         }
907 
908         boolean remainingItemsMatch(Iterator<Matcher<T>> expectedIterator,
909             Iterator<T> actualIterator) {
910             if (!expectedIterator.hasNext() && !actualIterator.hasNext()) {
911                 return true;
912             }
913             if (expectedIterator.hasNext() && actualIterator.hasNext()) {
914                 Matcher<T> nextExpected = expectedIterator.next();
915                 expectedAccumulator.add(nextExpected);
916                 T nextActual = actualIterator.next();
917                 actualAccumulator.add(nextActual);
918                 if (nextExpected.matches(nextActual)) {
919                     return remainingItemsMatch(expectedIterator,
920                         actualIterator);
921                 }
922             }
923             expectedIterator.forEachRemaining(expectedAccumulator::add);
924             actualIterator.forEachRemaining(actualAccumulator::add);
925             return false;
926         }
927     }
928 
929     private static void allMatchMismatch(Description mismatchDescription,
930         long position, Object nonMatch) {
931         mismatchDescription.appendText("Item ")
932             .appendText(Long.toString(position))
933             .appendText(" failed to match: ").appendValue(nonMatch);
934     }
935 
936     private static abstract class StreamAllMatches<T>
937         extends TypeSafeMatcher<Stream<T>> {
938         private T                nonMatching;
939         private long             positionNonMatching = -1L;
940         private final Matcher<T> matcher;
941 
942         StreamAllMatches(Matcher<T> matcher) {
943             this.matcher = matcher;
944         }
945 
946         @Override
947         protected boolean matchesSafely(Stream<T> actual) {
948             return actual
949                 .peek(i -> {
950                     nonMatching = i;
951                     positionNonMatching++;
952                 })
953                 .allMatch(matcher::matches);
954         }
955 
956         @Override
957         protected void describeMismatchSafely(Stream<T> actual,
958             Description mismatchDescription) {
959             allMatchMismatch(mismatchDescription, positionNonMatching,
960                 nonMatching);
961         }
962     }
963 
964     private static abstract class IntStreamAllMatches
965         extends TypeSafeMatcher<IntStream> {
966         private int                    nonMatching;
967         private long                   positionNonMatching = -1L;
968         private final Matcher<Integer> matcher;
969 
970         IntStreamAllMatches(Matcher<Integer> matcher) {
971             this.matcher = matcher;
972         }
973 
974         @Override
975         protected boolean matchesSafely(IntStream actual) {
976             return actual
977                 .peek(i -> {
978                     nonMatching = i;
979                     positionNonMatching++;
980                 })
981                 .allMatch(matcher::matches);
982         }
983 
984         @Override
985         protected void describeMismatchSafely(IntStream actual,
986             Description mismatchDescription) {
987             allMatchMismatch(mismatchDescription, positionNonMatching,
988                 nonMatching);
989         }
990     }
991 
992     private static abstract class LongStreamAllMatches
993         extends TypeSafeMatcher<LongStream> {
994         private long                nonMatching;
995         private long                positionNonMatching = -1L;
996         private final Matcher<Long> matcher;
997 
998         LongStreamAllMatches(Matcher<Long> matcher) {
999             this.matcher = matcher;
1000         }
1001 
1002         @Override
1003         protected boolean matchesSafely(LongStream actual) {
1004             return actual
1005                 .peek(i -> {
1006                     nonMatching = i;
1007                     positionNonMatching++;
1008                 })
1009                 .allMatch(matcher::matches);
1010         }
1011 
1012         @Override
1013         protected void describeMismatchSafely(LongStream actual,
1014             Description mismatchDescription) {
1015             allMatchMismatch(mismatchDescription, positionNonMatching,
1016                 nonMatching);
1017         }
1018     }
1019 
1020     private static abstract class DoubleStreamAllMatches
1021         extends TypeSafeMatcher<DoubleStream> {
1022         private double                nonMatching;
1023         private long                  positionNonMatching = -1L;
1024         private final Matcher<Double> matcher;
1025 
1026         DoubleStreamAllMatches(Matcher<Double> matcher) {
1027             this.matcher = matcher;
1028         }
1029 
1030         @Override
1031         protected boolean matchesSafely(DoubleStream actual) {
1032             return actual
1033                 .peek(i -> {
1034                     nonMatching = i;
1035                     positionNonMatching++;
1036                 })
1037                 .allMatch(matcher::matches);
1038         }
1039 
1040         @Override
1041         protected void describeMismatchSafely(DoubleStream actual,
1042             Description mismatchDescription) {
1043             allMatchMismatch(mismatchDescription, positionNonMatching,
1044                 nonMatching);
1045         }
1046     }
1047 
1048     private static void anyMatchMismatch(Description mismatchDescription,
1049         List<?> accumulator) {
1050         mismatchDescription
1051             .appendText("None of these items matched: ")
1052             .appendValueList("[", ",", "]", accumulator);
1053     }
1054 
1055     private static abstract class StreamAnyMatches<T>
1056         extends TypeSafeMatcher<Stream<T>> {
1057         final List<T>    accumulator = new LinkedList<>();
1058         final Matcher<T> matcher;
1059 
1060         StreamAnyMatches(Matcher<T> matcher) {
1061             this.matcher = matcher;
1062         }
1063 
1064         @Override
1065         protected boolean matchesSafely(Stream<T> actual) {
1066             return actual.peek(accumulator::add).anyMatch(matcher::matches);
1067         }
1068 
1069         @Override
1070         protected void describeMismatchSafely(Stream<T> actual,
1071             Description mismatchDescription) {
1072             anyMatchMismatch(mismatchDescription, accumulator);
1073         }
1074     }
1075 
1076     private static abstract class LongStreamAnyMatches
1077         extends TypeSafeMatcher<LongStream> {
1078         final List<Long>    accumulator = new LinkedList<>();
1079         final Matcher<Long> matcher;
1080 
1081         LongStreamAnyMatches(Matcher<Long> matcher) {
1082             this.matcher = matcher;
1083         }
1084 
1085         @Override
1086         protected boolean matchesSafely(LongStream actual) {
1087             return actual.peek(accumulator::add).anyMatch(matcher::matches);
1088         }
1089 
1090         @Override
1091         protected void describeMismatchSafely(LongStream actual,
1092             Description mismatchDescription) {
1093             anyMatchMismatch(mismatchDescription, accumulator);
1094         }
1095     }
1096 
1097     private static abstract class IntStreamAnyMatches
1098         extends TypeSafeMatcher<IntStream> {
1099         final List<Integer>    accumulator = new LinkedList<>();
1100         final Matcher<Integer> matcher;
1101 
1102         IntStreamAnyMatches(Matcher<Integer> matcher) {
1103             this.matcher = matcher;
1104         }
1105 
1106         @Override
1107         protected boolean matchesSafely(IntStream actual) {
1108             return actual.peek(accumulator::add).anyMatch(matcher::matches);
1109         }
1110 
1111         @Override
1112         protected void describeMismatchSafely(IntStream actual,
1113             Description mismatchDescription) {
1114             anyMatchMismatch(mismatchDescription, accumulator);
1115         }
1116     }
1117 
1118     private static abstract class DoubleStreamAnyMatches
1119         extends TypeSafeMatcher<DoubleStream> {
1120         final List<Double>    accumulator = new LinkedList<>();
1121         final Matcher<Double> matcher;
1122 
1123         DoubleStreamAnyMatches(Matcher<Double> matcher) {
1124             this.matcher = matcher;
1125         }
1126 
1127         @Override
1128         protected boolean matchesSafely(DoubleStream actual) {
1129             return actual.peek(accumulator::add).anyMatch(matcher::matches);
1130         }
1131 
1132         @Override
1133         protected void describeMismatchSafely(DoubleStream actual,
1134             Description mismatchDescription) {
1135             anyMatchMismatch(mismatchDescription, accumulator);
1136         }
1137     }
1138 
1139     private static class ArrayIterator<T> implements Iterator<T> {
1140         private final T[] expected;
1141         private int       currentPos = 0;
1142 
1143         @SafeVarargs
1144         public ArrayIterator(T... expected) {
1145             this.expected = expected;
1146         }
1147 
1148         @Override
1149         public boolean hasNext() {
1150             return currentPos < expected.length;
1151         }
1152 
1153         @Override
1154         public T next() {
1155             return expected[currentPos++];
1156         }
1157     }
1158 
1159     private static class IntArrayIterator implements PrimitiveIterator.OfInt {
1160         private final int[] expected;
1161         private int         currentPos = 0;
1162 
1163         public IntArrayIterator(int... expected) {
1164             this.expected = expected;
1165         }
1166 
1167         @Override
1168         public boolean hasNext() {
1169             return currentPos < expected.length;
1170         }
1171 
1172         @Override
1173         public int nextInt() {
1174             return expected[currentPos++];
1175         }
1176     }
1177 
1178     private static class LongArrayIterator implements PrimitiveIterator.OfLong {
1179         private final long[] expected;
1180         private int          currentPos = 0;
1181 
1182         public LongArrayIterator(long... expected) {
1183             this.expected = expected;
1184         }
1185 
1186         @Override
1187         public boolean hasNext() {
1188             return currentPos < expected.length;
1189         }
1190 
1191         @Override
1192         public long nextLong() {
1193             return expected[currentPos++];
1194         }
1195     }
1196 
1197     private static class DoubleArrayIterator
1198         implements PrimitiveIterator.OfDouble {
1199         private final double[] expected;
1200         private int            currentPos = 0;
1201 
1202         public DoubleArrayIterator(double... expected) {
1203             this.expected = expected;
1204         }
1205 
1206         @Override
1207         public boolean hasNext() {
1208             return currentPos < expected.length;
1209         }
1210 
1211         @Override
1212         public double nextDouble() {
1213             return expected[currentPos++];
1214         }
1215     }
1216 }