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