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