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