| /* |
| * Copyright 2016 Google Inc. |
| * |
| * 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.gwt.emultest.java8.util.stream; |
| |
| import static java.util.stream.Collectors.averagingDouble; |
| import static java.util.stream.Collectors.averagingInt; |
| import static java.util.stream.Collectors.averagingLong; |
| import static java.util.stream.Collectors.collectingAndThen; |
| import static java.util.stream.Collectors.counting; |
| import static java.util.stream.Collectors.groupingBy; |
| import static java.util.stream.Collectors.joining; |
| import static java.util.stream.Collectors.mapping; |
| import static java.util.stream.Collectors.maxBy; |
| import static java.util.stream.Collectors.minBy; |
| import static java.util.stream.Collectors.partitioningBy; |
| import static java.util.stream.Collectors.summarizingDouble; |
| import static java.util.stream.Collectors.summarizingInt; |
| import static java.util.stream.Collectors.summarizingLong; |
| import static java.util.stream.Collectors.summingDouble; |
| import static java.util.stream.Collectors.summingInt; |
| import static java.util.stream.Collectors.summingLong; |
| import static java.util.stream.Collectors.toList; |
| import static java.util.stream.Collectors.toMap; |
| import static java.util.stream.Collectors.toSet; |
| |
| import com.google.gwt.emultest.java.util.EmulTestBase; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.DoubleSummaryStatistics; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.IntSummaryStatistics; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.LongSummaryStatistics; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.Set; |
| import java.util.function.BiConsumer; |
| import java.util.function.BiPredicate; |
| import java.util.function.BinaryOperator; |
| import java.util.function.Function; |
| import java.util.function.Supplier; |
| import java.util.stream.Collector; |
| |
| /** |
| * Tests {@link java.util.stream.Collectors}. |
| * <p /> |
| * Methods that are presently only tested indirectly: |
| * <ul> |
| * <li>reducing: counting, minBy/maxBy use this</li> |
| * <li>toCollection tested by toList (toSet now uses its own impl)</li> |
| * </ul> |
| */ |
| public class CollectorsTest extends EmulTestBase { |
| |
| public void testAveragingDouble() { |
| Collector<Double, ?, Double> c = averagingDouble(Double::doubleValue); |
| applyItems((4.0 + 8.0) / 2.0, c, 4.0, 8.0); |
| |
| assertZeroItemsCollectedAs(0D, c); |
| assertSingleItemCollectedAs(5D, c, 5D); |
| } |
| |
| public void testAveragingInt() { |
| Collector<Integer, ?, Double> c = averagingInt(Integer::intValue); |
| applyItems((4.0 + 8.0) / 2.0, c, 4, 8); |
| |
| assertZeroItemsCollectedAs(0D, c); |
| assertSingleItemCollectedAs(5D, c, 5); |
| } |
| |
| public void testAveragingLong() { |
| Collector<Long, ?, Double> c = averagingLong(Long::longValue); |
| applyItems((4.0 + 8.0) / 2.0, c, 4L, 8L); |
| |
| assertZeroItemsCollectedAs(0D, c); |
| assertSingleItemCollectedAs(5D, c, 5L); |
| } |
| |
| public void testCollectingAndThen() { |
| Collector<Object, ?, List<Object>> listIdentityCollector = |
| collectingAndThen(toList(), Function.identity()); |
| // same test as toList(): |
| // same items (allow dups) |
| applyItems( |
| Arrays.asList("a", "a"), |
| listIdentityCollector, |
| "a", "a" |
| ); |
| |
| // ordered |
| applyItems( |
| Arrays.asList("a", "b"), |
| listIdentityCollector, |
| "a", "b" |
| ); |
| assertZeroItemsCollectedAs(Collections.emptyList(), listIdentityCollector); |
| assertSingleItemCollectedAs(Collections.singletonList("a"), listIdentityCollector, "a"); |
| |
| Collector<Object, ?, Integer> uglyCount = collectingAndThen(toList(), List::size); |
| // (nearly) same test as counting(): |
| applyItems(2, uglyCount, "1", new Object()); |
| |
| assertZeroItemsCollectedAs(0, uglyCount); |
| assertSingleItemCollectedAs(1, uglyCount, new Object()); |
| } |
| |
| public void testCounting() { |
| Collector<Object, ?, Long> c = counting(); |
| applyItems(2L, c, "1", new Object()); |
| |
| assertZeroItemsCollectedAs(0L, c); |
| assertSingleItemCollectedAs(1L, c, new Object()); |
| } |
| |
| public void testGroupingBy() { |
| Collector<String, ?, Map<String, List<String>>> c1 = groupingBy(Function.identity()); |
| |
| Map<String, List<String>> mapOfLists = new HashMap<>(); |
| mapOfLists.put("a", Arrays.asList("a", "a")); |
| applyItems(mapOfLists, c1, "a", "a"); |
| mapOfLists.clear(); |
| mapOfLists.put("a", Collections.singletonList("a")); |
| mapOfLists.put("b", Collections.singletonList("b")); |
| applyItems(mapOfLists, c1, "a", "b"); |
| |
| assertZeroItemsCollectedAs(Collections.emptyMap(), c1); |
| assertSingleItemCollectedAs( |
| Collections.singletonMap("a", Collections.singletonList("a")), c1, "a"); |
| |
| Collector<String, ?, LinkedHashMap<String, Set<String>>> c2 = |
| groupingBy(Function.identity(), LinkedHashMap::new, toSet()); |
| |
| LinkedHashMap<String, Set<String>> linkedMapOfSets = new LinkedHashMap<>(); |
| linkedMapOfSets.put("a", Collections.singleton("a")); |
| applyItems(linkedMapOfSets, c2, "a", "a"); |
| linkedMapOfSets.clear(); |
| linkedMapOfSets.put("a", Collections.singleton("a")); |
| linkedMapOfSets.put("b", Collections.singleton("b")); |
| applyItems(linkedMapOfSets, c2, "a", "b"); |
| |
| // check to make sure we actually get the linked results, and that they are ordered how we want |
| // them |
| LinkedHashMap<String, Set<String>> out = applyItemsWithoutSplitting(c2, "a", "b"); |
| assertEquals(Arrays.asList("a", "b"), new ArrayList<>(out.keySet())); |
| out = applyItemsWithoutSplitting(c2, "b", "a"); |
| assertEquals(Arrays.asList("b", "a"), new ArrayList<>(out.keySet())); |
| |
| assertZeroItemsCollectedAs(new LinkedHashMap<>(), c2); |
| linkedMapOfSets.clear(); |
| linkedMapOfSets.put("a", Collections.singleton("a")); |
| assertSingleItemCollectedAs(linkedMapOfSets, c2, "a"); |
| } |
| |
| public void testJoining() { |
| Collector<CharSequence, ?, String> c = joining(); |
| applyItems("ab", c, "a", "b"); |
| applyItems("a,", c, "a", ","); |
| applyItems("", c, "", ""); |
| assertZeroItemsCollectedAs("", c); |
| assertSingleItemCollectedAs("a", c, "a"); |
| assertSingleItemCollectedAs("", c, ""); |
| |
| c = joining(","); |
| applyItems("a,b", c, "a", "b"); |
| applyItems("a,,", c, "a", ","); |
| applyItems(",", c, "", ""); |
| assertZeroItemsCollectedAs("", c); |
| assertSingleItemCollectedAs("a", c, "a"); |
| assertSingleItemCollectedAs("", c, ""); |
| |
| c = joining("-", "{", "}"); |
| applyItems("{a-b}", c, "a", "b"); |
| assertZeroItemsCollectedAs("{}", c); |
| assertSingleItemCollectedAs("{a}", c, "a"); |
| assertSingleItemCollectedAs("{}", c, ""); |
| } |
| |
| public void testMapping() { |
| Collector<String, ?, List<String>> identityMapping = mapping(Function.identity(), toList()); |
| // same test as toList(): |
| // same items (allow dups) |
| applyItems( |
| Arrays.asList("a", "a"), |
| identityMapping, |
| "a", "a" |
| ); |
| |
| // ordered |
| applyItems( |
| Arrays.asList("a", "b"), |
| identityMapping, |
| "a", "b" |
| ); |
| assertZeroItemsCollectedAs(Collections.emptyList(), identityMapping); |
| assertSingleItemCollectedAs(Collections.singletonList("a"), identityMapping, "a"); |
| |
| Collector<Integer, ?, List<String>> numberMapping = mapping(s -> "#" + s, toList()); |
| // poke the same tests as list, make sure the mapper is run |
| applyItems( |
| Arrays.asList("#1", "#2"), |
| numberMapping, |
| 1, 2 |
| ); |
| |
| // ordered |
| applyItems( |
| Arrays.asList("#1", "#2"), |
| numberMapping, |
| 1, 2 |
| ); |
| assertZeroItemsCollectedAs(Collections.emptyList(), numberMapping); |
| assertSingleItemCollectedAs(Collections.singletonList("#10"), numberMapping, 10); |
| } |
| |
| public void testMaxBy() { |
| Collector<String, ?, Optional<String>> c = maxBy(Comparator.naturalOrder()); |
| applyItems(Optional.of("z"), c, "a", "z"); |
| applyItems(Optional.of("z"), c, "z", "a"); |
| |
| assertZeroItemsCollectedAs(Optional.empty(), c); |
| assertSingleItemCollectedAs(Optional.of("foo"), c, "foo"); |
| } |
| |
| public void testMinBy() { |
| Collector<String, ?, Optional<String>> c = minBy(Comparator.naturalOrder()); |
| applyItems(Optional.of("a"), c, "a", "z"); |
| applyItems(Optional.of("a"), c, "z", "a"); |
| |
| assertZeroItemsCollectedAs(Optional.empty(), c); |
| assertSingleItemCollectedAs(Optional.of("foo"), c, "foo"); |
| } |
| |
| public void testPartitioningBy() { |
| Collector<Boolean, ?, Map<Boolean, List<Boolean>>> c1 = partitioningBy(Boolean::valueOf); |
| |
| Map<Boolean, List<Boolean>> mapOfLists = new HashMap<>(); |
| mapOfLists.put(true, Collections.singletonList(true)); |
| mapOfLists.put(false, Collections.singletonList(false)); |
| applyItems(mapOfLists, c1, true, false); |
| |
| mapOfLists.clear(); |
| mapOfLists.put(false, Collections.emptyList()); |
| mapOfLists.put(true, Arrays.asList(true, true)); |
| applyItems(mapOfLists, c1, true, true); |
| |
| mapOfLists.clear(); |
| mapOfLists.put(false, Arrays.asList(false, false)); |
| mapOfLists.put(true, Collections.emptyList()); |
| applyItems(mapOfLists, c1, false, false); |
| |
| mapOfLists.clear(); |
| mapOfLists.put(false, Collections.emptyList()); |
| mapOfLists.put(true, Collections.emptyList()); |
| assertZeroItemsCollectedAs(mapOfLists, c1); |
| |
| mapOfLists.clear(); |
| mapOfLists.put(false, Collections.emptyList()); |
| mapOfLists.put(true, Collections.singletonList(true)); |
| assertSingleItemCollectedAs(mapOfLists, c1, true); |
| |
| mapOfLists.clear(); |
| mapOfLists.put(false, Collections.singletonList(false)); |
| mapOfLists.put(true, Collections.emptyList()); |
| assertSingleItemCollectedAs(mapOfLists, c1, false); |
| |
| Collector<Boolean, ?, Map<Boolean, Set<Boolean>>> c2 = |
| partitioningBy(Boolean::valueOf, toSet()); |
| |
| Map<Boolean, Set<Boolean>> mapOfSets = new HashMap<>(); |
| mapOfSets.put(true, Collections.singleton(true)); |
| mapOfSets.put(false, Collections.singleton(false)); |
| applyItems(mapOfSets, c2, true, false); |
| |
| mapOfSets.clear(); |
| mapOfSets.put(false, Collections.emptySet()); |
| mapOfSets.put(true, Collections.singleton(true)); |
| applyItems(mapOfSets, c2, true, true); |
| |
| mapOfSets.clear(); |
| mapOfSets.put(false, Collections.singleton(false)); |
| mapOfSets.put(true, Collections.emptySet()); |
| applyItems(mapOfSets, c2, false, false); |
| } |
| |
| public void testSummarizingDouble() { |
| Collector<Double, ?, DoubleSummaryStatistics> c = summarizingDouble(Double::doubleValue); |
| DoubleSummaryStatistics stats = new DoubleSummaryStatistics(); |
| stats.accept(5.1); |
| stats.accept(7); |
| BiPredicate<DoubleSummaryStatistics, DoubleSummaryStatistics> equals = (s1, s2) -> |
| s1.getSum() == s2.getSum() |
| && s1.getAverage() == s2.getAverage() |
| && s1.getCount() == s2.getCount() |
| && s1.getMin() == s2.getMin() |
| && s1.getMax() == s2.getMax(); |
| applyItems(stats, c, 5.1, 7.0, equals); |
| applyItems(stats, c, 7.0, 5.1, equals);//probably unnecessary to run these backward |
| |
| assertZeroItemsCollectedAs(new DoubleSummaryStatistics(), c, equals); |
| stats = new DoubleSummaryStatistics(); |
| stats.accept(7.3); |
| assertSingleItemCollectedAs(stats, c, 7.3, equals); |
| } |
| |
| public void testSummarizingInt() { |
| Collector<Integer, ?, IntSummaryStatistics> c = summarizingInt(Integer::intValue); |
| IntSummaryStatistics stats = new IntSummaryStatistics(); |
| stats.accept(2); |
| stats.accept(10); |
| BiPredicate<IntSummaryStatistics, IntSummaryStatistics> equals = (s1, s2) -> |
| s1.getSum() == s2.getSum() |
| && s1.getAverage() == s2.getAverage() |
| && s1.getCount() == s2.getCount() |
| && s1.getMin() == s2.getMin() |
| && s1.getMax() == s2.getMax(); |
| applyItems(stats, c, 2, 10, equals); |
| applyItems(stats, c, 10, 2, equals); |
| |
| assertZeroItemsCollectedAs(new IntSummaryStatistics(), c, equals); |
| stats = new IntSummaryStatistics(); |
| stats.accept(7); |
| assertSingleItemCollectedAs(stats, c, 7, equals); |
| } |
| |
| public void testSummarizingLong() { |
| Collector<Long, ?, LongSummaryStatistics> c = summarizingLong(Long::longValue); |
| LongSummaryStatistics stats = new LongSummaryStatistics(); |
| stats.accept(2); |
| stats.accept(10); |
| BiPredicate<LongSummaryStatistics, LongSummaryStatistics> equals = (s1, s2) -> |
| s1.getSum() == s2.getSum() |
| && s1.getAverage() == s2.getAverage() |
| && s1.getCount() == s2.getCount() |
| && s1.getMin() == s2.getMin() |
| && s1.getMax() == s2.getMax(); |
| applyItems(stats, c, 2L, 10L, equals); |
| applyItems(stats, c, 10L, 2L, equals); |
| |
| assertZeroItemsCollectedAs(new LongSummaryStatistics(), c, equals); |
| stats = new LongSummaryStatistics(); |
| stats.accept(7L); |
| assertSingleItemCollectedAs(stats, c, 7L, equals); |
| } |
| |
| public void testSummingDouble() { |
| Collector<Double, ?, Double> c = summingDouble(Double::doubleValue); |
| applyItems(4.1 + 8.2, c, 4.1, 8.2); |
| |
| assertZeroItemsCollectedAs(0d, c); |
| assertSingleItemCollectedAs(7.3, c, 7.3); |
| } |
| |
| public void testSummingInt() { |
| Collector<Integer, ?, Integer> c = summingInt(Integer::intValue); |
| applyItems(4 + 8, c, 4, 8); |
| |
| assertZeroItemsCollectedAs(0, c); |
| assertSingleItemCollectedAs(7, c, 7); |
| } |
| |
| public void testSummingLong() { |
| Collector<Long, ?, Long> c = summingLong(Long::longValue); |
| applyItems(4L + 8L, c, 4L, 8L); |
| |
| assertZeroItemsCollectedAs(0L, c); |
| assertSingleItemCollectedAs(5L, c, 5L); |
| } |
| |
| public void testList() { |
| Collector<String, ?, List<String>> c = toList(); |
| |
| // same items (allow dups) |
| applyItems( |
| Arrays.asList("a", "a"), |
| c, |
| "a", "a" |
| ); |
| |
| // ordered |
| applyItems( |
| Arrays.asList("a", "b"), |
| c, |
| "a", "b" |
| ); |
| assertZeroItemsCollectedAs(Collections.emptyList(), c); |
| assertSingleItemCollectedAs(Collections.singletonList("a"), c, "a"); |
| } |
| |
| public void testMap() { |
| Collector<String, ?, Map<String, String>> c = toMap(Function.identity(), Function.identity()); |
| |
| // two distinct items |
| Map<String, String> map = new HashMap<>(); |
| map.put("a", "a"); |
| map.put("b", "b"); |
| applyItems(map, c, "a", "b"); |
| |
| // inline applyItems and test each to confirm failure for duplicates |
| try { |
| applyItemsWithoutSplitting(c, "a", "a"); |
| fail("expected IllegalStateException"); |
| } catch (IllegalStateException expected) { |
| } |
| try { |
| applyItemsWithSplitting(c, "a", "a"); |
| fail("expected IllegalStateException"); |
| } catch (IllegalStateException expected) { |
| } |
| |
| assertZeroItemsCollectedAs(Collections.emptyMap(), c); |
| assertSingleItemCollectedAs(Collections.singletonMap("a", "a"), c, "a"); |
| |
| List<String> seen = new ArrayList<>(); |
| c = toMap(Function.identity(), Function.identity(), (s, s2) -> { |
| seen.add("first: " + s); |
| seen.add("second: " + s2); |
| return s + "," + s2; |
| }); |
| map = new HashMap<>(); |
| map.put("a", "a,a"); |
| applyItems(map, c, "a", "a"); |
| assertEquals(Arrays.asList("first: a", "second: a", "first: a", "second: a"), seen); |
| } |
| |
| public void testSet() { |
| Collector<String, ?, Set<String>> c = toSet(); |
| |
| // same items (no dups) |
| applyItems( |
| Collections.singleton("a"), |
| c, |
| "a", "a" |
| ); |
| |
| // different items |
| applyItems( |
| new HashSet<>(Arrays.asList("a", "b")), |
| c, |
| "a", "b" |
| ); |
| |
| assertZeroItemsCollectedAs(Collections.emptySet(), c); |
| assertSingleItemCollectedAs(Collections.singleton("a"), c, "a"); |
| } |
| |
| /** |
| * This method attempts to apply a collector to items as a stream might do, so that we can simply |
| * verify the output. Taken from the Collector class's javadoc. |
| */ |
| private static <T, A, R> void applyItems( |
| R expected, Collector<T, A, R> collector, T t1, T t2, BiPredicate<R, R> equals) { |
| assertTrue( |
| "failed without splitting", |
| equals.test(expected, applyItemsWithoutSplitting(collector, t1, t2))); |
| assertTrue( |
| "failed with splitting", equals.test(expected, applyItemsWithSplitting(collector, t1, t2))); |
| } |
| |
| /** |
| * This method attempts to apply a collector to items as a stream might do, so that we |
| * can simply verify the output. Taken from the Collector class's javadoc. |
| */ |
| private static <T, A, R> void applyItems(R expected, Collector<T, A, R> collector, T t1, T t2) { |
| applyItems(expected, collector, t1, t2, Object::equals); |
| } |
| |
| /** |
| * Helper for applyItems. |
| */ |
| private static <T, A, R> R applyItemsWithoutSplitting(Collector<T, A, R> collector, T t1, T t2) { |
| Supplier<A> supplier = collector.supplier(); |
| BiConsumer<A, T> accumulator = collector.accumulator(); |
| // unused in this impl |
| BinaryOperator<A> combiner = collector.combiner(); |
| Function<A, R> finisher = collector.finisher(); |
| |
| A a1 = supplier.get(); |
| |
| accumulator.accept(a1, t1); |
| accumulator.accept(a1, t2); |
| |
| // result without splitting |
| R r1 = finisher.apply(a1); |
| return r1; |
| } |
| |
| /** |
| * Helper for applyItems. |
| */ |
| private static <T, A, R> R applyItemsWithSplitting(Collector<T, A, R> collector, T t1, T t2) { |
| Supplier<A> supplier = collector.supplier(); |
| BiConsumer<A, T> accumulator = collector.accumulator(); |
| // actually used in this impl |
| BinaryOperator<A> combiner = collector.combiner(); |
| Function<A, R> finisher = collector.finisher(); |
| |
| A a2 = supplier.get(); |
| accumulator.accept(a2, t1); |
| A a3 = supplier.get(); |
| accumulator.accept(a3, t2); |
| |
| // result with splitting |
| R r2 = finisher.apply(combiner.apply(a2, a3)); |
| return r2; |
| } |
| |
| private static <T, A, R> void assertZeroItemsCollectedAs( |
| R expected, Collector<T, A, R> collector) { |
| assertZeroItemsCollectedAs(expected, collector, Object::equals); |
| } |
| |
| private static <T, A, R> void assertZeroItemsCollectedAs( |
| R expected, Collector<T, A, R> collector, BiPredicate<R, R> equals) { |
| Supplier<A> supplier = collector.supplier(); |
| // unused in this impl |
| BiConsumer<A, T> accumulator = collector.accumulator(); |
| // shouldn't really be used, just handy to poke the internals quick |
| BinaryOperator<A> combiner = collector.combiner(); |
| Function<A, R> finisher = collector.finisher(); |
| |
| R actual = finisher.apply(supplier.get()); |
| assertTrue(equals, expected, actual); |
| // doesn't actually ever happen, just internal checks |
| actual = finisher.apply(combiner.apply(supplier.get(), supplier.get())); |
| assertTrue(equals, expected, actual); |
| } |
| |
| private static <T, A, R> void assertSingleItemCollectedAs( |
| R expected, Collector<T, A, R> collector, T item) { |
| assertSingleItemCollectedAs(expected, collector, item, Object::equals); |
| } |
| |
| private static <T, A, R> void assertSingleItemCollectedAs( |
| R expected, Collector<T, A, R> collector, T item, BiPredicate<R, R> equals) { |
| Supplier<A> supplier = collector.supplier(); |
| BiConsumer<A, T> accumulator = collector.accumulator(); |
| // shouldn't really be used, just handy to poke the internals quick |
| BinaryOperator<A> combiner = collector.combiner(); |
| Function<A, R> finisher = collector.finisher(); |
| |
| A a1 = supplier.get(); |
| |
| accumulator.accept(a1, item); |
| |
| R actual = finisher.apply(a1); |
| // normal test |
| assertTrue(equals, expected, actual); |
| // these shouldn't really be used, just handy to poke the internals quick |
| actual = finisher.apply(combiner.apply(a1, supplier.get())); |
| assertTrue(equals, expected, actual); |
| actual = finisher.apply(combiner.apply(supplier.get(), a1)); |
| assertTrue(equals, expected, actual); |
| } |
| |
| private static <T, U> void assertTrue(BiPredicate<T, U> predicate, T expected, U actual) { |
| assertTrue("expected= " + expected + ", actual=" + actual, predicate.test(expected, actual)); |
| } |
| |
| } |