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