• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012, 2017, 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 package org.openjdk.testlib.java.util;
24 
25 import java.util.function.*;
26 import org.openjdk.testlib.java.util.stream.LambdaTestHelpers;
27 import java.util.*;
28 
29 import static org.testng.Assert.*;
30 
31 /**
32  * Assertion methods for spliterators, to be called from other tests
33  */
34 public class SpliteratorTestHelper {
35 
36     public interface ContentAsserter<T> {
assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered)37         void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered);
38     }
39 
40     private static ContentAsserter<Object> DEFAULT_CONTENT_ASSERTER
41             = SpliteratorTestHelper::assertContents;
42 
43     @SuppressWarnings("unchecked")
defaultContentAsserter()44     private static <T> ContentAsserter<T> defaultContentAsserter() {
45         return (ContentAsserter<T>) DEFAULT_CONTENT_ASSERTER;
46     }
47 
testSpliterator(Supplier<Spliterator<Integer>> supplier)48     public static void testSpliterator(Supplier<Spliterator<Integer>> supplier) {
49         testSpliterator(supplier, defaultContentAsserter());
50     }
51 
testSpliterator(Supplier<Spliterator<Integer>> supplier, ContentAsserter<Integer> asserter)52     public static void testSpliterator(Supplier<Spliterator<Integer>> supplier,
53                                        ContentAsserter<Integer> asserter) {
54         testSpliterator(supplier, (Consumer<Integer> b) -> b, asserter);
55     }
56 
testIntSpliterator(Supplier<Spliterator.OfInt> supplier)57     public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier) {
58         testIntSpliterator(supplier, defaultContentAsserter());
59     }
60 
testIntSpliterator(Supplier<Spliterator.OfInt> supplier, ContentAsserter<Integer> asserter)61     public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier,
62                                           ContentAsserter<Integer> asserter) {
63         testSpliterator(supplier, intBoxingConsumer(), asserter);
64     }
65 
testLongSpliterator(Supplier<Spliterator.OfLong> supplier)66     public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier) {
67         testLongSpliterator(supplier, defaultContentAsserter());
68     }
69 
testLongSpliterator(Supplier<Spliterator.OfLong> supplier, ContentAsserter<Long> asserter)70     public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier,
71                                            ContentAsserter<Long> asserter) {
72         testSpliterator(supplier, longBoxingConsumer(), asserter);
73     }
74 
testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier)75     public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier) {
76         testDoubleSpliterator(supplier, defaultContentAsserter());
77     }
78 
testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier, ContentAsserter<Double> asserter)79     public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier,
80                                              ContentAsserter<Double> asserter) {
81         testSpliterator(supplier, doubleBoxingConsumer(), asserter);
82     }
83 
intBoxingConsumer()84     public static UnaryOperator<Consumer<Integer>> intBoxingConsumer() {
85         class BoxingAdapter implements Consumer<Integer>, IntConsumer {
86             private final Consumer<Integer> b;
87 
88             BoxingAdapter(Consumer<Integer> b) {
89                 this.b = b;
90             }
91 
92             @Override
93             public void accept(Integer value) {
94                 throw new IllegalStateException();
95             }
96 
97             @Override
98             public void accept(int value) {
99                 b.accept(value);
100             }
101         }
102 
103         return b -> new BoxingAdapter(b);
104     }
105 
longBoxingConsumer()106     public static UnaryOperator<Consumer<Long>> longBoxingConsumer() {
107         class BoxingAdapter implements Consumer<Long>, LongConsumer {
108             private final Consumer<Long> b;
109 
110             BoxingAdapter(Consumer<Long> b) {
111                 this.b = b;
112             }
113 
114             @Override
115             public void accept(Long value) {
116                 throw new IllegalStateException();
117             }
118 
119             @Override
120             public void accept(long value) {
121                 b.accept(value);
122             }
123         }
124 
125         return b -> new BoxingAdapter(b);
126     }
127 
doubleBoxingConsumer()128     public static UnaryOperator<Consumer<Double>> doubleBoxingConsumer() {
129         class BoxingAdapter implements Consumer<Double>, DoubleConsumer {
130             private final Consumer<Double> b;
131 
132             BoxingAdapter(Consumer<Double> b) {
133                 this.b = b;
134             }
135 
136             @Override
137             public void accept(Double value) {
138                 throw new IllegalStateException();
139             }
140 
141             @Override
142             public void accept(double value) {
143                 b.accept(value);
144             }
145         }
146 
147         return b -> new BoxingAdapter(b);
148     }
149 
testSpliterator(Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)150     public static <T, S extends Spliterator<T>> void testSpliterator(Supplier<S> supplier,
151                                                               UnaryOperator<Consumer<T>> boxingAdapter,
152                                                               ContentAsserter<T> asserter) {
153         ArrayList<T> fromForEach = new ArrayList<>();
154         Spliterator<T> spliterator = supplier.get();
155         Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
156         spliterator.forEachRemaining(addToFromForEach);
157 
158         Collection<T> exp = Collections.unmodifiableList(fromForEach);
159 
160         testNullPointerException(supplier);
161         testForEach(exp, supplier, boxingAdapter, asserter);
162         testTryAdvance(exp, supplier, boxingAdapter, asserter);
163         testMixedTryAdvanceForEach(exp, supplier, boxingAdapter, asserter);
164         testMixedTraverseAndSplit(exp, supplier, boxingAdapter, asserter);
165         testSplitAfterFullTraversal(supplier, boxingAdapter);
166         testSplitOnce(exp, supplier, boxingAdapter, asserter);
167         testSplitSixDeep(exp, supplier, boxingAdapter, asserter);
168         testSplitUntilNull(exp, supplier, boxingAdapter, asserter);
169     }
170 
testForEach( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)171     public static <T, S extends Spliterator<T>> void testForEach(
172             Collection<T> exp,
173             Supplier<S> supplier,
174             UnaryOperator<Consumer<T>> boxingAdapter) {
175         testForEach(exp, supplier, boxingAdapter, defaultContentAsserter());
176     }
177 
testTryAdvance( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)178     public static <T, S extends Spliterator<T>> void testTryAdvance(
179             Collection<T> exp,
180             Supplier<S> supplier,
181             UnaryOperator<Consumer<T>> boxingAdapter) {
182         testTryAdvance(exp, supplier, boxingAdapter, defaultContentAsserter());
183     }
184 
testMixedTryAdvanceForEach( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)185     public static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(
186             Collection<T> exp,
187             Supplier<S> supplier,
188             UnaryOperator<Consumer<T>> boxingAdapter) {
189         testMixedTryAdvanceForEach(exp, supplier, boxingAdapter, defaultContentAsserter());
190     }
191 
testMixedTraverseAndSplit( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)192     public static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
193             Collection<T> exp,
194             Supplier<S> supplier,
195             UnaryOperator<Consumer<T>> boxingAdapter) {
196         testMixedTraverseAndSplit(exp, supplier, boxingAdapter, defaultContentAsserter());
197     }
198 
testSplitOnce( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)199     public static <T, S extends Spliterator<T>> void testSplitOnce(
200             Collection<T> exp,
201             Supplier<S> supplier,
202             UnaryOperator<Consumer<T>> boxingAdapter) {
203         testSplitOnce(exp, supplier, boxingAdapter, defaultContentAsserter());
204     }
205 
testSplitSixDeep( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)206     public static <T, S extends Spliterator<T>> void testSplitSixDeep(
207             Collection<T> exp,
208             Supplier<S> supplier,
209             UnaryOperator<Consumer<T>> boxingAdapter) {
210         testSplitSixDeep(exp, supplier, boxingAdapter, defaultContentAsserter());
211     }
212 
testSplitUntilNull( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)213     public static <T, S extends Spliterator<T>> void testSplitUntilNull(
214             Collection<T> exp,
215             Supplier<S> supplier,
216             UnaryOperator<Consumer<T>> boxingAdapter) {
217         testSplitUntilNull(exp, supplier, boxingAdapter, defaultContentAsserter());
218     }
219 
testNullPointerException(Supplier<S> s)220     private static <T, S extends Spliterator<T>> void testNullPointerException(Supplier<S> s) {
221         S sp = s.get();
222         // Have to check instances and use casts to avoid tripwire messages and
223         // directly test the primitive methods
224         if (sp instanceof Spliterator.OfInt) {
225             Spliterator.OfInt psp = (Spliterator.OfInt) sp;
226             assertThrowsNPE(() -> psp.forEachRemaining((IntConsumer) null));
227             assertThrowsNPE(() -> psp.tryAdvance((IntConsumer) null));
228         }
229         else if (sp instanceof Spliterator.OfLong) {
230             Spliterator.OfLong psp = (Spliterator.OfLong) sp;
231             assertThrowsNPE(() -> psp.forEachRemaining((LongConsumer) null));
232             assertThrowsNPE(() -> psp.tryAdvance((LongConsumer) null));
233         }
234         else if (sp instanceof Spliterator.OfDouble) {
235             Spliterator.OfDouble psp = (Spliterator.OfDouble) sp;
236             assertThrowsNPE(() -> psp.forEachRemaining((DoubleConsumer) null));
237             assertThrowsNPE(() -> psp.tryAdvance((DoubleConsumer) null));
238         }
239         else {
240             assertThrowsNPE(() -> sp.forEachRemaining(null));
241             assertThrowsNPE(() -> sp.tryAdvance(null));
242         }
243     }
244 
testForEach( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)245     private static <T, S extends Spliterator<T>> void testForEach(
246             Collection<T> exp,
247             Supplier<S> supplier,
248             UnaryOperator<Consumer<T>> boxingAdapter,
249             ContentAsserter<T> asserter) {
250         S spliterator = supplier.get();
251         long sizeIfKnown = spliterator.getExactSizeIfKnown();
252         boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
253 
254         ArrayList<T> fromForEach = new ArrayList<>();
255         spliterator = supplier.get();
256         Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
257         spliterator.forEachRemaining(addToFromForEach);
258 
259         // Assert that forEach now produces no elements
260         spliterator.forEachRemaining(boxingAdapter.apply(
261                 e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
262         // Assert that tryAdvance now produce no elements
263         spliterator.tryAdvance(boxingAdapter.apply(
264                 e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
265 
266         // assert that size, tryAdvance, and forEach are consistent
267         if (sizeIfKnown >= 0) {
268             assertEquals(sizeIfKnown, exp.size());
269         }
270         if (exp.contains(null)) {
271             assertTrue(fromForEach.contains(null));
272         }
273         assertEquals(fromForEach.size(), exp.size());
274 
275         asserter.assertContents(fromForEach, exp, isOrdered);
276     }
277 
testTryAdvance( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)278     private static <T, S extends Spliterator<T>> void testTryAdvance(
279             Collection<T> exp,
280             Supplier<S> supplier,
281             UnaryOperator<Consumer<T>> boxingAdapter,
282             ContentAsserter<T> asserter) {
283         S spliterator = supplier.get();
284         long sizeIfKnown = spliterator.getExactSizeIfKnown();
285         boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
286 
287         spliterator = supplier.get();
288         ArrayList<T> fromTryAdvance = new ArrayList<>();
289         Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add);
290         while (spliterator.tryAdvance(addToFromTryAdvance)) { }
291 
292         // Assert that forEach now produces no elements
293         spliterator.forEachRemaining(boxingAdapter.apply(
294                 e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
295         // Assert that tryAdvance now produce no elements
296         spliterator.tryAdvance(boxingAdapter.apply(
297                 e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
298 
299         // assert that size, tryAdvance, and forEach are consistent
300         if (sizeIfKnown >= 0) {
301             assertEquals(sizeIfKnown, exp.size());
302         }
303         assertEquals(fromTryAdvance.size(), exp.size());
304 
305         asserter.assertContents(fromTryAdvance, exp, isOrdered);
306     }
307 
testMixedTryAdvanceForEach( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)308     private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(
309             Collection<T> exp,
310             Supplier<S> supplier,
311             UnaryOperator<Consumer<T>> boxingAdapter,
312             ContentAsserter<T> asserter) {
313         S spliterator = supplier.get();
314         long sizeIfKnown = spliterator.getExactSizeIfKnown();
315         boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
316 
317         // tryAdvance first few elements, then forEach rest
318         ArrayList<T> dest = new ArrayList<>();
319         spliterator = supplier.get();
320         Consumer<T> addToDest = boxingAdapter.apply(dest::add);
321         for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { }
322         spliterator.forEachRemaining(addToDest);
323 
324         // Assert that forEach now produces no elements
325         spliterator.forEachRemaining(boxingAdapter.apply(
326                 e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
327         // Assert that tryAdvance now produce no elements
328         spliterator.tryAdvance(boxingAdapter.apply(
329                 e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
330 
331         if (sizeIfKnown >= 0) {
332             assertEquals(sizeIfKnown, dest.size());
333         }
334         assertEquals(dest.size(), exp.size());
335 
336         asserter.assertContents(dest, exp, isOrdered);
337     }
338 
testMixedTraverseAndSplit( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)339     private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
340             Collection<T> exp,
341             Supplier<S> supplier,
342             UnaryOperator<Consumer<T>> boxingAdapter,
343             ContentAsserter<T> asserter) {
344         S spliterator = supplier.get();
345         long sizeIfKnown = spliterator.getExactSizeIfKnown();
346         boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
347 
348         // tryAdvance first few elements, then forEach rest
349         ArrayList<T> dest = new ArrayList<>();
350         spliterator = supplier.get();
351         Consumer<T> b = boxingAdapter.apply(dest::add);
352 
353         Spliterator<T> spl1, spl2, spl3;
354         spliterator.tryAdvance(b);
355         spl2 = spliterator.trySplit();
356         if (spl2 != null) {
357             spl2.tryAdvance(b);
358             spl1 = spl2.trySplit();
359             if (spl1 != null) {
360                 spl1.tryAdvance(b);
361                 spl1.forEachRemaining(b);
362             }
363             spl2.tryAdvance(b);
364             spl2.forEachRemaining(b);
365         }
366         spliterator.tryAdvance(b);
367         spl3 = spliterator.trySplit();
368         if (spl3 != null) {
369             spl3.tryAdvance(b);
370             spl3.forEachRemaining(b);
371         }
372         spliterator.tryAdvance(b);
373         spliterator.forEachRemaining(b);
374 
375         if (sizeIfKnown >= 0) {
376             assertEquals(sizeIfKnown, dest.size());
377         }
378         assertEquals(dest.size(), exp.size());
379 
380         asserter.assertContents(dest, exp, isOrdered);
381     }
382 
testSplitAfterFullTraversal( Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter)383     public static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(
384             Supplier<S> supplier,
385             UnaryOperator<Consumer<T>> boxingAdapter) {
386         // Full traversal using tryAdvance
387         Spliterator<T> spliterator = supplier.get();
388         while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { }
389         Spliterator<T> split = spliterator.trySplit();
390         assertNull(split);
391 
392         // Full traversal using forEach
393         spliterator = supplier.get();
394         spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
395         split = spliterator.trySplit();
396         assertNull(split);
397 
398         // Full traversal using tryAdvance then forEach
399         spliterator = supplier.get();
400         spliterator.tryAdvance(boxingAdapter.apply(e -> { }));
401         spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
402         split = spliterator.trySplit();
403         assertNull(split);
404     }
405 
testSplitOnce( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)406     private static <T, S extends Spliterator<T>> void testSplitOnce(
407             Collection<T> exp,
408             Supplier<S> supplier,
409             UnaryOperator<Consumer<T>> boxingAdapter,
410             ContentAsserter<T> asserter) {
411         S spliterator = supplier.get();
412         long sizeIfKnown = spliterator.getExactSizeIfKnown();
413         boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
414 
415         ArrayList<T> fromSplit = new ArrayList<>();
416         Spliterator<T> s1 = supplier.get();
417         Spliterator<T> s2 = s1.trySplit();
418         long s1Size = s1.getExactSizeIfKnown();
419         long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;
420         Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);
421         if (s2 != null)
422             s2.forEachRemaining(addToFromSplit);
423         s1.forEachRemaining(addToFromSplit);
424 
425         if (sizeIfKnown >= 0) {
426             assertEquals(sizeIfKnown, fromSplit.size());
427             if (s1Size >= 0 && s2Size >= 0)
428                 assertEquals(sizeIfKnown, s1Size + s2Size);
429         }
430 
431         asserter.assertContents(fromSplit, exp, isOrdered);
432     }
433 
testSplitSixDeep( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)434     private static <T, S extends Spliterator<T>> void testSplitSixDeep(
435             Collection<T> exp,
436             Supplier<S> supplier,
437             UnaryOperator<Consumer<T>> boxingAdapter,
438             ContentAsserter<T> asserter) {
439         S spliterator = supplier.get();
440         boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
441 
442         for (int depth=0; depth < 6; depth++) {
443             List<T> dest = new ArrayList<>();
444             spliterator = supplier.get();
445 
446             assertSpliterator(spliterator);
447 
448             // verify splitting with forEach
449             splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);
450             asserter.assertContents(dest, exp, isOrdered);
451 
452             // verify splitting with tryAdvance
453             dest.clear();
454             spliterator = supplier.get();
455             splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);
456             asserter.assertContents(dest, exp, isOrdered);
457         }
458     }
459 
460     private static <T, S extends Spliterator<T>>
splitSixDeepVisitor(int depth, int curLevel, List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter, int rootCharacteristics, boolean useTryAdvance)461     void splitSixDeepVisitor(int depth, int curLevel,
462                              List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
463                              int rootCharacteristics, boolean useTryAdvance) {
464         if (curLevel < depth) {
465             long beforeSize = spliterator.getExactSizeIfKnown();
466             Spliterator<T> split = spliterator.trySplit();
467             if (split != null) {
468                 assertSpliterator(split, rootCharacteristics);
469                 assertSpliterator(spliterator, rootCharacteristics);
470 
471                 if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&
472                     (rootCharacteristics & Spliterator.SIZED) != 0) {
473                     assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());
474                 }
475                 splitSixDeepVisitor(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
476             }
477             splitSixDeepVisitor(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
478         }
479         else {
480             long sizeIfKnown = spliterator.getExactSizeIfKnown();
481             if (useTryAdvance) {
482                 Consumer<T> addToDest = boxingAdapter.apply(dest::add);
483                 int count = 0;
484                 while (spliterator.tryAdvance(addToDest)) {
485                     ++count;
486                 }
487 
488                 if (sizeIfKnown >= 0)
489                     assertEquals(sizeIfKnown, count);
490 
491                 // Assert that forEach now produces no elements
492                 spliterator.forEachRemaining(boxingAdapter.apply(
493                         e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
494 
495                 Spliterator<T> split = spliterator.trySplit();
496                 assertNull(split);
497             }
498             else {
499                 List<T> leafDest = new ArrayList<>();
500                 Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);
501                 spliterator.forEachRemaining(addToLeafDest);
502 
503                 if (sizeIfKnown >= 0)
504                     assertEquals(sizeIfKnown, leafDest.size());
505 
506                 // Assert that forEach now produces no elements
507                 spliterator.tryAdvance(boxingAdapter.apply(
508                         e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
509 
510                 Spliterator<T> split = spliterator.trySplit();
511                 assertNull(split);
512 
513                 dest.addAll(leafDest);
514             }
515         }
516     }
517 
testSplitUntilNull( Collection<T> exp, Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter, ContentAsserter<T> asserter)518     private static <T, S extends Spliterator<T>> void testSplitUntilNull(
519             Collection<T> exp,
520             Supplier<S> supplier,
521             UnaryOperator<Consumer<T>> boxingAdapter,
522             ContentAsserter<T> asserter) {
523         Spliterator<T> s = supplier.get();
524         boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED);
525         assertSpliterator(s);
526 
527         List<T> splits = new ArrayList<>();
528         Consumer<T> c = boxingAdapter.apply(splits::add);
529 
530         testSplitUntilNull(new SplitNode<T>(c, s));
531         asserter.assertContents(splits, exp, isOrdered);
532     }
533 
534     private static class SplitNode<T> {
535         // Constant for every node
536         final Consumer<T> c;
537         final int rootCharacteristics;
538 
539         final Spliterator<T> s;
540 
SplitNode(Consumer<T> c, Spliterator<T> s)541         SplitNode(Consumer<T> c, Spliterator<T> s) {
542             this(c, s.characteristics(), s);
543         }
544 
SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s)545         private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {
546             this.c = c;
547             this.rootCharacteristics = rootCharacteristics;
548             this.s = s;
549         }
550 
fromSplit(Spliterator<T> split)551         SplitNode<T> fromSplit(Spliterator<T> split) {
552             return new SplitNode<>(c, rootCharacteristics, split);
553         }
554     }
555 
556     /**
557      * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator
558      * while not unduly disrupting test infrastructure given the test data sizes that are used are small.
559      * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26).
560      */
561     private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB
562 
testSplitUntilNull(SplitNode<T> e)563     private static <T> void testSplitUntilNull(SplitNode<T> e) {
564         // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator
565         // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or
566         // for a spliterator that is badly behaved.
567         Deque<SplitNode<T>> stack = new ArrayDeque<>();
568         stack.push(e);
569 
570         int iteration = 0;
571         while (!stack.isEmpty()) {
572             assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");
573 
574             e = stack.pop();
575             Spliterator<T> parentAndRightSplit = e.s;
576 
577             long parentEstimateSize = parentAndRightSplit.estimateSize();
578             assertTrue(parentEstimateSize >= 0,
579                        String.format("Split size estimate %d < 0", parentEstimateSize));
580 
581             long parentSize = parentAndRightSplit.getExactSizeIfKnown();
582             Spliterator<T> leftSplit = parentAndRightSplit.trySplit();
583             if (leftSplit == null) {
584                 parentAndRightSplit.forEachRemaining(e.c);
585                 continue;
586             }
587 
588             assertSpliterator(leftSplit, e.rootCharacteristics);
589             assertSpliterator(parentAndRightSplit, e.rootCharacteristics);
590 
591             if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0
592                 && parentAndRightSplit.estimateSize() > 0) {
593                 assertTrue(leftSplit.estimateSize() < parentEstimateSize,
594                            String.format("Left split size estimate %d >= parent split size estimate %d",
595                                          leftSplit.estimateSize(), parentEstimateSize));
596                 assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize,
597                            String.format("Right split size estimate %d >= parent split size estimate %d",
598                                          leftSplit.estimateSize(), parentEstimateSize));
599             }
600             else {
601                 assertTrue(leftSplit.estimateSize() <= parentEstimateSize,
602                            String.format("Left split size estimate %d > parent split size estimate %d",
603                                          leftSplit.estimateSize(), parentEstimateSize));
604                 assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize,
605                            String.format("Right split size estimate %d > parent split size estimate %d",
606                                          leftSplit.estimateSize(), parentEstimateSize));
607             }
608 
609             long leftSize = leftSplit.getExactSizeIfKnown();
610             long rightSize = parentAndRightSplit.getExactSizeIfKnown();
611             if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)
612                 assertEquals(parentSize, leftSize + rightSize,
613                              String.format("exact left split size %d + exact right split size %d != parent exact split size %d",
614                                            leftSize, rightSize, parentSize));
615 
616             // Add right side to stack first so left side is popped off first
617             stack.push(e.fromSplit(parentAndRightSplit));
618             stack.push(e.fromSplit(leftSplit));
619         }
620     }
621 
622     private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {
623         if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {
624             assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),
625                        "Child split is not SUBSIZED when root split is SUBSIZED");
626         }
627         assertSpliterator(s);
628     }
629 
630     private static void assertSpliterator(Spliterator<?> s) {
631         if (s.hasCharacteristics(Spliterator.SUBSIZED)) {
632             assertTrue(s.hasCharacteristics(Spliterator.SIZED));
633         }
634         if (s.hasCharacteristics(Spliterator.SIZED)) {
635             assertTrue(s.estimateSize() != Long.MAX_VALUE);
636             assertTrue(s.getExactSizeIfKnown() >= 0);
637         }
638         try {
639             s.getComparator();
640             assertTrue(s.hasCharacteristics(Spliterator.SORTED));
641         } catch (IllegalStateException e) {
642             assertFalse(s.hasCharacteristics(Spliterator.SORTED));
643         }
644     }
645 
assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered)646     private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
647         if (isOrdered) {
648             assertEquals(actual, expected);
649         }
650         else {
651             LambdaTestHelpers.assertContentsUnordered(actual, expected);
652         }
653     }
654 
assertThrowsNPE(ThrowingRunnable r)655     public static void assertThrowsNPE(ThrowingRunnable r) {
656         assertThrows(NullPointerException.class, r);
657     }
658 
mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop)659     public static<U> void mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop) {
660         Spliterator<U> spl1, spl2, spl3;
661         splTop.tryAdvance(b);
662         spl2 = splTop.trySplit();
663         if (spl2 != null) {
664             spl2.tryAdvance(b);
665             spl1 = spl2.trySplit();
666             if (spl1 != null) {
667                 spl1.tryAdvance(b);
668                 spl1.forEachRemaining(b);
669             }
670             spl2.tryAdvance(b);
671             spl2.forEachRemaining(b);
672         }
673         splTop.tryAdvance(b);
674         spl3 = splTop.trySplit();
675         if (spl3 != null) {
676             spl3.tryAdvance(b);
677             spl3.forEachRemaining(b);
678         }
679         splTop.tryAdvance(b);
680         splTop.forEachRemaining(b);
681     }
682 
mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop)683     public static void mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop) {
684         Spliterator.OfInt spl1, spl2, spl3;
685         splTop.tryAdvance(b);
686         spl2 = splTop.trySplit();
687         if (spl2 != null) {
688             spl2.tryAdvance(b);
689             spl1 = spl2.trySplit();
690             if (spl1 != null) {
691                 spl1.tryAdvance(b);
692                 spl1.forEachRemaining(b);
693             }
694             spl2.tryAdvance(b);
695             spl2.forEachRemaining(b);
696         }
697         splTop.tryAdvance(b);
698         spl3 = splTop.trySplit();
699         if (spl3 != null) {
700             spl3.tryAdvance(b);
701             spl3.forEachRemaining(b);
702         }
703         splTop.tryAdvance(b);
704         splTop.forEachRemaining(b);
705     }
706 
mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop)707     public static void mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop) {
708         Spliterator.OfLong spl1, spl2, spl3;
709         splTop.tryAdvance(b);
710         spl2 = splTop.trySplit();
711         if (spl2 != null) {
712             spl2.tryAdvance(b);
713             spl1 = spl2.trySplit();
714             if (spl1 != null) {
715                 spl1.tryAdvance(b);
716                 spl1.forEachRemaining(b);
717             }
718             spl2.tryAdvance(b);
719             spl2.forEachRemaining(b);
720         }
721         splTop.tryAdvance(b);
722         spl3 = splTop.trySplit();
723         if (spl3 != null) {
724             spl3.tryAdvance(b);
725             spl3.forEachRemaining(b);
726         }
727         splTop.tryAdvance(b);
728         splTop.forEachRemaining(b);
729     }
730 
mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop)731     public static void mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop) {
732         Spliterator.OfDouble spl1, spl2, spl3;
733         splTop.tryAdvance(b);
734         spl2 = splTop.trySplit();
735         if (spl2 != null) {
736             spl2.tryAdvance(b);
737             spl1 = spl2.trySplit();
738             if (spl1 != null) {
739                 spl1.tryAdvance(b);
740                 spl1.forEachRemaining(b);
741             }
742             spl2.tryAdvance(b);
743             spl2.forEachRemaining(b);
744         }
745         splTop.tryAdvance(b);
746         spl3 = splTop.trySplit();
747         if (spl3 != null) {
748             spl3.tryAdvance(b);
749             spl3.forEachRemaining(b);
750         }
751         splTop.tryAdvance(b);
752         splTop.forEachRemaining(b);
753     }
754 
755 }
756