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.openjdk.testlib.java.util.stream.LambdaTestHelpers;
26import org.openjdk.testlib.java.util.stream.OpTestCase;
27import org.openjdk.testlib.java.util.stream.StreamTestDataProvider;
28import org.openjdk.testlib.java.util.stream.TestData;
29
30import org.testng.annotations.Test;
31
32import java.util.*;
33import java.util.concurrent.atomic.AtomicInteger;
34import java.util.function.Consumer;
35import java.util.function.Function;
36import java.util.stream.Collectors;
37import java.util.stream.DoubleStream;
38import java.util.stream.IntStream;
39import java.util.stream.LongStream;
40import java.util.stream.Stream;
41import java.util.stream.StreamSupport;
42
43import static org.openjdk.testlib.java.util.stream.LambdaTestHelpers.*;
44
45/**
46 * SliceOpTest
47 *
48 * @author Brian Goetz
49 */
50@Test
51public class SliceOpTest extends OpTestCase {
52
53    public void testSkip() {
54        assertCountSum(countTo(0).stream().skip(0), 0, 0);
55        assertCountSum(countTo(0).stream().skip(4), 0, 0);
56        assertCountSum(countTo(4).stream().skip(4), 0, 0);
57        assertCountSum(countTo(4).stream().skip(2), 2, 7);
58        assertCountSum(countTo(4).stream().skip(0), 4, 10);
59
60        assertCountSum(countTo(0).parallelStream().skip(0), 0, 0);
61        assertCountSum(countTo(0).parallelStream().skip(4), 0, 0);
62        assertCountSum(countTo(4).parallelStream().skip(4), 0, 0);
63        assertCountSum(countTo(4).parallelStream().skip(2), 2, 7);
64        assertCountSum(countTo(4).parallelStream().skip(0), 4, 10);
65
66        exerciseOps(Collections.emptyList(), s -> s.skip(0), Collections.emptyList());
67        exerciseOps(Collections.emptyList(), s -> s.skip(10), Collections.emptyList());
68
69        exerciseOps(countTo(1), s -> s.skip(0), countTo(1));
70        exerciseOps(countTo(1), s -> s.skip(1), Collections.emptyList());
71        exerciseOps(countTo(100), s -> s.skip(0), countTo(100));
72        exerciseOps(countTo(100), s -> s.skip(10), range(11, 100));
73        exerciseOps(countTo(100), s -> s.skip(100), Collections.emptyList());
74        exerciseOps(countTo(100), s -> s.skip(200), Collections.emptyList());
75    }
76
77    public void testLimit() {
78        assertCountSum(countTo(0).stream().limit(4), 0, 0);
79        assertCountSum(countTo(2).stream().limit(4), 2, 3);
80        assertCountSum(countTo(4).stream().limit(4), 4, 10);
81        assertCountSum(countTo(8).stream().limit(4), 4, 10);
82
83        assertCountSum(countTo(0).parallelStream().limit(4), 0, 0);
84        assertCountSum(countTo(2).parallelStream().limit(4), 2, 3);
85        assertCountSum(countTo(4).parallelStream().limit(4), 4, 10);
86        assertCountSum(countTo(8).parallelStream().limit(4), 4, 10);
87
88        exerciseOps(Collections.emptyList(), s -> s.limit(0), Collections.emptyList());
89        exerciseOps(Collections.emptyList(), s -> s.limit(10), Collections.emptyList());
90        exerciseOps(countTo(1), s -> s.limit(0), Collections.emptyList());
91        exerciseOps(countTo(1), s -> s.limit(1), countTo(1));
92        exerciseOps(countTo(100), s -> s.limit(0), Collections.emptyList());
93        exerciseOps(countTo(100), s -> s.limit(10), countTo(10));
94        exerciseOps(countTo(100), s -> s.limit(10).limit(10), countTo(10));
95        exerciseOps(countTo(100), s -> s.limit(100), countTo(100));
96        exerciseOps(countTo(100), s -> s.limit(100).limit(10), countTo(10));
97        exerciseOps(countTo(100), s -> s.limit(200), countTo(100));
98    }
99
100    public void testSkipLimit() {
101        exerciseOps(Collections.emptyList(), s -> s.skip(0).limit(0), Collections.emptyList());
102        exerciseOps(Collections.emptyList(), s -> s.skip(0).limit(10), Collections.emptyList());
103        exerciseOps(Collections.emptyList(), s -> s.skip(10).limit(0), Collections.emptyList());
104        exerciseOps(Collections.emptyList(), s -> s.skip(10).limit(10), Collections.emptyList());
105
106        exerciseOps(countTo(100), s -> s.skip(0).limit(100), countTo(100));
107        exerciseOps(countTo(100), s -> s.skip(0).limit(10), countTo(10));
108        exerciseOps(countTo(100), s -> s.skip(0).limit(0), Collections.emptyList());
109        exerciseOps(countTo(100), s -> s.skip(10).limit(100), range(11, 100));
110        exerciseOps(countTo(100), s -> s.skip(10).limit(10), range(11, 20));
111        exerciseOps(countTo(100), s -> s.skip(10).limit(0), Collections.emptyList());
112        exerciseOps(countTo(100), s -> s.skip(100).limit(100), Collections.emptyList());
113        exerciseOps(countTo(100), s -> s.skip(100).limit(10), Collections.emptyList());
114        exerciseOps(countTo(100), s -> s.skip(100).limit(0), Collections.emptyList());
115        exerciseOps(countTo(100), s -> s.skip(200).limit(100), Collections.emptyList());
116        exerciseOps(countTo(100), s -> s.skip(200).limit(10), Collections.emptyList());
117        exerciseOps(countTo(100), s -> s.skip(200).limit(0), Collections.emptyList());
118    }
119
120    public void testSlice() {
121        exerciseOps(Collections.emptyList(), s -> s.skip(0).limit(0), Collections.emptyList());
122        exerciseOps(Collections.emptyList(), s -> s.skip(0).limit(10), Collections.emptyList());
123        exerciseOps(Collections.emptyList(), s -> s.skip(10).limit(10), Collections.emptyList());
124        exerciseOps(Collections.emptyList(), s -> s.skip(10).limit(20), Collections.emptyList());
125
126        exerciseOps(countTo(100), s -> s.skip(0).limit(100), countTo(100));
127        exerciseOps(countTo(100), s -> s.skip(0).limit(10), countTo(10));
128        exerciseOps(countTo(100), s -> s.skip(0).limit(0), Collections.emptyList());
129        exerciseOps(countTo(100), s -> s.skip(10).limit(100), range(11, 100));
130        exerciseOps(countTo(100), s -> s.skip(10).limit(10), range(11, 20));
131        exerciseOps(countTo(100), s -> s.skip(10).limit(0), Collections.emptyList());
132        exerciseOps(countTo(100), s -> s.skip(100).limit(100), Collections.emptyList());
133        exerciseOps(countTo(100), s -> s.skip(100).limit(10), Collections.emptyList());
134        exerciseOps(countTo(100), s -> s.skip(100).limit(0), Collections.emptyList());
135        exerciseOps(countTo(100), s -> s.skip(200).limit(100), Collections.emptyList());
136        exerciseOps(countTo(100), s -> s.skip(200).limit(10), Collections.emptyList());
137        exerciseOps(countTo(100), s -> s.skip(200).limit(0), Collections.emptyList());
138    }
139
140    private int sliceSize(int dataSize, int skip, int limit) {
141        int size = Math.max(0, dataSize - skip);
142        if (limit >= 0)
143            size = Math.min(size, limit);
144        return size;
145    }
146
147    private int sliceSize(int dataSize, int skip) {
148        return Math.max(0, dataSize - skip);
149    }
150
151    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
152          groups = { "serialization-hostile" })
153    public void testSkipOps(String name, TestData.OfRef<Integer> data) {
154        List<Integer> skips = sizes(data.size());
155
156        for (int s : skips) {
157            setContext("skip", s);
158            testSliceMulti(data,
159                           sliceSize(data.size(), s),
160                           st -> st.skip(s),
161                           st -> st.skip(s),
162                           st -> st.skip(s),
163                           st -> st.skip(s));
164
165            testSliceMulti(data,
166                           sliceSize(sliceSize(data.size(), s), s/2),
167                           st -> st.skip(s).skip(s / 2),
168                           st -> st.skip(s).skip(s / 2),
169                           st -> st.skip(s).skip(s / 2),
170                           st -> st.skip(s).skip(s / 2));
171        }
172    }
173
174    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
175          groups = { "serialization-hostile" })
176    public void testSkipLimitOps(String name, TestData.OfRef<Integer> data) {
177        List<Integer> skips = sizes(data.size());
178        List<Integer> limits = skips;
179
180        for (int s : skips) {
181            setContext("skip", s);
182            for (int l : limits) {
183                setContext("limit", l);
184                testSliceMulti(data,
185                               sliceSize(sliceSize(data.size(), s), 0, l),
186                               st -> st.skip(s).limit(l),
187                               st -> st.skip(s).limit(l),
188                               st -> st.skip(s).limit(l),
189                               st -> st.skip(s).limit(l));
190            }
191        }
192    }
193
194    public void testSkipLimitOpsWithNonSplittingSpliterator() {
195        class NonSplittingNotSubsizedOrderedSpliterator<T> implements Spliterator<T> {
196            Spliterator<T> s;
197
198            NonSplittingNotSubsizedOrderedSpliterator(Spliterator<T> s) {
199                assert s.hasCharacteristics(Spliterator.ORDERED);
200                this.s = s;
201            }
202
203            @Override
204            public boolean tryAdvance(Consumer<? super T> action) {
205                return s.tryAdvance(action);
206            }
207
208            @Override
209            public void forEachRemaining(Consumer<? super T> action) {
210                s.forEachRemaining(action);
211            }
212
213            @Override
214            public Spliterator<T> trySplit() {
215                return null;
216            }
217
218            @Override
219            public long estimateSize() {
220                return s.estimateSize();
221            }
222
223            @Override
224            public int characteristics() {
225                return s.characteristics() & ~(Spliterator.SUBSIZED);
226            }
227
228            @Override
229            public Comparator<? super T> getComparator() {
230                return s.getComparator();
231            }
232        }
233        List<Integer> list = IntStream.range(0, 100).boxed().collect(Collectors.toList());
234        TestData.OfRef<Integer> data = TestData.Factory.ofSupplier(
235                "Non splitting, not SUBSIZED, ORDERED, stream",
236                () -> StreamSupport.stream(new NonSplittingNotSubsizedOrderedSpliterator<>(list.spliterator()), false));
237
238        testSkipLimitOps("testSkipLimitOpsWithNonSplittingSpliterator", data);
239    }
240
241    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
242          groups = { "serialization-hostile" })
243    public void testLimitOps(String name, TestData.OfRef<Integer> data) {
244        List<Integer> limits = sizes(data.size());
245
246        for (int l : limits) {
247            setContext("limit", l);
248            testSliceMulti(data,
249                           sliceSize(data.size(), 0, l),
250                           st -> st.limit(l),
251                           st -> st.limit(l),
252                           st -> st.limit(l),
253                           st -> st.limit(l));
254        }
255
256        for (int l : limits) {
257            setContext("limit", l);
258            testSliceMulti(data,
259                           sliceSize(sliceSize(data.size(), 0, l), 0, l / 2),
260                           st -> st.limit(l).limit(l / 2),
261                           st -> st.limit(l).limit(l / 2),
262                           st -> st.limit(l).limit(l / 2),
263                           st -> st.limit(l).limit(l / 2));
264        }
265    }
266
267    private ResultAsserter<Iterable<Integer>> sliceResultAsserter(Iterable<Integer> data,
268                                                                  int expectedSize) {
269        return (act, exp, ord, par) -> {
270            if (par & !ord) {
271                List<Integer> expected = new ArrayList<>();
272                data.forEach(expected::add);
273
274                List<Integer> actual = new ArrayList<>();
275                act.forEach(actual::add);
276
277                assertEquals(actual.size(), expectedSize);
278                assertTrue(expected.containsAll(actual));
279            }
280            else {
281                LambdaTestHelpers.assertContents(act, exp);
282            }
283        };
284    }
285
286    private void testSliceMulti(TestData.OfRef<Integer> data,
287                                int expectedSize,
288                                Function<Stream<Integer>, Stream<Integer>> mRef,
289                                Function<IntStream, IntStream> mInt,
290                                Function<LongStream, LongStream> mLong,
291                                Function<DoubleStream, DoubleStream> mDouble) {
292
293        @SuppressWarnings({ "rawtypes", "unchecked" })
294        Function<Stream<Integer>, Stream<Integer>>[] ms = new Function[4];
295        ms[0] = mRef;
296        ms[1] = s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e);
297        ms[2] = s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e);
298        ms[3] = s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e);
299        testSliceMulti(data, expectedSize, ms);
300    }
301
302    @SafeVarargs
303    private final void testSliceMulti(TestData.OfRef<Integer> data,
304                                      int expectedSize,
305                                      Function<Stream<Integer>, Stream<Integer>>... ms) {
306        for (int i = 0; i < ms.length; i++) {
307            setContext("mIndex", i);
308            Function<Stream<Integer>, Stream<Integer>> m = ms[i];
309            Collection<Integer> sr = withData(data)
310                    .stream(m)
311                    .resultAsserter(sliceResultAsserter(data, expectedSize))
312                    .exercise();
313            assertEquals(sr.size(), expectedSize);
314        }
315    }
316
317    public void testLimitSort() {
318        List<Integer> l = countTo(100);
319        Collections.reverse(l);
320        exerciseOps(l, s -> s.limit(10).sorted(Comparator.naturalOrder()));
321    }
322
323    @Test(groups = { "serialization-hostile" })
324    public void testLimitShortCircuit() {
325        for (int l : Arrays.asList(0, 10)) {
326            setContext("l", l);
327            AtomicInteger ai = new AtomicInteger();
328            countTo(100).stream()
329                    .peek(i -> ai.getAndIncrement())
330                    .limit(l).toArray();
331            // For the case of a zero limit, one element will get pushed through the sink chain
332            assertEquals(ai.get(), l, "tee block was called too many times");
333        }
334    }
335
336    private List<Integer> sizes(int size) {
337        if (size < 4) {
338            return Arrays.asList(0, 1, 2, 3, 4, 6);
339        }
340        else {
341            return Arrays.asList(0, 1, size / 2, size - 1, size, size + 1, 2 * size);
342        }
343    }
344}
345