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