1/*
2 * Copyright (c) 2012, 2015, 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.DataProvider;
26import org.testng.annotations.Test;
27
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.DoubleStreamTestScenario;
32import org.openjdk.testlib.java.util.stream.IntStreamTestScenario;
33import org.openjdk.testlib.java.util.stream.LongStreamTestScenario;
34import org.openjdk.testlib.java.util.stream.LambdaTestHelpers;
35import org.openjdk.testlib.java.util.stream.StreamTestScenario;
36
37import java.lang.reflect.InvocationHandler;
38import java.lang.reflect.Method;
39import java.lang.reflect.Proxy;
40import java.util.ArrayList;
41import java.util.List;
42import java.util.Spliterator;
43import java.util.function.Function;
44import java.util.function.UnaryOperator;
45import java.util.stream.DoubleStream;
46import java.util.stream.IntStream;
47import java.util.stream.LongStream;
48import java.util.stream.Stream;
49import java.util.stream.StreamSupport;
50
51import static org.openjdk.testlib.java.util.stream.LambdaTestHelpers.assertUnique;
52
53
54@Test
55public class InfiniteStreamWithLimitOpTest extends OpTestCase {
56
57    private static final long SKIP_LIMIT_SIZE = 1 << 16;
58
59    @DataProvider(name = "Stream.limit")
60    @SuppressWarnings("rawtypes")
61    public static Object[][] sliceFunctionsDataProvider() {
62        Function<String, String> f = s -> String.format(s, SKIP_LIMIT_SIZE);
63
64        List<Object[]> data = new ArrayList<>();
65
66        data.add(new Object[]{f.apply("Stream.limit(%d)"),
67                (UnaryOperator<Stream>) s -> s.limit(SKIP_LIMIT_SIZE)});
68        data.add(new Object[]{f.apply("Stream.skip(%1$d).limit(%1$d)"),
69                (UnaryOperator<Stream>) s -> s.skip(SKIP_LIMIT_SIZE).limit(SKIP_LIMIT_SIZE)});
70
71        return data.toArray(new Object[0][]);
72    }
73
74    @DataProvider(name = "IntStream.limit")
75    public static Object[][] intSliceFunctionsDataProvider() {
76        Function<String, String> f = s -> String.format(s, SKIP_LIMIT_SIZE);
77
78        List<Object[]> data = new ArrayList<>();
79
80        data.add(new Object[]{f.apply("IntStream.limit(%d)"),
81                (UnaryOperator<IntStream>) s -> s.limit(SKIP_LIMIT_SIZE)});
82        data.add(new Object[]{f.apply("IntStream.skip(%1$d).limit(%1$d)"),
83                (UnaryOperator<IntStream>) s -> s.skip(SKIP_LIMIT_SIZE).limit(SKIP_LIMIT_SIZE)});
84
85        return data.toArray(new Object[0][]);
86    }
87
88    @DataProvider(name = "LongStream.limit")
89    public static Object[][] longSliceFunctionsDataProvider() {
90        Function<String, String> f = s -> String.format(s, SKIP_LIMIT_SIZE);
91
92        List<Object[]> data = new ArrayList<>();
93
94        data.add(new Object[]{f.apply("LongStream.limit(%d)"),
95                (UnaryOperator<LongStream>) s -> s.limit(SKIP_LIMIT_SIZE)});
96        data.add(new Object[]{f.apply("LongStream.skip(%1$d).limit(%1$d)"),
97                (UnaryOperator<LongStream>) s -> s.skip(SKIP_LIMIT_SIZE).limit(SKIP_LIMIT_SIZE)});
98
99        return data.toArray(new Object[0][]);
100    }
101
102    @DataProvider(name = "DoubleStream.limit")
103    public static Object[][] doubleSliceFunctionsDataProvider() {
104        Function<String, String> f = s -> String.format(s, SKIP_LIMIT_SIZE);
105
106        List<Object[]> data = new ArrayList<>();
107
108        data.add(new Object[]{f.apply("DoubleStream.limit(%d)"),
109                (UnaryOperator<DoubleStream>) s -> s.limit(SKIP_LIMIT_SIZE)});
110        data.add(new Object[]{f.apply("DoubleStream.skip(%1$d).limit(%1$d)"),
111                (UnaryOperator<DoubleStream>) s -> s.skip(SKIP_LIMIT_SIZE).limit(SKIP_LIMIT_SIZE)});
112
113        return data.toArray(new Object[0][]);
114    }
115
116    private <T> ResultAsserter<Iterable<T>> unorderedAsserter() {
117        return (act, exp, ord, par) -> {
118            if (par & !ord) {
119                // Can only assert that all elements of the actual result
120                // are distinct and that the count is the limit size
121                // any element within the range [0, Long.MAX_VALUE) may be
122                // present
123                assertUnique(act);
124                long count = 0;
125                for (T l : act) {
126                    count++;
127                }
128                assertEquals(count, SKIP_LIMIT_SIZE, "size not equal");
129            }
130            else {
131                LambdaTestHelpers.assertContents(act, exp);
132            }
133        };
134    }
135
136    private TestData.OfRef<Long> refLongs() {
137        return refLongRange(0, Long.MAX_VALUE);
138    }
139
140    private TestData.OfRef<Long> refLongRange(long l, long u) {
141        return TestData.Factory.ofSupplier(
142                String.format("[%d, %d)", l, u),
143                () -> LongStream.range(l, u).boxed());
144    }
145
146    private TestData.OfInt ints() {
147        return intRange(0, Integer.MAX_VALUE);
148    }
149
150    private TestData.OfInt intRange(int l, int u) {
151        return TestData.Factory.ofIntSupplier(
152                String.format("[%d, %d)", l, u),
153                () -> IntStream.range(l, u));
154    }
155
156    private TestData.OfLong longs() {
157        return longRange(0, Long.MAX_VALUE);
158    }
159
160    private TestData.OfLong longRange(long l, long u) {
161        return TestData.Factory.ofLongSupplier(
162                String.format("[%d, %d)", l, u),
163                () -> LongStream.range(l, u));
164    }
165
166    private TestData.OfDouble doubles() {
167        return doubleRange(0, 1L << 53);
168    }
169
170    private TestData.OfDouble doubleRange(long l, long u) {
171        return TestData.Factory.ofDoubleSupplier(
172                String.format("[%d, %d)", l, u),
173                () -> LongStream.range(l, u).mapToDouble(i -> (double) i));
174    }
175
176
177    // Sized/subsized range
178
179    @Test(dataProvider = "Stream.limit")
180    public void testSubsizedWithRange(String description, UnaryOperator<Stream<Long>> fs) {
181        // Range is [0, Long.MAX_VALUE), splits are SUBSIZED
182        // Such a size will induce out of memory errors for incorrect
183        // slice implementations
184        withData(refLongs()).
185                stream(s -> fs.apply(s)).
186                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
187                exercise();
188    }
189
190    @Test(dataProvider = "IntStream.limit")
191    public void testIntSubsizedWithRange(String description, UnaryOperator<IntStream> fs) {
192        // Range is [0, Integer.MAX_VALUE), splits are SUBSIZED
193        // Such a size will induce out of memory errors for incorrect
194        // slice implementations
195        withData(ints()).
196                stream(s -> fs.apply(s)).
197                without(IntStreamTestScenario.CLEAR_SIZED_SCENARIOS).
198                exercise();
199    }
200
201    @Test(dataProvider = "LongStream.limit")
202    public void testLongSubsizedWithRange(String description, UnaryOperator<LongStream> fs) {
203        // Range is [0, Long.MAX_VALUE), splits are SUBSIZED
204        // Such a size will induce out of memory errors for incorrect
205        // slice implementations
206        withData(longs()).
207                stream(s -> fs.apply(s)).
208                without(LongStreamTestScenario.CLEAR_SIZED_SCENARIOS).
209                exercise();
210    }
211
212    @Test(dataProvider = "DoubleStream.limit")
213    public void testDoubleSubsizedWithRange(String description, UnaryOperator<DoubleStream> fs) {
214        // Range is [0, 2^53), splits are SUBSIZED
215        // Such a size will induce out of memory errors for incorrect
216        // slice implementations
217        withData(doubles()).
218                stream(s -> fs.apply(s)).
219                without(DoubleStreamTestScenario.CLEAR_SIZED_SCENARIOS).
220                exercise();
221    }
222
223
224    // Unordered finite not SIZED/SUBSIZED
225
226    @Test(dataProvider = "Stream.limit")
227    public void testUnorderedFinite(String description, UnaryOperator<Stream<Long>> fs) {
228        // Range is [0, Long.MAX_VALUE), splits are SUBSIZED
229        // Such a size will induce out of memory errors for incorrect
230        // slice implementations
231        withData(longs()).
232                stream(s -> fs.apply(s.filter(i -> true).unordered().boxed())).
233                resultAsserter(unorderedAsserter()).
234                exercise();
235    }
236
237    @Test(dataProvider = "IntStream.limit")
238    public void testIntUnorderedFinite(String description, UnaryOperator<IntStream> fs) {
239        // Range is [0, Integer.MAX_VALUE), splits are SUBSIZED
240        // Such a size will induce out of memory errors for incorrect
241        // slice implementations
242        withData(ints()).
243                stream(s -> fs.apply(s.filter(i -> true).unordered())).
244                resultAsserter(unorderedAsserter()).
245                exercise();
246    }
247
248    @Test(dataProvider = "LongStream.limit")
249    public void testLongUnorderedFinite(String description, UnaryOperator<LongStream> fs) {
250        // Range is [0, Long.MAX_VALUE), splits are SUBSIZED
251        // Such a size will induce out of memory errors for incorrect
252        // slice implementations
253        withData(longs()).
254                stream(s -> fs.apply(s.filter(i -> true).unordered())).
255                resultAsserter(unorderedAsserter()).
256                exercise();
257    }
258
259    @Test(dataProvider = "DoubleStream.limit")
260    public void testDoubleUnorderedFinite(String description, UnaryOperator<DoubleStream> fs) {
261        // Range is [0, 1L << 53), splits are SUBSIZED
262        // Such a size will induce out of memory errors for incorrect
263        // slice implementations
264        // Upper bound ensures values mapped to doubles will be unique
265        withData(doubles()).
266                stream(s -> fs.apply(s.filter(i -> true).unordered())).
267                resultAsserter(unorderedAsserter()).
268                exercise();
269    }
270
271
272    // Unordered finite not SUBSIZED
273
274    @SuppressWarnings({"rawtypes", "unchecked"})
275    private Spliterator.OfLong proxyNotSubsized(Spliterator.OfLong s) {
276        InvocationHandler ih = new InvocationHandler() {
277            @Override
278            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
279                switch (method.getName()) {
280                    case "characteristics": {
281                        int c = (Integer) method.invoke(s, args);
282                        return c & ~Spliterator.SUBSIZED;
283                    }
284                    case "hasCharacteristics": {
285                        int c = (Integer) args[0];
286                        boolean b = (Boolean) method.invoke(s, args);
287                        return b & ((c & Spliterator.SUBSIZED) == 0);
288                    }
289                    default:
290                        return method.invoke(s, args);
291                }
292            }
293        };
294
295        return (Spliterator.OfLong) Proxy.newProxyInstance(this.getClass().getClassLoader(),
296                                                           new Class[]{Spliterator.OfLong.class},
297                                                           ih);
298    }
299
300    private TestData.OfLong proxiedLongRange(long l, long u) {
301        return TestData.Factory.ofLongSupplier(
302                String.format("[%d, %d)", l, u),
303                () -> StreamSupport.longStream(proxyNotSubsized(LongStream.range(l, u).spliterator()), false));
304    }
305
306    @Test(dataProvider = "Stream.limit")
307    public void testUnorderedSizedNotSubsizedFinite(String description, UnaryOperator<Stream<Long>> fs) {
308        // Range is [0, Long.MAX_VALUE), splits are not SUBSIZED (proxy clears
309        // the SUBSIZED characteristic)
310        // Such a size will induce out of memory errors for incorrect
311        // slice implementations
312        withData(proxiedLongRange(0, Long.MAX_VALUE)).
313                stream(s -> fs.apply(s.unordered().boxed())).
314                resultAsserter(unorderedAsserter()).
315                exercise();
316    }
317
318    @Test(dataProvider = "IntStream.limit")
319    public void testIntUnorderedSizedNotSubsizedFinite(String description, UnaryOperator<IntStream> fs) {
320        // Range is [0, Integer.MAX_VALUE), splits are not SUBSIZED (proxy clears
321        // the SUBSIZED characteristic)
322        // Such a size will induce out of memory errors for incorrect
323        // slice implementations
324        withData(proxiedLongRange(0, Integer.MAX_VALUE)).
325                stream(s -> fs.apply(s.unordered().mapToInt(i -> (int) i))).
326                resultAsserter(unorderedAsserter()).
327                exercise();
328    }
329
330    @Test(dataProvider = "LongStream.limit")
331    public void testLongUnorderedSizedNotSubsizedFinite(String description, UnaryOperator<LongStream> fs) {
332        // Range is [0, Long.MAX_VALUE), splits are not SUBSIZED (proxy clears
333        // the SUBSIZED characteristic)
334        // Such a size will induce out of memory errors for incorrect
335        // slice implementations
336        withData(proxiedLongRange(0, Long.MAX_VALUE)).
337                stream(s -> fs.apply(s.unordered())).
338                resultAsserter(unorderedAsserter()).
339                exercise();
340    }
341
342    @Test(dataProvider = "DoubleStream.limit")
343    public void testDoubleUnorderedSizedNotSubsizedFinite(String description, UnaryOperator<DoubleStream> fs) {
344        // Range is [0, Double.MAX_VALUE), splits are not SUBSIZED (proxy clears
345        // the SUBSIZED characteristic)
346        // Such a size will induce out of memory errors for incorrect
347        // slice implementations
348        withData(proxiedLongRange(0, 1L << 53)).
349                stream(s -> fs.apply(s.unordered().mapToDouble(i -> (double) i))).
350                resultAsserter(unorderedAsserter()).
351                exercise();
352    }
353
354
355    // Unordered generation
356
357    @Test(dataProvider = "Stream.limit")
358    public void testUnorderedGenerator(String description, UnaryOperator<Stream<Long>> fs) {
359        // Source is spliterator of infinite size
360        TestData.OfRef<Long> generator = TestData.Factory.ofSupplier(
361                "[1L, 1L, ...]", () -> Stream.generate(() -> 1L));
362
363        withData(generator).
364                stream(s -> fs.apply(s.filter(i -> true).unordered())).
365                exercise();
366    }
367
368    @Test(dataProvider = "IntStream.limit")
369    public void testIntUnorderedGenerator(String description, UnaryOperator<IntStream> fs) {
370        // Source is spliterator of infinite size
371        TestData.OfInt generator = TestData.Factory.ofIntSupplier(
372                "[1, 1, ...]", () -> IntStream.generate(() -> 1));
373
374        withData(generator).
375                stream(s -> fs.apply(s.filter(i -> true).unordered())).
376                exercise();
377    }
378
379    @Test(dataProvider = "LongStream.limit")
380    public void testLongUnorderedGenerator(String description, UnaryOperator<LongStream> fs) {
381        // Source is spliterator of infinite size
382        TestData.OfLong generator = TestData.Factory.ofLongSupplier(
383                "[1L, 1L, ...]", () -> LongStream.generate(() -> 1));
384
385        withData(generator).
386                stream(s -> fs.apply(s.filter(i -> true).unordered())).
387                exercise();
388    }
389
390    @Test(dataProvider = "DoubleStream.limit")
391    public void testDoubleUnorderedGenerator(String description, UnaryOperator<DoubleStream> fs) {
392        // Source is spliterator of infinite size
393        TestData.OfDouble generator = TestData.Factory.ofDoubleSupplier(
394                "[1.0, 1.0, ...]", () -> DoubleStream.generate(() -> 1.0));
395
396        withData(generator).
397                stream(s -> fs.apply(s.filter(i -> true).unordered())).
398                exercise();
399    }
400
401
402    // Unordered iteration
403
404    @Test(dataProvider = "Stream.limit")
405    public void testUnorderedIteration(String description, UnaryOperator<Stream<Long>> fs) {
406        // Source is a right-balanced tree of infinite size
407        TestData.OfRef<Long> iterator = TestData.Factory.ofSupplier(
408                "[1L, 2L, 3L, ...]", () -> Stream.iterate(1L, i -> i + 1L));
409
410        // Ref
411        withData(iterator).
412                stream(s -> fs.apply(s.unordered())).
413                resultAsserter(unorderedAsserter()).
414                exercise();
415    }
416
417    @Test(dataProvider = "IntStream.limit")
418    public void testIntUnorderedIteration(String description, UnaryOperator<IntStream> fs) {
419        // Source is a right-balanced tree of infinite size
420        TestData.OfInt iterator = TestData.Factory.ofIntSupplier(
421                "[1, 2, 3, ...]", () -> IntStream.iterate(1, i -> i + 1));
422
423        // Ref
424        withData(iterator).
425                stream(s -> fs.apply(s.unordered())).
426                resultAsserter(unorderedAsserter()).
427                exercise();
428    }
429
430    @Test(dataProvider = "LongStream.limit")
431    public void testLongUnorderedIteration(String description, UnaryOperator<LongStream> fs) {
432        // Source is a right-balanced tree of infinite size
433        TestData.OfLong iterator = TestData.Factory.ofLongSupplier(
434                "[1L, 2L, 3L, ...]", () -> LongStream.iterate(1, i -> i + 1));
435
436        // Ref
437        withData(iterator).
438                stream(s -> fs.apply(s.unordered())).
439                resultAsserter(unorderedAsserter()).
440                exercise();
441    }
442
443    @Test(dataProvider = "DoubleStream.limit")
444    public void testDoubleUnorderedIteration(String description, UnaryOperator<DoubleStream> fs) {
445        // Source is a right-balanced tree of infinite size
446        TestData.OfDouble iterator = TestData.Factory.ofDoubleSupplier(
447                "[1.0, 2.0, 3.0, ...]", () -> DoubleStream.iterate(1, i -> i + 1));
448
449        // Ref
450        withData(iterator).
451                stream(s -> fs.apply(s.unordered())).
452                resultAsserter(unorderedAsserter()).
453                exercise();
454    }
455}
456