Home | History | Annotate | Download | only in stream
      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  */
     23 package java.util.stream;
     24 
     25 import org.testng.annotations.Test;
     26 
     27 import java.util.ArrayDeque;
     28 import java.util.ArrayList;
     29 import java.util.Collection;
     30 import java.util.Collections;
     31 import java.util.Deque;
     32 import java.util.HashMap;
     33 import java.util.List;
     34 import java.util.Map;
     35 import java.util.Spliterator;
     36 import java.util.function.*;
     37 
     38 import static org.testng.Assert.*;
     39 import static org.testng.Assert.assertEquals;
     40 import static org.testng.Assert.fail;
     41 
     42 /**
     43  * Assertion methods for spliterators, to be called from other tests
     44  */
     45 public 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