1 /*
   2  * Copyright (c) 2013, 2026, 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  * @library /lib/testlibrary/bootlib
  28  * @build java.base/java.util.SpliteratorOfIntDataBuilder
  29  *        java.base/java.util.SpliteratorTestHelper
  30  * @run testng SpliteratorTraversingAndSplittingTest
  31  * @bug 8020016 8071477 8072784 8169838
  32  */
  33 
  34 import org.testng.annotations.DataProvider;
  35 import org.testng.annotations.Test;
  36 
  37 import java.nio.CharBuffer;
  38 import java.util.AbstractCollection;
  39 import java.util.AbstractList;
  40 import java.util.AbstractSet;
  41 import java.util.ArrayDeque;
  42 import java.util.ArrayList;
  43 import java.util.Arrays;
  44 import java.util.Collection;
  45 import java.util.Collections;
  46 import java.util.Comparator;
  47 import java.util.HashMap;
  48 import java.util.HashSet;
  49 import java.util.IdentityHashMap;
  50 import java.util.Iterator;
  51 import java.util.LinkedHashMap;
  52 import java.util.LinkedHashSet;
  53 import java.util.LinkedList;
  54 import java.util.List;
  55 import java.util.ListIterator;
  56 import java.util.Map;
  57 import java.util.PriorityQueue;
  58 import java.util.RandomAccess;
  59 import java.util.Set;
  60 import java.util.SortedSet;
  61 import java.util.Spliterator;
  62 import java.util.SpliteratorOfIntDataBuilder;
  63 import java.util.SpliteratorTestHelper;
  64 import java.util.Spliterators;
  65 import java.util.Stack;
  66 import java.util.TreeMap;
  67 import java.util.TreeSet;
  68 import java.util.Vector;
  69 import java.util.WeakHashMap;
  70 import java.util.concurrent.ArrayBlockingQueue;
  71 import java.util.concurrent.ConcurrentHashMap;
  72 import java.util.concurrent.ConcurrentLinkedQueue;
  73 import java.util.concurrent.ConcurrentSkipListMap;
  74 import java.util.concurrent.ConcurrentSkipListSet;
  75 import java.util.concurrent.CopyOnWriteArrayList;
  76 import java.util.concurrent.CopyOnWriteArraySet;
  77 import java.util.concurrent.LinkedBlockingDeque;
  78 import java.util.concurrent.LinkedBlockingQueue;
  79 import java.util.concurrent.LinkedTransferQueue;
  80 import java.util.concurrent.PriorityBlockingQueue;
  81 import java.util.function.Consumer;
  82 import java.util.function.DoubleConsumer;
  83 import java.util.function.Function;
  84 import java.util.function.IntConsumer;
  85 import java.util.function.LongConsumer;
  86 import java.util.function.Supplier;
  87 import java.util.function.UnaryOperator;
  88 
  89 public class SpliteratorTraversingAndSplittingTest extends SpliteratorTestHelper {
  90 
  91     private static final List<Integer> SIZES = Arrays.asList(0, 1, 10, 42);
  92 
  93     private static final String LOW = new String(new char[] {Character.MIN_LOW_SURROGATE});
  94     private static final String HIGH = new String(new char[] {Character.MIN_HIGH_SURROGATE});
  95     private static final String HIGH_LOW = HIGH + LOW;
  96     private static final String CHAR_HIGH_LOW = "A" + HIGH_LOW;
  97     private static final String HIGH_LOW_CHAR = HIGH_LOW + "A";
  98     private static final String CHAR_HIGH_LOW_CHAR = "A" + HIGH_LOW + "A";
  99 
 100     private static final List<String> STRINGS = generateTestStrings();
 101 
 102     private static List<String> generateTestStrings() {
 103         List<String> strings = new ArrayList<>();
 104         for (int n : Arrays.asList(1, 2, 3, 16, 17)) {
 105             strings.add(generate("A", n));
 106             strings.add(generate(LOW, n));
 107             strings.add(generate(HIGH, n));
 108             strings.add(generate(HIGH_LOW, n));
 109             strings.add(generate(CHAR_HIGH_LOW, n));
 110             strings.add(generate(HIGH_LOW_CHAR, n));
 111             strings.add(generate(CHAR_HIGH_LOW_CHAR, n));
 112         }
 113         return strings;
 114     }
 115 
 116     private static String generate(String s, int n) {
 117         StringBuilder sb = new StringBuilder();
 118         for (int i = 0; i < n; i++) {
 119             sb.append(s);
 120         }
 121         return sb.toString();
 122     }
 123 
 124     private static class SpliteratorDataBuilder<T> {
 125         List<Object[]> data;
 126 
 127         List<T> exp;
 128 
 129         List<T> expRev;
 130 
 131         Map<T, T> mExp;
 132 
 133         Map<T, T> mExpRev;
 134 
 135         SpliteratorDataBuilder(List<Object[]> data, List<T> exp) {
 136             this.data = data;
 137             this.exp = exp;
 138             this.expRev = new ArrayList<>(exp);
 139             Collections.reverse(this.expRev);
 140             this.mExp = createMap(exp);
 141             this.mExpRev = createMap(expRev);
 142         }
 143 
 144         Map<T, T> createMap(List<T> l) {
 145             Map<T, T> m = new LinkedHashMap<>();
 146             for (T t : l) {
 147                 m.put(t, t);
 148             }
 149             return m;
 150         }
 151 
 152         void add(String description, Collection<?> expected, Supplier<Spliterator<?>> s) {
 153             description = joiner(description).toString();
 154             data.add(new Object[]{description, expected, s});
 155         }
 156 
 157         void add(String description, Supplier<Spliterator<?>> s) {
 158             add(description, exp, s);
 159         }
 160 
 161         void addCollection(Function<Collection<T>, ? extends Collection<T>> c) {
 162             add("new " + c.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator()",
 163                 () -> c.apply(exp).spliterator());
 164         }
 165 
 166         void addList(Function<Collection<T>, ? extends List<T>> l) {
 167             addCollection(l);
 168             addCollection(l.andThen(list -> list.subList(0, list.size())));
 169         }
 170 
 171         void addMap(Function<Map<T, T>, ? extends Map<T, T>> m) {
 172             String description = "new " + m.apply(Collections.<T, T>emptyMap()).getClass().getName();
 173             addMap(m, description);
 174         }
 175 
 176         void addDescendingMap(Function<Map<T, T>, ? extends Map<T, T>> m) {
 177             String description = "new " + m.apply(Collections.<T, T>emptyMap()).getClass().getName();
 178             addDescendingMap(m, description);
 179         }
 180 
 181         void addMap(Function<Map<T, T>, ? extends Map<T, T>> m, String description) {
 182             add(description + ".keySet().spliterator()", () -> m.apply(mExp).keySet().spliterator());
 183             add(description + ".values().spliterator()", () -> m.apply(mExp).values().spliterator());
 184             add(description + ".entrySet().spliterator()", mExp.entrySet(), () -> m.apply(mExp).entrySet().spliterator());
 185         }
 186 
 187         void addDescendingMap(Function<Map<T, T>, ? extends Map<T, T>> m, String description) {
 188             add(description + ".keySet().spliterator()", expRev, () -> m.apply(mExp).keySet().spliterator());
 189             add(description + ".values().spliterator()", expRev, () -> m.apply(mExp).values().spliterator());
 190             add(description + ".entrySet().spliterator()", mExpRev.entrySet(), () -> m.apply(mExp).entrySet().spliterator());
 191         }
 192 
 193         StringBuilder joiner(String description) {
 194             return new StringBuilder(description).
 195                     append(" {").
 196                     append("size=").append(exp.size()).
 197                     append("}");
 198         }
 199     }
 200 
 201     static Object[][] spliteratorDataProvider;
 202 
 203     @DataProvider(name = "Spliterator<Integer>")
 204     public static Object[][] spliteratorDataProvider() {
 205         if (spliteratorDataProvider != null) {
 206             return spliteratorDataProvider;
 207         }
 208 
 209         List<Object[]> data = new ArrayList<>();
 210         for (int size : SIZES) {
 211             List<Integer> exp = listIntRange(size);
 212             SpliteratorDataBuilder<Integer> db = new SpliteratorDataBuilder<>(data, exp);
 213 
 214             // Direct spliterator methods
 215 
 216             db.add("Spliterators.spliterator(Collection, ...)",
 217                    () -> Spliterators.spliterator(exp, 0));
 218 
 219             db.add("Spliterators.spliterator(Iterator, ...)",
 220                    () -> Spliterators.spliterator(exp.iterator(), exp.size(), 0));
 221 
 222             db.add("Spliterators.spliteratorUnknownSize(Iterator, ...)",
 223                    () -> Spliterators.spliteratorUnknownSize(exp.iterator(), 0));
 224 
 225             db.add("Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Spliterator ), ...)",
 226                    () -> Spliterators.spliterator(Spliterators.iterator(exp.spliterator()), exp.size(), 0));
 227 
 228             db.add("Spliterators.spliterator(T[], ...)",
 229                    () -> Spliterators.spliterator(exp.toArray(new Integer[0]), 0));
 230 
 231             db.add("Arrays.spliterator(T[], ...)",
 232                    () -> Arrays.spliterator(exp.toArray(new Integer[0])));
 233 
 234             class SpliteratorFromIterator extends Spliterators.AbstractSpliterator<Integer> {
 235                 Iterator<Integer> it;
 236 
 237                 SpliteratorFromIterator(Iterator<Integer> it, long est) {
 238                     super(est, Spliterator.SIZED);
 239                     this.it = it;
 240                 }
 241 
 242                 @Override
 243                 public boolean tryAdvance(Consumer<? super Integer> action) {
 244                     if (action == null)
 245                         throw new NullPointerException();
 246                     if (it.hasNext()) {
 247                         action.accept(it.next());
 248                         return true;
 249                     }
 250                     else {
 251                         return false;
 252                     }
 253                 }
 254             }
 255             db.add("new Spliterators.AbstractSpliterator()",
 256                    () -> new SpliteratorFromIterator(exp.iterator(), exp.size()));
 257 
 258             // Collections
 259 
 260             // default method implementations
 261 
 262             class AbstractCollectionImpl extends AbstractCollection<Integer> {
 263                 Collection<Integer> c;
 264 
 265                 AbstractCollectionImpl(Collection<Integer> c) {
 266                     this.c = c;
 267                 }
 268 
 269                 @Override
 270                 public Iterator<Integer> iterator() {
 271                     return c.iterator();
 272                 }
 273 
 274                 @Override
 275                 public int size() {
 276                     return c.size();
 277                 }
 278             }
 279             db.addCollection(
 280                     c -> new AbstractCollectionImpl(c));
 281 
 282             class AbstractListImpl extends AbstractList<Integer> {
 283                 List<Integer> l;
 284 
 285                 AbstractListImpl(Collection<Integer> c) {
 286                     this.l = new ArrayList<>(c);
 287                 }
 288 
 289                 @Override
 290                 public Integer get(int index) {
 291                     return l.get(index);
 292                 }
 293 
 294                 @Override
 295                 public int size() {
 296                     return l.size();
 297                 }
 298             }
 299             db.addCollection(
 300                     c -> new AbstractListImpl(c));
 301 
 302             class AbstractSetImpl extends AbstractSet<Integer> {
 303                 Set<Integer> s;
 304 
 305                 AbstractSetImpl(Collection<Integer> c) {
 306                     this.s = new HashSet<>(c);
 307                 }
 308 
 309                 @Override
 310                 public Iterator<Integer> iterator() {
 311                     return s.iterator();
 312                 }
 313 
 314                 @Override
 315                 public int size() {
 316                     return s.size();
 317                 }
 318             }
 319             db.addCollection(
 320                     c -> new AbstractSetImpl(c));
 321 
 322             class AbstractSortedSetImpl extends AbstractSet<Integer> implements SortedSet<Integer> {
 323                 SortedSet<Integer> s;
 324 
 325                 AbstractSortedSetImpl(Collection<Integer> c) {
 326                     this.s = new TreeSet<>(c);
 327                 }
 328 
 329                 @Override
 330                 public Iterator<Integer> iterator() {
 331                     return s.iterator();
 332                 }
 333 
 334                 @Override
 335                 public int size() {
 336                     return s.size();
 337                 }
 338 
 339                 @Override
 340                 public Comparator<? super Integer> comparator() {
 341                     return s.comparator();
 342                 }
 343 
 344                 @Override
 345                 public SortedSet<Integer> subSet(Integer fromElement, Integer toElement) {
 346                     return s.subSet(fromElement, toElement);
 347                 }
 348 
 349                 @Override
 350                 public SortedSet<Integer> headSet(Integer toElement) {
 351                     return s.headSet(toElement);
 352                 }
 353 
 354                 @Override
 355                 public SortedSet<Integer> tailSet(Integer fromElement) {
 356                     return s.tailSet(fromElement);
 357                 }
 358 
 359                 @Override
 360                 public Integer first() {
 361                     return s.first();
 362                 }
 363 
 364                 @Override
 365                 public Integer last() {
 366                     return s.last();
 367                 }
 368 
 369                 @Override
 370                 public Spliterator<Integer> spliterator() {
 371                     return SortedSet.super.spliterator();
 372                 }
 373             }
 374             db.addCollection(
 375                     c -> new AbstractSortedSetImpl(c));
 376 
 377             class IterableWrapper implements Iterable<Integer> {
 378                 final Iterable<Integer> it;
 379 
 380                 IterableWrapper(Iterable<Integer> it) {
 381                     this.it = it;
 382                 }
 383 
 384                 @Override
 385                 public Iterator<Integer> iterator() {
 386                     return it.iterator();
 387                 }
 388             }
 389             db.add("new Iterable.spliterator()",
 390                    () -> new IterableWrapper(exp).spliterator());
 391 
 392             //
 393 
 394             db.add("Arrays.asList().spliterator()",
 395                    () -> Spliterators.spliterator(Arrays.asList(exp.toArray(new Integer[0])), 0));
 396 
 397             db.addList(ArrayList::new);
 398 
 399             db.addList(LinkedList::new);
 400 
 401             db.addList(Vector::new);
 402 
 403             class AbstractRandomAccessListImpl extends AbstractList<Integer> implements RandomAccess {
 404                 Integer[] ia;
 405 
 406                 AbstractRandomAccessListImpl(Collection<Integer> c) {
 407                     this.ia = c.toArray(new Integer[c.size()]);
 408                 }
 409 
 410                 @Override
 411                 public Integer get(int index) {
 412                     return ia[index];
 413                 }
 414 
 415                 @Override
 416                 public int size() {
 417                     return ia.length;
 418                 }
 419             }
 420             db.addList(AbstractRandomAccessListImpl::new);
 421 
 422             class RandomAccessListImpl implements List<Integer>, RandomAccess {
 423                 Integer[] ia;
 424                 List<Integer> l;
 425 
 426                 RandomAccessListImpl(Collection<Integer> c) {
 427                     this.ia = c.toArray(new Integer[c.size()]);
 428                     this.l = Arrays.asList(ia);
 429                 }
 430 
 431                 @Override
 432                 public Integer get(int index) {
 433                     return ia[index];
 434                 }
 435 
 436                 @Override
 437                 public Integer set(int index, Integer element) {
 438                     throw new UnsupportedOperationException();
 439                 }
 440 
 441                 @Override
 442                 public void add(int index, Integer element) {
 443                     throw new UnsupportedOperationException();
 444                 }
 445 
 446                 @Override
 447                 public Integer remove(int index) {
 448                     throw new UnsupportedOperationException();
 449                 }
 450 
 451                 @Override
 452                 public int indexOf(Object o) {
 453                     return l.indexOf(o);
 454                 }
 455 
 456                 @Override
 457                 public int lastIndexOf(Object o) {
 458                     return Arrays.asList(ia).lastIndexOf(o);
 459                 }
 460 
 461                 @Override
 462                 public ListIterator<Integer> listIterator() {
 463                     return l.listIterator();
 464                 }
 465 
 466                 @Override
 467                 public ListIterator<Integer> listIterator(int index) {
 468                     return l.listIterator(index);
 469                 }
 470 
 471                 @Override
 472                 public List<Integer> subList(int fromIndex, int toIndex) {
 473                     return l.subList(fromIndex, toIndex);
 474                 }
 475 
 476                 @Override
 477                 public int size() {
 478                     return ia.length;
 479                 }
 480 
 481                 @Override
 482                 public boolean isEmpty() {
 483                     return size() != 0;
 484                 }
 485 
 486                 @Override
 487                 public boolean contains(Object o) {
 488                     return l.contains(o);
 489                 }
 490 
 491                 @Override
 492                 public Iterator<Integer> iterator() {
 493                     return l.iterator();
 494                 }
 495 
 496                 @Override
 497                 public Object[] toArray() {
 498                     return l.toArray();
 499                 }
 500 
 501                 @Override
 502                 public <T> T[] toArray(T[] a) {
 503                     return l.toArray(a);
 504                 }
 505 
 506                 @Override
 507                 public boolean add(Integer integer) {
 508                     throw new UnsupportedOperationException();
 509                 }
 510 
 511                 @Override
 512                 public boolean remove(Object o) {
 513                     throw new UnsupportedOperationException();
 514                 }
 515 
 516                 @Override
 517                 public boolean containsAll(Collection<?> c) {
 518                     return l.containsAll(c);
 519                 }
 520 
 521                 @Override
 522                 public boolean addAll(Collection<? extends Integer> c) {
 523                     throw new UnsupportedOperationException();
 524                 }
 525 
 526                 @Override
 527                 public boolean addAll(int index, Collection<? extends Integer> c) {
 528                     throw new UnsupportedOperationException();
 529                 }
 530 
 531                 @Override
 532                 public boolean removeAll(Collection<?> c) {
 533                     throw new UnsupportedOperationException();
 534                 }
 535 
 536                 @Override
 537                 public boolean retainAll(Collection<?> c) {
 538                     throw new UnsupportedOperationException();
 539                 }
 540 
 541                 @Override
 542                 public void clear() {
 543                     throw new UnsupportedOperationException();
 544                 }
 545             }
 546             db.addList(RandomAccessListImpl::new);
 547 
 548             db.addCollection(HashSet::new);
 549 
 550             db.addCollection(LinkedHashSet::new);
 551 
 552             db.addCollection(TreeSet::new);
 553 
 554 
 555             db.addCollection(c -> { Stack<Integer> s = new Stack<>(); s.addAll(c); return s;});
 556 
 557             db.addCollection(PriorityQueue::new);
 558 
 559             db.addCollection(ArrayDeque::new);
 560 
 561 
 562             db.addCollection(ConcurrentSkipListSet::new);
 563 
 564             if (size > 0) {
 565                 db.addCollection(c -> {
 566                     ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<>(size);
 567                     abq.addAll(c);
 568                     return abq;
 569                 });
 570             }
 571 
 572             db.addCollection(PriorityBlockingQueue::new);
 573 
 574             db.addCollection(LinkedBlockingQueue::new);
 575 
 576             db.addCollection(LinkedTransferQueue::new);
 577 
 578             db.addCollection(ConcurrentLinkedQueue::new);
 579 
 580             db.addCollection(LinkedBlockingDeque::new);
 581 
 582             db.addCollection(CopyOnWriteArrayList::new);
 583 
 584             db.addCollection(CopyOnWriteArraySet::new);
 585 
 586             if (size == 0) {
 587                 db.addCollection(c -> Collections.<Integer>emptySet());
 588                 db.addList(c -> Collections.<Integer>emptyList());
 589             }
 590             else if (size == 1) {
 591                 db.addCollection(c -> Collections.singleton(exp.get(0)));
 592                 db.addCollection(c -> Collections.singletonList(exp.get(0)));
 593             }
 594 
 595             {
 596                 Integer[] ai = new Integer[size];
 597                 Arrays.fill(ai, 1);
 598                 db.add(String.format("Collections.nCopies(%d, 1)", exp.size()),
 599                        Arrays.asList(ai),
 600                        () -> Collections.nCopies(exp.size(), 1).spliterator());
 601             }
 602 
 603             // Collections.synchronized/unmodifiable/checked wrappers
 604             db.addCollection(Collections::unmodifiableCollection);
 605             db.addCollection(c -> Collections.unmodifiableSet(new HashSet<>(c)));
 606             db.addCollection(c -> Collections.unmodifiableSortedSet(new TreeSet<>(c)));
 607             db.addList(c -> Collections.unmodifiableList(new ArrayList<>(c)));
 608             db.addMap(Collections::unmodifiableMap);
 609             db.addMap(m -> Collections.unmodifiableSortedMap(new TreeMap<>(m)));
 610 
 611             db.addCollection(Collections::synchronizedCollection);
 612             db.addCollection(c -> Collections.synchronizedSet(new HashSet<>(c)));
 613             db.addCollection(c -> Collections.synchronizedSortedSet(new TreeSet<>(c)));
 614             db.addList(c -> Collections.synchronizedList(new ArrayList<>(c)));
 615             db.addMap(Collections::synchronizedMap);
 616             db.addMap(m -> Collections.synchronizedSortedMap(new TreeMap<>(m)));
 617 
 618             db.addCollection(c -> Collections.checkedCollection(c, Integer.class));
 619             db.addCollection(c -> Collections.checkedQueue(new ArrayDeque<>(c), Integer.class));
 620             db.addCollection(c -> Collections.checkedSet(new HashSet<>(c), Integer.class));
 621             db.addCollection(c -> Collections.checkedSortedSet(new TreeSet<>(c), Integer.class));
 622             db.addList(c -> Collections.checkedList(new ArrayList<>(c), Integer.class));
 623             db.addMap(c -> Collections.checkedMap(c, Integer.class, Integer.class));
 624             db.addMap(m -> Collections.checkedSortedMap(new TreeMap<>(m), Integer.class, Integer.class));
 625 
 626             // Maps
 627 
 628             db.addMap(HashMap::new);
 629 
 630             db.addMap(m -> {
 631                 // Create a Map ensuring that for large sizes
 632                 // buckets will contain 2 or more entries
 633                 HashMap<Integer, Integer> cm = new HashMap<>(1, m.size() + 1);
 634                 // Don't use putAll which inflates the table by
 635                 // m.size() * loadFactor, thus creating a very sparse
 636                 // map for 1000 entries defeating the purpose of this test,
 637                 // in addition it will cause the split until null test to fail
 638                 // because the number of valid splits is larger than the
 639                 // threshold
 640                 for (Map.Entry<Integer, Integer> e : m.entrySet())
 641                     cm.put(e.getKey(), e.getValue());
 642                 return cm;
 643             }, "new java.util.HashMap(1, size + 1)");
 644 
 645             db.addMap(LinkedHashMap::new);
 646 
 647             db.addMap(IdentityHashMap::new);
 648 
 649             db.addMap(WeakHashMap::new);
 650 
 651             db.addMap(m -> {
 652                 // Create a Map ensuring that for large sizes
 653                 // buckets will be consist of 2 or more entries
 654                 WeakHashMap<Integer, Integer> cm = new WeakHashMap<>(1, m.size() + 1);
 655                 for (Map.Entry<Integer, Integer> e : m.entrySet())
 656                     cm.put(e.getKey(), e.getValue());
 657                 return cm;
 658             }, "new java.util.WeakHashMap(1, size + 1)");
 659 
 660             db.addMap(TreeMap::new);
 661             db.addMap(m -> new TreeMap<>(m).tailMap(Integer.MIN_VALUE));
 662             db.addMap(m -> new TreeMap<>(m).headMap(Integer.MAX_VALUE));
 663             db.addMap(m -> new TreeMap<>(m).subMap(Integer.MIN_VALUE, Integer.MAX_VALUE));
 664             db.addDescendingMap(m -> new TreeMap<>(m).descendingMap());
 665             db.addDescendingMap(m -> new TreeMap<>(m).descendingMap().tailMap(Integer.MAX_VALUE));
 666             db.addDescendingMap(m -> new TreeMap<>(m).descendingMap().headMap(Integer.MIN_VALUE));
 667             db.addDescendingMap(m -> new TreeMap<>(m).descendingMap().subMap(Integer.MAX_VALUE, Integer.MIN_VALUE));
 668 
 669             db.addMap(ConcurrentHashMap::new);
 670 
 671             db.addMap(ConcurrentSkipListMap::new);
 672 
 673             if (size == 0) {
 674                 db.addMap(m -> Collections.<Integer, Integer>emptyMap());
 675             }
 676             else if (size == 1) {
 677                 db.addMap(m -> Collections.singletonMap(exp.get(0), exp.get(0)));
 678             }
 679         }
 680 
 681         return spliteratorDataProvider = data.toArray(new Object[0][]);
 682     }
 683 
 684     private static List<Integer> listIntRange(int upTo) {
 685         List<Integer> exp = new ArrayList<>();
 686         for (int i = 0; i < upTo; i++)
 687             exp.add(i);
 688         return Collections.unmodifiableList(exp);
 689     }
 690 
 691     @Test(dataProvider = "Spliterator<Integer>")
 692     public void testNullPointerException(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 693         assertThrowsNPE(() -> s.get().forEachRemaining(null));
 694         assertThrowsNPE(() -> s.get().tryAdvance(null));
 695     }
 696 
 697     @Test(dataProvider = "Spliterator<Integer>")
 698     public void testForEach(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 699         testForEach(exp, s, UnaryOperator.identity());
 700     }
 701 
 702     @Test(dataProvider = "Spliterator<Integer>")
 703     public void testTryAdvance(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 704         testTryAdvance(exp, s, UnaryOperator.identity());
 705     }
 706 
 707     @Test(dataProvider = "Spliterator<Integer>")
 708     public void testMixedTryAdvanceForEach(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 709         testMixedTryAdvanceForEach(exp, s, UnaryOperator.identity());
 710     }
 711 
 712     @Test(dataProvider = "Spliterator<Integer>")
 713     public void testMixedTraverseAndSplit(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 714         testMixedTraverseAndSplit(exp, s, UnaryOperator.identity());
 715     }
 716 
 717     @Test(dataProvider = "Spliterator<Integer>")
 718     public void testSplitAfterFullTraversal(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 719         testSplitAfterFullTraversal(s, UnaryOperator.identity());
 720     }
 721 
 722     @Test(dataProvider = "Spliterator<Integer>")
 723     public void testSplitOnce(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 724         testSplitOnce(exp, s, UnaryOperator.identity());
 725     }
 726 
 727     @Test(dataProvider = "Spliterator<Integer>")
 728     public void testSplitSixDeep(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 729         testSplitSixDeep(exp, s, UnaryOperator.identity());
 730     }
 731 
 732     @Test(dataProvider = "Spliterator<Integer>")
 733     public void testSplitUntilNull(String description, Collection<Integer> exp, Supplier<Spliterator<Integer>> s) {
 734         testSplitUntilNull(exp, s, UnaryOperator.identity());
 735     }
 736 
 737     //
 738     private static class SpliteratorOfIntCharDataBuilder {
 739         List<Object[]> data;
 740 
 741         String s;
 742 
 743         List<Integer> expChars;
 744 
 745         List<Integer> expCodePoints;
 746 
 747         SpliteratorOfIntCharDataBuilder(List<Object[]> data, String s) {
 748             this.data = data;
 749             this.s = s;
 750             this.expChars = transform(s, false);
 751             this.expCodePoints = transform(s, true);
 752         }
 753 
 754         static List<Integer> transform(String s, boolean toCodePoints) {
 755             List<Integer> l = new ArrayList<>();
 756 
 757             if (!toCodePoints) {
 758                 for (int i = 0; i < s.length(); i++) {
 759                     l.add((int) s.charAt(i));
 760                 }
 761             }
 762             else {
 763                 for (int i = 0; i < s.length();) {
 764                     char c1 = s.charAt(i++);
 765                     int cp = c1;
 766                     if (Character.isHighSurrogate(c1) && i < s.length()) {
 767                         char c2 = s.charAt(i);
 768                         if (Character.isLowSurrogate(c2)) {
 769                             i++;
 770                             cp = Character.toCodePoint(c1, c2);
 771                         }
 772                     }
 773                     l.add(cp);
 774                 }
 775             }
 776             return l;
 777         }
 778 
 779         void add(String description, Function<String, CharSequence> f) {
 780             description = description.replace("%s", s);
 781             {
 782                 Supplier<Spliterator.OfInt> supplier = () -> f.apply(s).chars().spliterator();
 783                 data.add(new Object[]{description + ".chars().spliterator()", expChars, supplier});
 784             }
 785             {
 786                 Supplier<Spliterator.OfInt> supplier = () -> f.apply(s).codePoints().spliterator();
 787                 data.add(new Object[]{description + ".codePoints().spliterator()", expCodePoints, supplier});
 788             }
 789         }
 790     }
 791 
 792     static Object[][] spliteratorOfIntDataProvider;
 793 
 794     @DataProvider(name = "Spliterator.OfInt")
 795     public static Object[][] spliteratorOfIntDataProvider() {
 796         if (spliteratorOfIntDataProvider != null) {
 797             return spliteratorOfIntDataProvider;
 798         }
 799 
 800         List<Object[]> data = new ArrayList<>();
 801         for (int size : SIZES) {
 802             int exp[] = arrayIntRange(size);
 803             SpliteratorOfIntDataBuilder db = new SpliteratorOfIntDataBuilder(data, listIntRange(size));
 804 
 805             db.add("Spliterators.spliterator(int[], ...)",
 806                    () -> Spliterators.spliterator(exp, 0));
 807 
 808             db.add("Arrays.spliterator(int[], ...)",
 809                    () -> Arrays.spliterator(exp));
 810 
 811             db.add("Spliterators.spliterator(PrimitiveIterator.OfInt, ...)",
 812                    () -> Spliterators.spliterator(Spliterators.iterator(Arrays.spliterator(exp)), exp.length, 0));
 813 
 814             db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfInt, ...)",
 815                    () -> Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(exp)), 0));
 816 
 817             class IntSpliteratorFromArray extends Spliterators.AbstractIntSpliterator {
 818                 int[] a;
 819                 int index = 0;
 820 
 821                 IntSpliteratorFromArray(int[] a) {
 822                     super(a.length, Spliterator.SIZED);
 823                     this.a = a;
 824                 }
 825 
 826                 @Override
 827                 public boolean tryAdvance(IntConsumer action) {
 828                     if (action == null)
 829                         throw new NullPointerException();
 830                     if (index < a.length) {
 831                         action.accept(a[index++]);
 832                         return true;
 833                     }
 834                     else {
 835                         return false;
 836                     }
 837                 }
 838             }
 839             db.add("new Spliterators.AbstractIntAdvancingSpliterator()",
 840                    () -> new IntSpliteratorFromArray(exp));
 841         }
 842 
 843         // Class for testing default methods
 844         class CharSequenceImpl implements CharSequence {
 845             final String s;
 846 
 847             public CharSequenceImpl(String s) {
 848                 this.s = s;
 849             }
 850 
 851             @Override
 852             public int length() {
 853                 return s.length();
 854             }
 855 
 856             @Override
 857             public char charAt(int index) {
 858                 return s.charAt(index);
 859             }
 860 
 861             @Override
 862             public CharSequence subSequence(int start, int end) {
 863                 return s.subSequence(start, end);
 864             }
 865 
 866             @Override
 867             public String toString() {
 868                 return s;
 869             }
 870         }
 871 
 872         for (String string : STRINGS) {
 873             SpliteratorOfIntCharDataBuilder cdb = new SpliteratorOfIntCharDataBuilder(data, string);
 874             cdb.add("\"%s\"", s -> s);
 875             cdb.add("new CharSequenceImpl(\"%s\")", CharSequenceImpl::new);
 876             cdb.add("new StringBuilder(\"%s\")", StringBuilder::new);
 877             cdb.add("new StringBuffer(\"%s\")", StringBuffer::new);
 878             cdb.add("CharBuffer.wrap(\"%s\".toCharArray())", s -> CharBuffer.wrap(s.toCharArray()));
 879         }
 880 
 881         return spliteratorOfIntDataProvider = data.toArray(new Object[0][]);
 882     }
 883 
 884     private static int[] arrayIntRange(int upTo) {
 885         int[] exp = new int[upTo];
 886         for (int i = 0; i < upTo; i++)
 887             exp[i] = i;
 888         return exp;
 889     }
 890 
 891     @Test(dataProvider = "Spliterator.OfInt")
 892     public void testIntNullPointerException(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 893         assertThrowsNPE(() -> s.get().forEachRemaining((IntConsumer) null));
 894         assertThrowsNPE(() -> s.get().tryAdvance((IntConsumer) null));
 895     }
 896 
 897     @Test(dataProvider = "Spliterator.OfInt")
 898     public void testIntForEach(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 899         testForEach(exp, s, intBoxingConsumer());
 900     }
 901 
 902     @Test(dataProvider = "Spliterator.OfInt")
 903     public void testIntTryAdvance(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 904         testTryAdvance(exp, s, intBoxingConsumer());
 905     }
 906 
 907     @Test(dataProvider = "Spliterator.OfInt")
 908     public void testIntMixedTryAdvanceForEach(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 909         testMixedTryAdvanceForEach(exp, s, intBoxingConsumer());
 910     }
 911 
 912     @Test(dataProvider = "Spliterator.OfInt")
 913     public void testIntMixedTraverseAndSplit(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 914         testMixedTraverseAndSplit(exp, s, intBoxingConsumer());
 915     }
 916 
 917     @Test(dataProvider = "Spliterator.OfInt")
 918     public void testIntSplitAfterFullTraversal(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 919         testSplitAfterFullTraversal(s, intBoxingConsumer());
 920     }
 921 
 922     @Test(dataProvider = "Spliterator.OfInt")
 923     public void testIntSplitOnce(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 924         testSplitOnce(exp, s, intBoxingConsumer());
 925     }
 926 
 927     @Test(dataProvider = "Spliterator.OfInt")
 928     public void testIntSplitSixDeep(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 929         testSplitSixDeep(exp, s, intBoxingConsumer());
 930     }
 931 
 932     @Test(dataProvider = "Spliterator.OfInt")
 933     public void testIntSplitUntilNull(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
 934         testSplitUntilNull(exp, s, intBoxingConsumer());
 935     }
 936 
 937     //
 938 
 939     private static class SpliteratorOfLongDataBuilder {
 940         List<Object[]> data;
 941 
 942         List<Long> exp;
 943 
 944         SpliteratorOfLongDataBuilder(List<Object[]> data, List<Long> exp) {
 945             this.data = data;
 946             this.exp = exp;
 947         }
 948 
 949         void add(String description, List<Long> expected, Supplier<Spliterator.OfLong> s) {
 950             description = joiner(description).toString();
 951             data.add(new Object[]{description, expected, s});
 952         }
 953 
 954         void add(String description, Supplier<Spliterator.OfLong> s) {
 955             add(description, exp, s);
 956         }
 957 
 958         StringBuilder joiner(String description) {
 959             return new StringBuilder(description).
 960                     append(" {").
 961                     append("size=").append(exp.size()).
 962                     append("}");
 963         }
 964     }
 965 
 966     static Object[][] spliteratorOfLongDataProvider;
 967 
 968     @DataProvider(name = "Spliterator.OfLong")
 969     public static Object[][] spliteratorOfLongDataProvider() {
 970         if (spliteratorOfLongDataProvider != null) {
 971             return spliteratorOfLongDataProvider;
 972         }
 973 
 974         List<Object[]> data = new ArrayList<>();
 975         for (int size : SIZES) {
 976             long exp[] = arrayLongRange(size);
 977             SpliteratorOfLongDataBuilder db = new SpliteratorOfLongDataBuilder(data, listLongRange(size));
 978 
 979             db.add("Spliterators.spliterator(long[], ...)",
 980                    () -> Spliterators.spliterator(exp, 0));
 981 
 982             db.add("Arrays.spliterator(long[], ...)",
 983                    () -> Arrays.spliterator(exp));
 984 
 985             db.add("Spliterators.spliterator(PrimitiveIterator.OfLong, ...)",
 986                    () -> Spliterators.spliterator(Spliterators.iterator(Arrays.spliterator(exp)), exp.length, 0));
 987 
 988             db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfLong, ...)",
 989                    () -> Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(exp)), 0));
 990 
 991             class LongSpliteratorFromArray extends Spliterators.AbstractLongSpliterator {
 992                 long[] a;
 993                 int index = 0;
 994 
 995                 LongSpliteratorFromArray(long[] a) {
 996                     super(a.length, Spliterator.SIZED);
 997                     this.a = a;
 998                 }
 999 
1000                 @Override
1001                 public boolean tryAdvance(LongConsumer action) {
1002                     if (action == null)
1003                         throw new NullPointerException();
1004                     if (index < a.length) {
1005                         action.accept(a[index++]);
1006                         return true;
1007                     }
1008                     else {
1009                         return false;
1010                     }
1011                 }
1012             }
1013             db.add("new Spliterators.AbstractLongAdvancingSpliterator()",
1014                    () -> new LongSpliteratorFromArray(exp));
1015         }
1016 
1017         return spliteratorOfLongDataProvider = data.toArray(new Object[0][]);
1018     }
1019 
1020     private static List<Long> listLongRange(int upTo) {
1021         List<Long> exp = new ArrayList<>();
1022         for (long i = 0; i < upTo; i++)
1023             exp.add(i);
1024         return Collections.unmodifiableList(exp);
1025     }
1026 
1027     private static long[] arrayLongRange(int upTo) {
1028         long[] exp = new long[upTo];
1029         for (int i = 0; i < upTo; i++)
1030             exp[i] = i;
1031         return exp;
1032     }
1033 
1034     @Test(dataProvider = "Spliterator.OfLong")
1035     public void testLongNullPointerException(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1036         assertThrowsNPE(() -> s.get().forEachRemaining((LongConsumer) null));
1037         assertThrowsNPE(() -> s.get().tryAdvance((LongConsumer) null));
1038     }
1039 
1040     @Test(dataProvider = "Spliterator.OfLong")
1041     public void testLongForEach(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1042         testForEach(exp, s, longBoxingConsumer());
1043     }
1044 
1045     @Test(dataProvider = "Spliterator.OfLong")
1046     public void testLongTryAdvance(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1047         testTryAdvance(exp, s, longBoxingConsumer());
1048     }
1049 
1050     @Test(dataProvider = "Spliterator.OfLong")
1051     public void testLongMixedTryAdvanceForEach(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1052         testMixedTryAdvanceForEach(exp, s, longBoxingConsumer());
1053     }
1054 
1055     @Test(dataProvider = "Spliterator.OfLong")
1056     public void testLongMixedTraverseAndSplit(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1057         testMixedTraverseAndSplit(exp, s, longBoxingConsumer());
1058     }
1059 
1060     @Test(dataProvider = "Spliterator.OfLong")
1061     public void testLongSplitAfterFullTraversal(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1062         testSplitAfterFullTraversal(s, longBoxingConsumer());
1063     }
1064 
1065     @Test(dataProvider = "Spliterator.OfLong")
1066     public void testLongSplitOnce(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1067         testSplitOnce(exp, s, longBoxingConsumer());
1068     }
1069 
1070     @Test(dataProvider = "Spliterator.OfLong")
1071     public void testLongSplitSixDeep(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1072         testSplitSixDeep(exp, s, longBoxingConsumer());
1073     }
1074 
1075     @Test(dataProvider = "Spliterator.OfLong")
1076     public void testLongSplitUntilNull(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
1077         testSplitUntilNull(exp, s, longBoxingConsumer());
1078     }
1079 
1080     //
1081 
1082     private static class SpliteratorOfDoubleDataBuilder {
1083         List<Object[]> data;
1084 
1085         List<Double> exp;
1086 
1087         SpliteratorOfDoubleDataBuilder(List<Object[]> data, List<Double> exp) {
1088             this.data = data;
1089             this.exp = exp;
1090         }
1091 
1092         void add(String description, List<Double> expected, Supplier<Spliterator.OfDouble> s) {
1093             description = joiner(description).toString();
1094             data.add(new Object[]{description, expected, s});
1095         }
1096 
1097         void add(String description, Supplier<Spliterator.OfDouble> s) {
1098             add(description, exp, s);
1099         }
1100 
1101         StringBuilder joiner(String description) {
1102             return new StringBuilder(description).
1103                     append(" {").
1104                     append("size=").append(exp.size()).
1105                     append("}");
1106         }
1107     }
1108 
1109     static Object[][] spliteratorOfDoubleDataProvider;
1110 
1111     @DataProvider(name = "Spliterator.OfDouble")
1112     public static Object[][] spliteratorOfDoubleDataProvider() {
1113         if (spliteratorOfDoubleDataProvider != null) {
1114             return spliteratorOfDoubleDataProvider;
1115         }
1116 
1117         List<Object[]> data = new ArrayList<>();
1118         for (int size : SIZES) {
1119             double exp[] = arrayDoubleRange(size);
1120             SpliteratorOfDoubleDataBuilder db = new SpliteratorOfDoubleDataBuilder(data, listDoubleRange(size));
1121 
1122             db.add("Spliterators.spliterator(double[], ...)",
1123                    () -> Spliterators.spliterator(exp, 0));
1124 
1125             db.add("Arrays.spliterator(double[], ...)",
1126                    () -> Arrays.spliterator(exp));
1127 
1128             db.add("Spliterators.spliterator(PrimitiveIterator.OfDouble, ...)",
1129                    () -> Spliterators.spliterator(Spliterators.iterator(Arrays.spliterator(exp)), exp.length, 0));
1130 
1131             db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfDouble, ...)",
1132                    () -> Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(exp)), 0));
1133 
1134             class DoubleSpliteratorFromArray extends Spliterators.AbstractDoubleSpliterator {
1135                 double[] a;
1136                 int index = 0;
1137 
1138                 DoubleSpliteratorFromArray(double[] a) {
1139                     super(a.length, Spliterator.SIZED);
1140                     this.a = a;
1141                 }
1142 
1143                 @Override
1144                 public boolean tryAdvance(DoubleConsumer action) {
1145                     if (action == null)
1146                         throw new NullPointerException();
1147                     if (index < a.length) {
1148                         action.accept(a[index++]);
1149                         return true;
1150                     }
1151                     else {
1152                         return false;
1153                     }
1154                 }
1155             }
1156             db.add("new Spliterators.AbstractDoubleAdvancingSpliterator()",
1157                    () -> new DoubleSpliteratorFromArray(exp));
1158         }
1159 
1160         return spliteratorOfDoubleDataProvider = data.toArray(new Object[0][]);
1161     }
1162 
1163     private static List<Double> listDoubleRange(int upTo) {
1164         List<Double> exp = new ArrayList<>();
1165         for (double i = 0; i < upTo; i++)
1166             exp.add(i);
1167         return Collections.unmodifiableList(exp);
1168     }
1169 
1170     private static double[] arrayDoubleRange(int upTo) {
1171         double[] exp = new double[upTo];
1172         for (int i = 0; i < upTo; i++)
1173             exp[i] = i;
1174         return exp;
1175     }
1176 
1177     @Test(dataProvider = "Spliterator.OfDouble")
1178     public void testDoubleNullPointerException(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1179         assertThrowsNPE(() -> s.get().forEachRemaining((DoubleConsumer) null));
1180         assertThrowsNPE(() -> s.get().tryAdvance((DoubleConsumer) null));
1181     }
1182 
1183     @Test(dataProvider = "Spliterator.OfDouble")
1184     public void testDoubleForEach(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1185         testForEach(exp, s, doubleBoxingConsumer());
1186     }
1187 
1188     @Test(dataProvider = "Spliterator.OfDouble")
1189     public void testDoubleTryAdvance(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1190         testTryAdvance(exp, s, doubleBoxingConsumer());
1191     }
1192 
1193     @Test(dataProvider = "Spliterator.OfDouble")
1194     public void testDoubleMixedTryAdvanceForEach(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1195         testMixedTryAdvanceForEach(exp, s, doubleBoxingConsumer());
1196     }
1197 
1198     @Test(dataProvider = "Spliterator.OfDouble")
1199     public void testDoubleMixedTraverseAndSplit(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1200         testMixedTraverseAndSplit(exp, s, doubleBoxingConsumer());
1201     }
1202 
1203     @Test(dataProvider = "Spliterator.OfDouble")
1204     public void testDoubleSplitAfterFullTraversal(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1205         testSplitAfterFullTraversal(s, doubleBoxingConsumer());
1206     }
1207 
1208     @Test(dataProvider = "Spliterator.OfDouble")
1209     public void testDoubleSplitOnce(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1210         testSplitOnce(exp, s, doubleBoxingConsumer());
1211     }
1212 
1213     @Test(dataProvider = "Spliterator.OfDouble")
1214     public void testDoubleSplitSixDeep(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1215         testSplitSixDeep(exp, s, doubleBoxingConsumer());
1216     }
1217 
1218     @Test(dataProvider = "Spliterator.OfDouble")
1219     public void testDoubleSplitUntilNull(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
1220         testSplitUntilNull(exp, s, doubleBoxingConsumer());
1221     }
1222 
1223 }