• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.collect;
16 
17 import static com.google.common.collect.Streams.findLast;
18 import static com.google.common.collect.Streams.stream;
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import com.google.common.annotations.GwtCompatible;
22 import com.google.common.annotations.GwtIncompatible;
23 import com.google.common.collect.testing.SpliteratorTester;
24 import com.google.common.primitives.Doubles;
25 import com.google.common.truth.IterableSubject;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.LinkedHashSet;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.OptionalDouble;
33 import java.util.OptionalInt;
34 import java.util.OptionalLong;
35 import java.util.concurrent.atomic.AtomicInteger;
36 import java.util.function.Function;
37 import java.util.stream.Collectors;
38 import java.util.stream.DoubleStream;
39 import java.util.stream.IntStream;
40 import java.util.stream.LongStream;
41 import java.util.stream.Stream;
42 import junit.framework.TestCase;
43 import org.checkerframework.checker.nullness.qual.Nullable;
44 
45 /** Unit test for {@link Streams}. */
46 @GwtCompatible(emulated = true)
47 @ElementTypesAreNonnullByDefault
48 public class StreamsTest extends TestCase {
49   /*
50    * Full and proper black-box testing of a Stream-returning method is extremely involved, and is
51    * overkill when nearly all Streams are produced using well-tested JDK calls. So, we cheat and
52    * just test that the toArray() contents are as expected.
53    */
testStream_nonCollection()54   public void testStream_nonCollection() {
55     assertThat(stream(FluentIterable.of())).isEmpty();
56     assertThat(stream(FluentIterable.of("a"))).containsExactly("a");
57     assertThat(stream(FluentIterable.of(1, 2, 3)).filter(n -> n > 1)).containsExactly(2, 3);
58   }
59 
60   @SuppressWarnings("deprecation")
testStream_collection()61   public void testStream_collection() {
62     assertThat(stream(Arrays.asList())).isEmpty();
63     assertThat(stream(Arrays.asList("a"))).containsExactly("a");
64     assertThat(stream(Arrays.asList(1, 2, 3)).filter(n -> n > 1)).containsExactly(2, 3);
65   }
66 
testStream_iterator()67   public void testStream_iterator() {
68     assertThat(stream(Arrays.asList().iterator())).isEmpty();
69     assertThat(stream(Arrays.asList("a").iterator())).containsExactly("a");
70     assertThat(stream(Arrays.asList(1, 2, 3).iterator()).filter(n -> n > 1)).containsExactly(2, 3);
71   }
72 
testStream_googleOptional()73   public void testStream_googleOptional() {
74     assertThat(stream(com.google.common.base.Optional.absent())).isEmpty();
75     assertThat(stream(com.google.common.base.Optional.of("a"))).containsExactly("a");
76   }
77 
testStream_javaOptional()78   public void testStream_javaOptional() {
79     assertThat(stream(java.util.Optional.empty())).isEmpty();
80     assertThat(stream(java.util.Optional.of("a"))).containsExactly("a");
81   }
82 
testFindLast_refStream()83   public void testFindLast_refStream() {
84     assertThat(findLast(Stream.of())).isEmpty();
85     assertThat(findLast(Stream.of("a", "b", "c", "d"))).hasValue("d");
86 
87     // test with a large, not-subsized Spliterator
88     List<Integer> list =
89         IntStream.rangeClosed(0, 10000).boxed().collect(Collectors.toCollection(LinkedList::new));
90     assertThat(findLast(list.stream())).hasValue(10000);
91 
92     // no way to find out the stream is empty without walking its spliterator
93     assertThat(findLast(list.stream().filter(i -> i < 0))).isEmpty();
94   }
95 
testFindLast_intStream()96   public void testFindLast_intStream() {
97     assertThat(findLast(IntStream.of())).isEqualTo(OptionalInt.empty());
98     assertThat(findLast(IntStream.of(1, 2, 3, 4, 5))).isEqualTo(OptionalInt.of(5));
99 
100     // test with a large, not-subsized Spliterator
101     List<Integer> list =
102         IntStream.rangeClosed(0, 10000).boxed().collect(Collectors.toCollection(LinkedList::new));
103     assertThat(findLast(list.stream().mapToInt(i -> i))).isEqualTo(OptionalInt.of(10000));
104 
105     // no way to find out the stream is empty without walking its spliterator
106     assertThat(findLast(list.stream().mapToInt(i -> i).filter(i -> i < 0)))
107         .isEqualTo(OptionalInt.empty());
108   }
109 
testFindLast_longStream()110   public void testFindLast_longStream() {
111     assertThat(findLast(LongStream.of())).isEqualTo(OptionalLong.empty());
112     assertThat(findLast(LongStream.of(1, 2, 3, 4, 5))).isEqualTo(OptionalLong.of(5));
113 
114     // test with a large, not-subsized Spliterator
115     List<Long> list =
116         LongStream.rangeClosed(0, 10000).boxed().collect(Collectors.toCollection(LinkedList::new));
117     assertThat(findLast(list.stream().mapToLong(i -> i))).isEqualTo(OptionalLong.of(10000));
118 
119     // no way to find out the stream is empty without walking its spliterator
120     assertThat(findLast(list.stream().mapToLong(i -> i).filter(i -> i < 0)))
121         .isEqualTo(OptionalLong.empty());
122   }
123 
testFindLast_doubleStream()124   public void testFindLast_doubleStream() {
125     assertThat(findLast(DoubleStream.of())).isEqualTo(OptionalDouble.empty());
126     assertThat(findLast(DoubleStream.of(1, 2, 3, 4, 5))).isEqualTo(OptionalDouble.of(5));
127 
128     // test with a large, not-subsized Spliterator
129     List<Long> list =
130         LongStream.rangeClosed(0, 10000).boxed().collect(Collectors.toCollection(LinkedList::new));
131     assertThat(findLast(list.stream().mapToDouble(i -> i))).isEqualTo(OptionalDouble.of(10000));
132 
133     // no way to find out the stream is empty without walking its spliterator
134     assertThat(findLast(list.stream().mapToDouble(i -> i).filter(i -> i < 0)))
135         .isEqualTo(OptionalDouble.empty());
136   }
137 
testConcat_refStream()138   public void testConcat_refStream() {
139     assertThat(Streams.concat(Stream.of("a"), Stream.of("b"), Stream.empty(), Stream.of("c", "d")))
140         .containsExactly("a", "b", "c", "d")
141         .inOrder();
142     SpliteratorTester.of(
143             () ->
144                 Streams.concat(Stream.of("a"), Stream.of("b"), Stream.empty(), Stream.of("c", "d"))
145                     .spliterator())
146         .expect("a", "b", "c", "d");
147   }
148 
testConcat_refStream_closeIsPropagated()149   public void testConcat_refStream_closeIsPropagated() {
150     AtomicInteger closeCountB = new AtomicInteger(0);
151     Stream<String> streamB = Stream.of("b").onClose(closeCountB::incrementAndGet);
152     Stream<String> concatenated =
153         Streams.concat(Stream.of("a"), streamB, Stream.empty(), Stream.of("c", "d"));
154     assertThat(concatenated).containsExactly("a", "b", "c", "d").inOrder();
155     concatenated.close();
156     assertThat(closeCountB.get()).isEqualTo(1);
157   }
158 
testConcat_refStream_closeIsPropagated_stream_concat()159   public void testConcat_refStream_closeIsPropagated_stream_concat() {
160     // Just to demonstrate behavior of Stream::concat in the standard library
161     AtomicInteger closeCountB = new AtomicInteger(0);
162     Stream<String> streamB = Stream.of("b").onClose(closeCountB::incrementAndGet);
163     Stream<String> concatenated =
164         Stream.<Stream<String>>of(Stream.of("a"), streamB, Stream.empty(), Stream.of("c", "d"))
165             .reduce(Stream.empty(), Stream::concat);
166     assertThat(concatenated).containsExactly("a", "b", "c", "d").inOrder();
167     concatenated.close();
168     assertThat(closeCountB.get()).isEqualTo(1);
169   }
170 
testConcat_refStream_closeIsPropagated_stream_flatMap()171   public void testConcat_refStream_closeIsPropagated_stream_flatMap() {
172     // Just to demonstrate behavior of Stream::flatMap in the standard library
173     AtomicInteger closeCountB = new AtomicInteger(0);
174     Stream<String> streamB = Stream.of("b").onClose(closeCountB::incrementAndGet);
175     Stream<String> concatenated =
176         Stream.<Stream<String>>of(Stream.of("a"), streamB, Stream.empty(), Stream.of("c", "d"))
177             .flatMap(x -> x);
178     assertThat(concatenated).containsExactly("a", "b", "c", "d").inOrder();
179     concatenated.close();
180     // even without close, see doc for flatMap
181     assertThat(closeCountB.get()).isEqualTo(1);
182   }
183 
testConcat_refStream_closeIsPropagated_exceptionsChained()184   public void testConcat_refStream_closeIsPropagated_exceptionsChained() {
185     RuntimeException exception1 = new IllegalArgumentException("exception from stream 1");
186     RuntimeException exception2 = new IllegalStateException("exception from stream 2");
187     RuntimeException exception3 = new ArithmeticException("exception from stream 3");
188     Stream<String> stream1 = Stream.of("foo", "bar").onClose(doThrow(exception1));
189     Stream<String> stream2 = Stream.of("baz", "buh").onClose(doThrow(exception2));
190     Stream<String> stream3 = Stream.of("quux").onClose(doThrow(exception3));
191     RuntimeException exception = null;
192     try (Stream<String> concatenated = Streams.concat(stream1, stream2, stream3)) {
193     } catch (RuntimeException e) {
194       exception = e;
195     }
196     assertThat(exception).isEqualTo(exception1);
197     assertThat(exception.getSuppressed())
198         .asList()
199         .containsExactly(exception2, exception3)
200         .inOrder();
201   }
202 
doThrow(RuntimeException exception)203   private static Runnable doThrow(RuntimeException exception) {
204     return () -> {
205       throw exception;
206     };
207   }
208 
testConcat_refStream_parallel()209   public void testConcat_refStream_parallel() {
210     assertThat(
211             Streams.concat(Stream.of("a"), Stream.of("b"), Stream.empty(), Stream.of("c", "d"))
212                 .parallel()
213                 .toArray())
214         .asList()
215         .containsExactly("a", "b", "c", "d")
216         .inOrder();
217   }
218 
testConcat_intStream()219   public void testConcat_intStream() {
220     assertThat(
221             Streams.concat(IntStream.of(1), IntStream.of(2), IntStream.empty(), IntStream.of(3, 4)))
222         .containsExactly(1, 2, 3, 4)
223         .inOrder();
224   }
225 
testConcat_longStream()226   public void testConcat_longStream() {
227     assertThat(
228             Streams.concat(
229                 LongStream.of(1), LongStream.of(2), LongStream.empty(), LongStream.of(3, 4)))
230         .containsExactly(1L, 2L, 3L, 4L)
231         .inOrder();
232   }
233 
testConcat_doubleStream()234   public void testConcat_doubleStream() {
235     assertThatDoubleStream(
236             Streams.concat(
237                 DoubleStream.of(1),
238                 DoubleStream.of(2),
239                 DoubleStream.empty(),
240                 DoubleStream.of(3, 4)))
241         .containsExactly(1.0, 2.0, 3.0, 4.0)
242         .inOrder();
243   }
244 
testStream_optionalInt()245   public void testStream_optionalInt() {
246     assertThat(stream(OptionalInt.empty())).isEmpty();
247     assertThat(stream(OptionalInt.of(5))).containsExactly(5);
248   }
249 
testStream_optionalLong()250   public void testStream_optionalLong() {
251     assertThat(stream(OptionalLong.empty())).isEmpty();
252     assertThat(stream(OptionalLong.of(5L))).containsExactly(5L);
253   }
254 
testStream_optionalDouble()255   public void testStream_optionalDouble() {
256     assertThatDoubleStream(stream(OptionalDouble.empty())).isEmpty();
257     assertThatDoubleStream(stream(OptionalDouble.of(5.0))).containsExactly(5.0);
258   }
259 
testConcatInfiniteStream()260   public void testConcatInfiniteStream() {
261     assertThat(Streams.concat(Stream.of(1, 2, 3), Stream.generate(() -> 5)).limit(5))
262         .containsExactly(1, 2, 3, 5, 5)
263         .inOrder();
264   }
265 
testConcatInfiniteStream_int()266   public void testConcatInfiniteStream_int() {
267     assertThat(Streams.concat(IntStream.of(1, 2, 3), IntStream.generate(() -> 5)).limit(5))
268         .containsExactly(1, 2, 3, 5, 5)
269         .inOrder();
270   }
271 
testConcatInfiniteStream_long()272   public void testConcatInfiniteStream_long() {
273     assertThat(Streams.concat(LongStream.of(1, 2, 3), LongStream.generate(() -> 5)).limit(5))
274         .containsExactly(1L, 2L, 3L, 5L, 5L)
275         .inOrder();
276   }
277 
testConcatInfiniteStream_double()278   public void testConcatInfiniteStream_double() {
279     assertThatDoubleStream(
280             Streams.concat(DoubleStream.of(1, 2, 3), DoubleStream.generate(() -> 5)).limit(5))
281         .containsExactly(1., 2., 3., 5., 5.)
282         .inOrder();
283   }
284 
testMapWithIndex(Function<Collection<String>, Stream<String>> collectionImpl)285   private void testMapWithIndex(Function<Collection<String>, Stream<String>> collectionImpl) {
286     SpliteratorTester.of(
287             () ->
288                 Streams.mapWithIndex(
289                         collectionImpl.apply(ImmutableList.of()), (str, i) -> str + ":" + i)
290                     .spliterator())
291         .expect(ImmutableList.of());
292     SpliteratorTester.of(
293             () ->
294                 Streams.mapWithIndex(
295                         collectionImpl.apply(ImmutableList.of("a", "b", "c", "d", "e")),
296                         (str, i) -> str + ":" + i)
297                     .spliterator())
298         .expect("a:0", "b:1", "c:2", "d:3", "e:4");
299   }
300 
testMapWithIndex_arrayListSource()301   public void testMapWithIndex_arrayListSource() {
302     testMapWithIndex(elems -> new ArrayList<>(elems).stream());
303   }
304 
testMapWithIndex_linkedHashSetSource()305   public void testMapWithIndex_linkedHashSetSource() {
306     testMapWithIndex(elems -> new LinkedHashSet<>(elems).stream());
307   }
308 
testMapWithIndex_unsizedSource()309   public void testMapWithIndex_unsizedSource() {
310     testMapWithIndex(
311         elems ->
312             Stream.<@Nullable Object>of((Object) null)
313                 .flatMap(unused -> ImmutableList.copyOf(elems).stream()));
314   }
315 
testMapWithIndex_closeIsPropagated_sizedSource()316   public void testMapWithIndex_closeIsPropagated_sizedSource() {
317     testMapWithIndex_closeIsPropagated(Stream.of("a", "b", "c"));
318   }
319 
testMapWithIndex_closeIsPropagated_unsizedSource()320   public void testMapWithIndex_closeIsPropagated_unsizedSource() {
321     testMapWithIndex_closeIsPropagated(
322         Stream.<@Nullable Object>of((Object) null).flatMap(unused -> Stream.of("a", "b", "c")));
323   }
324 
testMapWithIndex_closeIsPropagated(Stream<String> source)325   private void testMapWithIndex_closeIsPropagated(Stream<String> source) {
326     AtomicInteger stringsCloseCount = new AtomicInteger();
327     Stream<String> strings = source.onClose(stringsCloseCount::incrementAndGet);
328     Stream<String> withIndex = Streams.mapWithIndex(strings, (str, i) -> str + ":" + i);
329 
330     withIndex.close();
331 
332     assertThat(stringsCloseCount.get()).isEqualTo(1);
333   }
334 
testMapWithIndex_intStream()335   public void testMapWithIndex_intStream() {
336     SpliteratorTester.of(
337             () -> Streams.mapWithIndex(IntStream.of(0, 1, 2), (x, i) -> x + ":" + i).spliterator())
338         .expect("0:0", "1:1", "2:2");
339   }
340 
testMapWithIndex_intStream_closeIsPropagated_sized()341   public void testMapWithIndex_intStream_closeIsPropagated_sized() {
342     testMapWithIndex_intStream_closeIsPropagated(IntStream.of(1, 2, 3));
343   }
344 
testMapWithIndex_intStream_closeIsPropagated_unsized()345   public void testMapWithIndex_intStream_closeIsPropagated_unsized() {
346     testMapWithIndex_intStream_closeIsPropagated(
347         IntStream.of(0).flatMap(unused -> IntStream.of(1, 2, 3)));
348   }
349 
testMapWithIndex_intStream_closeIsPropagated(IntStream source)350   private void testMapWithIndex_intStream_closeIsPropagated(IntStream source) {
351     AtomicInteger intStreamCloseCount = new AtomicInteger();
352     IntStream intStream = source.onClose(intStreamCloseCount::incrementAndGet);
353     Stream<String> withIndex = Streams.mapWithIndex(intStream, (str, i) -> str + ":" + i);
354 
355     withIndex.close();
356 
357     assertThat(intStreamCloseCount.get()).isEqualTo(1);
358   }
359 
testMapWithIndex_longStream()360   public void testMapWithIndex_longStream() {
361     SpliteratorTester.of(
362             () -> Streams.mapWithIndex(LongStream.of(0, 1, 2), (x, i) -> x + ":" + i).spliterator())
363         .expect("0:0", "1:1", "2:2");
364   }
365 
testMapWithIndex_longStream_closeIsPropagated_sized()366   public void testMapWithIndex_longStream_closeIsPropagated_sized() {
367     testMapWithIndex_longStream_closeIsPropagated(LongStream.of(1, 2, 3));
368   }
369 
testMapWithIndex_longStream_closeIsPropagated_unsized()370   public void testMapWithIndex_longStream_closeIsPropagated_unsized() {
371     testMapWithIndex_longStream_closeIsPropagated(
372         LongStream.of(0).flatMap(unused -> LongStream.of(1, 2, 3)));
373   }
374 
testMapWithIndex_longStream_closeIsPropagated(LongStream source)375   private void testMapWithIndex_longStream_closeIsPropagated(LongStream source) {
376     AtomicInteger longStreamCloseCount = new AtomicInteger();
377     LongStream longStream = source.onClose(longStreamCloseCount::incrementAndGet);
378     Stream<String> withIndex = Streams.mapWithIndex(longStream, (str, i) -> str + ":" + i);
379 
380     withIndex.close();
381 
382     assertThat(longStreamCloseCount.get()).isEqualTo(1);
383   }
384 
385   @GwtIncompatible // TODO(b/38490623): reenable after GWT double-to-string conversion is fixed
testMapWithIndex_doubleStream()386   public void testMapWithIndex_doubleStream() {
387     SpliteratorTester.of(
388             () ->
389                 Streams.mapWithIndex(DoubleStream.of(0, 1, 2), (x, i) -> x + ":" + i).spliterator())
390         .expect("0.0:0", "1.0:1", "2.0:2");
391   }
392 
testMapWithIndex_doubleStream_closeIsPropagated_sized()393   public void testMapWithIndex_doubleStream_closeIsPropagated_sized() {
394     testMapWithIndex_doubleStream_closeIsPropagated(DoubleStream.of(1, 2, 3));
395   }
396 
testMapWithIndex_doubleStream_closeIsPropagated_unsized()397   public void testMapWithIndex_doubleStream_closeIsPropagated_unsized() {
398     testMapWithIndex_doubleStream_closeIsPropagated(
399         DoubleStream.of(0).flatMap(unused -> DoubleStream.of(1, 2, 3)));
400   }
401 
testMapWithIndex_doubleStream_closeIsPropagated(DoubleStream source)402   private void testMapWithIndex_doubleStream_closeIsPropagated(DoubleStream source) {
403     AtomicInteger doubleStreamCloseCount = new AtomicInteger();
404     DoubleStream doubleStream = source.onClose(doubleStreamCloseCount::incrementAndGet);
405     Stream<String> withIndex = Streams.mapWithIndex(doubleStream, (str, i) -> str + ":" + i);
406 
407     withIndex.close();
408 
409     assertThat(doubleStreamCloseCount.get()).isEqualTo(1);
410   }
411 
testZip()412   public void testZip() {
413     assertThat(Streams.zip(Stream.of("a", "b", "c"), Stream.of(1, 2, 3), (a, b) -> a + ":" + b))
414         .containsExactly("a:1", "b:2", "c:3")
415         .inOrder();
416   }
417 
testZip_closeIsPropagated()418   public void testZip_closeIsPropagated() {
419     AtomicInteger lettersCloseCount = new AtomicInteger();
420     Stream<String> letters = Stream.of("a", "b", "c").onClose(lettersCloseCount::incrementAndGet);
421     AtomicInteger numbersCloseCount = new AtomicInteger();
422     Stream<Integer> numbers = Stream.of(1, 2, 3).onClose(numbersCloseCount::incrementAndGet);
423 
424     Stream<String> zipped = Streams.zip(letters, numbers, (a, b) -> a + ":" + b);
425 
426     zipped.close();
427 
428     assertThat(lettersCloseCount.get()).isEqualTo(1);
429     assertThat(numbersCloseCount.get()).isEqualTo(1);
430   }
431 
testZipFiniteWithInfinite()432   public void testZipFiniteWithInfinite() {
433     assertThat(
434             Streams.zip(
435                 Stream.of("a", "b", "c"), Stream.iterate(1, i -> i + 1), (a, b) -> a + ":" + b))
436         .containsExactly("a:1", "b:2", "c:3")
437         .inOrder();
438   }
439 
testZipInfiniteWithInfinite()440   public void testZipInfiniteWithInfinite() {
441     // zip is doing an infinite zip, but we truncate the result so we can actually test it
442     // but we want the zip itself to work
443     assertThat(
444             Streams.zip(
445                     Stream.iterate(1, i -> i + 1).map(String::valueOf),
446                     Stream.iterate(1, i -> i + 1),
447                     (String str, Integer i) -> str.equals(Integer.toString(i)))
448                 .limit(100))
449         .doesNotContain(false);
450   }
451 
testZipDifferingLengths()452   public void testZipDifferingLengths() {
453     assertThat(
454             Streams.zip(Stream.of("a", "b", "c", "d"), Stream.of(1, 2, 3), (a, b) -> a + ":" + b))
455         .containsExactly("a:1", "b:2", "c:3")
456         .inOrder();
457     assertThat(Streams.zip(Stream.of("a", "b", "c"), Stream.of(1, 2, 3, 4), (a, b) -> a + ":" + b))
458         .containsExactly("a:1", "b:2", "c:3")
459         .inOrder();
460   }
461 
testForEachPair()462   public void testForEachPair() {
463     List<String> list = new ArrayList<>();
464     Streams.forEachPair(
465         Stream.of("a", "b", "c"), Stream.of(1, 2, 3), (a, b) -> list.add(a + ":" + b));
466     assertThat(list).containsExactly("a:1", "b:2", "c:3");
467   }
468 
testForEachPair_differingLengths1()469   public void testForEachPair_differingLengths1() {
470     List<String> list = new ArrayList<>();
471     Streams.forEachPair(
472         Stream.of("a", "b", "c", "d"), Stream.of(1, 2, 3), (a, b) -> list.add(a + ":" + b));
473     assertThat(list).containsExactly("a:1", "b:2", "c:3");
474   }
475 
testForEachPair_differingLengths2()476   public void testForEachPair_differingLengths2() {
477     List<String> list = new ArrayList<>();
478     Streams.forEachPair(
479         Stream.of("a", "b", "c"), Stream.of(1, 2, 3, 4), (a, b) -> list.add(a + ":" + b));
480     assertThat(list).containsExactly("a:1", "b:2", "c:3");
481   }
482 
testForEachPair_oneEmpty()483   public void testForEachPair_oneEmpty() {
484     Streams.forEachPair(Stream.of("a"), Stream.empty(), (a, b) -> fail());
485   }
486 
testForEachPair_finiteWithInfinite()487   public void testForEachPair_finiteWithInfinite() {
488     List<String> list = new ArrayList<>();
489     Streams.forEachPair(
490         Stream.of("a", "b", "c"), Stream.iterate(1, i -> i + 1), (a, b) -> list.add(a + ":" + b));
491     assertThat(list).containsExactly("a:1", "b:2", "c:3");
492   }
493 
testForEachPair_parallel()494   public void testForEachPair_parallel() {
495     Stream<String> streamA = IntStream.range(0, 100000).mapToObj(String::valueOf).parallel();
496     Stream<Integer> streamB = IntStream.range(0, 100000).mapToObj(i -> i).parallel();
497 
498     AtomicInteger count = new AtomicInteger(0);
499     Streams.forEachPair(
500         streamA,
501         streamB,
502         (a, b) -> {
503           count.incrementAndGet();
504           assertThat(a.equals(String.valueOf(b))).isTrue();
505         });
506     assertThat(count.get()).isEqualTo(100000);
507     // of course, this test doesn't prove that anything actually happened in parallel...
508   }
509 
510   // TODO(kevinb): switch to importing Truth's assertThat(DoubleStream) if we get that added
assertThatDoubleStream(DoubleStream stream)511   private static IterableSubject assertThatDoubleStream(DoubleStream stream) {
512     return assertThat(Doubles.asList(stream.toArray()));
513   }
514 }
515