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