/* * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * @test * @bug 8005698 * @library ../stream/bootlib * @build java.base/java.util.SpliteratorTestHelper * @run testng SpliteratorCollisions * @summary Spliterator traversing and splitting hash maps containing colliding hashes */ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Spliterator; import java.util.SpliteratorTestHelper; import java.util.TreeSet; import java.util.function.Function; import java.util.function.Supplier; import java.util.function.UnaryOperator; public class SpliteratorCollisions extends SpliteratorTestHelper { private static final List SIZES = Arrays.asList(0, 1, 10, 100, 1000); private static class SpliteratorDataBuilder { List data; List exp; Map mExp; SpliteratorDataBuilder(List data, List exp) { this.data = data; this.exp = exp; this.mExp = createMap(exp); } Map createMap(List l) { Map m = new LinkedHashMap<>(); for (T t : l) { m.put(t, t); } return m; } void add(String description, Collection expected, Supplier> s) { description = joiner(description).toString(); data.add(new Object[]{description, expected, s}); } void add(String description, Supplier> s) { add(description, exp, s); } void addCollection(Function, ? extends Collection> c) { add("new " + c.apply(Collections.emptyList()).getClass().getName() + ".spliterator()", () -> c.apply(exp).spliterator()); } void addList(Function, ? extends List> l) { // @@@ If collection is instance of List then add sub-list tests addCollection(l); } void addMap(Function, ? extends Map> m) { String description = "new " + m.apply(Collections.emptyMap()).getClass().getName(); add(description + ".keySet().spliterator()", () -> m.apply(mExp).keySet().spliterator()); add(description + ".values().spliterator()", () -> m.apply(mExp).values().spliterator()); add(description + ".entrySet().spliterator()", mExp.entrySet(), () -> m.apply(mExp).entrySet().spliterator()); } StringBuilder joiner(String description) { return new StringBuilder(description). append(" {"). append("size=").append(exp.size()). append("}"); } } static Object[][] spliteratorDataProvider; @DataProvider(name = "HashableIntSpliterator") public static Object[][] spliteratorDataProvider() { if (spliteratorDataProvider != null) { return spliteratorDataProvider; } List data = new ArrayList<>(); for (int size : SIZES) { List exp = listIntRange(size, false); SpliteratorDataBuilder db = new SpliteratorDataBuilder<>(data, exp); // Maps db.addMap(HashMap::new); db.addMap(LinkedHashMap::new); // Collections that use HashMap db.addCollection(HashSet::new); db.addCollection(LinkedHashSet::new); db.addCollection(TreeSet::new); } return spliteratorDataProvider = data.toArray(new Object[0][]); } static Object[][] spliteratorDataProviderWithNull; @DataProvider(name = "HashableIntSpliteratorWithNull") public static Object[][] spliteratorNullDataProvider() { if (spliteratorDataProviderWithNull != null) { return spliteratorDataProviderWithNull; } List data = new ArrayList<>(); for (int size : SIZES) { List exp = listIntRange(size, true); SpliteratorDataBuilder db = new SpliteratorDataBuilder<>(data, exp); // Maps db.addMap(HashMap::new); db.addMap(LinkedHashMap::new); // TODO: add this back in if we decide to keep TreeBin in WeakHashMap //db.addMap(WeakHashMap::new); // Collections that use HashMap db.addCollection(HashSet::new); db.addCollection(LinkedHashSet::new); // db.addCollection(TreeSet::new); } return spliteratorDataProviderWithNull = data.toArray(new Object[0][]); } static final class HashableInteger implements Comparable { final int value; final int hashmask; //yes duplication HashableInteger(int value, int hashmask) { this.value = value; this.hashmask = hashmask; } @Override public boolean equals(Object obj) { if (obj instanceof HashableInteger) { HashableInteger other = (HashableInteger) obj; return other.value == value; } return false; } @Override public int hashCode() { return value % hashmask; } @Override public int compareTo(HashableInteger o) { return value - o.value; } @Override public String toString() { return Integer.toString(value); } } private static List listIntRange(int upTo, boolean withNull) { List exp = new ArrayList<>(); if (withNull) { exp.add(null); } for (int i = 0; i < upTo; i++) { exp.add(new HashableInteger(i, 10)); } return Collections.unmodifiableList(exp); } @Test(dataProvider = "HashableIntSpliterator") void testNullPointerException(String description, Collection exp, Supplier> s) { executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining(null)); executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance(null)); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testNullPointerExceptionWithNull(String description, Collection exp, Supplier> s) { executeAndCatch(NullPointerException.class, () -> s.get().forEachRemaining(null)); executeAndCatch(NullPointerException.class, () -> s.get().tryAdvance(null)); } @Test(dataProvider = "HashableIntSpliterator") void testForEach(String description, Collection exp, Supplier> s) { testForEach(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testForEachWithNull(String description, Collection exp, Supplier> s) { testForEach(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliterator") void testTryAdvance(String description, Collection exp, Supplier> s) { testTryAdvance(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testTryAdvanceWithNull(String description, Collection exp, Supplier> s) { testTryAdvance(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliterator") void testMixedTryAdvanceForEach(String description, Collection exp, Supplier> s) { testMixedTryAdvanceForEach(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testMixedTryAdvanceForEachWithNull(String description, Collection exp, Supplier> s) { testMixedTryAdvanceForEach(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliterator") void testMixedTraverseAndSplit(String description, Collection exp, Supplier> s) { testMixedTraverseAndSplit(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testMixedTraverseAndSplitWithNull(String description, Collection exp, Supplier> s) { testMixedTraverseAndSplit(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliterator") void testSplitAfterFullTraversal(String description, Collection exp, Supplier> s) { testSplitAfterFullTraversal(s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testSplitAfterFullTraversalWithNull(String description, Collection exp, Supplier> s) { testSplitAfterFullTraversal(s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliterator") void testSplitOnce(String description, Collection exp, Supplier> s) { testSplitOnce(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testSplitOnceWithNull(String description, Collection exp, Supplier> s) { testSplitOnce(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliterator") void testSplitSixDeep(String description, Collection exp, Supplier> s) { testSplitSixDeep(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testSplitSixDeepWithNull(String description, Collection exp, Supplier> s) { testSplitSixDeep(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliterator") void testSplitUntilNull(String description, Collection exp, Supplier> s) { testSplitUntilNull(exp, s, UnaryOperator.identity()); } @Test(dataProvider = "HashableIntSpliteratorWithNull") void testSplitUntilNullWithNull(String description, Collection exp, Supplier> s) { testSplitUntilNull(exp, s, UnaryOperator.identity()); } }