1 /* 2 * Copyright (c) 2012, 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.testlib.java.util; 24 25 import java.util.function.*; 26 import org.openjdk.testlib.java.util.stream.LambdaTestHelpers; 27 import java.util.*; 28 29 import static org.testng.Assert.*; 30 31 /** 32 * Assertion methods for spliterators, to be called from other tests 33 */ 34 public class SpliteratorTestHelper { 35 36 public interface ContentAsserter<T> { assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered)37 void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered); 38 } 39 40 private static ContentAsserter<Object> DEFAULT_CONTENT_ASSERTER 41 = SpliteratorTestHelper::assertContents; 42 43 @SuppressWarnings("unchecked") defaultContentAsserter()44 private static <T> ContentAsserter<T> defaultContentAsserter() { 45 return (ContentAsserter<T>) DEFAULT_CONTENT_ASSERTER; 46 } 47 testSpliterator(Supplier<Spliterator<Integer>> supplier)48 public static void testSpliterator(Supplier<Spliterator<Integer>> supplier) { 49 testSpliterator(supplier, defaultContentAsserter()); 50 } 51 testSpliterator(Supplier<Spliterator<Integer>> supplier, ContentAsserter<Integer> asserter)52 public static void testSpliterator(Supplier<Spliterator<Integer>> supplier, 53 ContentAsserter<Integer> asserter) { 54 testSpliterator(supplier, (Consumer<Integer> b) -> b, asserter); 55 } 56 testIntSpliterator(Supplier<Spliterator.OfInt> supplier)57 public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier) { 58 testIntSpliterator(supplier, defaultContentAsserter()); 59 } 60 testIntSpliterator(Supplier<Spliterator.OfInt> supplier, ContentAsserter<Integer> asserter)61 public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier, 62 ContentAsserter<Integer> asserter) { 63 testSpliterator(supplier, intBoxingConsumer(), asserter); 64 } 65 testLongSpliterator(Supplier<Spliterator.OfLong> supplier)66 public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier) { 67 testLongSpliterator(supplier, defaultContentAsserter()); 68 } 69 testLongSpliterator(Supplier<Spliterator.OfLong> supplier, ContentAsserter<Long> asserter)70 public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier, 71 ContentAsserter<Long> asserter) { 72 testSpliterator(supplier, longBoxingConsumer(), asserter); 73 } 74 testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier)75 public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier) { 76 testDoubleSpliterator(supplier, defaultContentAsserter()); 77 } 78 testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier, ContentAsserter<Double> asserter)79 public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier, 80 ContentAsserter<Double> asserter) { 81 testSpliterator(supplier, doubleBoxingConsumer(), asserter); 82 } 83 intBoxingConsumer()84 public static UnaryOperator<Consumer<Integer>> intBoxingConsumer() { 85 class BoxingAdapter implements Consumer<Integer>, IntConsumer { 86 private final Consumer<Integer> b; 87 88 BoxingAdapter(Consumer<Integer> b) { 89 this.b = b; 90 } 91 92 @Override 93 public void accept(Integer value) { 94 throw new IllegalStateException(); 95 } 96 97 @Override 98 public void accept(int value) { 99 b.accept(value); 100 } 101 } 102 103 return b -> new BoxingAdapter(b); 104 } 105 longBoxingConsumer()106 public static UnaryOperator<Consumer<Long>> longBoxingConsumer() { 107 class BoxingAdapter implements Consumer<Long>, LongConsumer { 108 private final Consumer<Long> b; 109 110 BoxingAdapter(Consumer<Long> b) { 111 this.b = b; 112 } 113 114 @Override 115 public void accept(Long value) { 116 throw new IllegalStateException(); 117 } 118 119 @Override 120 public void accept(long value) { 121 b.accept(value); 122 } 123 } 124 125 return b -> new BoxingAdapter(b); 126 } 127 doubleBoxingConsumer()128 public static UnaryOperator<Consumer<Double>> doubleBoxingConsumer() { 129 class BoxingAdapter implements Consumer<Double>, DoubleConsumer { 130 private final Consumer<Double> b; 131 132 BoxingAdapter(Consumer<Double> b) { 133 this.b = b; 134 } 135 136 @Override 137 public void accept(Double value) { 138 throw new IllegalStateException(); 139 } 140 141 @Override 142 public void accept(double value) { 143 b.accept(value); 144 } 145 } 146 147 return b -> new BoxingAdapter(b); 148 } 149 testSpliterator(Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)150 public static <T, S extends Spliterator<T>> void testSpliterator(Supplier<S> supplier, 151 UnaryOperator<Consumer<T>> boxingAdapter, 152 ContentAsserter<T> asserter) { 153 ArrayList<T> fromForEach = new ArrayList<>(); 154 Spliterator<T> spliterator = supplier.get(); 155 Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add); 156 spliterator.forEachRemaining(addToFromForEach); 157 158 Collection<T> exp = Collections.unmodifiableList(fromForEach); 159 160 testNullPointerException(supplier); 161 testForEach(exp, supplier, boxingAdapter, asserter); 162 testTryAdvance(exp, supplier, boxingAdapter, asserter); 163 testMixedTryAdvanceForEach(exp, supplier, boxingAdapter, asserter); 164 testMixedTraverseAndSplit(exp, supplier, boxingAdapter, asserter); 165 testSplitAfterFullTraversal(supplier, boxingAdapter); 166 testSplitOnce(exp, supplier, boxingAdapter, asserter); 167 testSplitSixDeep(exp, supplier, boxingAdapter, asserter); 168 testSplitUntilNull(exp, supplier, boxingAdapter, asserter); 169 } 170 testForEach( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)171 public static <T, S extends Spliterator<T>> void testForEach( 172 Collection<T> exp, 173 Supplier<S> supplier, 174 UnaryOperator<Consumer<T>> boxingAdapter) { 175 testForEach(exp, supplier, boxingAdapter, defaultContentAsserter()); 176 } 177 testTryAdvance( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)178 public static <T, S extends Spliterator<T>> void testTryAdvance( 179 Collection<T> exp, 180 Supplier<S> supplier, 181 UnaryOperator<Consumer<T>> boxingAdapter) { 182 testTryAdvance(exp, supplier, boxingAdapter, defaultContentAsserter()); 183 } 184 testMixedTryAdvanceForEach( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)185 public static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach( 186 Collection<T> exp, 187 Supplier<S> supplier, 188 UnaryOperator<Consumer<T>> boxingAdapter) { 189 testMixedTryAdvanceForEach(exp, supplier, boxingAdapter, defaultContentAsserter()); 190 } 191 testMixedTraverseAndSplit( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)192 public static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit( 193 Collection<T> exp, 194 Supplier<S> supplier, 195 UnaryOperator<Consumer<T>> boxingAdapter) { 196 testMixedTraverseAndSplit(exp, supplier, boxingAdapter, defaultContentAsserter()); 197 } 198 testSplitOnce( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)199 public static <T, S extends Spliterator<T>> void testSplitOnce( 200 Collection<T> exp, 201 Supplier<S> supplier, 202 UnaryOperator<Consumer<T>> boxingAdapter) { 203 testSplitOnce(exp, supplier, boxingAdapter, defaultContentAsserter()); 204 } 205 testSplitSixDeep( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)206 public static <T, S extends Spliterator<T>> void testSplitSixDeep( 207 Collection<T> exp, 208 Supplier<S> supplier, 209 UnaryOperator<Consumer<T>> boxingAdapter) { 210 testSplitSixDeep(exp, supplier, boxingAdapter, defaultContentAsserter()); 211 } 212 testSplitUntilNull( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)213 public static <T, S extends Spliterator<T>> void testSplitUntilNull( 214 Collection<T> exp, 215 Supplier<S> supplier, 216 UnaryOperator<Consumer<T>> boxingAdapter) { 217 testSplitUntilNull(exp, supplier, boxingAdapter, defaultContentAsserter()); 218 } 219 testNullPointerException(Supplier<S> s)220 private static <T, S extends Spliterator<T>> void testNullPointerException(Supplier<S> s) { 221 S sp = s.get(); 222 // Have to check instances and use casts to avoid tripwire messages and 223 // directly test the primitive methods 224 if (sp instanceof Spliterator.OfInt) { 225 Spliterator.OfInt psp = (Spliterator.OfInt) sp; 226 assertThrowsNPE(() -> psp.forEachRemaining((IntConsumer) null)); 227 assertThrowsNPE(() -> psp.tryAdvance((IntConsumer) null)); 228 } 229 else if (sp instanceof Spliterator.OfLong) { 230 Spliterator.OfLong psp = (Spliterator.OfLong) sp; 231 assertThrowsNPE(() -> psp.forEachRemaining((LongConsumer) null)); 232 assertThrowsNPE(() -> psp.tryAdvance((LongConsumer) null)); 233 } 234 else if (sp instanceof Spliterator.OfDouble) { 235 Spliterator.OfDouble psp = (Spliterator.OfDouble) sp; 236 assertThrowsNPE(() -> psp.forEachRemaining((DoubleConsumer) null)); 237 assertThrowsNPE(() -> psp.tryAdvance((DoubleConsumer) null)); 238 } 239 else { 240 assertThrowsNPE(() -> sp.forEachRemaining(null)); 241 assertThrowsNPE(() -> sp.tryAdvance(null)); 242 } 243 } 244 testForEach( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)245 private static <T, S extends Spliterator<T>> void testForEach( 246 Collection<T> exp, 247 Supplier<S> supplier, 248 UnaryOperator<Consumer<T>> boxingAdapter, 249 ContentAsserter<T> asserter) { 250 S spliterator = supplier.get(); 251 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 252 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 253 254 ArrayList<T> fromForEach = new ArrayList<>(); 255 spliterator = supplier.get(); 256 Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add); 257 spliterator.forEachRemaining(addToFromForEach); 258 259 // Assert that forEach now produces no elements 260 spliterator.forEachRemaining(boxingAdapter.apply( 261 e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); 262 // Assert that tryAdvance now produce no elements 263 spliterator.tryAdvance(boxingAdapter.apply( 264 e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); 265 266 // assert that size, tryAdvance, and forEach are consistent 267 if (sizeIfKnown >= 0) { 268 assertEquals(sizeIfKnown, exp.size()); 269 } 270 if (exp.contains(null)) { 271 assertTrue(fromForEach.contains(null)); 272 } 273 assertEquals(fromForEach.size(), exp.size()); 274 275 asserter.assertContents(fromForEach, exp, isOrdered); 276 } 277 testTryAdvance( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)278 private static <T, S extends Spliterator<T>> void testTryAdvance( 279 Collection<T> exp, 280 Supplier<S> supplier, 281 UnaryOperator<Consumer<T>> boxingAdapter, 282 ContentAsserter<T> asserter) { 283 S spliterator = supplier.get(); 284 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 285 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 286 287 spliterator = supplier.get(); 288 ArrayList<T> fromTryAdvance = new ArrayList<>(); 289 Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add); 290 while (spliterator.tryAdvance(addToFromTryAdvance)) { } 291 292 // Assert that forEach now produces no elements 293 spliterator.forEachRemaining(boxingAdapter.apply( 294 e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); 295 // Assert that tryAdvance now produce no elements 296 spliterator.tryAdvance(boxingAdapter.apply( 297 e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); 298 299 // assert that size, tryAdvance, and forEach are consistent 300 if (sizeIfKnown >= 0) { 301 assertEquals(sizeIfKnown, exp.size()); 302 } 303 assertEquals(fromTryAdvance.size(), exp.size()); 304 305 asserter.assertContents(fromTryAdvance, exp, isOrdered); 306 } 307 testMixedTryAdvanceForEach( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)308 private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach( 309 Collection<T> exp, 310 Supplier<S> supplier, 311 UnaryOperator<Consumer<T>> boxingAdapter, 312 ContentAsserter<T> asserter) { 313 S spliterator = supplier.get(); 314 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 315 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 316 317 // tryAdvance first few elements, then forEach rest 318 ArrayList<T> dest = new ArrayList<>(); 319 spliterator = supplier.get(); 320 Consumer<T> addToDest = boxingAdapter.apply(dest::add); 321 for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { } 322 spliterator.forEachRemaining(addToDest); 323 324 // Assert that forEach now produces no elements 325 spliterator.forEachRemaining(boxingAdapter.apply( 326 e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); 327 // Assert that tryAdvance now produce no elements 328 spliterator.tryAdvance(boxingAdapter.apply( 329 e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); 330 331 if (sizeIfKnown >= 0) { 332 assertEquals(sizeIfKnown, dest.size()); 333 } 334 assertEquals(dest.size(), exp.size()); 335 336 asserter.assertContents(dest, exp, isOrdered); 337 } 338 testMixedTraverseAndSplit( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)339 private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit( 340 Collection<T> exp, 341 Supplier<S> supplier, 342 UnaryOperator<Consumer<T>> boxingAdapter, 343 ContentAsserter<T> asserter) { 344 S spliterator = supplier.get(); 345 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 346 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 347 348 // tryAdvance first few elements, then forEach rest 349 ArrayList<T> dest = new ArrayList<>(); 350 spliterator = supplier.get(); 351 Consumer<T> b = boxingAdapter.apply(dest::add); 352 353 Spliterator<T> spl1, spl2, spl3; 354 spliterator.tryAdvance(b); 355 spl2 = spliterator.trySplit(); 356 if (spl2 != null) { 357 spl2.tryAdvance(b); 358 spl1 = spl2.trySplit(); 359 if (spl1 != null) { 360 spl1.tryAdvance(b); 361 spl1.forEachRemaining(b); 362 } 363 spl2.tryAdvance(b); 364 spl2.forEachRemaining(b); 365 } 366 spliterator.tryAdvance(b); 367 spl3 = spliterator.trySplit(); 368 if (spl3 != null) { 369 spl3.tryAdvance(b); 370 spl3.forEachRemaining(b); 371 } 372 spliterator.tryAdvance(b); 373 spliterator.forEachRemaining(b); 374 375 if (sizeIfKnown >= 0) { 376 assertEquals(sizeIfKnown, dest.size()); 377 } 378 assertEquals(dest.size(), exp.size()); 379 380 asserter.assertContents(dest, exp, isOrdered); 381 } 382 testSplitAfterFullTraversal( Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)383 public static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal( 384 Supplier<S> supplier, 385 UnaryOperator<Consumer<T>> boxingAdapter) { 386 // Full traversal using tryAdvance 387 Spliterator<T> spliterator = supplier.get(); 388 while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { } 389 Spliterator<T> split = spliterator.trySplit(); 390 assertNull(split); 391 392 // Full traversal using forEach 393 spliterator = supplier.get(); 394 spliterator.forEachRemaining(boxingAdapter.apply(e -> { })); 395 split = spliterator.trySplit(); 396 assertNull(split); 397 398 // Full traversal using tryAdvance then forEach 399 spliterator = supplier.get(); 400 spliterator.tryAdvance(boxingAdapter.apply(e -> { })); 401 spliterator.forEachRemaining(boxingAdapter.apply(e -> { })); 402 split = spliterator.trySplit(); 403 assertNull(split); 404 } 405 testSplitOnce( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)406 private static <T, S extends Spliterator<T>> void testSplitOnce( 407 Collection<T> exp, 408 Supplier<S> supplier, 409 UnaryOperator<Consumer<T>> boxingAdapter, 410 ContentAsserter<T> asserter) { 411 S spliterator = supplier.get(); 412 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 413 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 414 415 ArrayList<T> fromSplit = new ArrayList<>(); 416 Spliterator<T> s1 = supplier.get(); 417 Spliterator<T> s2 = s1.trySplit(); 418 long s1Size = s1.getExactSizeIfKnown(); 419 long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0; 420 Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add); 421 if (s2 != null) 422 s2.forEachRemaining(addToFromSplit); 423 s1.forEachRemaining(addToFromSplit); 424 425 if (sizeIfKnown >= 0) { 426 assertEquals(sizeIfKnown, fromSplit.size()); 427 if (s1Size >= 0 && s2Size >= 0) 428 assertEquals(sizeIfKnown, s1Size + s2Size); 429 } 430 431 asserter.assertContents(fromSplit, exp, isOrdered); 432 } 433 testSplitSixDeep( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)434 private static <T, S extends Spliterator<T>> void testSplitSixDeep( 435 Collection<T> exp, 436 Supplier<S> supplier, 437 UnaryOperator<Consumer<T>> boxingAdapter, 438 ContentAsserter<T> asserter) { 439 S spliterator = supplier.get(); 440 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 441 442 for (int depth=0; depth < 6; depth++) { 443 List<T> dest = new ArrayList<>(); 444 spliterator = supplier.get(); 445 446 assertSpliterator(spliterator); 447 448 // verify splitting with forEach 449 splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false); 450 asserter.assertContents(dest, exp, isOrdered); 451 452 // verify splitting with tryAdvance 453 dest.clear(); 454 spliterator = supplier.get(); 455 splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true); 456 asserter.assertContents(dest, exp, isOrdered); 457 } 458 } 459 460 private static <T, S extends Spliterator<T>> splitSixDeepVisitor(int depth, int curLevel, List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter, int rootCharacteristics, boolean useTryAdvance)461 void splitSixDeepVisitor(int depth, int curLevel, 462 List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter, 463 int rootCharacteristics, boolean useTryAdvance) { 464 if (curLevel < depth) { 465 long beforeSize = spliterator.getExactSizeIfKnown(); 466 Spliterator<T> split = spliterator.trySplit(); 467 if (split != null) { 468 assertSpliterator(split, rootCharacteristics); 469 assertSpliterator(spliterator, rootCharacteristics); 470 471 if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 && 472 (rootCharacteristics & Spliterator.SIZED) != 0) { 473 assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize()); 474 } 475 splitSixDeepVisitor(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance); 476 } 477 splitSixDeepVisitor(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance); 478 } 479 else { 480 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 481 if (useTryAdvance) { 482 Consumer<T> addToDest = boxingAdapter.apply(dest::add); 483 int count = 0; 484 while (spliterator.tryAdvance(addToDest)) { 485 ++count; 486 } 487 488 if (sizeIfKnown >= 0) 489 assertEquals(sizeIfKnown, count); 490 491 // Assert that forEach now produces no elements 492 spliterator.forEachRemaining(boxingAdapter.apply( 493 e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); 494 495 Spliterator<T> split = spliterator.trySplit(); 496 assertNull(split); 497 } 498 else { 499 List<T> leafDest = new ArrayList<>(); 500 Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add); 501 spliterator.forEachRemaining(addToLeafDest); 502 503 if (sizeIfKnown >= 0) 504 assertEquals(sizeIfKnown, leafDest.size()); 505 506 // Assert that forEach now produces no elements 507 spliterator.tryAdvance(boxingAdapter.apply( 508 e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); 509 510 Spliterator<T> split = spliterator.trySplit(); 511 assertNull(split); 512 513 dest.addAll(leafDest); 514 } 515 } 516 } 517 testSplitUntilNull( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)518 private static <T, S extends Spliterator<T>> void testSplitUntilNull( 519 Collection<T> exp, 520 Supplier<S> supplier, 521 UnaryOperator<Consumer<T>> boxingAdapter, 522 ContentAsserter<T> asserter) { 523 Spliterator<T> s = supplier.get(); 524 boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED); 525 assertSpliterator(s); 526 527 List<T> splits = new ArrayList<>(); 528 Consumer<T> c = boxingAdapter.apply(splits::add); 529 530 testSplitUntilNull(new SplitNode<T>(c, s)); 531 asserter.assertContents(splits, exp, isOrdered); 532 } 533 534 private static class SplitNode<T> { 535 // Constant for every node 536 final Consumer<T> c; 537 final int rootCharacteristics; 538 539 final Spliterator<T> s; 540 SplitNode(Consumer<T> c, Spliterator<T> s)541 SplitNode(Consumer<T> c, Spliterator<T> s) { 542 this(c, s.characteristics(), s); 543 } 544 SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s)545 private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) { 546 this.c = c; 547 this.rootCharacteristics = rootCharacteristics; 548 this.s = s; 549 } 550 fromSplit(Spliterator<T> split)551 SplitNode<T> fromSplit(Spliterator<T> split) { 552 return new SplitNode<>(c, rootCharacteristics, split); 553 } 554 } 555 556 /** 557 * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator 558 * while not unduly disrupting test infrastructure given the test data sizes that are used are small. 559 * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26). 560 */ 561 private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB 562 testSplitUntilNull(SplitNode<T> e)563 private static <T> void testSplitUntilNull(SplitNode<T> e) { 564 // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator 565 // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or 566 // for a spliterator that is badly behaved. 567 Deque<SplitNode<T>> stack = new ArrayDeque<>(); 568 stack.push(e); 569 570 int iteration = 0; 571 while (!stack.isEmpty()) { 572 assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18"); 573 574 e = stack.pop(); 575 Spliterator<T> parentAndRightSplit = e.s; 576 577 long parentEstimateSize = parentAndRightSplit.estimateSize(); 578 assertTrue(parentEstimateSize >= 0, 579 String.format("Split size estimate %d < 0", parentEstimateSize)); 580 581 long parentSize = parentAndRightSplit.getExactSizeIfKnown(); 582 Spliterator<T> leftSplit = parentAndRightSplit.trySplit(); 583 if (leftSplit == null) { 584 parentAndRightSplit.forEachRemaining(e.c); 585 continue; 586 } 587 588 assertSpliterator(leftSplit, e.rootCharacteristics); 589 assertSpliterator(parentAndRightSplit, e.rootCharacteristics); 590 591 if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0 592 && parentAndRightSplit.estimateSize() > 0) { 593 assertTrue(leftSplit.estimateSize() < parentEstimateSize, 594 String.format("Left split size estimate %d >= parent split size estimate %d", 595 leftSplit.estimateSize(), parentEstimateSize)); 596 assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize, 597 String.format("Right split size estimate %d >= parent split size estimate %d", 598 leftSplit.estimateSize(), parentEstimateSize)); 599 } 600 else { 601 assertTrue(leftSplit.estimateSize() <= parentEstimateSize, 602 String.format("Left split size estimate %d > parent split size estimate %d", 603 leftSplit.estimateSize(), parentEstimateSize)); 604 assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize, 605 String.format("Right split size estimate %d > parent split size estimate %d", 606 leftSplit.estimateSize(), parentEstimateSize)); 607 } 608 609 long leftSize = leftSplit.getExactSizeIfKnown(); 610 long rightSize = parentAndRightSplit.getExactSizeIfKnown(); 611 if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0) 612 assertEquals(parentSize, leftSize + rightSize, 613 String.format("exact left split size %d + exact right split size %d != parent exact split size %d", 614 leftSize, rightSize, parentSize)); 615 616 // Add right side to stack first so left side is popped off first 617 stack.push(e.fromSplit(parentAndRightSplit)); 618 stack.push(e.fromSplit(leftSplit)); 619 } 620 } 621 622 private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) { 623 if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) { 624 assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED), 625 "Child split is not SUBSIZED when root split is SUBSIZED"); 626 } 627 assertSpliterator(s); 628 } 629 630 private static void assertSpliterator(Spliterator<?> s) { 631 if (s.hasCharacteristics(Spliterator.SUBSIZED)) { 632 assertTrue(s.hasCharacteristics(Spliterator.SIZED)); 633 } 634 if (s.hasCharacteristics(Spliterator.SIZED)) { 635 assertTrue(s.estimateSize() != Long.MAX_VALUE); 636 assertTrue(s.getExactSizeIfKnown() >= 0); 637 } 638 try { 639 s.getComparator(); 640 assertTrue(s.hasCharacteristics(Spliterator.SORTED)); 641 } catch (IllegalStateException e) { 642 assertFalse(s.hasCharacteristics(Spliterator.SORTED)); 643 } 644 } 645 assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered)646 private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) { 647 if (isOrdered) { 648 assertEquals(actual, expected); 649 } 650 else { 651 LambdaTestHelpers.assertContentsUnordered(actual, expected); 652 } 653 } 654 assertThrowsNPE(ThrowingRunnable r)655 public static void assertThrowsNPE(ThrowingRunnable r) { 656 assertThrows(NullPointerException.class, r); 657 } 658 mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop)659 public static<U> void mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop) { 660 Spliterator<U> spl1, spl2, spl3; 661 splTop.tryAdvance(b); 662 spl2 = splTop.trySplit(); 663 if (spl2 != null) { 664 spl2.tryAdvance(b); 665 spl1 = spl2.trySplit(); 666 if (spl1 != null) { 667 spl1.tryAdvance(b); 668 spl1.forEachRemaining(b); 669 } 670 spl2.tryAdvance(b); 671 spl2.forEachRemaining(b); 672 } 673 splTop.tryAdvance(b); 674 spl3 = splTop.trySplit(); 675 if (spl3 != null) { 676 spl3.tryAdvance(b); 677 spl3.forEachRemaining(b); 678 } 679 splTop.tryAdvance(b); 680 splTop.forEachRemaining(b); 681 } 682 mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop)683 public static void mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop) { 684 Spliterator.OfInt spl1, spl2, spl3; 685 splTop.tryAdvance(b); 686 spl2 = splTop.trySplit(); 687 if (spl2 != null) { 688 spl2.tryAdvance(b); 689 spl1 = spl2.trySplit(); 690 if (spl1 != null) { 691 spl1.tryAdvance(b); 692 spl1.forEachRemaining(b); 693 } 694 spl2.tryAdvance(b); 695 spl2.forEachRemaining(b); 696 } 697 splTop.tryAdvance(b); 698 spl3 = splTop.trySplit(); 699 if (spl3 != null) { 700 spl3.tryAdvance(b); 701 spl3.forEachRemaining(b); 702 } 703 splTop.tryAdvance(b); 704 splTop.forEachRemaining(b); 705 } 706 mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop)707 public static void mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop) { 708 Spliterator.OfLong spl1, spl2, spl3; 709 splTop.tryAdvance(b); 710 spl2 = splTop.trySplit(); 711 if (spl2 != null) { 712 spl2.tryAdvance(b); 713 spl1 = spl2.trySplit(); 714 if (spl1 != null) { 715 spl1.tryAdvance(b); 716 spl1.forEachRemaining(b); 717 } 718 spl2.tryAdvance(b); 719 spl2.forEachRemaining(b); 720 } 721 splTop.tryAdvance(b); 722 spl3 = splTop.trySplit(); 723 if (spl3 != null) { 724 spl3.tryAdvance(b); 725 spl3.forEachRemaining(b); 726 } 727 splTop.tryAdvance(b); 728 splTop.forEachRemaining(b); 729 } 730 mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop)731 public static void mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop) { 732 Spliterator.OfDouble spl1, spl2, spl3; 733 splTop.tryAdvance(b); 734 spl2 = splTop.trySplit(); 735 if (spl2 != null) { 736 spl2.tryAdvance(b); 737 spl1 = spl2.trySplit(); 738 if (spl1 != null) { 739 spl1.tryAdvance(b); 740 spl1.forEachRemaining(b); 741 } 742 spl2.tryAdvance(b); 743 spl2.forEachRemaining(b); 744 } 745 splTop.tryAdvance(b); 746 spl3 = splTop.trySplit(); 747 if (spl3 != null) { 748 spl3.tryAdvance(b); 749 spl3.forEachRemaining(b); 750 } 751 splTop.tryAdvance(b); 752 splTop.forEachRemaining(b); 753 } 754 755 } 756