ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/jtreg/util/Spliterator/SpliteratorTraversingAndSplittingTest.java
Revision: 1.4
Committed: Thu Apr 7 17:43:07 2016 UTC (8 years, 1 month ago) by jsr166
Branch: MAIN
Changes since 1.3: +2 -2 lines
Log Message:
sync from upstream

File Contents

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