Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/util/Spliterator/SpliteratorCollisions.java
38811 views
/*1* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 800569826* @run testng SpliteratorCollisions27* @summary Spliterator traversing and splitting hash maps containing colliding hashes28* @author Brent Christian29*/3031import org.testng.annotations.DataProvider;32import org.testng.annotations.Test;3334import java.util.ArrayDeque;35import java.util.ArrayList;36import java.util.Arrays;37import java.util.Collection;38import java.util.Collections;39import java.util.Deque;40import java.util.HashMap;41import java.util.HashSet;42import java.util.LinkedHashMap;43import java.util.LinkedHashSet;44import java.util.List;45import java.util.Map;46import java.util.Spliterator;47import java.util.TreeSet;48import java.util.function.Consumer;49import java.util.function.Function;50import java.util.function.Supplier;51import java.util.function.UnaryOperator;5253import static org.testng.Assert.*;54import static org.testng.Assert.assertEquals;5556@Test57public class SpliteratorCollisions {5859private static List<Integer> SIZES = Arrays.asList(0, 1, 10, 100, 1000);6061private static class SpliteratorDataBuilder<T> {62List<Object[]> data;63List<T> exp;64Map<T, T> mExp;6566SpliteratorDataBuilder(List<Object[]> data, List<T> exp) {67this.data = data;68this.exp = exp;69this.mExp = createMap(exp);70}7172Map<T, T> createMap(List<T> l) {73Map<T, T> m = new LinkedHashMap<>();74for (T t : l) {75m.put(t, t);76}77return m;78}7980void add(String description, Collection<?> expected, Supplier<Spliterator<?>> s) {81description = joiner(description).toString();82data.add(new Object[]{description, expected, s});83}8485void add(String description, Supplier<Spliterator<?>> s) {86add(description, exp, s);87}8889void addCollection(Function<Collection<T>, ? extends Collection<T>> c) {90add("new " + c.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator()",91() -> c.apply(exp).spliterator());92}9394void addList(Function<Collection<T>, ? extends List<T>> l) {95// @@@ If collection is instance of List then add sub-list tests96addCollection(l);97}9899void addMap(Function<Map<T, T>, ? extends Map<T, T>> m) {100String description = "new " + m.apply(Collections.<T, T>emptyMap()).getClass().getName();101add(description + ".keySet().spliterator()", () -> m.apply(mExp).keySet().spliterator());102add(description + ".values().spliterator()", () -> m.apply(mExp).values().spliterator());103add(description + ".entrySet().spliterator()", mExp.entrySet(), () -> m.apply(mExp).entrySet().spliterator());104}105106StringBuilder joiner(String description) {107return new StringBuilder(description).108append(" {").109append("size=").append(exp.size()).110append("}");111}112}113114static Object[][] spliteratorDataProvider;115116@DataProvider(name = "HashableIntSpliterator")117public static Object[][] spliteratorDataProvider() {118if (spliteratorDataProvider != null) {119return spliteratorDataProvider;120}121122List<Object[]> data = new ArrayList<>();123for (int size : SIZES) {124List<HashableInteger> exp = listIntRange(size, false);125SpliteratorDataBuilder<HashableInteger> db = new SpliteratorDataBuilder<>(data, exp);126127// Maps128db.addMap(HashMap::new);129db.addMap(LinkedHashMap::new);130131// Collections that use HashMap132db.addCollection(HashSet::new);133db.addCollection(LinkedHashSet::new);134db.addCollection(TreeSet::new);135}136return spliteratorDataProvider = data.toArray(new Object[0][]);137}138139static Object[][] spliteratorDataProviderWithNull;140141@DataProvider(name = "HashableIntSpliteratorWithNull")142public static Object[][] spliteratorNullDataProvider() {143if (spliteratorDataProviderWithNull != null) {144return spliteratorDataProviderWithNull;145}146147List<Object[]> data = new ArrayList<>();148for (int size : SIZES) {149List<HashableInteger> exp = listIntRange(size, true);150SpliteratorDataBuilder<HashableInteger> db = new SpliteratorDataBuilder<>(data, exp);151152// Maps153db.addMap(HashMap::new);154db.addMap(LinkedHashMap::new);155// TODO: add this back in if we decide to keep TreeBin in WeakHashMap156//db.addMap(WeakHashMap::new);157158// Collections that use HashMap159db.addCollection(HashSet::new);160db.addCollection(LinkedHashSet::new);161// db.addCollection(TreeSet::new);162163}164return spliteratorDataProviderWithNull = data.toArray(new Object[0][]);165}166167final static class HashableInteger implements Comparable<HashableInteger> {168169final int value;170final int hashmask; //yes duplication171172HashableInteger(int value, int hashmask) {173this.value = value;174this.hashmask = hashmask;175}176177@Override178public boolean equals(Object obj) {179if (obj instanceof HashableInteger) {180HashableInteger other = (HashableInteger) obj;181182return other.value == value;183}184185return false;186}187188@Override189public int hashCode() {190return value % hashmask;191}192193@Override194public int compareTo(HashableInteger o) {195return value - o.value;196}197198@Override199public String toString() {200return Integer.toString(value);201}202}203204private static List<HashableInteger> listIntRange(int upTo, boolean withNull) {205List<HashableInteger> exp = new ArrayList<>();206if (withNull) {207exp.add(null);208}209for (int i = 0; i < upTo; i++) {210exp.add(new HashableInteger(i, 10));211}212return Collections.unmodifiableList(exp);213}214215@Test(dataProvider = "HashableIntSpliterator")216@SuppressWarnings({"unchecked", "rawtypes"})217public void testNullPointerException(String description, Collection exp, Supplier<Spliterator> s) {218executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining(null));219executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance(null));220}221222@Test(dataProvider = "HashableIntSpliteratorWithNull")223@SuppressWarnings({"unchecked", "rawtypes"})224public void testNullPointerExceptionWithNull(String description, Collection exp, Supplier<Spliterator> s) {225executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining(null));226executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance(null));227}228229230@Test(dataProvider = "HashableIntSpliterator")231@SuppressWarnings({"unchecked", "rawtypes"})232public void testForEach(String description, Collection exp, Supplier<Spliterator> s) {233testForEach(exp, s, (Consumer<Object> b) -> b);234}235236@Test(dataProvider = "HashableIntSpliteratorWithNull")237@SuppressWarnings({"unchecked", "rawtypes"})238public void testForEachWithNull(String description, Collection exp, Supplier<Spliterator> s) {239testForEach(exp, s, (Consumer<Object> b) -> b);240}241242243@Test(dataProvider = "HashableIntSpliterator")244@SuppressWarnings({"unchecked", "rawtypes"})245public void testTryAdvance(String description, Collection exp, Supplier<Spliterator> s) {246testTryAdvance(exp, s, (Consumer<Object> b) -> b);247}248249@Test(dataProvider = "HashableIntSpliteratorWithNull")250@SuppressWarnings({"unchecked", "rawtypes"})251public void testTryAdvanceWithNull(String description, Collection exp, Supplier<Spliterator> s) {252testTryAdvance(exp, s, (Consumer<Object> b) -> b);253}254255/* skip this test until 8013649 is fixed256@Test(dataProvider = "HashableIntSpliterator")257@SuppressWarnings({"unchecked", "rawtypes"})258public void testMixedTryAdvanceForEach(String description, Collection exp, Supplier<Spliterator> s) {259testMixedTryAdvanceForEach(exp, s, (Consumer<Object> b) -> b);260}261262@Test(dataProvider = "HashableIntSpliteratorWithNull")263@SuppressWarnings({"unchecked", "rawtypes"})264public void testMixedTryAdvanceForEachWithNull(String description, Collection exp, Supplier<Spliterator> s) {265testMixedTryAdvanceForEach(exp, s, (Consumer<Object> b) -> b);266}267*/268269@Test(dataProvider = "HashableIntSpliterator")270@SuppressWarnings({"unchecked", "rawtypes"})271public void testSplitAfterFullTraversal(String description, Collection exp, Supplier<Spliterator> s) {272testSplitAfterFullTraversal(s, (Consumer<Object> b) -> b);273}274275@Test(dataProvider = "HashableIntSpliteratorWithNull")276@SuppressWarnings({"unchecked", "rawtypes"})277public void testSplitAfterFullTraversalWithNull(String description, Collection exp, Supplier<Spliterator> s) {278testSplitAfterFullTraversal(s, (Consumer<Object> b) -> b);279}280281282@Test(dataProvider = "HashableIntSpliterator")283@SuppressWarnings({"unchecked", "rawtypes"})284public void testSplitOnce(String description, Collection exp, Supplier<Spliterator> s) {285testSplitOnce(exp, s, (Consumer<Object> b) -> b);286}287288@Test(dataProvider = "HashableIntSpliteratorWithNull")289@SuppressWarnings({"unchecked", "rawtypes"})290public void testSplitOnceWithNull(String description, Collection exp, Supplier<Spliterator> s) {291testSplitOnce(exp, s, (Consumer<Object> b) -> b);292}293294@Test(dataProvider = "HashableIntSpliterator")295@SuppressWarnings({"unchecked", "rawtypes"})296public void testSplitSixDeep(String description, Collection exp, Supplier<Spliterator> s) {297testSplitSixDeep(exp, s, (Consumer<Object> b) -> b);298}299300@Test(dataProvider = "HashableIntSpliteratorWithNull")301@SuppressWarnings({"unchecked", "rawtypes"})302public void testSplitSixDeepWithNull(String description, Collection exp, Supplier<Spliterator> s) {303testSplitSixDeep(exp, s, (Consumer<Object> b) -> b);304}305306@Test(dataProvider = "HashableIntSpliterator")307@SuppressWarnings({"unchecked", "rawtypes"})308public void testSplitUntilNull(String description, Collection exp, Supplier<Spliterator> s) {309testSplitUntilNull(exp, s, (Consumer<Object> b) -> b);310}311312@Test(dataProvider = "HashableIntSpliteratorWithNull")313@SuppressWarnings({"unchecked", "rawtypes"})314public void testSplitUntilNullWithNull(String description, Collection exp, Supplier<Spliterator> s) {315testSplitUntilNull(exp, s, (Consumer<Object> b) -> b);316}317318private static <T, S extends Spliterator<T>> void testForEach(319Collection<T> exp,320Supplier<S> supplier,321UnaryOperator<Consumer<T>> boxingAdapter) {322S spliterator = supplier.get();323long sizeIfKnown = spliterator.getExactSizeIfKnown();324boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);325326ArrayList<T> fromForEach = new ArrayList<>();327spliterator = supplier.get();328Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);329spliterator.forEachRemaining(addToFromForEach);330331// Assert that forEach now produces no elements332spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));333// Assert that tryAdvance now produce no elements334spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));335336// assert that size, tryAdvance, and forEach are consistent337if (sizeIfKnown >= 0) {338assertEquals(sizeIfKnown, exp.size());339}340if (exp.contains(null)) {341assertTrue(fromForEach.contains(null));342}343assertEquals(fromForEach.size(), exp.size());344345assertContents(fromForEach, exp, isOrdered);346}347348private static <T, S extends Spliterator<T>> void testTryAdvance(349Collection<T> exp,350Supplier<S> supplier,351UnaryOperator<Consumer<T>> boxingAdapter) {352S spliterator = supplier.get();353long sizeIfKnown = spliterator.getExactSizeIfKnown();354boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);355356spliterator = supplier.get();357ArrayList<T> fromTryAdvance = new ArrayList<>();358Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add);359while (spliterator.tryAdvance(addToFromTryAdvance)) { }360361// Assert that forEach now produces no elements362spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));363// Assert that tryAdvance now produce no elements364spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));365366// assert that size, tryAdvance, and forEach are consistent367if (sizeIfKnown >= 0) {368assertEquals(sizeIfKnown, exp.size());369}370assertEquals(fromTryAdvance.size(), exp.size());371372assertContents(fromTryAdvance, exp, isOrdered);373}374375private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(376Collection<T> exp,377Supplier<S> supplier,378UnaryOperator<Consumer<T>> boxingAdapter) {379S spliterator = supplier.get();380long sizeIfKnown = spliterator.getExactSizeIfKnown();381boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);382383// tryAdvance first few elements, then forEach rest384ArrayList<T> dest = new ArrayList<>();385spliterator = supplier.get();386Consumer<T> addToDest = boxingAdapter.apply(dest::add);387for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { }388spliterator.forEachRemaining(addToDest);389390// Assert that forEach now produces no elements391spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));392// Assert that tryAdvance now produce no elements393spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));394395if (sizeIfKnown >= 0) {396assertEquals(sizeIfKnown, dest.size());397}398assertEquals(dest.size(), exp.size());399400if (isOrdered) {401assertEquals(dest, exp);402}403else {404assertContentsUnordered(dest, exp);405}406}407408private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(409Supplier<S> supplier,410UnaryOperator<Consumer<T>> boxingAdapter) {411// Full traversal using tryAdvance412Spliterator<T> spliterator = supplier.get();413while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { }414Spliterator<T> split = spliterator.trySplit();415assertNull(split);416417// Full traversal using forEach418spliterator = supplier.get();419spliterator.forEachRemaining(boxingAdapter.apply(e -> {420}));421split = spliterator.trySplit();422assertNull(split);423424// Full traversal using tryAdvance then forEach425spliterator = supplier.get();426spliterator.tryAdvance(boxingAdapter.apply(e -> { }));427spliterator.forEachRemaining(boxingAdapter.apply(e -> {428}));429split = spliterator.trySplit();430assertNull(split);431}432433private static <T, S extends Spliterator<T>> void testSplitOnce(434Collection<T> exp,435Supplier<S> supplier,436UnaryOperator<Consumer<T>> boxingAdapter) {437S spliterator = supplier.get();438long sizeIfKnown = spliterator.getExactSizeIfKnown();439boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);440441ArrayList<T> fromSplit = new ArrayList<>();442Spliterator<T> s1 = supplier.get();443Spliterator<T> s2 = s1.trySplit();444long s1Size = s1.getExactSizeIfKnown();445long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;446447Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);448if (s2 != null)449s2.forEachRemaining(addToFromSplit);450s1.forEachRemaining(addToFromSplit);451452if (sizeIfKnown >= 0) {453assertEquals(sizeIfKnown, fromSplit.size());454if (s1Size >= 0 && s2Size >= 0)455assertEquals(sizeIfKnown, s1Size + s2Size);456}457assertContents(fromSplit, exp, isOrdered);458}459460private static <T, S extends Spliterator<T>> void testSplitSixDeep(461Collection<T> exp,462Supplier<S> supplier,463UnaryOperator<Consumer<T>> boxingAdapter) {464S spliterator = supplier.get();465boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);466467for (int depth=0; depth < 6; depth++) {468List<T> dest = new ArrayList<>();469spliterator = supplier.get();470471assertSpliterator(spliterator);472473// verify splitting with forEach474visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);475assertContents(dest, exp, isOrdered);476477// verify splitting with tryAdvance478dest.clear();479spliterator = supplier.get();480visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);481assertContents(dest, exp, isOrdered);482}483}484485private static <T, S extends Spliterator<T>> void visit(int depth, int curLevel,486List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter,487int rootCharacteristics, boolean useTryAdvance) {488if (curLevel < depth) {489long beforeSize = spliterator.getExactSizeIfKnown();490Spliterator<T> split = spliterator.trySplit();491if (split != null) {492assertSpliterator(split, rootCharacteristics);493assertSpliterator(spliterator, rootCharacteristics);494495if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&496(rootCharacteristics & Spliterator.SIZED) != 0) {497assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());498}499visit(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);500}501visit(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);502}503else {504long sizeIfKnown = spliterator.getExactSizeIfKnown();505if (useTryAdvance) {506Consumer<T> addToDest = boxingAdapter.apply(dest::add);507int count = 0;508while (spliterator.tryAdvance(addToDest)) {509++count;510}511512if (sizeIfKnown >= 0)513assertEquals(sizeIfKnown, count);514515// Assert that forEach now produces no elements516spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));517518Spliterator<T> split = spliterator.trySplit();519assertNull(split);520}521else {522List<T> leafDest = new ArrayList<>();523Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);524spliterator.forEachRemaining(addToLeafDest);525526if (sizeIfKnown >= 0)527assertEquals(sizeIfKnown, leafDest.size());528529// Assert that forEach now produces no elements530spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));531532Spliterator<T> split = spliterator.trySplit();533assertNull(split);534535dest.addAll(leafDest);536}537}538}539540private static <T, S extends Spliterator<T>> void testSplitUntilNull(541Collection<T> exp,542Supplier<S> supplier,543UnaryOperator<Consumer<T>> boxingAdapter) {544Spliterator<T> s = supplier.get();545boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED);546assertSpliterator(s);547548List<T> splits = new ArrayList<>();549Consumer<T> c = boxingAdapter.apply(splits::add);550551testSplitUntilNull(new SplitNode<T>(c, s));552assertContents(splits, exp, isOrdered);553}554555private static class SplitNode<T> {556// Constant for every node557final Consumer<T> c;558final int rootCharacteristics;559560final Spliterator<T> s;561562SplitNode(Consumer<T> c, Spliterator<T> s) {563this(c, s.characteristics(), s);564}565566private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {567this.c = c;568this.rootCharacteristics = rootCharacteristics;569this.s = s;570}571572SplitNode<T> fromSplit(Spliterator<T> split) {573return new SplitNode<>(c, rootCharacteristics, split);574}575}576577/**578* Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator579* while not unduly disrupting test infrastructure given the test data sizes that are used are small.580* Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26).581*/582private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB583584private static <T> void testSplitUntilNull(SplitNode<T> e) {585// Use an explicit stack to avoid a StackOverflowException when testing a Spliterator586// that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or587// for a spliterator that is badly behaved.588Deque<SplitNode<T>> stack = new ArrayDeque<>();589stack.push(e);590591int iteration = 0;592while (!stack.isEmpty()) {593assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");594595e = stack.pop();596Spliterator<T> parentAndRightSplit = e.s;597598long parentEstimateSize = parentAndRightSplit.estimateSize();599assertTrue(parentEstimateSize >= 0,600String.format("Split size estimate %d < 0", parentEstimateSize));601602long parentSize = parentAndRightSplit.getExactSizeIfKnown();603Spliterator<T> leftSplit = parentAndRightSplit.trySplit();604if (leftSplit == null) {605parentAndRightSplit.forEachRemaining(e.c);606continue;607}608609assertSpliterator(leftSplit, e.rootCharacteristics);610assertSpliterator(parentAndRightSplit, e.rootCharacteristics);611612if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0 && parentAndRightSplit.estimateSize() > 0) {613assertTrue(leftSplit.estimateSize() < parentEstimateSize,614String.format("Left split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize));615assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize,616String.format("Right split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize));617}618else {619assertTrue(leftSplit.estimateSize() <= parentEstimateSize,620String.format("Left split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize));621assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize,622String.format("Right split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize));623}624625long leftSize = leftSplit.getExactSizeIfKnown();626long rightSize = parentAndRightSplit.getExactSizeIfKnown();627if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)628assertEquals(parentSize, leftSize + rightSize,629String.format("exact left split size %d + exact right split size %d != parent exact split size %d",630leftSize, rightSize, parentSize));631632// Add right side to stack first so left side is popped off first633stack.push(e.fromSplit(parentAndRightSplit));634stack.push(e.fromSplit(leftSplit));635}636}637638private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {639if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {640assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),641"Child split is not SUBSIZED when root split is SUBSIZED");642}643assertSpliterator(s);644}645646private static void assertSpliterator(Spliterator<?> s) {647if (s.hasCharacteristics(Spliterator.SUBSIZED)) {648assertTrue(s.hasCharacteristics(Spliterator.SIZED));649}650if (s.hasCharacteristics(Spliterator.SIZED)) {651assertTrue(s.estimateSize() != Long.MAX_VALUE);652assertTrue(s.getExactSizeIfKnown() >= 0);653}654try {655s.getComparator();656assertTrue(s.hasCharacteristics(Spliterator.SORTED));657} catch (IllegalStateException e) {658assertFalse(s.hasCharacteristics(Spliterator.SORTED));659}660}661662private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {663if (isOrdered) {664assertEquals(actual, expected);665}666else {667assertContentsUnordered(actual, expected);668}669}670671private static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {672assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));673}674675private static <T> Map<T, HashableInteger> toBoxedMultiset(Iterable<T> c) {676Map<T, HashableInteger> result = new HashMap<>();677c.forEach(e -> {678if (result.containsKey(e)) {679result.put(e, new HashableInteger(result.get(e).value + 1, 10));680} else {681result.put(e, new HashableInteger(1, 10));682}683});684return result;685}686687private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {688Exception caught = null;689try {690r.run();691}692catch (Exception e) {693caught = e;694}695696assertNotNull(caught,697String.format("No Exception was thrown, expected an Exception of %s to be thrown",698expected.getName()));699assertTrue(expected.isInstance(caught),700String.format("Exception thrown %s not an instance of %s",701caught.getClass().getName(), expected.getName()));702}703704}705706707