ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/jtreg/util/Spliterator/SpliteratorTraversingAndSplittingTest.java
Revision: 1.8
Committed: Mon Dec 11 03:02:35 2017 UTC (6 years, 5 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +2 -2 lines
Log Message:
fix errorprone [MixedArrayDimensions] warnings

File Contents

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