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