ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/jtreg/util/Spliterator/SpliteratorTraversingAndSplittingTest.java
Revision: 1.1
Committed: Tue Jun 16 23:47:14 2015 UTC (8 years, 11 months ago) by jsr166
Branch: MAIN
Log Message:
import upstream Spliterator tests

File Contents

# Content
1 /*
2 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /**
25 * @test
26 * @summary Spliterator traversing and splitting tests
27 * @run testng SpliteratorTraversingAndSplittingTest
28 * @bug 8020016 8071477
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 private static final List<Integer> SIZES = Arrays.asList(0, 1, 10, 100, 1000);
89
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 Map<T,T> mExp;
127
128 SpliteratorDataBuilder(List<Object[]> data, List<T> exp) {
129 this.data = data;
130 this.exp = exp;
131 this.mExp = createMap(exp);
132 }
133
134 Map<T,T> createMap(List<T> l) {
135 Map<T,T> m = new LinkedHashMap<>();
136 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 // @@@ If collection is instance of List then add sub-list tests
158 addCollection(l);
159 }
160
161 void addMap(Function<Map<T,T>, ? extends Map<T,T>> m) {
162 String description = "new " + m.apply(Collections.<T,T>emptyMap()).getClass().getName();
163 addMap(m, description);
164 }
165
166 void addMap(Function<Map<T,T>, ? extends Map<T,T>> m, String description) {
167 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 }