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