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