1 /*
2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package org.openjdk.tests.java.util.stream;
24
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.Comparator;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Optional;
36 import java.util.Set;
37 import java.util.StringJoiner;
38 import java.util.TreeMap;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.ConcurrentSkipListMap;
41 import java.util.concurrent.atomic.AtomicInteger;
42 import java.util.function.BinaryOperator;
43 import java.util.function.Function;
44 import java.util.function.Predicate;
45 import java.util.function.Supplier;
46 import java.util.stream.Collector;
47 import java.util.stream.Collectors;
48 import java.util.stream.LambdaTestHelpers;
49 import java.util.stream.OpTestCase;
50 import java.util.stream.Stream;
51 import java.util.stream.StreamOpFlagTestHelper;
52 import java.util.stream.StreamTestDataProvider;
53 import java.util.stream.TestData;
54
55 import org.testng.annotations.Test;
56
57 import static java.util.stream.Collectors.collectingAndThen;
58 import static java.util.stream.Collectors.flatMapping;
59 import static java.util.stream.Collectors.filtering;
60 import static java.util.stream.Collectors.groupingBy;
61 import static java.util.stream.Collectors.groupingByConcurrent;
79 public class CollectorsTest extends OpTestCase {
80
81 private abstract static class CollectorAssertion<T, U> {
82 abstract void assertValue(U value,
83 Supplier<Stream<T>> source,
84 boolean ordered) throws ReflectiveOperationException;
85 }
86
87 static class MappingAssertion<T, V, R> extends CollectorAssertion<T, R> {
88 private final Function<T, V> mapper;
89 private final CollectorAssertion<V, R> downstream;
90
91 MappingAssertion(Function<T, V> mapper, CollectorAssertion<V, R> downstream) {
92 this.mapper = mapper;
93 this.downstream = downstream;
94 }
95
96 @Override
97 void assertValue(R value, Supplier<Stream<T>> source, boolean ordered) throws ReflectiveOperationException {
98 downstream.assertValue(value,
99 () -> source.get().map(mapper::apply),
100 ordered);
101 }
102 }
103
104 static class FlatMappingAssertion<T, V, R> extends CollectorAssertion<T, R> {
105 private final Function<T, Stream<V>> mapper;
106 private final CollectorAssertion<V, R> downstream;
107
108 FlatMappingAssertion(Function<T, Stream<V>> mapper,
109 CollectorAssertion<V, R> downstream) {
110 this.mapper = mapper;
111 this.downstream = downstream;
112 }
113
114 @Override
115 void assertValue(R value, Supplier<Stream<T>> source, boolean ordered) throws ReflectiveOperationException {
116 downstream.assertValue(value,
117 () -> source.get().flatMap(mapper::apply),
118 ordered);
119 }
120 }
121
122 static class FilteringAssertion<T, R> extends CollectorAssertion<T, R> {
123 private final Predicate<T> filter;
124 private final CollectorAssertion<T, R> downstream;
125
126 public FilteringAssertion(Predicate<T> filter, CollectorAssertion<T, R> downstream) {
127 this.filter = filter;
128 this.downstream = downstream;
129 }
130
131 @Override
132 void assertValue(R value, Supplier<Stream<T>> source, boolean ordered) throws ReflectiveOperationException {
133 downstream.assertValue(value,
134 () -> source.get().filter(filter),
135 ordered);
136 }
137 }
270 this.identity = identity;
271 this.mapper = mapper;
272 this.reducer = reducer;
273 }
274
275 @Override
276 void assertValue(U value, Supplier<Stream<T>> source, boolean ordered)
277 throws ReflectiveOperationException {
278 Optional<U> reduced = source.get().map(mapper).reduce(reducer);
279 if (value == null)
280 assertTrue(!reduced.isPresent());
281 else if (!reduced.isPresent()) {
282 assertEquals(value, identity);
283 }
284 else {
285 assertEquals(value, reduced.get());
286 }
287 }
288 }
289
290 private <T> ResultAsserter<T> mapTabulationAsserter(boolean ordered) {
291 return (act, exp, ord, par) -> {
292 if (par && (!ordered || !ord)) {
293 CollectorsTest.nestedMapEqualityAssertion(act, exp);
294 }
295 else {
296 LambdaTestHelpers.assertContentsEqual(act, exp);
297 }
298 };
299 }
300
301 private<T, M extends Map>
302 void exerciseMapCollection(TestData<T, Stream<T>> data,
303 Collector<T, ?, ? extends M> collector,
304 CollectorAssertion<T, M> assertion)
305 throws ReflectiveOperationException {
306 boolean ordered = !collector.characteristics().contains(Collector.Characteristics.UNORDERED);
307
308 M m = withData(data)
309 .terminal(s -> s.collect(collector))
729
730 // Two level partition with reduce
731 exerciseMapCollection(data,
732 partitioningBy(classifier, reducing(0, Integer::sum)),
733 new PartitioningByAssertion<>(classifier,
734 new ReducingAssertion<>(0, LambdaTestHelpers.identity(), Integer::sum)));
735 }
736
737 @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
738 public void testComposeFinisher(String name, TestData.OfRef<Integer> data) throws ReflectiveOperationException {
739 List<Integer> asList = exerciseTerminalOps(data, s -> s.collect(toList()));
740 List<Integer> asImmutableList = exerciseTerminalOps(data, s -> s.collect(collectingAndThen(toList(), Collections::unmodifiableList)));
741 assertEquals(asList, asImmutableList);
742 try {
743 asImmutableList.add(0);
744 fail("Expecting immutable result");
745 }
746 catch (UnsupportedOperationException ignored) { }
747 }
748
749 }
|
1 /*
2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package org.openjdk.tests.java.util.stream;
24
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.Comparator;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.IntSummaryStatistics;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Optional;
37 import java.util.Set;
38 import java.util.StringJoiner;
39 import java.util.TreeMap;
40 import java.util.concurrent.ConcurrentHashMap;
41 import java.util.concurrent.ConcurrentSkipListMap;
42 import java.util.concurrent.atomic.AtomicInteger;
43 import java.util.function.BiFunction;
44 import java.util.function.BinaryOperator;
45 import java.util.function.Function;
46 import java.util.function.Predicate;
47 import java.util.function.Supplier;
48 import java.util.stream.Collector;
49 import java.util.stream.Collectors;
50 import java.util.stream.LambdaTestHelpers;
51 import java.util.stream.OpTestCase;
52 import java.util.stream.Stream;
53 import java.util.stream.StreamOpFlagTestHelper;
54 import java.util.stream.StreamTestDataProvider;
55 import java.util.stream.TestData;
56
57 import org.testng.annotations.Test;
58
59 import static java.util.stream.Collectors.collectingAndThen;
60 import static java.util.stream.Collectors.flatMapping;
61 import static java.util.stream.Collectors.filtering;
62 import static java.util.stream.Collectors.groupingBy;
63 import static java.util.stream.Collectors.groupingByConcurrent;
81 public class CollectorsTest extends OpTestCase {
82
83 private abstract static class CollectorAssertion<T, U> {
84 abstract void assertValue(U value,
85 Supplier<Stream<T>> source,
86 boolean ordered) throws ReflectiveOperationException;
87 }
88
89 static class MappingAssertion<T, V, R> extends CollectorAssertion<T, R> {
90 private final Function<T, V> mapper;
91 private final CollectorAssertion<V, R> downstream;
92
93 MappingAssertion(Function<T, V> mapper, CollectorAssertion<V, R> downstream) {
94 this.mapper = mapper;
95 this.downstream = downstream;
96 }
97
98 @Override
99 void assertValue(R value, Supplier<Stream<T>> source, boolean ordered) throws ReflectiveOperationException {
100 downstream.assertValue(value,
101 () -> source.get().map(mapper),
102 ordered);
103 }
104 }
105
106 static class FlatMappingAssertion<T, V, R> extends CollectorAssertion<T, R> {
107 private final Function<T, Stream<V>> mapper;
108 private final CollectorAssertion<V, R> downstream;
109
110 FlatMappingAssertion(Function<T, Stream<V>> mapper,
111 CollectorAssertion<V, R> downstream) {
112 this.mapper = mapper;
113 this.downstream = downstream;
114 }
115
116 @Override
117 void assertValue(R value, Supplier<Stream<T>> source, boolean ordered) throws ReflectiveOperationException {
118 downstream.assertValue(value,
119 () -> source.get().flatMap(mapper),
120 ordered);
121 }
122 }
123
124 static class FilteringAssertion<T, R> extends CollectorAssertion<T, R> {
125 private final Predicate<T> filter;
126 private final CollectorAssertion<T, R> downstream;
127
128 public FilteringAssertion(Predicate<T> filter, CollectorAssertion<T, R> downstream) {
129 this.filter = filter;
130 this.downstream = downstream;
131 }
132
133 @Override
134 void assertValue(R value, Supplier<Stream<T>> source, boolean ordered) throws ReflectiveOperationException {
135 downstream.assertValue(value,
136 () -> source.get().filter(filter),
137 ordered);
138 }
139 }
272 this.identity = identity;
273 this.mapper = mapper;
274 this.reducer = reducer;
275 }
276
277 @Override
278 void assertValue(U value, Supplier<Stream<T>> source, boolean ordered)
279 throws ReflectiveOperationException {
280 Optional<U> reduced = source.get().map(mapper).reduce(reducer);
281 if (value == null)
282 assertTrue(!reduced.isPresent());
283 else if (!reduced.isPresent()) {
284 assertEquals(value, identity);
285 }
286 else {
287 assertEquals(value, reduced.get());
288 }
289 }
290 }
291
292 static class DuplexingAssertion<T, R1, R2, RR> extends CollectorAssertion<T, RR> {
293 private final Collector<T, ?, R1> c1;
294 private final Collector<T, ?, R2> c2;
295 private final BiFunction<? super R1, ? super R2, ? extends RR> finisher;
296
297 DuplexingAssertion(Collector<T, ?, R1> c1, Collector<T, ?, R2> c2,
298 BiFunction<? super R1, ? super R2, ? extends RR> finisher) {
299 this.c1 = c1;
300 this.c2 = c2;
301 this.finisher = finisher;
302 }
303
304 @Override
305 void assertValue(RR value, Supplier<Stream<T>> source, boolean ordered) {
306 R1 r1 = source.get().collect(c1);
307 R2 r2 = source.get().collect(c2);
308 RR expected = finisher.apply(r1, r2);
309 assertEquals(value, expected);
310 }
311 }
312
313 private <T> ResultAsserter<T> mapTabulationAsserter(boolean ordered) {
314 return (act, exp, ord, par) -> {
315 if (par && (!ordered || !ord)) {
316 CollectorsTest.nestedMapEqualityAssertion(act, exp);
317 }
318 else {
319 LambdaTestHelpers.assertContentsEqual(act, exp);
320 }
321 };
322 }
323
324 private<T, M extends Map>
325 void exerciseMapCollection(TestData<T, Stream<T>> data,
326 Collector<T, ?, ? extends M> collector,
327 CollectorAssertion<T, M> assertion)
328 throws ReflectiveOperationException {
329 boolean ordered = !collector.characteristics().contains(Collector.Characteristics.UNORDERED);
330
331 M m = withData(data)
332 .terminal(s -> s.collect(collector))
752
753 // Two level partition with reduce
754 exerciseMapCollection(data,
755 partitioningBy(classifier, reducing(0, Integer::sum)),
756 new PartitioningByAssertion<>(classifier,
757 new ReducingAssertion<>(0, LambdaTestHelpers.identity(), Integer::sum)));
758 }
759
760 @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
761 public void testComposeFinisher(String name, TestData.OfRef<Integer> data) throws ReflectiveOperationException {
762 List<Integer> asList = exerciseTerminalOps(data, s -> s.collect(toList()));
763 List<Integer> asImmutableList = exerciseTerminalOps(data, s -> s.collect(collectingAndThen(toList(), Collections::unmodifiableList)));
764 assertEquals(asList, asImmutableList);
765 try {
766 asImmutableList.add(0);
767 fail("Expecting immutable result");
768 }
769 catch (UnsupportedOperationException ignored) { }
770 }
771
772 @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
773 public void testDuplexing(String name, TestData.OfRef<Integer> data) throws ReflectiveOperationException {
774 Collector<Integer, ?, Long> summing = Collectors.summingLong(Integer::valueOf);
775 Collector<Integer, ?, Long> counting = Collectors.counting();
776 Collector<Integer, ?, Integer> min = collectingAndThen(Collectors.<Integer>minBy(Comparator.naturalOrder()),
777 opt -> opt.orElse(Integer.MAX_VALUE));
778 Collector<Integer, ?, Integer> max = collectingAndThen(Collectors.<Integer>maxBy(Comparator.naturalOrder()),
779 opt -> opt.orElse(Integer.MIN_VALUE));
780 Collector<Integer, ?, String> joining = mapping(String::valueOf, Collectors.joining(", ", "[", "]"));
781
782 Collector<Integer, ?, Map.Entry<Long, Long>> sumAndCount = Collectors.duplexing(summing, counting, Map::entry);
783 Collector<Integer, ?, Map.Entry<Integer, Integer>> minAndMax = Collectors.duplexing(min, max, Map::entry);
784 Collector<Integer, ?, Double> averaging = Collectors.duplexing(summing, counting,
785 (sum, count) -> ((double)sum) / count);
786 Collector<Integer, ?, String> summaryStatistics = Collectors.duplexing(sumAndCount, minAndMax,
787 (sumCountEntry, minMaxEntry) -> new IntSummaryStatistics(
788 sumCountEntry.getValue(), minMaxEntry.getKey(),
789 minMaxEntry.getValue(), sumCountEntry.getKey()).toString());
790 Collector<Integer, ?, String> countAndContent = Collectors.duplexing(counting, joining,
791 (count, content) -> count+": "+content);
792
793 assertCollect(data, sumAndCount, stream -> {
794 List<Integer> list = stream.collect(toList());
795 return Map.entry(list.stream().mapToLong(Integer::intValue).sum(), (long) list.size());
796 });
797 assertCollect(data, averaging, stream -> stream.mapToInt(Integer::intValue).average().orElse(Double.NaN));
798 assertCollect(data, summaryStatistics,
799 stream -> stream.mapToInt(Integer::intValue).summaryStatistics().toString());
800 assertCollect(data, countAndContent, stream -> {
801 List<Integer> list = stream.collect(toList());
802 return list.size()+": "+list;
803 });
804
805 Function<Integer, Integer> classifier = i -> i % 3;
806 exerciseMapCollection(data, groupingBy(classifier, sumAndCount),
807 new GroupingByAssertion<>(classifier, Map.class,
808 new DuplexingAssertion<>(summing, counting, Map::entry)));
809 }
810 }
|