1 /* 2 * Copyright (c) 2013, 2016, 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 * @summary Spliterator traversing and splitting tests 27 * @run testng SpliteratorTraversingAndSplittingTest 28 * @bug 8020016 8071477 8072784 8169838 29 */ 30 31 import org.testng.annotations.DataProvider; 32 import org.testng.annotations.Test; 33 34 import java.nio.CharBuffer; 35 import java.util.AbstractCollection; 36 import java.util.AbstractList; 37 import java.util.AbstractSet; 38 import java.util.ArrayDeque; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.BitSet; 42 import java.util.Collection; 43 import java.util.Collections; 44 import java.util.Comparator; 45 import java.util.Deque; 46 import java.util.HashMap; 47 import java.util.HashSet; 48 import java.util.IdentityHashMap; 49 import java.util.Iterator; 50 import java.util.LinkedHashMap; 51 import java.util.LinkedHashSet; 52 import java.util.LinkedList; 53 import java.util.List; 54 import java.util.ListIterator; 55 import java.util.Map; 56 import java.util.PriorityQueue; 57 import java.util.RandomAccess; 58 import java.util.Set; 59 import java.util.SortedSet; 60 import java.util.Spliterator; 61 import java.util.Spliterators; 62 import java.util.Stack; 63 import java.util.TreeMap; 64 import java.util.TreeSet; 65 import java.util.Vector; 66 import java.util.WeakHashMap; 67 import java.util.concurrent.ArrayBlockingQueue; 68 import java.util.concurrent.ConcurrentHashMap; 69 import java.util.concurrent.ConcurrentLinkedQueue; 70 import java.util.concurrent.ConcurrentSkipListMap; 71 import java.util.concurrent.ConcurrentSkipListSet; 72 import java.util.concurrent.CopyOnWriteArrayList; 73 import java.util.concurrent.CopyOnWriteArraySet; 74 import java.util.concurrent.LinkedBlockingDeque; 75 import java.util.concurrent.LinkedBlockingQueue; 76 import java.util.concurrent.LinkedTransferQueue; 77 import java.util.concurrent.PriorityBlockingQueue; 78 import java.util.function.Consumer; 79 import java.util.function.DoubleConsumer; 80 import java.util.function.Function; 81 import java.util.function.IntConsumer; 82 import java.util.function.LongConsumer; 83 import java.util.function.Supplier; 84 import java.util.function.UnaryOperator; 85 import java.util.stream.IntStream; 86 87 import static java.util.stream.Collectors.toList; 88 import static org.testng.Assert.*; 89 import static org.testng.Assert.assertEquals; 90 91 @Test 92 public class SpliteratorTraversingAndSplittingTest { 93 94 private static final List<Integer> SIZES = Arrays.asList(0, 1, 10, 42); 95 96 private static final String LOW = new String(new char[] {Character.MIN_LOW_SURROGATE}); 97 private static final String HIGH = new String(new char[] {Character.MIN_HIGH_SURROGATE}); 98 private static final String HIGH_LOW = HIGH + LOW; 99 private static final String CHAR_HIGH_LOW = "A" + HIGH_LOW; 100 private static final String HIGH_LOW_CHAR = HIGH_LOW + "A"; 101 private static final String CHAR_HIGH_LOW_CHAR = "A" + HIGH_LOW + "A"; 102 103 private static final List<String> STRINGS = generateTestStrings(); 104 105 private static List<String> generateTestStrings() { 106 List<String> strings = new ArrayList<>(); 107 for (int n : Arrays.asList(1, 2, 3, 16, 17)) { 108 strings.add(generate("A", n)); 109 strings.add(generate(LOW, n)); 110 strings.add(generate(HIGH, n)); 111 strings.add(generate(HIGH_LOW, n)); 112 strings.add(generate(CHAR_HIGH_LOW, n)); 113 strings.add(generate(HIGH_LOW_CHAR, n)); 114 strings.add(generate(CHAR_HIGH_LOW_CHAR, n)); 115 } 116 return strings; 117 } 118 119 private static String generate(String s, int n) { 120 StringBuilder sb = new StringBuilder(); 121 for (int i = 0; i < n; i++) { 122 sb.append(s); 123 } 124 return sb.toString(); 125 } 126 127 private static class SpliteratorDataBuilder<T> { 128 List<Object[]> data; 129 130 List<T> exp; 131 132 Map<T, T> mExp; 133 134 SpliteratorDataBuilder(List<Object[]> data, List<T> exp) { 135 this.data = data; 136 this.exp = exp; 137 this.mExp = createMap(exp); 138 } 139 140 Map<T, T> createMap(List<T> l) { 141 Map<T, T> m = new LinkedHashMap<>(); 142 for (T t : l) { 143 m.put(t, t); 144 } 145 return m; 146 } 147 148 void add(String description, Collection<?> expected, Supplier<Spliterator<?>> s) { 149 description = joiner(description).toString(); 150 data.add(new Object[]{description, expected, s}); 151 } 152 153 void add(String description, Supplier<Spliterator<?>> s) { 154 add(description, exp, s); 155 } 156 157 void addCollection(Function<Collection<T>, ? extends Collection<T>> c) { 158 add("new " + c.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator()", 159 () -> c.apply(exp).spliterator()); 160 } 161 162 void addList(Function<Collection<T>, ? extends List<T>> l) { 163 addCollection(l); 164 addCollection(l.andThen(list -> list.subList(0, list.size()))); 165 } 166 167 void addMap(Function<Map<T, T>, ? extends Map<T, T>> m) { 168 String description = "new " + m.apply(Collections.<T, T>emptyMap()).getClass().getName(); 169 addMap(m, description); 170 } 171 172 void addMap(Function<Map<T, T>, ? extends Map<T, T>> m, String description) { 173 add(description + ".keySet().spliterator()", () -> m.apply(mExp).keySet().spliterator()); 174 add(description + ".values().spliterator()", () -> m.apply(mExp).values().spliterator()); 175 add(description + ".entrySet().spliterator()", mExp.entrySet(), () -> m.apply(mExp).entrySet().spliterator()); 176 } 177 178 StringBuilder joiner(String description) { 179 return new StringBuilder(description). 180 append(" {"). 181 append("size=").append(exp.size()). 182 append("}"); 183 } 184 } 185 186 static Object[][] spliteratorDataProvider; 187 188 @DataProvider(name = "Spliterator<Integer>") 189 public static Object[][] spliteratorDataProvider() { 190 if (spliteratorDataProvider != null) { 191 return spliteratorDataProvider; 192 } 193 194 List<Object[]> data = new ArrayList<>(); 195 for (int size : SIZES) { 196 List<Integer> exp = listIntRange(size); 197 SpliteratorDataBuilder<Integer> db = new SpliteratorDataBuilder<>(data, exp); 198 199 // Direct spliterator methods 200 201 db.add("Spliterators.spliterator(Collection, ...)", 202 () -> Spliterators.spliterator(exp, 0)); 203 204 db.add("Spliterators.spliterator(Iterator, ...)", 205 () -> Spliterators.spliterator(exp.iterator(), exp.size(), 0)); 206 207 db.add("Spliterators.spliteratorUnknownSize(Iterator, ...)", 208 () -> Spliterators.spliteratorUnknownSize(exp.iterator(), 0)); 209 210 db.add("Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Spliterator ), ...)", 211 () -> Spliterators.spliterator(Spliterators.iterator(exp.spliterator()), exp.size(), 0)); 212 213 db.add("Spliterators.spliterator(T[], ...)", 214 () -> Spliterators.spliterator(exp.toArray(new Integer[0]), 0)); 215 216 db.add("Arrays.spliterator(T[], ...)", 217 () -> Arrays.spliterator(exp.toArray(new Integer[0]))); 218 219 class SpliteratorFromIterator extends Spliterators.AbstractSpliterator<Integer> { 220 Iterator<Integer> it; 221 222 SpliteratorFromIterator(Iterator<Integer> it, long est) { 223 super(est, Spliterator.SIZED); 224 this.it = it; 225 } 226 227 @Override 228 public boolean tryAdvance(Consumer<? super Integer> action) { 229 if (action == null) 230 throw new NullPointerException(); 231 if (it.hasNext()) { 232 action.accept(it.next()); 233 return true; 234 } 235 else { 236 return false; 237 } 238 } 239 } 240 db.add("new Spliterators.AbstractSpliterator()", 241 () -> new SpliteratorFromIterator(exp.iterator(), exp.size())); 242 243 // Collections 244 245 // default method implementations 246 247 class AbstractCollectionImpl extends AbstractCollection<Integer> { 248 Collection<Integer> c; 249 250 AbstractCollectionImpl(Collection<Integer> c) { 251 this.c = c; 252 } 253 254 @Override 255 public Iterator<Integer> iterator() { 256 return c.iterator(); 257 } 258 259 @Override 260 public int size() { 261 return c.size(); 262 } 263 } 264 db.addCollection( 265 c -> new AbstractCollectionImpl(c)); 266 267 class AbstractListImpl extends AbstractList<Integer> { 268 List<Integer> l; 269 270 AbstractListImpl(Collection<Integer> c) { 271 this.l = new ArrayList<>(c); 272 } 273 274 @Override 275 public Integer get(int index) { 276 return l.get(index); 277 } 278 279 @Override 280 public int size() { 281 return l.size(); 282 } 283 } 284 db.addCollection( 285 c -> new AbstractListImpl(c)); 286 287 class AbstractSetImpl extends AbstractSet<Integer> { 288 Set<Integer> s; 289 290 AbstractSetImpl(Collection<Integer> c) { 291 this.s = new HashSet<>(c); 292 } 293 294 @Override 295 public Iterator<Integer> iterator() { 296 return s.iterator(); 297 } 298 299 @Override 300 public int size() { 301 return s.size(); 302 } 303 } 304 db.addCollection( 305 c -> new AbstractSetImpl(c)); 306 307 class AbstractSortedSetImpl extends AbstractSet<Integer> implements SortedSet<Integer> { 308 SortedSet<Integer> s; 309 310 AbstractSortedSetImpl(Collection<Integer> c) { 311 this.s = new TreeSet<>(c); 312 } 313 314 @Override 315 public Iterator<Integer> iterator() { 316 return s.iterator(); 317 } 318 319 @Override 320 public int size() { 321 return s.size(); 322 } 323 324 @Override 325 public Comparator<? super Integer> comparator() { 326 return s.comparator(); 327 } 328 329 @Override 330 public SortedSet<Integer> subSet(Integer fromElement, Integer toElement) { 331 return s.subSet(fromElement, toElement); 332 } 333 334 @Override 335 public SortedSet<Integer> headSet(Integer toElement) { 336 return s.headSet(toElement); 337 } 338 339 @Override 340 public SortedSet<Integer> tailSet(Integer fromElement) { 341 return s.tailSet(fromElement); 342 } 343 344 @Override 345 public Integer first() { 346 return s.first(); 347 } 348 349 @Override 350 public Integer last() { 351 return s.last(); 352 } 353 354 @Override 355 public Spliterator<Integer> spliterator() { 356 return SortedSet.super.spliterator(); 357 } 358 } 359 db.addCollection( 360 c -> new AbstractSortedSetImpl(c)); 361 362 class IterableWrapper implements Iterable<Integer> { 363 final Iterable<Integer> it; 364 365 IterableWrapper(Iterable<Integer> it) { 366 this.it = it; 367 } 368 369 @Override 370 public Iterator<Integer> iterator() { 371 return it.iterator(); 372 } 373 } 374 db.add("new Iterable.spliterator()", 375 () -> new IterableWrapper(exp).spliterator()); 376 377 // 378 379 db.add("Arrays.asList().spliterator()", 380 () -> Spliterators.spliterator(Arrays.asList(exp.toArray(new Integer[0])), 0)); 381 382 db.addList(ArrayList::new); 383 384 db.addList(LinkedList::new); 385 386 db.addList(Vector::new); 387 388 class AbstractRandomAccessListImpl extends AbstractList<Integer> implements RandomAccess { 389 Integer[] ia; 390 391 AbstractRandomAccessListImpl(Collection<Integer> c) { 392 this.ia = c.toArray(new Integer[c.size()]); 393 } 394 395 @Override 396 public Integer get(int index) { 397 return ia[index]; 398 } 399 400 @Override 401 public int size() { 402 return ia.length; 403 } 404 } 405 db.addList(AbstractRandomAccessListImpl::new); 406 407 class RandomAccessListImpl implements List<Integer>, RandomAccess { 408 Integer[] ia; 409 List<Integer> l; 410 411 RandomAccessListImpl(Collection<Integer> c) { 412 this.ia = c.toArray(new Integer[c.size()]); 413 this.l = Arrays.asList(ia); 414 } 415 416 @Override 417 public Integer get(int index) { 418 return ia[index]; 419 } 420 421 @Override 422 public Integer set(int index, Integer element) { 423 throw new UnsupportedOperationException(); 424 } 425 426 @Override 427 public void add(int index, Integer element) { 428 throw new UnsupportedOperationException(); 429 } 430 431 @Override 432 public Integer remove(int index) { 433 throw new UnsupportedOperationException(); 434 } 435 436 @Override 437 public int indexOf(Object o) { 438 return l.indexOf(o); 439 } 440 441 @Override 442 public int lastIndexOf(Object o) { 443 return Arrays.asList(ia).lastIndexOf(o); 444 } 445 446 @Override 447 public ListIterator<Integer> listIterator() { 448 return l.listIterator(); 449 } 450 451 @Override 452 public ListIterator<Integer> listIterator(int index) { 453 return l.listIterator(index); 454 } 455 456 @Override 457 public List<Integer> subList(int fromIndex, int toIndex) { 458 return l.subList(fromIndex, toIndex); 459 } 460 461 @Override 462 public int size() { 463 return ia.length; 464 } 465 466 @Override 467 public boolean isEmpty() { 468 return size() != 0; 469 } 470 471 @Override 472 public boolean contains(Object o) { 473 return l.contains(o); 474 } 475 476 @Override 477 public Iterator<Integer> iterator() { 478 return l.iterator(); 479 } 480 481 @Override 482 public Object[] toArray() { 483 return l.toArray(); 484 } 485 486 @Override 487 public <T> T[] toArray(T[] a) { 488 return l.toArray(a); 489 } 490 491 @Override 492 public boolean add(Integer integer) { 493 throw new UnsupportedOperationException(); 494 } 495 496 @Override 497 public boolean remove(Object o) { 498 throw new UnsupportedOperationException(); 499 } 500 501 @Override 502 public boolean containsAll(Collection<?> c) { 503 return l.containsAll(c); 504 } 505 506 @Override 507 public boolean addAll(Collection<? extends Integer> c) { 508 throw new UnsupportedOperationException(); 509 } 510 511 @Override 512 public boolean addAll(int index, Collection<? extends Integer> c) { 513 throw new UnsupportedOperationException(); 514 } 515 516 @Override 517 public boolean removeAll(Collection<?> c) { 518 throw new UnsupportedOperationException(); 519 } 520 521 @Override 522 public boolean retainAll(Collection<?> c) { 523 throw new UnsupportedOperationException(); 524 } 525 526 @Override 527 public void clear() { 528 throw new UnsupportedOperationException(); 529 } 530 } 531 db.addList(RandomAccessListImpl::new); 532 533 db.addCollection(HashSet::new); 534 535 db.addCollection(LinkedHashSet::new); 536 537 db.addCollection(TreeSet::new); 538 539 540 db.addCollection(c -> { Stack<Integer> s = new Stack<>(); s.addAll(c); return s;}); 541 542 db.addCollection(PriorityQueue::new); 543 544 db.addCollection(ArrayDeque::new); 545 546 547 db.addCollection(ConcurrentSkipListSet::new); 548 549 if (size > 0) { 550 db.addCollection(c -> { 551 ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<>(size); 552 abq.addAll(c); 553 return abq; 554 }); 555 } 556 557 db.addCollection(PriorityBlockingQueue::new); 558 559 db.addCollection(LinkedBlockingQueue::new); 560 561 db.addCollection(LinkedTransferQueue::new); 562 563 db.addCollection(ConcurrentLinkedQueue::new); 564 565 db.addCollection(LinkedBlockingDeque::new); 566 567 db.addCollection(CopyOnWriteArrayList::new); 568 569 db.addCollection(CopyOnWriteArraySet::new); 570 571 if (size == 0) { 572 db.addCollection(c -> Collections.<Integer>emptySet()); 573 db.addList(c -> Collections.<Integer>emptyList()); 574 } 575 else if (size == 1) { 576 db.addCollection(c -> Collections.singleton(exp.get(0))); 577 db.addCollection(c -> Collections.singletonList(exp.get(0))); 578 } 579 580 { 581 Integer[] ai = new Integer[size]; 582 Arrays.fill(ai, 1); 583 db.add(String.format("Collections.nCopies(%d, 1)", exp.size()), 584 Arrays.asList(ai), 585 () -> Collections.nCopies(exp.size(), 1).spliterator()); 586 } 587 588 // Collections.synchronized/unmodifiable/checked wrappers 589 db.addCollection(Collections::unmodifiableCollection); 590 db.addCollection(c -> Collections.unmodifiableSet(new HashSet<>(c))); 591 db.addCollection(c -> Collections.unmodifiableSortedSet(new TreeSet<>(c))); 592 db.addList(c -> Collections.unmodifiableList(new ArrayList<>(c))); 593 db.addMap(Collections::unmodifiableMap); 594 db.addMap(m -> Collections.unmodifiableSortedMap(new TreeMap<>(m))); 595 596 db.addCollection(Collections::synchronizedCollection); 597 db.addCollection(c -> Collections.synchronizedSet(new HashSet<>(c))); 598 db.addCollection(c -> Collections.synchronizedSortedSet(new TreeSet<>(c))); 599 db.addList(c -> Collections.synchronizedList(new ArrayList<>(c))); 600 db.addMap(Collections::synchronizedMap); 601 db.addMap(m -> Collections.synchronizedSortedMap(new TreeMap<>(m))); 602 603 db.addCollection(c -> Collections.checkedCollection(c, Integer.class)); 604 db.addCollection(c -> Collections.checkedQueue(new ArrayDeque<>(c), Integer.class)); 605 db.addCollection(c -> Collections.checkedSet(new HashSet<>(c), Integer.class)); 606 db.addCollection(c -> Collections.checkedSortedSet(new TreeSet<>(c), Integer.class)); 607 db.addList(c -> Collections.checkedList(new ArrayList<>(c), Integer.class)); 608 db.addMap(c -> Collections.checkedMap(c, Integer.class, Integer.class)); 609 db.addMap(m -> Collections.checkedSortedMap(new TreeMap<>(m), Integer.class, Integer.class)); 610 611 // Maps 612 613 db.addMap(HashMap::new); 614 615 db.addMap(m -> { 616 // Create a Map ensuring that for large sizes 617 // buckets will contain 2 or more entries 618 HashMap<Integer, Integer> cm = new HashMap<>(1, m.size() + 1); 619 // Don't use putAll which inflates the table by 620 // m.size() * loadFactor, thus creating a very sparse 621 // map for 1000 entries defeating the purpose of this test, 622 // in addition it will cause the split until null test to fail 623 // because the number of valid splits is larger than the 624 // threshold 625 for (Map.Entry<Integer, Integer> e : m.entrySet()) 626 cm.put(e.getKey(), e.getValue()); 627 return cm; 628 }, "new java.util.HashMap(1, size + 1)"); 629 630 db.addMap(LinkedHashMap::new); 631 632 db.addMap(IdentityHashMap::new); 633 634 db.addMap(WeakHashMap::new); 635 636 db.addMap(m -> { 637 // Create a Map ensuring that for large sizes 638 // buckets will be consist of 2 or more entries 639 WeakHashMap<Integer, Integer> cm = new WeakHashMap<>(1, m.size() + 1); 640 for (Map.Entry<Integer, Integer> e : m.entrySet()) 641 cm.put(e.getKey(), e.getValue()); 642 return cm; 643 }, "new java.util.WeakHashMap(1, size + 1)"); 644 645 // @@@ Descending maps etc 646 db.addMap(TreeMap::new); 647 648 db.addMap(ConcurrentHashMap::new); 649 650 db.addMap(ConcurrentSkipListMap::new); 651 652 if (size == 0) { 653 db.addMap(m -> Collections.<Integer, Integer>emptyMap()); 654 } 655 else if (size == 1) { 656 db.addMap(m -> Collections.singletonMap(exp.get(0), exp.get(0))); 657 } 658 } 659 660 return spliteratorDataProvider = data.toArray(new Object[0][]); 661 } 662 663 private static List<Integer> listIntRange(int upTo) { 664 List<Integer> exp = new ArrayList<>(); 665 for (int i = 0; i < upTo; i++) 666 exp.add(i); 667 return Collections.unmodifiableList(exp); 668 } 669 670 @Test(dataProvider = "Spliterator<Integer>") 671 @SuppressWarnings({"unchecked", "rawtypes"}) 672 public void testNullPointerException(String description, Collection exp, Supplier<Spliterator> s) { 673 executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining(null)); 674 executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance(null)); 675 } 676 677 @Test(dataProvider = "Spliterator<Integer>") 678 @SuppressWarnings({"unchecked", "rawtypes"}) 679 public void testForEach(String description, Collection exp, Supplier<Spliterator> s) { 680 testForEach(exp, s, (Consumer<Object> b) -> b); 681 } 682 683 @Test(dataProvider = "Spliterator<Integer>") 684 @SuppressWarnings({"unchecked", "rawtypes"}) 685 public void testTryAdvance(String description, Collection exp, Supplier<Spliterator> s) { 686 testTryAdvance(exp, s, (Consumer<Object> b) -> b); 687 } 688 689 @Test(dataProvider = "Spliterator<Integer>") 690 @SuppressWarnings({"unchecked", "rawtypes"}) 691 public void testMixedTryAdvanceForEach(String description, Collection exp, Supplier<Spliterator> s) { 692 testMixedTryAdvanceForEach(exp, s, (Consumer<Object> b) -> b); 693 } 694 695 @Test(dataProvider = "Spliterator<Integer>") 696 @SuppressWarnings({"unchecked", "rawtypes"}) 697 public void testSplitAfterFullTraversal(String description, Collection exp, Supplier<Spliterator> s) { 698 testSplitAfterFullTraversal(s, (Consumer<Object> b) -> b); 699 } 700 701 @Test(dataProvider = "Spliterator<Integer>") 702 @SuppressWarnings({"unchecked", "rawtypes"}) 703 public void testSplitOnce(String description, Collection exp, Supplier<Spliterator> s) { 704 testSplitOnce(exp, s, (Consumer<Object> b) -> b); 705 } 706 707 @Test(dataProvider = "Spliterator<Integer>") 708 @SuppressWarnings({"unchecked", "rawtypes"}) 709 public void testSplitSixDeep(String description, Collection exp, Supplier<Spliterator> s) { 710 testSplitSixDeep(exp, s, (Consumer<Object> b) -> b); 711 } 712 713 @Test(dataProvider = "Spliterator<Integer>") 714 @SuppressWarnings({"unchecked", "rawtypes"}) 715 public void testSplitUntilNull(String description, Collection exp, Supplier<Spliterator> s) { 716 testSplitUntilNull(exp, s, (Consumer<Object> b) -> b); 717 } 718 719 // 720 721 private static class SpliteratorOfIntDataBuilder { 722 List<Object[]> data; 723 724 List<Integer> exp; 725 726 SpliteratorOfIntDataBuilder(List<Object[]> data, List<Integer> exp) { 727 this.data = data; 728 this.exp = exp; 729 } 730 731 void add(String description, List<Integer> expected, Supplier<Spliterator.OfInt> s) { 732 description = joiner(description).toString(); 733 data.add(new Object[]{description, expected, s}); 734 } 735 736 void add(String description, Supplier<Spliterator.OfInt> s) { 737 add(description, exp, s); 738 } 739 740 StringBuilder joiner(String description) { 741 return new StringBuilder(description). 742 append(" {"). 743 append("size=").append(exp.size()). 744 append("}"); 745 } 746 } 747 748 private static class SpliteratorOfIntCharDataBuilder { 749 List<Object[]> data; 750 751 String s; 752 753 List<Integer> expChars; 754 755 List<Integer> expCodePoints; 756 757 SpliteratorOfIntCharDataBuilder(List<Object[]> data, String s) { 758 this.data = data; 759 this.s = s; 760 this.expChars = transform(s, false); 761 this.expCodePoints = transform(s, true); 762 } 763 764 static List<Integer> transform(String s, boolean toCodePoints) { 765 List<Integer> l = new ArrayList<>(); 766 767 if (!toCodePoints) { 768 for (int i = 0; i < s.length(); i++) { 769 l.add((int) s.charAt(i)); 770 } 771 } 772 else { 773 for (int i = 0; i < s.length();) { 774 char c1 = s.charAt(i++); 775 int cp = c1; 776 if (Character.isHighSurrogate(c1) && i < s.length()) { 777 char c2 = s.charAt(i); 778 if (Character.isLowSurrogate(c2)) { 779 i++; 780 cp = Character.toCodePoint(c1, c2); 781 } 782 } 783 l.add(cp); 784 } 785 } 786 return l; 787 } 788 789 void add(String description, Function<String, CharSequence> f) { 790 description = description.replace("%s", s); 791 { 792 Supplier<Spliterator.OfInt> supplier = () -> f.apply(s).chars().spliterator(); 793 data.add(new Object[]{description + ".chars().spliterator()", expChars, supplier}); 794 } 795 { 796 Supplier<Spliterator.OfInt> supplier = () -> f.apply(s).codePoints().spliterator(); 797 data.add(new Object[]{description + ".codePoints().spliterator()", expCodePoints, supplier}); 798 } 799 } 800 } 801 802 static Object[][] spliteratorOfIntDataProvider; 803 804 @DataProvider(name = "Spliterator.OfInt") 805 public static Object[][] spliteratorOfIntDataProvider() { 806 if (spliteratorOfIntDataProvider != null) { 807 return spliteratorOfIntDataProvider; 808 } 809 810 List<Object[]> data = new ArrayList<>(); 811 for (int size : SIZES) { 812 int exp[] = arrayIntRange(size); 813 SpliteratorOfIntDataBuilder db = new SpliteratorOfIntDataBuilder(data, listIntRange(size)); 814 815 db.add("Spliterators.spliterator(int[], ...)", 816 () -> Spliterators.spliterator(exp, 0)); 817 818 db.add("Arrays.spliterator(int[], ...)", 819 () -> Arrays.spliterator(exp)); 820 821 db.add("Spliterators.spliterator(PrimitiveIterator.OfInt, ...)", 822 () -> Spliterators.spliterator(Spliterators.iterator(Arrays.spliterator(exp)), exp.length, 0)); 823 824 db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfInt, ...)", 825 () -> Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(exp)), 0)); 826 827 class IntSpliteratorFromArray extends Spliterators.AbstractIntSpliterator { 828 int[] a; 829 int index = 0; 830 831 IntSpliteratorFromArray(int[] a) { 832 super(a.length, Spliterator.SIZED); 833 this.a = a; 834 } 835 836 @Override 837 public boolean tryAdvance(IntConsumer action) { 838 if (action == null) 839 throw new NullPointerException(); 840 if (index < a.length) { 841 action.accept(a[index++]); 842 return true; 843 } 844 else { 845 return false; 846 } 847 } 848 } 849 db.add("new Spliterators.AbstractIntAdvancingSpliterator()", 850 () -> new IntSpliteratorFromArray(exp)); 851 } 852 853 // Class for testing default methods 854 class CharSequenceImpl implements CharSequence { 855 final String s; 856 857 public CharSequenceImpl(String s) { 858 this.s = s; 859 } 860 861 @Override 862 public int length() { 863 return s.length(); 864 } 865 866 @Override 867 public char charAt(int index) { 868 return s.charAt(index); 869 } 870 871 @Override 872 public CharSequence subSequence(int start, int end) { 873 return s.subSequence(start, end); 874 } 875 876 @Override 877 public String toString() { 878 return s; 879 } 880 } 881 882 for (String string : STRINGS) { 883 SpliteratorOfIntCharDataBuilder cdb = new SpliteratorOfIntCharDataBuilder(data, string); 884 cdb.add("\"%s\"", s -> s); 885 cdb.add("new CharSequenceImpl(\"%s\")", CharSequenceImpl::new); 886 cdb.add("new StringBuilder(\"%s\")", StringBuilder::new); 887 cdb.add("new StringBuffer(\"%s\")", StringBuffer::new); 888 cdb.add("CharBuffer.wrap(\"%s\".toCharArray())", s -> CharBuffer.wrap(s.toCharArray())); 889 } 890 891 892 Object[][] bitStreamTestcases = new Object[][] { 893 { "none", IntStream.empty().toArray() }, 894 { "index 0", IntStream.of(0).toArray() }, 895 { "index 255", IntStream.of(255).toArray() }, 896 { "index 0 and 255", IntStream.of(0, 255).toArray() }, 897 { "every bit", IntStream.range(0, 255).toArray() }, 898 { "step 2", IntStream.range(0, 255).map(f -> f * 2).toArray() }, 899 { "step 3", IntStream.range(0, 255).map(f -> f * 3).toArray() }, 900 { "step 5", IntStream.range(0, 255).map(f -> f * 5).toArray() }, 901 { "step 7", IntStream.range(0, 255).map(f -> f * 7).toArray() }, 902 { "1, 10, 100, 1000", IntStream.of(1, 10, 100, 1000).toArray() }, 903 }; 904 for (Object[] tc : bitStreamTestcases) { 905 String description = (String)tc[0]; 906 int[] exp = (int[])tc[1]; 907 SpliteratorOfIntDataBuilder db = new SpliteratorOfIntDataBuilder( 908 data, IntStream.of(exp).boxed().collect(toList())); 909 910 db.add("BitSet.stream.spliterator() {" + description + "}", () -> 911 IntStream.of(exp).collect(BitSet::new, BitSet::set, BitSet::or). 912 stream().spliterator() 913 ); 914 } 915 return spliteratorOfIntDataProvider = data.toArray(new Object[0][]); 916 } 917 918 private static int[] arrayIntRange(int upTo) { 919 int[] exp = new int[upTo]; 920 for (int i = 0; i < upTo; i++) 921 exp[i] = i; 922 return exp; 923 } 924 925 private static UnaryOperator<Consumer<Integer>> intBoxingConsumer() { 926 class BoxingAdapter implements Consumer<Integer>, IntConsumer { 927 private final Consumer<Integer> b; 928 929 BoxingAdapter(Consumer<Integer> b) { 930 this.b = b; 931 } 932 933 @Override 934 public void accept(Integer value) { 935 throw new IllegalStateException(); 936 } 937 938 @Override 939 public void accept(int value) { 940 b.accept(value); 941 } 942 } 943 944 return b -> new BoxingAdapter(b); 945 } 946 947 @Test(dataProvider = "Spliterator.OfInt") 948 public void testIntNullPointerException(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) { 949 executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining((IntConsumer) null)); 950 executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance((IntConsumer) null)); 951 } 952 953 @Test(dataProvider = "Spliterator.OfInt") 954 public void testIntForEach(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) { 955 testForEach(exp, s, intBoxingConsumer()); 956 } 957 958 @Test(dataProvider = "Spliterator.OfInt") 959 public void testIntTryAdvance(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) { 960 testTryAdvance(exp, s, intBoxingConsumer()); 961 } 962 963 @Test(dataProvider = "Spliterator.OfInt") 964 public void testIntMixedTryAdvanceForEach(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) { 965 testMixedTryAdvanceForEach(exp, s, intBoxingConsumer()); 966 } 967 968 @Test(dataProvider = "Spliterator.OfInt") 969 public void testIntSplitAfterFullTraversal(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) { 970 testSplitAfterFullTraversal(s, intBoxingConsumer()); 971 } 972 973 @Test(dataProvider = "Spliterator.OfInt") 974 public void testIntSplitOnce(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) { 975 testSplitOnce(exp, s, intBoxingConsumer()); 976 } 977 978 @Test(dataProvider = "Spliterator.OfInt") 979 public void testIntSplitSixDeep(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) { 980 testSplitSixDeep(exp, s, intBoxingConsumer()); 981 } 982 983 @Test(dataProvider = "Spliterator.OfInt") 984 public void testIntSplitUntilNull(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) { 985 testSplitUntilNull(exp, s, intBoxingConsumer()); 986 } 987 988 // 989 990 private static class SpliteratorOfLongDataBuilder { 991 List<Object[]> data; 992 993 List<Long> exp; 994 995 SpliteratorOfLongDataBuilder(List<Object[]> data, List<Long> exp) { 996 this.data = data; 997 this.exp = exp; 998 } 999 1000 void add(String description, List<Long> expected, Supplier<Spliterator.OfLong> s) { 1001 description = joiner(description).toString(); 1002 data.add(new Object[]{description, expected, s}); 1003 } 1004 1005 void add(String description, Supplier<Spliterator.OfLong> s) { 1006 add(description, exp, s); 1007 } 1008 1009 StringBuilder joiner(String description) { 1010 return new StringBuilder(description). 1011 append(" {"). 1012 append("size=").append(exp.size()). 1013 append("}"); 1014 } 1015 } 1016 1017 static Object[][] spliteratorOfLongDataProvider; 1018 1019 @DataProvider(name = "Spliterator.OfLong") 1020 public static Object[][] spliteratorOfLongDataProvider() { 1021 if (spliteratorOfLongDataProvider != null) { 1022 return spliteratorOfLongDataProvider; 1023 } 1024 1025 List<Object[]> data = new ArrayList<>(); 1026 for (int size : SIZES) { 1027 long exp[] = arrayLongRange(size); 1028 SpliteratorOfLongDataBuilder db = new SpliteratorOfLongDataBuilder(data, listLongRange(size)); 1029 1030 db.add("Spliterators.spliterator(long[], ...)", 1031 () -> Spliterators.spliterator(exp, 0)); 1032 1033 db.add("Arrays.spliterator(long[], ...)", 1034 () -> Arrays.spliterator(exp)); 1035 1036 db.add("Spliterators.spliterator(PrimitiveIterator.OfLong, ...)", 1037 () -> Spliterators.spliterator(Spliterators.iterator(Arrays.spliterator(exp)), exp.length, 0)); 1038 1039 db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfLong, ...)", 1040 () -> Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(exp)), 0)); 1041 1042 class LongSpliteratorFromArray extends Spliterators.AbstractLongSpliterator { 1043 long[] a; 1044 int index = 0; 1045 1046 LongSpliteratorFromArray(long[] a) { 1047 super(a.length, Spliterator.SIZED); 1048 this.a = a; 1049 } 1050 1051 @Override 1052 public boolean tryAdvance(LongConsumer action) { 1053 if (action == null) 1054 throw new NullPointerException(); 1055 if (index < a.length) { 1056 action.accept(a[index++]); 1057 return true; 1058 } 1059 else { 1060 return false; 1061 } 1062 } 1063 } 1064 db.add("new Spliterators.AbstractLongAdvancingSpliterator()", 1065 () -> new LongSpliteratorFromArray(exp)); 1066 } 1067 1068 return spliteratorOfLongDataProvider = data.toArray(new Object[0][]); 1069 } 1070 1071 private static List<Long> listLongRange(int upTo) { 1072 List<Long> exp = new ArrayList<>(); 1073 for (long i = 0; i < upTo; i++) 1074 exp.add(i); 1075 return Collections.unmodifiableList(exp); 1076 } 1077 1078 private static long[] arrayLongRange(int upTo) { 1079 long[] exp = new long[upTo]; 1080 for (int i = 0; i < upTo; i++) 1081 exp[i] = i; 1082 return exp; 1083 } 1084 1085 private static UnaryOperator<Consumer<Long>> longBoxingConsumer() { 1086 class BoxingAdapter implements Consumer<Long>, LongConsumer { 1087 private final Consumer<Long> b; 1088 1089 BoxingAdapter(Consumer<Long> b) { 1090 this.b = b; 1091 } 1092 1093 @Override 1094 public void accept(Long value) { 1095 throw new IllegalStateException(); 1096 } 1097 1098 @Override 1099 public void accept(long value) { 1100 b.accept(value); 1101 } 1102 } 1103 1104 return b -> new BoxingAdapter(b); 1105 } 1106 1107 @Test(dataProvider = "Spliterator.OfLong") 1108 public void testLongNullPointerException(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) { 1109 executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining((LongConsumer) null)); 1110 executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance((LongConsumer) null)); 1111 } 1112 1113 @Test(dataProvider = "Spliterator.OfLong") 1114 public void testLongForEach(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) { 1115 testForEach(exp, s, longBoxingConsumer()); 1116 } 1117 1118 @Test(dataProvider = "Spliterator.OfLong") 1119 public void testLongTryAdvance(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) { 1120 testTryAdvance(exp, s, longBoxingConsumer()); 1121 } 1122 1123 @Test(dataProvider = "Spliterator.OfLong") 1124 public void testLongMixedTryAdvanceForEach(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) { 1125 testMixedTryAdvanceForEach(exp, s, longBoxingConsumer()); 1126 } 1127 1128 @Test(dataProvider = "Spliterator.OfLong") 1129 public void testLongSplitAfterFullTraversal(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) { 1130 testSplitAfterFullTraversal(s, longBoxingConsumer()); 1131 } 1132 1133 @Test(dataProvider = "Spliterator.OfLong") 1134 public void testLongSplitOnce(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) { 1135 testSplitOnce(exp, s, longBoxingConsumer()); 1136 } 1137 1138 @Test(dataProvider = "Spliterator.OfLong") 1139 public void testLongSplitSixDeep(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) { 1140 testSplitSixDeep(exp, s, longBoxingConsumer()); 1141 } 1142 1143 @Test(dataProvider = "Spliterator.OfLong") 1144 public void testLongSplitUntilNull(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) { 1145 testSplitUntilNull(exp, s, longBoxingConsumer()); 1146 } 1147 1148 // 1149 1150 private static class SpliteratorOfDoubleDataBuilder { 1151 List<Object[]> data; 1152 1153 List<Double> exp; 1154 1155 SpliteratorOfDoubleDataBuilder(List<Object[]> data, List<Double> exp) { 1156 this.data = data; 1157 this.exp = exp; 1158 } 1159 1160 void add(String description, List<Double> expected, Supplier<Spliterator.OfDouble> s) { 1161 description = joiner(description).toString(); 1162 data.add(new Object[]{description, expected, s}); 1163 } 1164 1165 void add(String description, Supplier<Spliterator.OfDouble> s) { 1166 add(description, exp, s); 1167 } 1168 1169 StringBuilder joiner(String description) { 1170 return new StringBuilder(description). 1171 append(" {"). 1172 append("size=").append(exp.size()). 1173 append("}"); 1174 } 1175 } 1176 1177 static Object[][] spliteratorOfDoubleDataProvider; 1178 1179 @DataProvider(name = "Spliterator.OfDouble") 1180 public static Object[][] spliteratorOfDoubleDataProvider() { 1181 if (spliteratorOfDoubleDataProvider != null) { 1182 return spliteratorOfDoubleDataProvider; 1183 } 1184 1185 List<Object[]> data = new ArrayList<>(); 1186 for (int size : SIZES) { 1187 double exp[] = arrayDoubleRange(size); 1188 SpliteratorOfDoubleDataBuilder db = new SpliteratorOfDoubleDataBuilder(data, listDoubleRange(size)); 1189 1190 db.add("Spliterators.spliterator(double[], ...)", 1191 () -> Spliterators.spliterator(exp, 0)); 1192 1193 db.add("Arrays.spliterator(double[], ...)", 1194 () -> Arrays.spliterator(exp)); 1195 1196 db.add("Spliterators.spliterator(PrimitiveIterator.OfDouble, ...)", 1197 () -> Spliterators.spliterator(Spliterators.iterator(Arrays.spliterator(exp)), exp.length, 0)); 1198 1199 db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfDouble, ...)", 1200 () -> Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(exp)), 0)); 1201 1202 class DoubleSpliteratorFromArray extends Spliterators.AbstractDoubleSpliterator { 1203 double[] a; 1204 int index = 0; 1205 1206 DoubleSpliteratorFromArray(double[] a) { 1207 super(a.length, Spliterator.SIZED); 1208 this.a = a; 1209 } 1210 1211 @Override 1212 public boolean tryAdvance(DoubleConsumer action) { 1213 if (action == null) 1214 throw new NullPointerException(); 1215 if (index < a.length) { 1216 action.accept(a[index++]); 1217 return true; 1218 } 1219 else { 1220 return false; 1221 } 1222 } 1223 } 1224 db.add("new Spliterators.AbstractDoubleAdvancingSpliterator()", 1225 () -> new DoubleSpliteratorFromArray(exp)); 1226 } 1227 1228 return spliteratorOfDoubleDataProvider = data.toArray(new Object[0][]); 1229 } 1230 1231 private static List<Double> listDoubleRange(int upTo) { 1232 List<Double> exp = new ArrayList<>(); 1233 for (double i = 0; i < upTo; i++) 1234 exp.add(i); 1235 return Collections.unmodifiableList(exp); 1236 } 1237 1238 private static double[] arrayDoubleRange(int upTo) { 1239 double[] exp = new double[upTo]; 1240 for (int i = 0; i < upTo; i++) 1241 exp[i] = i; 1242 return exp; 1243 } 1244 1245 private static UnaryOperator<Consumer<Double>> doubleBoxingConsumer() { 1246 class BoxingAdapter implements Consumer<Double>, DoubleConsumer { 1247 private final Consumer<Double> b; 1248 1249 BoxingAdapter(Consumer<Double> b) { 1250 this.b = b; 1251 } 1252 1253 @Override 1254 public void accept(Double value) { 1255 throw new IllegalStateException(); 1256 } 1257 1258 @Override 1259 public void accept(double value) { 1260 b.accept(value); 1261 } 1262 } 1263 1264 return b -> new BoxingAdapter(b); 1265 } 1266 1267 @Test(dataProvider = "Spliterator.OfDouble") 1268 public void testDoubleNullPointerException(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) { 1269 executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining((DoubleConsumer) null)); 1270 executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance((DoubleConsumer) null)); 1271 } 1272 1273 @Test(dataProvider = "Spliterator.OfDouble") 1274 public void testDoubleForEach(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) { 1275 testForEach(exp, s, doubleBoxingConsumer()); 1276 } 1277 1278 @Test(dataProvider = "Spliterator.OfDouble") 1279 public void testDoubleTryAdvance(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) { 1280 testTryAdvance(exp, s, doubleBoxingConsumer()); 1281 } 1282 1283 @Test(dataProvider = "Spliterator.OfDouble") 1284 public void testDoubleMixedTryAdvanceForEach(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) { 1285 testMixedTryAdvanceForEach(exp, s, doubleBoxingConsumer()); 1286 } 1287 1288 @Test(dataProvider = "Spliterator.OfDouble") 1289 public void testDoubleSplitAfterFullTraversal(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) { 1290 testSplitAfterFullTraversal(s, doubleBoxingConsumer()); 1291 } 1292 1293 @Test(dataProvider = "Spliterator.OfDouble") 1294 public void testDoubleSplitOnce(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) { 1295 testSplitOnce(exp, s, doubleBoxingConsumer()); 1296 } 1297 1298 @Test(dataProvider = "Spliterator.OfDouble") 1299 public void testDoubleSplitSixDeep(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) { 1300 testSplitSixDeep(exp, s, doubleBoxingConsumer()); 1301 } 1302 1303 @Test(dataProvider = "Spliterator.OfDouble") 1304 public void testDoubleSplitUntilNull(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) { 1305 testSplitUntilNull(exp, s, doubleBoxingConsumer()); 1306 } 1307 1308 // 1309 1310 private static <T, S extends Spliterator<T>> void testForEach( 1311 Collection<T> exp, 1312 Supplier<S> supplier, 1313 UnaryOperator<Consumer<T>> boxingAdapter) { 1314 S spliterator = supplier.get(); 1315 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 1316 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 1317 1318 ArrayList<T> fromForEach = new ArrayList<>(); 1319 spliterator = supplier.get(); 1320 Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add); 1321 spliterator.forEachRemaining(addToFromForEach); 1322 1323 // Assert that forEach now produces no elements 1324 spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); 1325 // Assert that tryAdvance now produce no elements 1326 spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); 1327 1328 // assert that size, tryAdvance, and forEach are consistent 1329 if (sizeIfKnown >= 0) { 1330 assertEquals(sizeIfKnown, exp.size()); 1331 } 1332 assertEquals(fromForEach.size(), exp.size()); 1333 1334 assertContents(fromForEach, exp, isOrdered); 1335 } 1336 1337 private static <T, S extends Spliterator<T>> void testTryAdvance( 1338 Collection<T> exp, 1339 Supplier<S> supplier, 1340 UnaryOperator<Consumer<T>> boxingAdapter) { 1341 S spliterator = supplier.get(); 1342 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 1343 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 1344 1345 spliterator = supplier.get(); 1346 ArrayList<T> fromTryAdvance = new ArrayList<>(); 1347 Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add); 1348 while (spliterator.tryAdvance(addToFromTryAdvance)) { } 1349 1350 // Assert that forEach now produces no elements 1351 spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); 1352 // Assert that tryAdvance now produce no elements 1353 spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); 1354 1355 // assert that size, tryAdvance, and forEach are consistent 1356 if (sizeIfKnown >= 0) { 1357 assertEquals(sizeIfKnown, exp.size()); 1358 } 1359 assertEquals(fromTryAdvance.size(), exp.size()); 1360 1361 assertContents(fromTryAdvance, exp, isOrdered); 1362 } 1363 1364 private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach( 1365 Collection<T> exp, 1366 Supplier<S> supplier, 1367 UnaryOperator<Consumer<T>> boxingAdapter) { 1368 S spliterator = supplier.get(); 1369 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 1370 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 1371 1372 // tryAdvance first few elements, then forEach rest 1373 ArrayList<T> dest = new ArrayList<>(); 1374 spliterator = supplier.get(); 1375 Consumer<T> addToDest = boxingAdapter.apply(dest::add); 1376 for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { } 1377 spliterator.forEachRemaining(addToDest); 1378 1379 // Assert that forEach now produces no elements 1380 spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); 1381 // Assert that tryAdvance now produce no elements 1382 spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); 1383 1384 if (sizeIfKnown >= 0) { 1385 assertEquals(sizeIfKnown, dest.size()); 1386 } 1387 assertEquals(dest.size(), exp.size()); 1388 1389 if (isOrdered) { 1390 assertEquals(dest, exp); 1391 } 1392 else { 1393 assertContentsUnordered(dest, exp); 1394 } 1395 } 1396 1397 private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal( 1398 Supplier<S> supplier, 1399 UnaryOperator<Consumer<T>> boxingAdapter) { 1400 // Full traversal using tryAdvance 1401 Spliterator<T> spliterator = supplier.get(); 1402 while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { } 1403 Spliterator<T> split = spliterator.trySplit(); 1404 assertNull(split); 1405 1406 // Full traversal using forEach 1407 spliterator = supplier.get(); 1408 spliterator.forEachRemaining(boxingAdapter.apply(e -> { 1409 })); 1410 split = spliterator.trySplit(); 1411 assertNull(split); 1412 1413 // Full traversal using tryAdvance then forEach 1414 spliterator = supplier.get(); 1415 spliterator.tryAdvance(boxingAdapter.apply(e -> { })); 1416 spliterator.forEachRemaining(boxingAdapter.apply(e -> { 1417 })); 1418 split = spliterator.trySplit(); 1419 assertNull(split); 1420 } 1421 1422 private static <T, S extends Spliterator<T>> void testSplitOnce( 1423 Collection<T> exp, 1424 Supplier<S> supplier, 1425 UnaryOperator<Consumer<T>> boxingAdapter) { 1426 S spliterator = supplier.get(); 1427 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 1428 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 1429 1430 ArrayList<T> fromSplit = new ArrayList<>(); 1431 Spliterator<T> s1 = supplier.get(); 1432 Spliterator<T> s2 = s1.trySplit(); 1433 long s1Size = s1.getExactSizeIfKnown(); 1434 long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0; 1435 Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add); 1436 if (s2 != null) 1437 s2.forEachRemaining(addToFromSplit); 1438 s1.forEachRemaining(addToFromSplit); 1439 1440 if (sizeIfKnown >= 0) { 1441 assertEquals(sizeIfKnown, fromSplit.size()); 1442 if (s1Size >= 0 && s2Size >= 0) 1443 assertEquals(sizeIfKnown, s1Size + s2Size); 1444 } 1445 assertContents(fromSplit, exp, isOrdered); 1446 } 1447 1448 private static <T, S extends Spliterator<T>> void testSplitSixDeep( 1449 Collection<T> exp, 1450 Supplier<S> supplier, 1451 UnaryOperator<Consumer<T>> boxingAdapter) { 1452 S spliterator = supplier.get(); 1453 boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); 1454 1455 for (int depth=0; depth < 6; depth++) { 1456 List<T> dest = new ArrayList<>(); 1457 spliterator = supplier.get(); 1458 1459 assertRootSpliterator(spliterator); 1460 1461 // verify splitting with forEach 1462 visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false); 1463 assertContents(dest, exp, isOrdered); 1464 1465 // verify splitting with tryAdvance 1466 dest.clear(); 1467 spliterator = supplier.get(); 1468 visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true); 1469 assertContents(dest, exp, isOrdered); 1470 } 1471 } 1472 1473 private static <T, S extends Spliterator<T>> void visit(int depth, int curLevel, 1474 List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter, 1475 int rootCharacteristics, boolean useTryAdvance) { 1476 if (curLevel < depth) { 1477 long beforeSize = spliterator.getExactSizeIfKnown(); 1478 Spliterator<T> split = spliterator.trySplit(); 1479 if (split != null) { 1480 assertSpliterator(split, rootCharacteristics); 1481 assertSpliterator(spliterator, rootCharacteristics); 1482 1483 if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 && 1484 (rootCharacteristics & Spliterator.SIZED) != 0) { 1485 assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize()); 1486 } 1487 visit(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance); 1488 } 1489 visit(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance); 1490 } 1491 else { 1492 long sizeIfKnown = spliterator.getExactSizeIfKnown(); 1493 if (useTryAdvance) { 1494 Consumer<T> addToDest = boxingAdapter.apply(dest::add); 1495 int count = 0; 1496 while (spliterator.tryAdvance(addToDest)) { 1497 ++count; 1498 } 1499 1500 if (sizeIfKnown >= 0) 1501 assertEquals(sizeIfKnown, count); 1502 1503 // Assert that forEach now produces no elements 1504 spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); 1505 1506 Spliterator<T> split = spliterator.trySplit(); 1507 assertNull(split); 1508 } 1509 else { 1510 List<T> leafDest = new ArrayList<>(); 1511 Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add); 1512 spliterator.forEachRemaining(addToLeafDest); 1513 1514 if (sizeIfKnown >= 0) 1515 assertEquals(sizeIfKnown, leafDest.size()); 1516 1517 // Assert that forEach now produces no elements 1518 spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); 1519 1520 Spliterator<T> split = spliterator.trySplit(); 1521 assertNull(split); 1522 1523 dest.addAll(leafDest); 1524 } 1525 } 1526 } 1527 1528 private static <T, S extends Spliterator<T>> void testSplitUntilNull( 1529 Collection<T> exp, 1530 Supplier<S> supplier, 1531 UnaryOperator<Consumer<T>> boxingAdapter) { 1532 Spliterator<T> s = supplier.get(); 1533 boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED); 1534 assertRootSpliterator(s); 1535 1536 List<T> splits = new ArrayList<>(); 1537 Consumer<T> c = boxingAdapter.apply(splits::add); 1538 1539 testSplitUntilNull(new SplitNode<T>(c, s)); 1540 assertContents(splits, exp, isOrdered); 1541 } 1542 1543 private static class SplitNode<T> { 1544 // Constant for every node 1545 final Consumer<T> c; 1546 final int rootCharacteristics; 1547 1548 final Spliterator<T> s; 1549 1550 SplitNode(Consumer<T> c, Spliterator<T> s) { 1551 this(c, s.characteristics(), s); 1552 } 1553 1554 private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) { 1555 this.c = c; 1556 this.rootCharacteristics = rootCharacteristics; 1557 this.s = s; 1558 } 1559 1560 SplitNode<T> fromSplit(Spliterator<T> split) { 1561 return new SplitNode<>(c, rootCharacteristics, split); 1562 } 1563 } 1564 1565 /** 1566 * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator 1567 * while not unduly disrupting test infrastructure given the test data sizes that are used are small. 1568 * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26). 1569 */ 1570 private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB 1571 1572 private static <T> void testSplitUntilNull(SplitNode<T> e) { 1573 // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator 1574 // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or 1575 // for a spliterator that is badly behaved. 1576 Deque<SplitNode<T>> stack = new ArrayDeque<>(); 1577 stack.push(e); 1578 1579 int iteration = 0; 1580 while (!stack.isEmpty()) { 1581 assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18"); 1582 1583 e = stack.pop(); 1584 Spliterator<T> parentAndRightSplit = e.s; 1585 1586 long parentEstimateSize = parentAndRightSplit.estimateSize(); 1587 assertTrue(parentEstimateSize >= 0, 1588 String.format("Split size estimate %d < 0", parentEstimateSize)); 1589 1590 long parentSize = parentAndRightSplit.getExactSizeIfKnown(); 1591 Spliterator<T> leftSplit = parentAndRightSplit.trySplit(); 1592 if (leftSplit == null) { 1593 parentAndRightSplit.forEachRemaining(e.c); 1594 continue; 1595 } 1596 1597 assertSpliterator(leftSplit, e.rootCharacteristics); 1598 assertSpliterator(parentAndRightSplit, e.rootCharacteristics); 1599 1600 if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0 && parentAndRightSplit.estimateSize() > 0) { 1601 assertTrue(leftSplit.estimateSize() < parentEstimateSize, 1602 String.format("Left split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); 1603 assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize, 1604 String.format("Right split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); 1605 } 1606 else { 1607 assertTrue(leftSplit.estimateSize() <= parentEstimateSize, 1608 String.format("Left split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); 1609 assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize, 1610 String.format("Right split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); 1611 } 1612 1613 long leftSize = leftSplit.getExactSizeIfKnown(); 1614 long rightSize = parentAndRightSplit.getExactSizeIfKnown(); 1615 if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0) 1616 assertEquals(parentSize, leftSize + rightSize, 1617 String.format("exact left split size %d + exact right split size %d != parent exact split size %d", 1618 leftSize, rightSize, parentSize)); 1619 1620 // Add right side to stack first so left side is popped off first 1621 stack.push(e.fromSplit(parentAndRightSplit)); 1622 stack.push(e.fromSplit(leftSplit)); 1623 } 1624 } 1625 1626 private static void assertRootSpliterator(Spliterator<?> s) { 1627 assertFalse(s.hasCharacteristics(Spliterator.SIZED | Spliterator.CONCURRENT), 1628 "Root spliterator should not be SIZED and CONCURRENT"); 1629 1630 assertSpliterator(s); 1631 } 1632 1633 private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) { 1634 if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) { 1635 assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED), 1636 "Child split is not SUBSIZED when root split is SUBSIZED"); 1637 } 1638 assertSpliterator(s); 1639 } 1640 1641 private static void assertSpliterator(Spliterator<?> s) { 1642 if (s.hasCharacteristics(Spliterator.SUBSIZED)) { 1643 assertTrue(s.hasCharacteristics(Spliterator.SIZED)); 1644 } 1645 if (s.hasCharacteristics(Spliterator.SIZED)) { 1646 assertTrue(s.estimateSize() != Long.MAX_VALUE); 1647 assertTrue(s.getExactSizeIfKnown() >= 0); 1648 } 1649 try { 1650 s.getComparator(); 1651 assertTrue(s.hasCharacteristics(Spliterator.SORTED)); 1652 } catch (IllegalStateException e) { 1653 assertFalse(s.hasCharacteristics(Spliterator.SORTED)); 1654 } 1655 } 1656 1657 private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) { 1658 if (isOrdered) { 1659 assertEquals(actual, expected); 1660 } 1661 else { 1662 assertContentsUnordered(actual, expected); 1663 } 1664 } 1665 1666 private static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) { 1667 assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected)); 1668 } 1669 1670 private static <T> Map<T, Integer> toBoxedMultiset(Iterable<T> c) { 1671 Map<T, Integer> result = new HashMap<>(); 1672 c.forEach(e -> { 1673 if (result.containsKey(e)) result.put(e, result.get(e) + 1); 1674 else result.put(e, 1); 1675 }); 1676 return result; 1677 } 1678 1679 private void executeAndCatch(Class<? extends Exception> expected, Runnable r) { 1680 Exception caught = null; 1681 try { 1682 r.run(); 1683 } 1684 catch (Exception e) { 1685 caught = e; 1686 } 1687 1688 assertNotNull(caught, 1689 String.format("No Exception was thrown, expected an Exception of %s to be thrown", 1690 expected.getName())); 1691 assertTrue(expected.isInstance(caught), 1692 String.format("Exception thrown %s not an instance of %s", 1693 caught.getClass().getName(), expected.getName())); 1694 } 1695 1696 }