/* * Copyright (C) 2016 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.common.collect; import static com.google.common.collect.Streams.findLast; import static com.google.common.collect.Streams.stream; import com.google.common.collect.testing.SpliteratorTester; import com.google.common.primitives.Doubles; import com.google.common.truth.IterableSubject; import com.google.common.truth.Truth; import com.google.common.truth.Truth8; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.OptionalLong; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; import java.util.stream.Stream; import junit.framework.TestCase; /** Unit test for {@link Streams}. */ public class StreamsTest extends TestCase { /* * Full and proper black-box testing of a Stream-returning method is extremely involved, and is * overkill when nearly all Streams are produced using well-tested JDK calls. So, we cheat and * just test that the toArray() contents are as expected. */ public void testStream_nonCollection() { assertThat(stream(FluentIterable.of())).isEmpty(); assertThat(stream(FluentIterable.of("a"))).containsExactly("a"); assertThat(stream(FluentIterable.of(1, 2, 3)).filter(n -> n > 1)).containsExactly(2, 3); } @SuppressWarnings("deprecation") public void testStream_collection() { assertThat(stream(Arrays.asList())).isEmpty(); assertThat(stream(Arrays.asList("a"))).containsExactly("a"); assertThat(stream(Arrays.asList(1, 2, 3)).filter(n -> n > 1)).containsExactly(2, 3); } public void testStream_iterator() { assertThat(stream(Arrays.asList().iterator())).isEmpty(); assertThat(stream(Arrays.asList("a").iterator())).containsExactly("a"); assertThat(stream(Arrays.asList(1, 2, 3).iterator()).filter(n -> n > 1)).containsExactly(2, 3); } public void testStream_googleOptional() { assertThat(stream(com.google.common.base.Optional.absent())).isEmpty(); assertThat(stream(com.google.common.base.Optional.of("a"))).containsExactly("a"); } public void testStream_javaOptional() { assertThat(stream(java.util.Optional.empty())).isEmpty(); assertThat(stream(java.util.Optional.of("a"))).containsExactly("a"); } public void testFindLast_refStream() { Truth8.assertThat(findLast(Stream.of())).isEmpty(); Truth8.assertThat(findLast(Stream.of("a", "b", "c", "d"))).hasValue("d"); // test with a large, not-subsized Spliterator List<Integer> list = IntStream.rangeClosed(0, 10000).boxed().collect(Collectors.toCollection(LinkedList::new)); Truth8.assertThat(findLast(list.stream())).hasValue(10000); // no way to find out the stream is empty without walking its spliterator Truth8.assertThat(findLast(list.stream().filter(i -> i < 0))).isEmpty(); } public void testFindLast_intStream() { Truth.assertThat(findLast(IntStream.of())).isEqualTo(OptionalInt.empty()); Truth.assertThat(findLast(IntStream.of(1, 2, 3, 4, 5))).isEqualTo(OptionalInt.of(5)); // test with a large, not-subsized Spliterator List<Integer> list = IntStream.rangeClosed(0, 10000).boxed().collect(Collectors.toCollection(LinkedList::new)); Truth.assertThat(findLast(list.stream().mapToInt(i -> i))).isEqualTo(OptionalInt.of(10000)); // no way to find out the stream is empty without walking its spliterator Truth.assertThat(findLast(list.stream().mapToInt(i -> i).filter(i -> i < 0))) .isEqualTo(OptionalInt.empty()); } public void testFindLast_longStream() { Truth.assertThat(findLast(LongStream.of())).isEqualTo(OptionalLong.empty()); Truth.assertThat(findLast(LongStream.of(1, 2, 3, 4, 5))).isEqualTo(OptionalLong.of(5)); // test with a large, not-subsized Spliterator List<Long> list = LongStream.rangeClosed(0, 10000).boxed().collect(Collectors.toCollection(LinkedList::new)); Truth.assertThat(findLast(list.stream().mapToLong(i -> i))).isEqualTo(OptionalLong.of(10000)); // no way to find out the stream is empty without walking its spliterator Truth.assertThat(findLast(list.stream().mapToLong(i -> i).filter(i -> i < 0))) .isEqualTo(OptionalLong.empty()); } public void testFindLast_doubleStream() { Truth.assertThat(findLast(DoubleStream.of())).isEqualTo(OptionalDouble.empty()); Truth.assertThat(findLast(DoubleStream.of(1, 2, 3, 4, 5))).isEqualTo(OptionalDouble.of(5)); // test with a large, not-subsized Spliterator List<Long> list = LongStream.rangeClosed(0, 10000).boxed().collect(Collectors.toCollection(LinkedList::new)); Truth.assertThat(findLast(list.stream().mapToDouble(i -> i))) .isEqualTo(OptionalDouble.of(10000)); // no way to find out the stream is empty without walking its spliterator Truth.assertThat(findLast(list.stream().mapToDouble(i -> i).filter(i -> i < 0))) .isEqualTo(OptionalDouble.empty()); } public void testConcat_refStream() { assertThat(Streams.concat(Stream.of("a"), Stream.of("b"), Stream.empty(), Stream.of("c", "d"))) .containsExactly("a", "b", "c", "d") .inOrder(); SpliteratorTester.of( () -> Streams.concat(Stream.of("a"), Stream.of("b"), Stream.empty(), Stream.of("c", "d")) .spliterator()) .expect("a", "b", "c", "d"); } public void testConcat_refStream_parallel() { Truth.assertThat( Streams.concat(Stream.of("a"), Stream.of("b"), Stream.empty(), Stream.of("c", "d")) .parallel() .toArray()) .asList() .containsExactly("a", "b", "c", "d") .inOrder(); } public void testConcat_intStream() { assertThat( Streams.concat(IntStream.of(1), IntStream.of(2), IntStream.empty(), IntStream.of(3, 4))) .containsExactly(1, 2, 3, 4) .inOrder(); } public void testConcat_longStream() { assertThat( Streams.concat( LongStream.of(1), LongStream.of(2), LongStream.empty(), LongStream.of(3, 4))) .containsExactly(1L, 2L, 3L, 4L) .inOrder(); } public void testConcat_doubleStream() { assertThat( Streams.concat( DoubleStream.of(1), DoubleStream.of(2), DoubleStream.empty(), DoubleStream.of(3, 4))) .containsExactly(1.0, 2.0, 3.0, 4.0) .inOrder(); } public void testStream_optionalInt() { assertThat(stream(java.util.OptionalInt.empty())).isEmpty(); assertThat(stream(java.util.OptionalInt.of(5))).containsExactly(5); } public void testStream_optionalLong() { assertThat(stream(java.util.OptionalLong.empty())).isEmpty(); assertThat(stream(java.util.OptionalLong.of(5L))).containsExactly(5L); } public void testStream_optionalDouble() { assertThat(stream(java.util.OptionalDouble.empty())).isEmpty(); assertThat(stream(java.util.OptionalDouble.of(5.0))).containsExactly(5.0); } private void testMapWithIndex(Function<Collection<String>, Stream<String>> collectionImpl) { SpliteratorTester.of( () -> Streams.mapWithIndex( collectionImpl.apply(ImmutableList.of()), (str, i) -> str + ":" + i) .spliterator()) .expect(ImmutableList.of()); SpliteratorTester.of( () -> Streams.mapWithIndex( collectionImpl.apply(ImmutableList.of("a", "b", "c", "d", "e")), (str, i) -> str + ":" + i) .spliterator()) .expect("a:0", "b:1", "c:2", "d:3", "e:4"); } public void testMapWithIndex_arrayListSource() { testMapWithIndex(elems -> new ArrayList<>(elems).stream()); } public void testMapWithIndex_linkedHashSetSource() { testMapWithIndex(elems -> new LinkedHashSet<>(elems).stream()); } public void testMapWithIndex_unsizedSource() { testMapWithIndex( elems -> Stream.of((Object) null).flatMap(unused -> ImmutableList.copyOf(elems).stream())); } public void testMapWithIndex_intStream() { SpliteratorTester.of( () -> Streams.mapWithIndex(IntStream.of(0, 1, 2), (x, i) -> x + ":" + i).spliterator()) .expect("0:0", "1:1", "2:2"); } public void testMapWithIndex_longStream() { SpliteratorTester.of( () -> Streams.mapWithIndex(LongStream.of(0, 1, 2), (x, i) -> x + ":" + i).spliterator()) .expect("0:0", "1:1", "2:2"); } public void testMapWithIndex_doubleStream() { SpliteratorTester.of( () -> Streams.mapWithIndex(DoubleStream.of(0, 1, 2), (x, i) -> x + ":" + i).spliterator()) .expect("0.0:0", "1.0:1", "2.0:2"); } public void testZip() { assertThat(Streams.zip(Stream.of("a", "b", "c"), Stream.of(1, 2, 3), (a, b) -> a + ":" + b)) .containsExactly("a:1", "b:2", "c:3") .inOrder(); } public void testZipFiniteWithInfinite() { assertThat( Streams.zip( Stream.of("a", "b", "c"), Stream.iterate(1, i -> i + 1), (a, b) -> a + ":" + b)) .containsExactly("a:1", "b:2", "c:3") .inOrder(); } public void testZipInfiniteWithInfinite() { // zip is doing an infinite zip, but we truncate the result so we can actually test it // but we want the zip itself to work assertThat( Streams.zip( Stream.iterate(1, i -> i + 1).map(String::valueOf), Stream.iterate(1, i -> i + 1), (String str, Integer i) -> str.equals(Integer.toString(i))) .limit(100)) .doesNotContain(false); } public void testZipDifferingLengths() { assertThat( Streams.zip(Stream.of("a", "b", "c", "d"), Stream.of(1, 2, 3), (a, b) -> a + ":" + b)) .containsExactly("a:1", "b:2", "c:3") .inOrder(); assertThat(Streams.zip(Stream.of("a", "b", "c"), Stream.of(1, 2, 3, 4), (a, b) -> a + ":" + b)) .containsExactly("a:1", "b:2", "c:3") .inOrder(); } public void testForEachPair() { List<String> list = new ArrayList<>(); Streams.forEachPair( Stream.of("a", "b", "c"), Stream.of(1, 2, 3), (a, b) -> list.add(a + ":" + b)); Truth.assertThat(list).containsExactly("a:1", "b:2", "c:3"); } public void testForEachPair_differingLengths1() { List<String> list = new ArrayList<>(); Streams.forEachPair( Stream.of("a", "b", "c", "d"), Stream.of(1, 2, 3), (a, b) -> list.add(a + ":" + b)); Truth.assertThat(list).containsExactly("a:1", "b:2", "c:3"); } public void testForEachPair_differingLengths2() { List<String> list = new ArrayList<>(); Streams.forEachPair( Stream.of("a", "b", "c"), Stream.of(1, 2, 3, 4), (a, b) -> list.add(a + ":" + b)); Truth.assertThat(list).containsExactly("a:1", "b:2", "c:3"); } public void testForEachPair_oneEmpty() { Streams.forEachPair(Stream.of("a"), Stream.empty(), (a, b) -> fail()); } public void testForEachPair_finiteWithInfinite() { List<String> list = new ArrayList<>(); Streams.forEachPair( Stream.of("a", "b", "c"), Stream.iterate(1, i -> i + 1), (a, b) -> list.add(a + ":" + b)); Truth.assertThat(list).containsExactly("a:1", "b:2", "c:3"); } public void testForEachPair_parallel() { Stream<String> streamA = IntStream.range(0, 100000).mapToObj(String::valueOf).parallel(); Stream<Integer> streamB = IntStream.range(0, 100000).mapToObj(i -> i).parallel(); AtomicInteger count = new AtomicInteger(0); Streams.forEachPair( streamA, streamB, (a, b) -> { count.incrementAndGet(); Truth.assertThat(a.equals(String.valueOf(b))).isTrue(); }); Truth.assertThat(count.get()).isEqualTo(100000); // of course, this test doesn't prove that anything actually happened in parallel... } // TODO(kevinb): switch to importing Truth's assertThat(Stream) if we get that added private static IterableSubject assertThat(Stream<?> stream) { return Truth.assertThat(stream.toArray()).asList(); } private static IterableSubject assertThat(IntStream stream) { return Truth.assertThat(stream.toArray()).asList(); } private static IterableSubject assertThat(LongStream stream) { return Truth.assertThat(stream.toArray()).asList(); } private static IterableSubject assertThat(DoubleStream stream) { return Truth.assertThat(Doubles.asList(stream.toArray())); } }