1 /*
2  * Copyright (c) 2012, 2013, 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 org.testng.annotations.Test;
26 
27 import org.openjdk.testlib.java.util.stream.CollectorOps;
28 import org.openjdk.testlib.java.util.stream.DoubleStreamTestDataProvider;
29 import org.openjdk.testlib.java.util.stream.IntStreamTestDataProvider;
30 import org.openjdk.testlib.java.util.stream.LongStreamTestDataProvider;
31 import org.openjdk.testlib.java.util.stream.OpTestCase;
32 import org.openjdk.testlib.java.util.stream.StreamTestDataProvider;
33 import org.openjdk.testlib.java.util.stream.TestData;
34 
35 import java.util.*;
36 import java.util.Spliterators;
37 import java.util.concurrent.atomic.AtomicInteger;
38 import java.util.function.BiFunction;
39 import java.util.function.Consumer;
40 import java.util.function.Function;
41 import java.util.function.Supplier;
42 import java.util.stream.BaseStream;
43 import java.util.stream.DoubleStream;
44 import java.util.stream.IntStream;
45 import java.util.stream.LongStream;
46 import java.util.stream.Stream;
47 import java.util.stream.StreamSupport;
48 
49 import static org.openjdk.testlib.java.util.stream.LambdaTestHelpers.*;
50 import java.util.stream.*;
51 
52 /**
53  * SortedOpTest
54  *
55  * @author Brian Goetz
56  */
57 @Test
58 public class SortedOpTest extends OpTestCase {
59 
testRefStreamTooLarge()60     public void testRefStreamTooLarge() {
61         Function<LongStream, Stream<Long>> f = s ->
62                 // Clear the SORTED flag
63                 s.mapToObj(i -> i)
64                 .sorted();
65 
66         testStreamTooLarge(f, Stream::findFirst);
67     }
68 
testIntStreamTooLarge()69     public void testIntStreamTooLarge() {
70         Function<LongStream, IntStream> f = s ->
71                 // Clear the SORTED flag
72                 s.mapToInt(i -> (int) i)
73                 .sorted();
74 
75         testStreamTooLarge(f, IntStream::findFirst);
76     }
77 
testLongStreamTooLarge()78     public void testLongStreamTooLarge() {
79         Function<LongStream, LongStream> f = s ->
80                 // Clear the SORTED flag
81                 s.map(i -> i)
82                 .sorted();
83 
84         testStreamTooLarge(f, LongStream::findFirst);
85     }
86 
testDoubleStreamTooLarge()87     public void testDoubleStreamTooLarge() {
88         Function<LongStream, DoubleStream> f = s ->
89                 // Clear the SORTED flag
90                 s.mapToDouble(i -> (double) i)
91                 .sorted();
92 
93         testStreamTooLarge(f, DoubleStream::findFirst);
94     }
95 
testStreamTooLarge(Function<LongStream, S> s, Function<S, ?> terminal)96     <T, S extends BaseStream<T, S>> void testStreamTooLarge(Function<LongStream, S> s,
97                                                             Function<S, ?> terminal) {
98         // Set up conditions for a large input > maximum array size
99         Supplier<LongStream> input = () -> LongStream.range(0, 1L + Integer.MAX_VALUE);
100 
101         // Transformation functions
102         List<Function<LongStream, LongStream>> transforms = Arrays.asList(
103                 ls -> ls,
104                 ls -> ls.parallel(),
105                 // Clear the SIZED flag
106                 ls -> ls.limit(Long.MAX_VALUE),
107                 ls -> ls.limit(Long.MAX_VALUE).parallel());
108 
109         for (Function<LongStream, LongStream> transform : transforms) {
110             RuntimeException caught = null;
111             try {
112                 terminal.apply(s.apply(transform.apply(input.get())));
113             } catch (RuntimeException e) {
114                 caught = e;
115             }
116             assertNotNull(caught, "Expected an instance of exception IllegalArgumentException but no exception thrown");
117             assertTrue(caught instanceof IllegalArgumentException,
118                        String.format("Expected an instance of exception IllegalArgumentException but got %s", caught));
119         }
120     }
121 
testSorted()122     public void testSorted() {
123         assertCountSum(countTo(0).stream().sorted(), 0, 0);
124         assertCountSum(countTo(10).stream().sorted(), 10, 55);
125         assertCountSum(countTo(10).stream().sorted(cInteger.reversed()), 10, 55);
126 
127         List<Integer> to10 = countTo(10);
128         assertSorted(to10.stream().sorted(cInteger.reversed()).iterator(), cInteger.reversed());
129 
130         Collections.reverse(to10);
131         assertSorted(to10.stream().sorted().iterator());
132 
133         Spliterator<Integer> s = to10.stream().sorted().spliterator();
134         assertTrue(s.hasCharacteristics(Spliterator.SORTED));
135 
136         s = to10.stream().sorted(cInteger.reversed()).spliterator();
137         assertFalse(s.hasCharacteristics(Spliterator.SORTED));
138     }
139 
140     @Test(groups = { "serialization-hostile" })
testSequentialShortCircuitTerminal()141     public void testSequentialShortCircuitTerminal() {
142         // The sorted op for sequential evaluation will buffer all elements when
143         // accepting then at the end sort those elements and push those elements
144         // downstream
145         // A peek operation is added in-between the sorted() and terminal
146         // operation that counts the number of calls to its consumer and
147         // asserts that the number of calls is at most the required quantity
148 
149         List<Integer> l = Arrays.asList(5, 4, 3, 2, 1);
150 
151         Function<Integer, Stream<Integer>> knownSize = i -> assertNCallsOnly(
152                 l.stream().sorted(), Stream::peek, i);
153         Function<Integer, Stream<Integer>> unknownSize = i -> assertNCallsOnly
154                 (unknownSizeStream(l).sorted(), Stream::peek, i);
155 
156         // Find
157         assertEquals(knownSize.apply(1).findFirst(), Optional.of(1));
158         assertEquals(knownSize.apply(1).findAny(), Optional.of(1));
159         assertEquals(unknownSize.apply(1).findFirst(), Optional.of(1));
160         assertEquals(unknownSize.apply(1).findAny(), Optional.of(1));
161 
162         // Match
163         assertEquals(knownSize.apply(2).anyMatch(i -> i == 2), true);
164         assertEquals(knownSize.apply(2).noneMatch(i -> i == 2), false);
165         assertEquals(knownSize.apply(2).allMatch(i -> i == 2), false);
166         assertEquals(unknownSize.apply(2).anyMatch(i -> i == 2), true);
167         assertEquals(unknownSize.apply(2).noneMatch(i -> i == 2), false);
168         assertEquals(unknownSize.apply(2).allMatch(i -> i == 2), false);
169     }
170 
unknownSizeStream(List<T> l)171     private <T> Stream<T> unknownSizeStream(List<T> l) {
172         return StreamSupport.stream(Spliterators.spliteratorUnknownSize(l.iterator(), 0), false);
173     }
174 
175     @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
testOps(String name, TestData.OfRef<Integer> data)176     public void testOps(String name, TestData.OfRef<Integer> data) {
177         Collection<Integer> result = exerciseOpsInt(data, Stream::sorted, IntStream::sorted, LongStream::sorted, DoubleStream::sorted);
178         assertSorted(result.iterator());
179         assertContentsUnordered(data, result);
180 
181         result = exerciseOps(data, s -> s.sorted(cInteger.reversed()));
182         assertSorted(result.iterator(), cInteger.reversed());
183         assertContentsUnordered(data, result);
184     }
185 
186     @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
testSortSort(String name, TestData.OfRef<Integer> data)187     public void testSortSort(String name, TestData.OfRef<Integer> data) {
188         // For parallel cases ensure the size is known
189         Collection<Integer> result = withData(data)
190                 .stream(s -> s.sorted().sorted(),
191                         new CollectorOps.TestParallelSizedOp<Integer>())
192                 .exercise();
193 
194         assertSorted(result);
195         assertContentsUnordered(data, result);
196 
197         result = withData(data)
198                 .stream(s -> s.sorted(cInteger.reversed()).sorted(cInteger.reversed()),
199                         new CollectorOps.TestParallelSizedOp<Integer>())
200                 .exercise();
201 
202         assertSorted(result, cInteger.reversed());
203         assertContentsUnordered(data, result);
204 
205         result = withData(data)
206                 .stream(s -> s.sorted().sorted(cInteger.reversed()),
207                         new CollectorOps.TestParallelSizedOp<Integer>())
208                 .exercise();
209 
210         assertSorted(result, cInteger.reversed());
211         assertContentsUnordered(data, result);
212 
213         result = withData(data)
214                 .stream(s -> s.sorted(cInteger.reversed()).sorted(),
215                         new CollectorOps.TestParallelSizedOp<Integer>())
216                 .exercise();
217 
218         assertSorted(result);
219         assertContentsUnordered(data, result);
220     }
221 
222     //
223 
224     @Test(groups = { "serialization-hostile" })
testIntSequentialShortCircuitTerminal()225     public void testIntSequentialShortCircuitTerminal() {
226         int[] a = new int[]{5, 4, 3, 2, 1};
227 
228         Function<Integer, IntStream> knownSize = i -> assertNCallsOnly(
229                 Arrays.stream(a).sorted(), (s, c) -> s.peek(c::accept), i);
230         Function<Integer, IntStream> unknownSize = i -> assertNCallsOnly
231                 (unknownSizeIntStream(a).sorted(), (s, c) -> s.peek(c::accept), i);
232 
233         // Find
234         assertEquals(knownSize.apply(1).findFirst(), OptionalInt.of(1));
235         assertEquals(knownSize.apply(1).findAny(), OptionalInt.of(1));
236         assertEquals(unknownSize.apply(1).findFirst(), OptionalInt.of(1));
237         assertEquals(unknownSize.apply(1).findAny(), OptionalInt.of(1));
238 
239         // Match
240         assertEquals(knownSize.apply(2).anyMatch(i -> i == 2), true);
241         assertEquals(knownSize.apply(2).noneMatch(i -> i == 2), false);
242         assertEquals(knownSize.apply(2).allMatch(i -> i == 2), false);
243         assertEquals(unknownSize.apply(2).anyMatch(i -> i == 2), true);
244         assertEquals(unknownSize.apply(2).noneMatch(i -> i == 2), false);
245         assertEquals(unknownSize.apply(2).allMatch(i -> i == 2), false);
246     }
247 
unknownSizeIntStream(int[] a)248     private IntStream unknownSizeIntStream(int[] a) {
249         return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(a)), 0), false);
250     }
251 
252     @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
testIntOps(String name, TestData.OfInt data)253     public void testIntOps(String name, TestData.OfInt data) {
254         Collection<Integer> result = exerciseOps(data, s -> s.sorted());
255         assertSorted(result);
256         assertContentsUnordered(data, result);
257     }
258 
259     @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
testIntSortSort(String name, TestData.OfInt data)260     public void testIntSortSort(String name, TestData.OfInt data) {
261         // For parallel cases ensure the size is known
262         Collection<Integer> result = withData(data)
263                 .stream(s -> s.sorted().sorted(), new CollectorOps.TestParallelSizedOp.OfInt())
264                 .exercise();
265 
266         assertSorted(result);
267         assertContentsUnordered(data, result);
268     }
269 
270     //
271 
272     @Test(groups = { "serialization-hostile" })
testLongSequentialShortCircuitTerminal()273     public void testLongSequentialShortCircuitTerminal() {
274         long[] a = new long[]{5, 4, 3, 2, 1};
275 
276         Function<Integer, LongStream> knownSize = i -> assertNCallsOnly(
277                 Arrays.stream(a).sorted(), (s, c) -> s.peek(c::accept), i);
278         Function<Integer, LongStream> unknownSize = i -> assertNCallsOnly
279                 (unknownSizeLongStream(a).sorted(), (s, c) -> s.peek(c::accept), i);
280 
281         // Find
282         assertEquals(knownSize.apply(1).findFirst(), OptionalLong.of(1));
283         assertEquals(knownSize.apply(1).findAny(), OptionalLong.of(1));
284         assertEquals(unknownSize.apply(1).findFirst(), OptionalLong.of(1));
285         assertEquals(unknownSize.apply(1).findAny(), OptionalLong.of(1));
286 
287         // Match
288         assertEquals(knownSize.apply(2).anyMatch(i -> i == 2), true);
289         assertEquals(knownSize.apply(2).noneMatch(i -> i == 2), false);
290         assertEquals(knownSize.apply(2).allMatch(i -> i == 2), false);
291         assertEquals(unknownSize.apply(2).anyMatch(i -> i == 2), true);
292         assertEquals(unknownSize.apply(2).noneMatch(i -> i == 2), false);
293         assertEquals(unknownSize.apply(2).allMatch(i -> i == 2), false);
294     }
295 
unknownSizeLongStream(long[] a)296     private LongStream unknownSizeLongStream(long[] a) {
297         return StreamSupport.longStream(Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(a)), 0), false);
298     }
299 
300     @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
testLongOps(String name, TestData.OfLong data)301     public void testLongOps(String name, TestData.OfLong data) {
302         Collection<Long> result = exerciseOps(data, s -> s.sorted());
303         assertSorted(result);
304         assertContentsUnordered(data, result);
305     }
306 
307     @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
testLongSortSort(String name, TestData.OfLong data)308     public void testLongSortSort(String name, TestData.OfLong data) {
309         // For parallel cases ensure the size is known
310         Collection<Long> result = withData(data)
311                 .stream(s -> s.sorted().sorted(), new CollectorOps.TestParallelSizedOp.OfLong())
312                 .exercise();
313 
314         assertSorted(result);
315         assertContentsUnordered(data, result);
316     }
317 
318     //
319 
320     @Test(groups = { "serialization-hostile" })
testDoubleSequentialShortCircuitTerminal()321     public void testDoubleSequentialShortCircuitTerminal() {
322         double[] a = new double[]{5.0, 4.0, 3.0, 2.0, 1.0};
323 
324         Function<Integer, DoubleStream> knownSize = i -> assertNCallsOnly(
325                 Arrays.stream(a).sorted(), (s, c) -> s.peek(c::accept), i);
326         Function<Integer, DoubleStream> unknownSize = i -> assertNCallsOnly
327                 (unknownSizeDoubleStream(a).sorted(), (s, c) -> s.peek(c::accept), i);
328 
329         // Find
330         assertEquals(knownSize.apply(1).findFirst(), OptionalDouble.of(1));
331         assertEquals(knownSize.apply(1).findAny(), OptionalDouble.of(1));
332         assertEquals(unknownSize.apply(1).findFirst(), OptionalDouble.of(1));
333         assertEquals(unknownSize.apply(1).findAny(), OptionalDouble.of(1));
334 
335         // Match
336         assertEquals(knownSize.apply(2).anyMatch(i -> i == 2.0), true);
337         assertEquals(knownSize.apply(2).noneMatch(i -> i == 2.0), false);
338         assertEquals(knownSize.apply(2).allMatch(i -> i == 2.0), false);
339         assertEquals(unknownSize.apply(2).anyMatch(i -> i == 2.0), true);
340         assertEquals(unknownSize.apply(2).noneMatch(i -> i == 2.0), false);
341         assertEquals(unknownSize.apply(2).allMatch(i -> i == 2.0), false);
342     }
343 
unknownSizeDoubleStream(double[] a)344     private DoubleStream unknownSizeDoubleStream(double[] a) {
345         return StreamSupport.doubleStream(Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(a)), 0), false);
346     }
347 
348     @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
testDoubleOps(String name, TestData.OfDouble data)349     public void testDoubleOps(String name, TestData.OfDouble data) {
350         Collection<Double> result = exerciseOps(data, s -> s.sorted());
351         assertSorted(result);
352         assertContentsUnordered(data, result);
353     }
354 
355     @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
testDoubleSortSort(String name, TestData.OfDouble data)356     public void testDoubleSortSort(String name, TestData.OfDouble data) {
357         // For parallel cases ensure the size is known
358         Collection<Double> result = withData(data)
359                 .stream(s -> s.sorted().sorted(), new CollectorOps.TestParallelSizedOp.OfDouble())
360                 .exercise();
361 
362         assertSorted(result);
363         assertContentsUnordered(data, result);
364     }
365 
366     /**
367      * Interpose a consumer that asserts it is called at most N times.
368      */
assertNCallsOnly(S s, BiFunction<S, Consumer<T>, S> pf, int n)369     <T, S extends BaseStream<T, S>, R> S assertNCallsOnly(S s, BiFunction<S, Consumer<T>, S> pf, int n) {
370         AtomicInteger boxedInt = new AtomicInteger();
371         return pf.apply(s, i -> {
372             assertFalse(boxedInt.incrementAndGet() > n, "Intermediate op called more than " + n + " time(s)");
373         });
374     }
375 }
376