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 */
23package org.openjdk.tests.java.util.stream;
24
25import org.testng.annotations.Test;
26
27import java.util.*;
28import java.util.Spliterators;
29import java.util.concurrent.atomic.AtomicInteger;
30import java.util.function.BiFunction;
31import java.util.function.Consumer;
32import java.util.function.Function;
33import java.util.function.Supplier;
34import java.util.stream.*;
35
36import static java.util.stream.LambdaTestHelpers.*;
37
38/**
39 * SortedOpTest
40 *
41 * @author Brian Goetz
42 */
43@Test
44public class SortedOpTest extends OpTestCase {
45
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
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
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
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
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
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" })
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
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)
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)
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" })
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
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)
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)
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" })
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
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)
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)
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" })
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
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)
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)
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     */
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