1 /* 2 * Copyright (c) 2015, 2017, 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.DefaultMethodStreams; 26 import org.openjdk.testlib.java.util.stream.LambdaTestHelpers; 27 import org.openjdk.testlib.java.util.stream.OpTestCase; 28 import org.openjdk.testlib.java.util.stream.StreamTestDataProvider; 29 import org.openjdk.testlib.java.util.stream.TestData; 30 import org.testng.annotations.Test; 31 32 import java.util.ArrayList; 33 import java.util.Collection; 34 import java.util.HashMap; 35 import java.util.LinkedHashSet; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Set; 39 import java.util.concurrent.atomic.AtomicBoolean; 40 import java.util.function.Function; 41 import java.util.function.Predicate; 42 import java.util.stream.DoubleStream; 43 import java.util.stream.IntStream; 44 import java.util.stream.LongStream; 45 import java.util.stream.Stream; 46 47 /* 48 * @test 49 * @bug 8071597 8193856 50 * @run main/timeout=240 51 */ 52 @Test 53 // Android-changed: this test checks while/drop ops on reference and primitive streams. 54 // But in Android U only reference streams have those APIs, hence primitive streams part 55 // are commented out. 56 public class WhileOpTest extends OpTestCase { 57 58 @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class, 59 groups = { "serialization-hostile" }) testTakeWhileOps(String name, TestData.OfRef<Integer> data)60 public void testTakeWhileOps(String name, TestData.OfRef<Integer> data) { 61 for (int size : sizes(data.size())) { 62 setContext("takeWhile", size); 63 64 testWhileMulti(data, 65 whileResultAsserter(data, WhileOp.Take, e -> e < size), 66 s -> s.takeWhile(e -> e < size)); 67 // BEGIN Android-removed: Drop primitive stream test. 68 /* 69 s -> s.takeWhile(e -> e < size), 70 s -> s.takeWhile(e -> e < size), 71 s -> s.takeWhile(e -> e < size)); 72 */ 73 // END Android-removed: Drop primitive stream test. 74 75 76 testWhileMulti(data, 77 whileResultAsserter(data, WhileOp.Take, e -> e < size / 2), 78 s -> s.takeWhile(e -> e < size).takeWhile(e -> e < size / 2)); 79 // BEGIN Android-removed: Drop primitive stream test. 80 /* 81 s -> s.takeWhile(e -> e < size).takeWhile(e -> e < size / 2), 82 s -> s.takeWhile(e -> e < size).takeWhile(e -> e < size / 2), 83 s -> s.takeWhile(e -> e < size).takeWhile(e -> e < size / 2)); 84 */ 85 // END Android-removed: Drop primitive stream test. 86 } 87 } 88 89 @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class, 90 groups = { "serialization-hostile" }) testDropWhileOps(String name, TestData.OfRef<Integer> data)91 public void testDropWhileOps(String name, TestData.OfRef<Integer> data) { 92 for (int size : sizes(data.size())) { 93 setContext("dropWhile", size); 94 95 testWhileMulti(data, 96 whileResultAsserter(data, WhileOp.Drop, e -> e < size), 97 s -> s.dropWhile(e -> e < size)); 98 // BEGIN Android-removed: Drop primitive stream test. 99 /* 100 s -> s.dropWhile(e -> e < size), 101 s -> s.dropWhile(e -> e < size), 102 s -> s.dropWhile(e -> e < size)); 103 */ 104 // END Android-removed: Drop primitive stream test. 105 106 testWhileMulti(data, 107 whileResultAsserter(data, WhileOp.Drop, e -> e < size), 108 s -> s.dropWhile(e -> e < size / 2).dropWhile(e -> e < size)); 109 // BEGIN Android-removed: Drop primitive stream test. 110 /* 111 s -> s.dropWhile(e -> e < size / 2).dropWhile(e -> e < size), 112 s -> s.dropWhile(e -> e < size / 2).dropWhile(e -> e < size), 113 s -> s.dropWhile(e -> e < size / 2).dropWhile(e -> e < size)); 114 */ 115 // END Android-removed: Drop primitive stream test. 116 } 117 } 118 119 @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class, 120 groups = { "serialization-hostile" }) testDropTakeWhileOps(String name, TestData.OfRef<Integer> data)121 public void testDropTakeWhileOps(String name, TestData.OfRef<Integer> data) { 122 for (int size : sizes(data.size())) { 123 setContext("dropWhile", size); 124 125 testWhileMulti(data, 126 whileResultAsserter(data, WhileOp.Undefined, null), 127 s -> s.dropWhile(e -> e < size / 2).takeWhile(e -> e < size)); 128 // BEGIN Android-removed: Drop primitive stream test. 129 /* 130 s -> s.dropWhile(e -> e < size / 2).takeWhile(e -> e < size), 131 s -> s.dropWhile(e -> e < size / 2).takeWhile(e -> e < size), 132 s -> s.dropWhile(e -> e < size / 2).takeWhile(e -> e < size)); 133 */ 134 // END Android-removed: Drop primitive stream test. 135 } 136 } 137 138 /** 139 * While operation type to be asserted on 140 */ 141 enum WhileOp { 142 /** 143 * The takeWhile operation 144 */ 145 Take, 146 /** 147 * The dropWhile operation 148 */ 149 Drop, 150 /** 151 * The operation(s) are undefined 152 */ 153 Undefined 154 } 155 156 /** 157 * Create a result asserter for takeWhile or dropWhile operations. 158 * <p> 159 * If the stream pipeline consists of the takeWhile operation 160 * ({@link WhileOp#Take}) or the dropWhile operation ({@link WhileOp#Drop}) 161 * then specific assertions can be made on the actual result based on the 162 * input elements, {@code inputData}, and whether those elements match the 163 * predicate, {@code p}, of the operation. 164 * <p> 165 * If the input elements have an encounter order then the actual result 166 * is asserted against the result of operating sequentially on input 167 * elements given the predicate and in accordance with the operation 168 * semantics. (The actual result whether produced sequentially or in 169 * parallel should the same.) 170 * <p> 171 * If the input elements have no encounter order then an actual result 172 * is, for practical purposes, considered non-deterministic. 173 * Consider an input list of lists that contains all possible permutations 174 * of the input elements, and a output list of lists that is the result of 175 * applying the pipeline with the operation sequentially to each input 176 * list. 177 * Any list in the output lists is a valid result. It's not practical to 178 * test in such a manner. 179 * For a takeWhile operation the following assertions can be made if 180 * only some of the input elements match the predicate (i.e. taking will 181 * short-circuit the pipeline): 182 * <ol> 183 * <li>The set of output elements is a subset of the set of matching 184 * input elements</li> 185 * <li>The set of output elements and the set of non-matching input 186 * element are disjoint</li> 187 * </ol> 188 * For a dropWhile operation the following assertions can be made: 189 * <ol> 190 * <li>The set of non-matching input elements is a subset of the set of 191 * output elements</li> 192 * <li>The set of matching output elements is a subset of the set of 193 * matching input elements</li> 194 * </ol> 195 * 196 * @param inputData the elements input into the stream pipeline 197 * @param op the operation of the stream pipeline, one of takeWhile, 198 * dropWhile, or an undefined set of operations (possibly including 199 * two or more takeWhile and/or dropWhile operations, or because 200 * the predicate is not stateless). 201 * @param p the stateless predicate applied to the operation, ignored if 202 * the 203 * operation is {@link WhileOp#Undefined}. 204 * @param <T> the type of elements 205 * @return a result asserter 206 */ whileResultAsserter(Iterable<T> inputData, WhileOp op, Predicate<? super T> p)207 private <T> ResultAsserter<Iterable<T>> whileResultAsserter(Iterable<T> inputData, 208 WhileOp op, 209 Predicate<? super T> p) { 210 return (act, exp, ord, par) -> { 211 if (par & !ord) { 212 List<T> input = new ArrayList<>(); 213 inputData.forEach(input::add); 214 215 List<T> output = new ArrayList<>(); 216 act.forEach(output::add); 217 218 if (op == WhileOp.Take) { 219 List<T> matchingInput = new ArrayList<>(); 220 List<T> nonMatchingInput = new ArrayList<>(); 221 input.forEach(t -> { 222 if (p.test(t)) 223 matchingInput.add(t); 224 else 225 nonMatchingInput.add(t); 226 }); 227 228 // If some, not all, elements are taken 229 if (matchingInput.size() < input.size()) { 230 assertTrue(output.size() <= matchingInput.size(), 231 "Output is larger than the matching input"); 232 233 // The output must be a subset of the matching input 234 assertTrue(matchingInput.containsAll(output), 235 "Output is not a subset of the matching input"); 236 237 // The output must not contain any non matching elements 238 for (T nonMatching : nonMatchingInput) { 239 assertFalse(output.contains(nonMatching), 240 "Output and non-matching input are not disjoint"); 241 } 242 } 243 } 244 else if (op == WhileOp.Drop) { 245 List<T> matchingInput = new ArrayList<>(); 246 List<T> nonMatchingInput = new ArrayList<>(); 247 input.forEach(t -> { 248 if (p.test(t)) 249 matchingInput.add(t); 250 else 251 nonMatchingInput.add(t); 252 }); 253 254 // The non matching input must be a subset of output 255 assertTrue(output.containsAll(nonMatchingInput), 256 "Non-matching input is not a subset of the output"); 257 258 // The matching output must be a subset of the matching input 259 List<T> matchingOutput = new ArrayList<>(); 260 output.forEach(i -> { 261 if (p.test(i)) 262 matchingOutput.add(i); 263 }); 264 assertTrue(matchingInput.containsAll(matchingOutput), 265 "Matching output is not a subset of matching input"); 266 } 267 268 // Note: if there is a combination of takeWhile and dropWhile then specific 269 // assertions cannot be performed. 270 // All that can be reliably asserted is the output is a subset of the input 271 272 assertTrue(input.containsAll(output)); 273 } 274 else { 275 // For specific operations derive expected result from the input 276 if (op == WhileOp.Take) { 277 List<T> takeInput = new ArrayList<>(); 278 for (T t : inputData) { 279 if (p.test(t)) 280 takeInput.add(t); 281 else 282 break; 283 } 284 285 LambdaTestHelpers.assertContents(act, takeInput); 286 } 287 else if (op == WhileOp.Drop) { 288 List<T> dropInput = new ArrayList<>(); 289 for (T t : inputData) { 290 if (dropInput.size() > 0 || !p.test(t)) 291 dropInput.add(t); 292 } 293 294 LambdaTestHelpers.assertContents(act, dropInput); 295 } 296 297 LambdaTestHelpers.assertContents(act, exp); 298 } 299 }; 300 } 301 302 private Collection<Integer> sizes(int s) { 303 Set<Integer> sizes = new LinkedHashSet<>(); 304 305 sizes.add(0); 306 sizes.add(1); 307 sizes.add(s / 4); 308 sizes.add(s / 2); 309 sizes.add(3 * s / 4); 310 sizes.add(Math.max(0, s - 1)); 311 sizes.add(s); 312 sizes.add(Integer.MAX_VALUE); 313 314 return sizes; 315 } 316 317 private void testWhileMulti(TestData.OfRef<Integer> data, 318 ResultAsserter<Iterable<Integer>> ra, 319 Function<Stream<Integer>, Stream<Integer>> mRef) { 320 // BEGIN Android-removed: Drop primitive stream test. 321 /* 322 Function<IntStream, IntStream> mInt, 323 Function<LongStream, LongStream> mLong, 324 Function<DoubleStream, DoubleStream> mDouble) { 325 */ 326 // BEGIN Android-removed: Drop primitive stream test. 327 Map<String, Function<Stream<Integer>, Stream<Integer>>> ms = new HashMap<>(); 328 ms.put("Ref", mRef); 329 // Android-removed: Drop primitive stream test. 330 // ms.put("Int", s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e)); 331 // ms.put("Long", s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e)); 332 // ms.put("Double", s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e)); 333 ms.put("Ref using defaults", s -> mRef.apply(DefaultMethodStreams.delegateTo(s))); 334 // Android-removed: Drop primitive stream test. 335 // ms.put("Int using defaults", s -> mInt.apply(DefaultMethodStreams.delegateTo(s.mapToInt(e -> e))).mapToObj(e -> e)); 336 // ms.put("Long using defaults", s -> mLong.apply(DefaultMethodStreams.delegateTo(s.mapToLong(e -> e))).mapToObj(e -> (int) e)); 337 // ms.put("Double using defaults", s -> mDouble.apply(DefaultMethodStreams.delegateTo(s.mapToDouble(e -> e))).mapToObj(e -> (int) e)); 338 339 testWhileMulti(data, ra, ms); 340 } 341 342 private final void testWhileMulti(TestData.OfRef<Integer> data, 343 ResultAsserter<Iterable<Integer>> ra, 344 Map<String, Function<Stream<Integer>, Stream<Integer>>> ms) { 345 for (Map.Entry<String, Function<Stream<Integer>, Stream<Integer>>> e : ms.entrySet()) { 346 setContext("shape", e.getKey()); 347 348 withData(data) 349 .stream(e.getValue()) 350 .resultAsserter(ra) 351 .exercise(); 352 } 353 } 354 355 @Test(groups = { "serialization-hostile" }) 356 public void testRefDefaultClose() { 357 AtomicBoolean isClosed = new AtomicBoolean(); 358 Stream<Integer> s = Stream.of(1, 2, 3).onClose(() -> isClosed.set(true)); 359 try (Stream<Integer> ds = DefaultMethodStreams.delegateTo(s).takeWhile(e -> e < 3)) { 360 ds.count(); 361 } 362 assertTrue(isClosed.get()); 363 } 364 365 // BEGIN Android-removed: Drop primitive stream test. 366 /* 367 @Test(groups = { "serialization-hostile" }) 368 public void testIntDefaultClose() { 369 AtomicBoolean isClosed = new AtomicBoolean(); 370 IntStream s = IntStream.of(1, 2, 3).onClose(() -> isClosed.set(true)); 371 try (IntStream ds = DefaultMethodStreams.delegateTo(s).takeWhile(e -> e < 3)) { 372 ds.count(); 373 } 374 assertTrue(isClosed.get()); 375 } 376 377 @Test(groups = { "serialization-hostile" }) 378 public void testLongDefaultClose() { 379 AtomicBoolean isClosed = new AtomicBoolean(); 380 LongStream s = LongStream.of(1, 2, 3).onClose(() -> isClosed.set(true)); 381 try (LongStream ds = DefaultMethodStreams.delegateTo(s).takeWhile(e -> e < 3)) { 382 ds.count(); 383 } 384 assertTrue(isClosed.get()); 385 } 386 387 @Test(groups = { "serialization-hostile" }) 388 public void testDoubleDefaultClose() { 389 AtomicBoolean isClosed = new AtomicBoolean(); 390 DoubleStream s = DoubleStream.of(1, 2, 3).onClose(() -> isClosed.set(true)); 391 try (DoubleStream ds = DefaultMethodStreams.delegateTo(s).takeWhile(e -> e < 3)) { 392 ds.count(); 393 } 394 assertTrue(isClosed.get()); 395 } 396 */ 397 // END Android-removed: Drop primitive stream test. 398 399 @Test(groups = { "serialization-hostile" }) 400 public void testFlatMapThenTake() { 401 TestData.OfRef<Integer> range = TestData.Factory.ofSupplier( 402 "range", () -> IntStream.range(0, 100).boxed()); 403 404 exerciseOpsMulti(range, 405 // Reference result 406 s -> s.takeWhile(e -> e != 50), 407 // For other results collect into array, 408 // stream the single array (not the elements), 409 // then flat map to stream the array elements 410 s -> Stream.<Integer[]>of(s.toArray(Integer[]::new)). 411 flatMap(Stream::of). 412 takeWhile(e -> e != 50) 413 ); 414 // BEGIN Android-removed: Drop primitive stream test. 415 /* 416 s -> Stream.of(s.mapToInt(e -> e).toArray()). 417 flatMapToInt(IntStream::of). 418 takeWhile(e -> e != 50). 419 mapToObj(e -> e), 420 s -> Stream.of(s.mapToLong(e -> e).toArray()). 421 flatMapToLong(LongStream::of). 422 takeWhile(e -> e != 50L). 423 mapToObj(e -> (int) e), 424 s -> Stream.of(s.mapToDouble(e -> e).toArray()). 425 flatMapToDouble(DoubleStream::of). 426 takeWhile(e -> e != 50.0). 427 mapToObj(e -> (int) e) 428 ); 429 */ 430 // END Android-removed: Drop primitive stream test. 431 } 432 } 433