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 org.openjdk.testlib.java.util.stream.CollectorOps;
28import org.openjdk.testlib.java.util.stream.OpTestCase;
29import org.openjdk.testlib.java.util.stream.StreamTestDataProvider;
30import org.openjdk.testlib.java.util.stream.TestData;
31import org.openjdk.testlib.java.util.stream.*;
32
33import java.util.*;
34import java.util.Spliterators;
35import java.util.concurrent.atomic.AtomicInteger;
36import java.util.function.BiFunction;
37import java.util.function.Consumer;
38import java.util.function.Function;
39import java.util.function.Supplier;
40import java.util.stream.BaseStream;
41import java.util.stream.DoubleStream;
42import java.util.stream.IntStream;
43import java.util.stream.LongStream;
44import java.util.stream.Stream;
45import java.util.stream.StreamSupport;
46
47import static org.openjdk.testlib.java.util.stream.LambdaTestHelpers.*;
48
49/**
50 * SortedOpTest
51 *
52 * @author Brian Goetz
53 */
54@Test
55public class SortedOpTest extends OpTestCase {
56
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
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
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
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
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
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" })
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
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)
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)
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" })
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
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)
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)
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" })
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
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)
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)
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" })
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
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)
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)
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     */
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