undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,221 @@
/*
* Copyright (c) 2012, 2013, 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 8011200
* @run testng BasicSerialization
* @summary Ensure Maps can be serialized and deserialized.
* @author Mike Duigou
*/
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import org.testng.annotations.Test;
import org.testng.annotations.DataProvider;
import static org.testng.Assert.fail;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertSame;
public class BasicSerialization {
enum IntegerEnum {
e0, e1, e2, e3, e4, e5, e6, e7, e8, e9,
e10, e11, e12, e13, e14, e15, e16, e17, e18, e19,
e20, e21, e22, e23, e24, e25, e26, e27, e28, e29,
e30, e31, e32, e33, e34, e35, e36, e37, e38, e39,
e40, e41, e42, e43, e44, e45, e46, e47, e48, e49,
e50, e51, e52, e53, e54, e55, e56, e57, e58, e59,
e60, e61, e62, e63, e64, e65, e66, e67, e68, e69,
e70, e71, e72, e73, e74, e75, e76, e77, e78, e79,
e80, e81, e82, e83, e84, e85, e86, e87, e88, e89,
e90, e91, e92, e93, e94, e95, e96, e97, e98, e99,
EXTRA_KEY;
public static final int SIZE = values().length;
};
private static final int TEST_SIZE = IntegerEnum.SIZE - 1;
/**
* Realized keys ensure that there is always a hard ref to all test objects.
*/
private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE];
/**
* Realized values ensure that there is always a hard ref to all test
* objects.
*/
private static final String[] VALUES = new String[TEST_SIZE];
static {
IntegerEnum[] keys = IntegerEnum.values();
for (int each = 0; each < TEST_SIZE; each++) {
KEYS[each] = keys[each];
VALUES[each] = keys[each].name();
}
}
private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY;
private static final String EXTRA_VALUE = IntegerEnum.EXTRA_KEY.name();
public static <K, V> Map<K, V> mapClone(Map<K, V> map) {
Method cloneMethod;
try {
cloneMethod = map.getClass().getMethod("clone", new Class[]{});
} catch (NoSuchMethodException | SecurityException all) {
cloneMethod = null;
}
if (null != cloneMethod) {
try {
Map<K, V> result = (Map<K, V>)cloneMethod.invoke(map, new Object[]{});
return result;
} catch (Exception all) {
fail("clone() failed " + map.getClass().getSimpleName(), all);
return null;
}
} else {
Constructor<? extends Map> copyConstructor;
try {
copyConstructor = (Constructor<? extends Map>)map.getClass().getConstructor(new Class[]{Map.class});
Map<K, V> result = (Map<K, V>)copyConstructor.newInstance(new Object[]{map});
return result;
} catch (Exception all) {
return serialClone(map);
}
}
}
@Test(dataProvider = "Map<IntegerEnum,String>")
public void testSerialization(String description, Map<IntegerEnum, String> map) {
Object foo = new Object();
Map<IntegerEnum, String> clone = mapClone(map);
Map<IntegerEnum, String> serialClone = serialClone(map);
assertEquals(map, map, description + ":should equal self");
assertEquals(clone, map, description + ":should equal clone");
assertEquals(map, clone, description + ": should equal orginal map");
assertEquals(serialClone, map, description + ": should equal deserialized clone");
assertEquals(map, serialClone, description + ": should equal original map");
assertEquals(serialClone, clone, description + ": deserialized clone should equal clone");
assertEquals(clone, serialClone, description + ": clone should equal deserialized clone");
assertFalse(map.containsKey(EXTRA_KEY), description + ":unexpected key");
assertFalse(clone.containsKey(EXTRA_KEY), description + ":unexpected key");
assertFalse(serialClone.containsKey(EXTRA_KEY), description + ":unexpected key");
map.put(EXTRA_KEY, EXTRA_VALUE);
clone.put(EXTRA_KEY, EXTRA_VALUE);
serialClone.put(EXTRA_KEY, EXTRA_VALUE);
assertTrue(map.containsKey(EXTRA_KEY), description + ":missing key");
assertTrue(clone.containsKey(EXTRA_KEY), description + ":missing key");
assertTrue(serialClone.containsKey(EXTRA_KEY), description + ":missing key");
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value");
assertSame(clone.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value");
assertSame(serialClone.get(EXTRA_KEY), EXTRA_VALUE, description + ":wrong value");
assertEquals(map, map, description + ":should equal self");
assertEquals(clone, map, description + ":should equal clone");
assertEquals(map, clone, description + ": should equal orginal map");
assertEquals(serialClone, map, description + ": should equal deserialized clone");
assertEquals(map, serialClone, description + ": should equal original map");
assertEquals(serialClone, clone, description + ": deserialized clone should equal clone");
assertEquals(clone, serialClone, description + ": clone should equal deserialized clone");
}
static byte[] serializedForm(Object obj) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new ObjectOutputStream(baos).writeObject(obj);
return baos.toByteArray();
} catch (IOException e) {
fail("Unexpected Exception", e);
return null;
}
}
static Object readObject(byte[] bytes) throws IOException, ClassNotFoundException {
InputStream is = new ByteArrayInputStream(bytes);
return new ObjectInputStream(is).readObject();
}
@SuppressWarnings("unchecked")
static <T> T serialClone(T obj) {
try {
return (T)readObject(serializedForm(obj));
} catch (IOException | ClassNotFoundException e) {
fail("Unexpected Exception", e);
return null;
}
}
@DataProvider(name = "Map<IntegerEnum,String>", parallel = true)
private static Iterator<Object[]> makeMaps() {
return Arrays.asList(
// empty
new Object[]{"HashMap", new HashMap()},
new Object[]{"LinkedHashMap", new LinkedHashMap()},
new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(new HashMap(), IntegerEnum.class, String.class)},
new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(new HashMap())},
// null hostile
new Object[]{"EnumMap", new EnumMap(IntegerEnum.class)},
new Object[]{"Hashtable", new Hashtable()},
new Object[]{"TreeMap", new TreeMap()},
new Object[]{"ConcurrentHashMap", new ConcurrentHashMap()},
new Object[]{"ConcurrentSkipListMap", new ConcurrentSkipListMap()},
new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(new ConcurrentHashMap(), IntegerEnum.class, String.class)},
new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(new EnumMap(IntegerEnum.class))},
// filled
new Object[]{"HashMap", fillMap(new HashMap())},
new Object[]{"LinkedHashMap", fillMap(new LinkedHashMap())},
new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(fillMap(new HashMap()), IntegerEnum.class, String.class)},
new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(fillMap(new HashMap()))},
// null hostile
new Object[]{"EnumMap", fillMap(new EnumMap(IntegerEnum.class))},
new Object[]{"Hashtable", fillMap(new Hashtable())},
new Object[]{"TreeMap", fillMap(new TreeMap())},
new Object[]{"ConcurrentHashMap", fillMap(new ConcurrentHashMap())},
new Object[]{"ConcurrentSkipListMap", fillMap(new ConcurrentSkipListMap())},
new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(fillMap(new ConcurrentHashMap()), IntegerEnum.class, String.class)},
new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(fillMap(new EnumMap(IntegerEnum.class)))}).iterator();
}
private static Map<IntegerEnum, String> fillMap(Map<IntegerEnum, String> result) {
for (int each = 0; each < TEST_SIZE; each++) {
result.put(KEYS[each], VALUES[each]);
}
return result;
}
}

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2012, 2016, 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 7126277
* @run testng/othervm -Dtest.map.collisions.shortrun=true Collisions
* @summary Ensure Maps behave well with lots of hashCode() collisions.
*/
import java.util.BitSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Supplier;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
public class Collisions extends MapWithCollisionsProviders {
@Test(dataProvider = "mapsWithObjects")
void testIntegerIteration(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) {
Map<IntKey, IntKey> map = ms.get();
int mapSize = map.size();
BitSet all = new BitSet(mapSize);
for (Map.Entry<IntKey, IntKey> each : map.entrySet()) {
assertFalse(all.get(each.getKey().getValue()), "Iteration: key already seen");
all.set(each.getKey().getValue());
}
all.flip(0, mapSize);
assertTrue(all.isEmpty(), "Iteration: some keys not visited");
for (IntKey each : map.keySet()) {
assertFalse(all.get(each.getValue()), "Iteration: key already seen");
all.set(each.getValue());
}
all.flip(0, mapSize);
assertTrue(all.isEmpty(), "Iteration: some keys not visited");
int count = 0;
for (IntKey each : map.values()) {
count++;
}
assertEquals(map.size(), count,
String.format("Iteration: value count matches size m%d != c%d", map.size(), count));
}
@Test(dataProvider = "mapsWithStrings")
void testStringIteration(String desc, Supplier<Map<String, String>> ms, String val) {
Map<String, String> map = ms.get();
int mapSize = map.size();
BitSet all = new BitSet(mapSize);
for (Map.Entry<String, String> each : map.entrySet()) {
String key = each.getKey();
boolean longKey = key.length() > 5;
int index = key.hashCode() + (longKey ? mapSize / 2 : 0);
assertFalse(all.get(index), "key already seen");
all.set(index);
}
all.flip(0, mapSize);
assertTrue(all.isEmpty(), "some keys not visited");
for (String each : map.keySet()) {
boolean longKey = each.length() > 5;
int index = each.hashCode() + (longKey ? mapSize / 2 : 0);
assertFalse(all.get(index), "key already seen");
all.set(index);
}
all.flip(0, mapSize);
assertTrue(all.isEmpty(), "some keys not visited");
int count = 0;
for (String each : map.values()) {
count++;
}
assertEquals(map.size(), mapSize,
String.format("value count matches size m%d != k%d", map.size(), mapSize));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
for (int i = 0; i < keys.length; i++) {
Object each = keys[i];
assertNotNull(map.remove(each),
String.format("remove: %s[%d]%s", desc, i, each));
}
assertTrue(map.size() == 0 && map.isEmpty(),
String.format("remove: map empty. size=%d", map.size()));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testKeysIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Iterator<Object> each = map.keySet().iterator();
while (each.hasNext()) {
Object t = each.next();
each.remove();
assertFalse(map.containsKey(t), String.format("not removed: %s", each));
}
assertTrue(map.size() == 0 && map.isEmpty(),
String.format("remove: map empty. size=%d", map.size()));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testValuesIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Iterator<Object> each = map.values().iterator();
while (each.hasNext()) {
Object t = each.next();
each.remove();
assertFalse(map.containsValue(t), String.format("not removed: %s", each));
}
assertTrue(map.size() == 0 && map.isEmpty(),
String.format("remove: map empty. size=%d", map.size()));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testEntriesIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Iterator<Map.Entry<Object, Object>> each = map.entrySet().iterator();
while (each.hasNext()) {
Map.Entry<Object, Object> t = each.next();
Object key = t.getKey();
Object value = t.getValue();
each.remove();
assertTrue((map instanceof IdentityHashMap) || !map.entrySet().contains(t),
String.format("not removed: %s", each));
assertFalse(map.containsKey(key),
String.format("not removed: %s", each));
assertFalse(map.containsValue(value),
String.format("not removed: %s", each));
}
assertTrue(map.size() == 0 && map.isEmpty(),
String.format("remove: map empty. size=%d", map.size()));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2012, 2013, 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 8009736 8010279
* @run testng EntryComparators
*/
import java.util.function.Function;
import java.util.Comparator;
import java.util.AbstractMap;
import java.util.Map;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/**
* Unit tests for Map.Entry.comparing
*/
@Test(groups = "unit")
public class EntryComparators {
private <K, V> void assertPairComparison(K k1, V v1, K k2, V v2,
Comparator<Map.Entry<K, V>> ck,
Comparator<Map.Entry<K, V>> cv) {
final Map.Entry<K, V> p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1);
final Map.Entry<K, V> p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2);
final Map.Entry<K, V> p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1);
final Map.Entry<K, V> p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2);
assertTrue(ck.compare(p11, p11) == 0);
assertTrue(ck.compare(p12, p11) == 0);
assertTrue(ck.compare(p11, p12) == 0);
assertTrue(ck.compare(p12, p22) < 0);
assertTrue(ck.compare(p12, p21) < 0);
assertTrue(ck.compare(p21, p11) > 0);
assertTrue(ck.compare(p21, p12) > 0);
assertTrue(cv.compare(p11, p11) == 0);
assertTrue(cv.compare(p12, p11) > 0);
assertTrue(cv.compare(p11, p12) < 0);
assertTrue(cv.compare(p12, p22) == 0);
assertTrue(cv.compare(p12, p21) > 0);
assertTrue(cv.compare(p21, p11) == 0);
assertTrue(cv.compare(p21, p12) < 0);
Comparator<Map.Entry<K, V>> cmp = ck.thenComparing(cv);
assertTrue(cmp.compare(p11, p11) == 0);
assertTrue(cmp.compare(p12, p11) > 0);
assertTrue(cmp.compare(p11, p12) < 0);
assertTrue(cmp.compare(p12, p22) < 0);
assertTrue(cmp.compare(p12, p21) < 0);
assertTrue(cmp.compare(p21, p11) > 0);
assertTrue(cmp.compare(p21, p12) > 0);
cmp = cv.thenComparing(ck);
assertTrue(cmp.compare(p11, p11) == 0);
assertTrue(cmp.compare(p12, p11) > 0);
assertTrue(cmp.compare(p11, p12) < 0);
assertTrue(cmp.compare(p12, p22) < 0);
assertTrue(cmp.compare(p12, p21) > 0);
assertTrue(cmp.compare(p21, p11) > 0);
assertTrue(cmp.compare(p21, p12) < 0);
}
public void testKVComparables() {
assertPairComparison(1, "ABC", 2, "XYZ",
Map.Entry.<Integer, String>comparingByKey(),
Map.Entry.<Integer, String>comparingByValue());
}
private static class People {
final String firstName;
final String lastName;
final int age;
People(String first, String last, int age) {
firstName = first;
lastName = last;
this.age = age;
}
String getFirstName() { return firstName; }
String getLastName() { return lastName; }
int getAge() { return age; }
}
private final People people[] = {
new People("John", "Doe", 34),
new People("Mary", "Doe", 30),
};
public void testKVComparators() {
// Comparator<People> cmp = Comparator.naturalOrder(); // Should fail to compiler as People is not comparable
// We can use simple comparator, but those have been tested above.
// Thus choose to do compose for some level of interation.
Comparator<People> cmp1 = Comparator.comparing(People::getFirstName);
Comparator<People> cmp2 = Comparator.comparing(People::getLastName);
Comparator<People> cmp = cmp1.thenComparing(cmp2);
assertPairComparison(people[0], people[0], people[1], people[1],
Map.Entry.<People, People>comparingByKey(cmp),
Map.Entry.<People, People>comparingByValue(cmp));
}
public void testNulls() {
try {
Comparator<Map.Entry<String, String>> cmp = Map.Entry.comparingByKey(null);
fail("comparingByKey(null) should throw NPE");
} catch (NullPointerException npe) {}
try {
Comparator<Map.Entry<String, String>> cmp = Map.Entry.comparingByValue(null);
fail("comparingByValue(null) should throw NPE");
} catch (NullPointerException npe) {}
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2012, 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.
*/
/*
* Portions Copyright (c) 2012 IBM Corporation
*/
/*
* @test
* @bug 8000955
* @summary Map.Entry implementations need to comply with Map.Entry.hashCode() defined behaviour.
* @author ngmr
*/
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
public class EntryHashCode {
private static final int TEST_SIZE = 100;
static final Object[][] entryData = {
new Object[TEST_SIZE],
new Object[TEST_SIZE]
};
@SuppressWarnings("unchecked")
static final Map<Object,Object>[] maps = (Map<Object,Object>[])new Map[] {
new HashMap<>(),
new Hashtable<>(),
new IdentityHashMap<>(),
new LinkedHashMap<>(),
new TreeMap<>(),
new WeakHashMap<>(),
new ConcurrentHashMap<>(),
new ConcurrentSkipListMap<>()
};
static {
for (int i = 0; i < entryData[0].length; i++) {
// key objects need to be Comparable for use in TreeMap
entryData[0][i] = new Comparable<Object>() {
public int compareTo(Object o) {
return (hashCode() - o.hashCode());
}
};
entryData[1][i] = new Object();
}
}
private static void addTestData(Map<Object,Object> map) {
for (int i = 0; i < entryData[0].length; i++) {
map.put(entryData[0][i], entryData[1][i]);
}
}
public static void main(String[] args) throws Exception {
Exception failure = null;
for (Map<Object,Object> map: maps) {
addTestData(map);
try {
for (Map.Entry<Object,Object> e: map.entrySet()) {
Object key = e.getKey();
Object value = e.getValue();
int expectedEntryHashCode =
(Objects.hashCode(key) ^ Objects.hashCode(value));
if (e.hashCode() != expectedEntryHashCode) {
throw new Exception("FAILURE: " +
e.getClass().getName() +
".hashCode() does not conform to defined" +
" behaviour of java.util.Map.Entry.hashCode()");
}
}
} catch (Exception e) {
if (failure == null) {
failure = e;
} else {
failure.addSuppressed(e);
}
} finally {
map.clear();
}
}
if (failure != null) {
throw failure;
}
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2016, 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 8139233
* @summary ensure entry set's iterator doesn't have side effects on the entry set
* @run testng EntrySetIterator
*/
import java.util.*;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertEquals;
public class EntrySetIterator {
@Test
public void main() {
Map<String, String> map = Map.of("a", "1", "b", "2", "c", "3");
Set<Map.Entry<String, String>> entrySet = map.entrySet();
Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();
assertTrue(iterator.hasNext());
// copying implicitly iterates an iterator
Set<Map.Entry<String, String>> copy1 = new HashSet<>(entrySet);
Set<Map.Entry<String, String>> copy2 = new HashSet<>(entrySet);
assertEquals(copy2, copy1);
assertTrue(iterator.hasNext());
}
}

View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2015, 2020, 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.
*/
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiFunction;
import org.testng.annotations.Test;
import org.testng.annotations.DataProvider;
/**
* @test
* @bug 8071667
* @summary Ensure that ConcurrentModificationExceptions are thrown as specified from Map methods that accept Functions
* @author bchristi
* @build Defaults
* @run testng FunctionalCMEs
*/
public class FunctionalCMEs {
static final String KEY = "key";
@DataProvider(name = "Maps", parallel = true)
private static Iterator<Object[]> makeMaps() {
return Arrays.asList(
// Test maps that CME
new Object[]{new HashMap<>(), true},
new Object[]{new Hashtable<>(), true},
new Object[]{new LinkedHashMap<>(), true},
new Object[]{new TreeMap<>(), true},
// Test default Map methods - no CME
new Object[]{new Defaults.ExtendsAbstractMap<>(), false}
).iterator();
}
@Test(dataProvider = "Maps")
public void testComputeIfAbsent(Map<String,String> map, boolean expectCME) {
checkCME(() -> {
map.computeIfAbsent(KEY, k -> {
putToForceRehash(map);
return "computedValue";
});
}, expectCME);
}
@Test(dataProvider = "Maps")
public void testCompute(Map<String,String> map, boolean expectCME) {
checkCME(() -> {
map.compute(KEY, mkBiFunc(map));
}, expectCME);
}
@Test(dataProvider = "Maps")
public void testComputeWithKeyMapped(Map<String,String> map, boolean expectCME) {
map.put(KEY, "firstValue");
checkCME(() -> {
map.compute(KEY, mkBiFunc(map));
}, expectCME);
}
@Test(dataProvider = "Maps")
public void testComputeIfPresent(Map<String,String> map, boolean expectCME) {
map.put(KEY, "firstValue");
checkCME(() -> {
map.computeIfPresent(KEY, mkBiFunc(map));
}, expectCME);
}
@Test(dataProvider = "Maps")
public void testMerge(Map<String,String> map, boolean expectCME) {
map.put(KEY, "firstValue");
checkCME(() -> {
map.merge(KEY, "nextValue", mkBiFunc(map));
}, expectCME);
}
@Test(dataProvider = "Maps")
public void testForEach(Map<String,String> map, boolean ignored) {
checkCME(() -> {
map.put(KEY, "firstValue");
putToForceRehash(map);
map.forEach((k,v) -> {
map.remove(KEY);
});
}, true);
}
@Test(dataProvider = "Maps")
public void testReplaceAll(Map<String,String> map, boolean ignored) {
checkCME(() -> {
map.put(KEY, "firstValue");
putToForceRehash(map);
map.replaceAll((k,v) -> {
map.remove(KEY);
return "computedValue";
});
},true);
}
private static void checkCME(Runnable code, boolean expectCME) {
try {
code.run();
} catch (ConcurrentModificationException cme) {
if (expectCME) { return; } else { throw cme; }
}
if (expectCME) {
throw new RuntimeException("Expected CME, but wasn't thrown");
}
}
private static BiFunction<String,String,String> mkBiFunc(Map<String,String> map) {
return (k,v) -> {
putToForceRehash(map);
return "computedValue";
};
}
private static void putToForceRehash(Map<String,String> map) {
for (int i = 0; i < 64; ++i) {
map.put(i + "", "value");
}
}
}

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2005, 2012, 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 6306829
* @summary Verify assertions in get() javadocs
* @author Martin Buchholz
*/
import java.util.HashMap;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
public class Get {
private static void realMain(String[] args) throws Throwable {
testMap(new Hashtable<Character,Boolean>());
testMap(new HashMap<Character,Boolean>());
testMap(new IdentityHashMap<Character,Boolean>());
testMap(new LinkedHashMap<Character,Boolean>());
testMap(new ConcurrentHashMap<Character,Boolean>());
testMap(new WeakHashMap<Character,Boolean>());
testMap(new TreeMap<Character,Boolean>());
testMap(new ConcurrentSkipListMap<Character,Boolean>());
}
private static void put(Map<Character,Boolean> m,
Character key, Boolean value,
Boolean oldValue) {
if (oldValue != null) {
check("containsValue(oldValue)", m.containsValue(oldValue));
check("values.contains(oldValue)", m.values().contains(oldValue));
}
equal(m.put(key, value), oldValue);
equal(m.get(key), value);
check("containsKey", m.containsKey(key));
check("keySet.contains", m.keySet().contains(key));
check("containsValue", m.containsValue(value));
check("values.contains", m.values().contains(value));
check("!isEmpty", ! m.isEmpty());
}
private static void testMap(Map<Character,Boolean> m) {
// We verify following assertions in get(Object) method javadocs
boolean permitsNullKeys = (! (m instanceof ConcurrentMap ||
m instanceof Hashtable ||
m instanceof SortedMap));
boolean permitsNullValues = (! (m instanceof ConcurrentMap ||
m instanceof Hashtable));
boolean usesIdentity = m instanceof IdentityHashMap;
System.err.println(m.getClass());
put(m, 'A', true, null);
put(m, 'A', false, true); // Guaranteed identical by JLS
put(m, 'B', true, null);
put(m, new Character('A'), false, usesIdentity ? null : false);
if (permitsNullKeys) {
try {
put(m, null, true, null);
put(m, null, false, true);
}
catch (Throwable t) { unexpected(m.getClass().getName(), t); }
} else {
try { m.get(null); fail(m.getClass().getName() + " did not reject null key"); }
catch (NullPointerException e) {}
catch (Throwable t) { unexpected(m.getClass().getName(), t); }
try { m.put(null, true); fail(m.getClass().getName() + " did not reject null key"); }
catch (NullPointerException e) {}
catch (Throwable t) { unexpected(m.getClass().getName(), t); }
}
if (permitsNullValues) {
try {
put(m, 'C', null, null);
put(m, 'C', true, null);
put(m, 'C', null, true);
}
catch (Throwable t) { unexpected(m.getClass().getName(), t); }
} else {
try { m.put('A', null); fail(m.getClass().getName() + " did not reject null key"); }
catch (NullPointerException e) {}
catch (Throwable t) { unexpected(m.getClass().getName(), t); }
try { m.put('C', null); fail(m.getClass().getName() + " did not reject null key"); }
catch (NullPointerException e) {}
catch (Throwable t) { unexpected(m.getClass().getName(), t); }
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() { passed++; }
static void fail() { failed++; new Error("Failure").printStackTrace(System.err); }
static void fail(String msg) { failed++; new Error("Failure: " + msg).printStackTrace(System.err); }
static void unexpected(String msg, Throwable t) { System.err.println("Unexpected: " + msg); unexpected(t); }
static void unexpected(Throwable t) { failed++; t.printStackTrace(System.err); }
static void check(boolean cond) { if (cond) pass(); else fail(); }
static void check(String desc, boolean cond) { if (cond) pass(); else fail(desc); }
static void equal(Object x, Object y) {
if (Objects.equals(x,y)) pass(); else fail(x + " not equal to " + y);
}
public static void main(String[] args) throws Throwable {
try { realMain(args); } catch (Throwable t) { unexpected(t); }
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new Error("Some tests failed");
}
}

View file

@ -0,0 +1,544 @@
/*
* Copyright (c) 2013, 2021, 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
* @run testng/othervm -Dtest.map.collisions.shortrun=true InPlaceOpsCollisions
* @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions.
*/
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
public class InPlaceOpsCollisions extends MapWithCollisionsProviders {
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testPutIfAbsent(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
Object retVal;
removeOddKeys(map, keys);
for (int i = 0; i < keys.length; i++) {
retVal = map.putIfAbsent(keys[i], val);
if (i % 2 == 0) { // even: not absent, not put
assertEquals(retVal, keys[i],
String.format("putIfAbsent: (%s[%d]) retVal", desc, i));
assertEquals(keys[i], map.get(keys[i]),
String.format("putIfAbsent: get(%s[%d])", desc, i));
assertTrue(map.containsValue(keys[i]),
String.format("putIfAbsent: containsValue(%s[%d])", desc, i));
} else { // odd: absent, was put
assertNull(retVal,
String.format("putIfAbsent: (%s[%d]) retVal", desc, i));
assertEquals(val, map.get(keys[i]),
String.format("putIfAbsent: get(%s[%d])", desc, i));
assertFalse(map.containsValue(keys[i]),
String.format("putIfAbsent: !containsValue(%s[%d])", desc, i));
}
assertTrue(map.containsKey(keys[i]),
String.format("insertion: containsKey(%s[%d])", desc, i));
}
assertEquals(map.size(), keys.length,
String.format("map expected size m%d != k%d", map.size(), keys.length));
}
@Test(dataProvider = "nullValueFriendlyMaps")
void testPutIfAbsentOverwriteNull(String desc, Supplier<Map<Object, Object>> ms) {
Map<Object, Object> map = ms.get();
map.put("key", null);
assertEquals(map.size(), 1, desc + ": size != 1");
assertTrue(map.containsKey("key"), desc + ": does not have key");
assertNull(map.get("key"), desc + ": value is not null");
map.putIfAbsent("key", "value"); // must rewrite
assertEquals(map.size(), 1, desc + ": size != 1");
assertTrue(map.containsKey("key"), desc + ": does not have key");
assertEquals(map.get("key"), "value", desc + ": value is not 'value'");
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testRemoveMapping(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
boolean removed;
int removes = 0;
remapOddKeys(map, keys, val);
for (int i = 0; i < keys.length; i++) {
removed = map.remove(keys[i], keys[i]);
if (i % 2 == 0) { // even: original mapping, should be removed
assertTrue(removed,
String.format("removeMapping: retVal(%s[%d])", desc, i));
assertNull(map.get(keys[i]),
String.format("removeMapping: get(%s[%d])", desc, i));
assertFalse(map.containsKey(keys[i]),
String.format("removeMapping: !containsKey(%s[%d])", desc, i));
assertFalse(map.containsValue(keys[i]),
String.format("removeMapping: !containsValue(%s[%d])", desc, i));
removes++;
} else { // odd: new mapping, not removed
assertFalse(removed,
String.format("removeMapping: retVal(%s[%d])", desc, i));
assertEquals(val, map.get(keys[i]),
String.format("removeMapping: get(%s[%d])", desc, i));
assertTrue(map.containsKey(keys[i]),
String.format("removeMapping: containsKey(%s[%d])", desc, i));
assertTrue(map.containsValue(val),
String.format("removeMapping: containsValue(%s[%d])", desc, i));
}
}
assertEquals(map.size(), keys.length - removes,
String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testReplaceOldValue(String desc, Supplier<Map<Object, Object>> ms, Object val) {
// remap odds to val
// call replace to replace for val, for all keys
// check that all keys map to value from keys array
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
boolean replaced;
remapOddKeys(map, keys, val);
for (int i = 0; i < keys.length; i++) {
replaced = map.replace(keys[i], val, keys[i]);
if (i % 2 == 0) { // even: original mapping, should not be replaced
assertFalse(replaced,
String.format("replaceOldValue: retVal(%s[%d])", desc, i));
} else { // odd: new mapping, should be replaced
assertTrue(replaced,
String.format("replaceOldValue: get(%s[%d])", desc, i));
}
assertEquals(keys[i], map.get(keys[i]),
String.format("replaceOldValue: get(%s[%d])", desc, i));
assertTrue(map.containsKey(keys[i]),
String.format("replaceOldValue: containsKey(%s[%d])", desc, i));
assertTrue(map.containsValue(keys[i]),
String.format("replaceOldValue: containsValue(%s[%d])", desc, i));
}
assertFalse(map.containsValue(val),
String.format("replaceOldValue: !containsValue(%s[%s])", desc, val));
assertEquals(map.size(), keys.length,
String.format("map expected size m%d != k%d", map.size(), keys.length));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testReplaceIfMapped(String desc, Supplier<Map<Object, Object>> ms, Object val) {
// remove odd keys
// call replace for all keys[]
// odd keys should remain absent, even keys should be mapped to EXTRA, no value from keys[] should be in map
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
int expectedSize1 = 0;
removeOddKeys(map, keys);
int expectedSize2 = map.size();
for (int i = 0; i < keys.length; i++) {
Object retVal = map.replace(keys[i], val);
if (i % 2 == 0) { // even: still in map, should be replaced
assertEquals(retVal, keys[i],
String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
assertEquals(val, map.get(keys[i]),
String.format("replaceIfMapped: get(%s[%d])", desc, i));
assertTrue(map.containsKey(keys[i]),
String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
expectedSize1++;
} else { // odd: was removed, should not be replaced
assertNull(retVal,
String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
assertNull(map.get(keys[i]),
String.format("replaceIfMapped: get(%s[%d])", desc, i));
assertFalse(map.containsKey(keys[i]),
String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
}
assertFalse(map.containsValue(keys[i]),
String.format("replaceIfMapped: !containsValue(%s[%d])", desc, i));
}
assertTrue(map.containsValue(val),
String.format("replaceIfMapped: containsValue(%s[%s])", desc, val));
assertEquals(map.size(), expectedSize1,
String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1));
assertEquals(map.size(), expectedSize2,
String.format("map expected size#2 m%d != k%d", map.size(), expectedSize2));
}
private static <T> void testComputeIfAbsent(Map<T, T> map, String desc, T[] keys,
Function<T, T> mappingFunction) {
// remove a third of the keys
// call computeIfAbsent for all keys, func returns EXTRA
// check that removed keys now -> EXTRA, other keys -> original val
T expectedVal = mappingFunction.apply(keys[0]);
T retVal;
int expectedSize = 0;
removeThirdKeys(map, keys);
for (int i = 0; i < keys.length; i++) {
retVal = map.computeIfAbsent(keys[i], mappingFunction);
if (i % 3 != 2) { // key present, not computed
assertEquals(retVal, keys[i],
String.format("computeIfAbsent: (%s[%d]) retVal", desc, i));
assertEquals(keys[i], map.get(keys[i]),
String.format("computeIfAbsent: get(%s[%d])", desc, i));
assertTrue(map.containsValue(keys[i]),
String.format("computeIfAbsent: containsValue(%s[%d])", desc, i));
assertTrue(map.containsKey(keys[i]),
String.format("insertion: containsKey(%s[%d])", desc, i));
expectedSize++;
} else { // key absent, computed unless function return null
assertEquals(retVal, expectedVal,
String.format("computeIfAbsent: (%s[%d]) retVal", desc, i));
assertEquals(expectedVal, map.get(keys[i]),
String.format("computeIfAbsent: get(%s[%d])", desc, i));
assertFalse(map.containsValue(keys[i]),
String.format("computeIfAbsent: !containsValue(%s[%d])", desc, i));
// mapping should not be added if function returns null
assertTrue(map.containsKey(keys[i]) != (expectedVal == null),
String.format("insertion: containsKey(%s[%d])", desc, i));
if (expectedVal != null) {
expectedSize++;
}
}
}
if (expectedVal != null) {
assertTrue(map.containsValue(expectedVal),
String.format("computeIfAbsent: containsValue(%s[%s])", desc, expectedVal));
}
assertEquals(map.size(), expectedSize,
String.format("map expected size m%d != k%d", map.size(), expectedSize));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testComputeIfAbsentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
testComputeIfAbsent(map, desc, keys, (k) -> val);
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testComputeIfAbsentNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
testComputeIfAbsent(map, desc, keys, (k) -> null);
}
@Test(dataProvider = "nullValueFriendlyMaps")
void testComputeIfAbsentOverwriteNull(String desc, Supplier<Map<Object, Object>> ms) {
Map<Object, Object> map = ms.get();
map.put("key", null);
assertEquals(map.size(), 1, desc + ": size != 1");
assertTrue(map.containsKey("key"), desc + ": does not have key");
assertNull(map.get("key"), desc + ": value is not null");
Object result = map.computeIfAbsent("key", k -> "value"); // must rewrite
assertEquals(result, "value", desc + ": computeIfAbsent result is not 'value'");
assertEquals(map.size(), 1, desc + ": size != 1");
assertTrue(map.containsKey("key"), desc + ": does not have key");
assertEquals(map.get("key"), "value", desc + ": value is not 'value'");
}
private static <T> void testComputeIfPresent(Map<T, T> map, String desc, T[] keys,
BiFunction<T, T, T> mappingFunction) {
// remove a third of the keys
// call testComputeIfPresent for all keys[]
// removed keys should remain absent, even keys should be mapped to $RESULT
// no value from keys[] should be in map
T funcResult = mappingFunction.apply(keys[0], keys[0]);
int expectedSize1 = 0;
removeThirdKeys(map, keys);
for (int i = 0; i < keys.length; i++) {
T retVal = map.computeIfPresent(keys[i], mappingFunction);
if (i % 3 != 2) { // key present
if (funcResult == null) { // was removed
assertFalse(map.containsKey(keys[i]),
String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
} else { // value was replaced
assertTrue(map.containsKey(keys[i]),
String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
expectedSize1++;
}
assertEquals(retVal, funcResult,
String.format("computeIfPresent: retVal(%s[%s])", desc, i));
assertEquals(funcResult, map.get(keys[i]),
String.format("replaceIfMapped: get(%s[%d])", desc, i));
} else { // odd: was removed, should not be replaced
assertNull(retVal,
String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
assertNull(map.get(keys[i]),
String.format("replaceIfMapped: get(%s[%d])", desc, i));
assertFalse(map.containsKey(keys[i]),
String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
}
assertFalse(map.containsValue(keys[i]),
String.format("replaceIfMapped: !containsValue(%s[%d])", desc, i));
}
assertEquals(map.size(), expectedSize1,
String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testComputeIfPresentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
testComputeIfPresent(map, desc, keys, (k, v) -> val);
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testComputeIfPresentNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
testComputeIfPresent(map, desc, keys, (k, v) -> null);
}
@Test(dataProvider = "hashMapsWithObjects")
void testComputeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) {
// remove a third of the keys
// call compute() for all keys[]
// all keys should be present: removed keys -> EXTRA, others to k-1
Map<IntKey, IntKey> map = ms.get();
IntKey[] keys = map.keySet().stream().sorted().toArray(IntKey[]::new);
BiFunction<IntKey, IntKey, IntKey> mappingFunction = (k, v) -> {
if (v == null) {
return val;
} else {
return keys[k.getValue() - 1];
}
};
removeThirdKeys(map, keys);
for (int i = 1; i < keys.length; i++) {
IntKey retVal = map.compute(keys[i], mappingFunction);
if (i % 3 != 2) { // key present, should be mapped to k-1
assertEquals(retVal, keys[i - 1],
String.format("compute: retVal(%s[%d])", desc, i));
assertEquals(keys[i - 1], map.get(keys[i]),
String.format("compute: get(%s[%d])", desc, i));
} else { // odd: was removed, should be replaced with EXTRA
assertEquals(retVal, val,
String.format("compute: retVal(%s[%d])", desc, i));
assertEquals(val, map.get(keys[i]),
String.format("compute: get(%s[%d])", desc, i));
}
assertTrue(map.containsKey(keys[i]),
String.format("compute: containsKey(%s[%d])", desc, i));
}
assertEquals(map.size(), keys.length,
String.format("map expected size#1 m%d != k%d", map.size(), keys.length));
assertTrue(map.containsValue(val),
String.format("compute: containsValue(%s[%s])", desc, val));
assertFalse(map.containsValue(null),
String.format("compute: !containsValue(%s,[null])", desc));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testComputeNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
// remove a third of the keys
// call compute() for all keys[]
// removed keys should -> EXTRA
// for other keys: func returns null, should have no mapping
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
BiFunction<Object, Object, Object> mappingFunction = (k, v) -> {
// if absent/null -> EXTRA
// if present -> null
if (v == null) {
return val;
} else {
return null;
}
};
int expectedSize = 0;
removeThirdKeys(map, keys);
for (int i = 0; i < keys.length; i++) {
Object retVal = map.compute(keys[i], mappingFunction);
if (i % 3 != 2) { // key present, func returned null, should be absent from map
assertNull(retVal,
String.format("compute: retVal(%s[%d])", desc, i));
assertNull(map.get(keys[i]),
String.format("compute: get(%s[%d])", desc, i));
assertFalse(map.containsKey(keys[i]),
String.format("compute: containsKey(%s[%d])", desc, i));
assertFalse(map.containsValue(keys[i]),
String.format("compute: containsValue(%s[%s])", desc, i));
} else { // odd: was removed, should now be mapped to EXTRA
assertEquals(retVal, val,
String.format("compute: retVal(%s[%d])", desc, i));
assertEquals(val, map.get(keys[i]),
String.format("compute: get(%s[%d])", desc, i));
assertTrue(map.containsKey(keys[i]),
String.format("compute: containsKey(%s[%d])", desc, i));
expectedSize++;
}
}
assertTrue(map.containsValue(val),
String.format("compute: containsValue(%s[%s])", desc, val));
assertEquals(map.size(), expectedSize,
String.format("map expected size#1 m%d != k%d", map.size(), expectedSize));
}
@Test(dataProvider = "hashMapsWithObjects")
void testMergeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) {
// remove a third of the keys
// call merge() for all keys[]
// all keys should be present: removed keys now -> EXTRA, other keys -> k-1
Map<IntKey, IntKey> map = ms.get();
IntKey[] keys = map.keySet().stream().sorted().toArray(IntKey[]::new);
// Map to preceding key
BiFunction<IntKey, IntKey, IntKey> mappingFunction
= (k, v) -> keys[k.getValue() - 1];
removeThirdKeys(map, keys);
for (int i = 1; i < keys.length; i++) {
IntKey retVal = map.merge(keys[i], val, mappingFunction);
if (i % 3 != 2) { // key present, should be mapped to k-1
assertEquals(retVal, keys[i - 1],
String.format("compute: retVal(%s[%d])", desc, i));
assertEquals(keys[i - 1], map.get(keys[i]),
String.format("compute: get(%s[%d])", desc, i));
} else { // odd: was removed, should be replaced with EXTRA
assertEquals(retVal, val,
String.format("compute: retVal(%s[%d])", desc, i));
assertEquals(val, map.get(keys[i]),
String.format("compute: get(%s[%d])", desc, i));
}
assertTrue(map.containsKey(keys[i]),
String.format("compute: containsKey(%s[%d])", desc, i));
}
assertEquals(map.size(), keys.length,
String.format("map expected size#1 m%d != k%d", map.size(), keys.length));
assertTrue(map.containsValue(val),
String.format("compute: containsValue(%s[%s])", desc, val));
assertFalse(map.containsValue(null),
String.format("compute: !containsValue(%s,[null])", desc));
}
@Test(dataProvider = "mapsWithObjectsAndStrings")
void testMergeNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
// remove a third of the keys
// call merge() for all keys[]
// result: removed keys -> EXTRA, other keys absent
Map<Object, Object> map = ms.get();
Object[] keys = map.keySet().toArray();
BiFunction<Object, Object, Object> mappingFunction = (k, v) -> null;
int expectedSize = 0;
removeThirdKeys(map, keys);
for (int i = 0; i < keys.length; i++) {
Object retVal = map.merge(keys[i], val, mappingFunction);
if (i % 3 != 2) { // key present, func returned null, should be absent from map
assertNull(retVal,
String.format("compute: retVal(%s[%d])", desc, i));
assertNull(map.get(keys[i]),
String.format("compute: get(%s[%d])", desc, i));
assertFalse(map.containsKey(keys[i]),
String.format("compute: containsKey(%s[%d])", desc, i));
} else { // odd: was removed, should now be mapped to EXTRA
assertEquals(retVal, val,
String.format("compute: retVal(%s[%d])", desc, i));
assertEquals(val, map.get(keys[i]),
String.format("compute: get(%s[%d])", desc, i));
assertTrue(map.containsKey(keys[i]),
String.format("compute: containsKey(%s[%d])", desc, i));
expectedSize++;
}
assertFalse(map.containsValue(keys[i]),
String.format("compute: containsValue(%s[%s])", desc, i));
}
assertTrue(map.containsValue(val),
String.format("compute: containsValue(%s[%s])", desc, val));
assertEquals(map.size(), expectedSize,
String.format("map expected size#1 m%d != k%d", map.size(), expectedSize));
}
/*
* Remove half of the keys
*/
private static <T> void removeOddKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {
int removes = 0;
for (int i = 0; i < keys.length; i++) {
if (i % 2 != 0) {
map.remove(keys[i]);
removes++;
}
}
assertEquals(map.size(), keys.length - removes,
String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
}
/*
* Remove every third key
* This will hopefully leave some removed keys in TreeBins for, e.g., computeIfAbsent
* w/ a func that returns null.
*
* TODO: consider using this in other tests (and maybe adding a remapThirdKeys)
*/
private static <T> void removeThirdKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {
int removes = 0;
for (int i = 0; i < keys.length; i++) {
if (i % 3 == 2) {
map.remove(keys[i]);
removes++;
}
}
assertEquals(map.size(), keys.length - removes,
String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
}
/*
* Re-map the odd-numbered keys to map to the EXTRA value
*/
private static <T> void remapOddKeys(Map<T, T> map, T[] keys, T val) {
for (int i = 0; i < keys.length; i++) {
if (i % 2 != 0) {
map.put(keys[i], val);
}
}
}
@DataProvider
public Iterator<Object[]> nullValueFriendlyMaps() {
return Arrays.asList(
new Object[]{"HashMap", (Supplier<Map<?, ?>>) HashMap::new},
new Object[]{"LinkedHashMap", (Supplier<Map<?, ?>>) LinkedHashMap::new},
new Object[]{"TreeMap", (Supplier<Map<?, ?>>) TreeMap::new},
new Object[]{"TreeMap(cmp)", (Supplier<Map<?, ?>>) () -> new TreeMap<>(Comparator.reverseOrder())},
new Object[]{"TreeMap.descendingMap", (Supplier<Map<?, ?>>) () -> new TreeMap<>().descendingMap()}
).iterator();
}
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2008, 2013, 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 6612102
* @summary Test Map implementations for mutual compatibility
* @key randomness
*/
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
/**
* Based on the strange scenario required to reproduce
* (coll) IdentityHashMap.iterator().remove() might decrement size twice
*
* It would be good to add more "Lockstep-style" tests to this file.
*/
public class LockStep {
void mapsEqual(Map m1, Map m2) {
equal(m1, m2);
equal(m2, m1);
equal(m1.size(), m2.size());
equal(m1.isEmpty(), m2.isEmpty());
equal(m1.keySet(), m2.keySet());
equal(m2.keySet(), m1.keySet());
}
void mapsEqual(List<Map> maps) {
Map first = maps.get(0);
for (Map map : maps)
mapsEqual(first, map);
}
void put(List<Map> maps, Object key, Object val) {
for (Map map : maps)
map.put(key, val);
mapsEqual(maps);
}
void removeLastTwo(List<Map> maps) {
Map first = maps.get(0);
int size = first.size();
Iterator fit = first.keySet().iterator();
for (int j = 0; j < size - 2; j++)
fit.next();
Object x1 = fit.next();
Object x2 = fit.next();
for (Map map : maps) {
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
Object x = it.next();
if (x == x1 || x == x2)
it.remove();
}
}
mapsEqual(maps);
}
void remove(Map m, Iterator it) {
int size = m.size();
it.remove();
if (m.size() != size-1)
throw new Error(String.format("Incorrect size!%nmap=%s, size=%d%n",
m.toString(), m.size()));
}
void test(String[] args) throws Throwable {
final int iterations = 100;
final Random r = new Random();
for (int i = 0; i < iterations; i++) {
List<Map> maps = List.of(
new IdentityHashMap(11),
new HashMap(16),
new LinkedHashMap(16),
new WeakHashMap(16),
new Hashtable(16),
new TreeMap(),
new ConcurrentHashMap(16),
new ConcurrentSkipListMap(),
Collections.checkedMap(new HashMap(16), Integer.class, Integer.class),
Collections.checkedSortedMap(new TreeMap(), Integer.class, Integer.class),
Collections.checkedNavigableMap(new TreeMap(), Integer.class, Integer.class),
Collections.synchronizedMap(new HashMap(16)),
Collections.synchronizedSortedMap(new TreeMap()),
Collections.synchronizedNavigableMap(new TreeMap()));
for (int j = 0; j < 10; j++)
put(maps, r.nextInt(100), r.nextInt(100));
removeLastTwo(maps);
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new LockStep().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,240 @@
/*
* Copyright (c) 2013, 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.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.testng.Assert.assertEquals;
/*
* @test
* @bug 8023463
* @summary Test the case where a bin is treeified and vice verser
* @run testng MapBinToFromTreeTest
*/
@Test
public class MapBinToFromTreeTest {
// Initial capacity of map
// Should be >= the map capacity for treeifiying, see HashMap/ConcurrentMap.MIN_TREEIFY_CAPACITY
static final int INITIAL_CAPACITY = 64;
// Maximum size of map
// Should be > the treeify threshold, see HashMap/ConcurrentMap.TREEIFY_THRESHOLD
// Should be > INITIAL_CAPACITY to ensure resize occurs
static final int SIZE = 256;
// Load factor of map
// A value 1.0 will ensure that a new threshold == capacity
static final float LOAD_FACTOR = 1.0f;
@DataProvider(name = "maps")
static Object[][] mapProvider() {
return new Object[][] {
// Pass in the class name as a description for test reporting
// purposes
{ HashMap.class.getName(), new HashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
{ LinkedHashMap.class.getName(), new LinkedHashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
{ ConcurrentHashMap.class.getName(), new ConcurrentHashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
};
}
@Test(dataProvider = "maps")
public void testPutThenGet(String d, Map<HashCodeInteger, Integer> m) {
put(SIZE, m, (i, s) -> {
for (int j = 0; j < s; j++) {
assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
String.format("Map.get(%d)", j));
}
});
}
@Test(dataProvider = "maps")
public void testPutThenTraverse(String d, Map<HashCodeInteger, Integer> m) {
Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
put(SIZE, m, (i, s) -> {
// Note that it is OK to collect to a Set (HashSet) as long as
// integer values are used since these tests only check for
// collisions and other tests will verify more general functionality
Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
Collection<Integer> expected = IntStream.range(0, s).boxed().collect(c);
assertEquals(actual, expected, "Map.keySet()");
});
}
@Test(dataProvider = "maps")
public void testRemoveThenGet(String d, Map<HashCodeInteger, Integer> m) {
put(SIZE, m, (i, s) -> { });
remove(m, (i, s) -> {
for (int j = i + 1; j < SIZE; j++) {
assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
String.format("Map.get(%d)", j));
}
});
}
@Test(dataProvider = "maps")
public void testRemoveThenTraverse(String d, Map<HashCodeInteger, Integer> m) {
put(SIZE, m, (i, s) -> { });
Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
remove(m, (i, s) -> {
Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
Collection<Integer> expected = IntStream.range(i + 1, SIZE).boxed().collect(c);
assertEquals(actual, expected, "Map.keySet()");
});
}
@Test(dataProvider = "maps")
public void testUntreeifyOnResizeWithGet(String d, Map<HashCodeInteger, Integer> m) {
// Fill the map with 64 entries grouped into 4 buckets
put(INITIAL_CAPACITY, m, (i, s) -> { });
for (int i = INITIAL_CAPACITY; i < SIZE; i++) {
// Add further entries in the 0'th bucket so as not to disturb
// other buckets, entries of which may be distributed and/or
// the bucket untreeified on resize
m.put(new HashCodeInteger(i, 0), i);
for (int j = 0; j < INITIAL_CAPACITY; j++) {
assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
String.format("Map.get(%d) < INITIAL_CAPACITY", j));
}
for (int j = INITIAL_CAPACITY; j <= i; j++) {
assertEquals(m.get(new HashCodeInteger(j, 0)).intValue(), j,
String.format("Map.get(%d) >= INITIAL_CAPACITY", j));
}
}
}
@Test(dataProvider = "maps")
public void testUntreeifyOnResizeWithTraverse(String d, Map<HashCodeInteger, Integer> m) {
// Fill the map with 64 entries grouped into 4 buckets
put(INITIAL_CAPACITY, m, (i, s) -> { });
Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
for (int i = INITIAL_CAPACITY; i < SIZE; i++) {
// Add further entries in the 0'th bucket so as not to disturb
// other buckets, entries of which may be distributed and/or
// the bucket untreeified on resize
m.put(new HashCodeInteger(i, 0), i);
Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
Collection<Integer> expected = IntStream.rangeClosed(0, i).boxed().collect(c);
assertEquals(actual, expected, "Key set");
}
}
Collector<Integer, ?, ? extends Collection<Integer>> getCollector(Map<?, ?> m) {
Collector<Integer, ?, ? extends Collection<Integer>> collector = m instanceof LinkedHashMap
? Collectors.toList()
: Collectors.toSet();
return collector;
}
void put(int size, Map<HashCodeInteger, Integer> m, BiConsumer<Integer, Integer> c) {
for (int i = 0; i < size; i++) {
m.put(new HashCodeInteger(i), i);
c.accept(i, m.size());
}
}
void remove(Map<HashCodeInteger, Integer> m, BiConsumer<Integer, Integer> c) {
int size = m.size();
// Remove all elements thus ensuring at some point trees will be
// converting back to bins
for (int i = 0; i < size; i++) {
m.remove(new HashCodeInteger(i));
c.accept(i, m.size());
}
}
static final class HashCodeInteger implements Comparable<HashCodeInteger> {
final int value;
final int hashcode;
HashCodeInteger(int value) {
this(value, hash(value));
}
HashCodeInteger(int value, int hashcode) {
this.value = value;
this.hashcode = hashcode;
}
static int hash(int i) {
// Assuming 64 entries with keys from 0 to 63 then a map:
// - of capacity 64 will have 4 buckets with 16 entries per-bucket
// - of capacity 128 will have 8 buckets with 8 entries per-bucket
// - of capacity 256 will have 16 buckets with 4 entries per-bucket
//
// Re-sizing will result in re-distribution, doubling the buckets
// and reducing the entries by half. This will result in
// untreeifying when the number of entries is less than untreeify
// threshold (see HashMap/ConcurrentMap.UNTREEIFY_THRESHOLD)
return (i % 4) + (i / 4) * INITIAL_CAPACITY;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof HashCodeInteger) {
HashCodeInteger other = (HashCodeInteger) obj;
return other.value == value;
}
return false;
}
@Override
public int hashCode() {
return hashcode;
}
@Override
public int compareTo(HashCodeInteger o) {
return value - o.value;
}
@Override
public String toString() {
return Integer.toString(value);
}
}
}

View file

@ -0,0 +1,558 @@
/*
* Copyright (c) 2015, 2021, 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.
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertNotSame;
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertThrows;
import static org.testng.Assert.assertTrue;
/*
* @test
* @bug 8048330 8221924
* @summary Test convenience static factory methods on Map.
* @run testng MapFactories
*/
public class MapFactories {
static final int MAX_ENTRIES = 20; // should be larger than the largest fixed-arg overload
static String valueFor(int i) {
// the String literal below should be of length MAX_ENTRIES
return "abcdefghijklmnopqrst".substring(i, i+1);
}
// for "expected" values
Map<Integer,String> genMap(int n) {
Map<Integer,String> result = new HashMap<>();
for (int i = 0; i < n; i++) {
result.put(i, valueFor(i));
}
return result;
}
// for varargs Map.Entry methods
@SuppressWarnings("unchecked")
Map.Entry<Integer,String>[] genEmptyEntryArray1() {
return (Map.Entry<Integer,String>[])new Map.Entry<?,?>[1];
}
@SuppressWarnings("unchecked")
Map.Entry<Integer,String>[] genEntries(int n) {
return IntStream.range(0, n)
.mapToObj(i -> Map.entry(i, valueFor(i)))
.toArray(Map.Entry[]::new);
}
// returns array of [actual, expected]
static Object[] a(Map<Integer,String> act, Map<Integer,String> exp) {
return new Object[] { act, exp };
}
@DataProvider(name="empty")
public Iterator<Object[]> empty() {
return Collections.singletonList(
a(Map.of(), genMap(0))
).iterator();
}
@DataProvider(name="nonempty")
@SuppressWarnings("unchecked")
public Iterator<Object[]> nonempty() {
return Arrays.asList(
a(Map.of(0, "a"), genMap(1)),
a(Map.of(0, "a", 1, "b"), genMap(2)),
a(Map.of(0, "a", 1, "b", 2, "c"), genMap(3)),
a(Map.of(0, "a", 1, "b", 2, "c", 3, "d"), genMap(4)),
a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e"), genMap(5)),
a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f"), genMap(6)),
a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g"), genMap(7)),
a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h"), genMap(8)),
a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i"), genMap(9)),
a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j"), genMap(10)),
a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j"),
Map.of(4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j", 0, "a", 1, "b", 2, "c", 3, "d")),
a(Map.ofEntries(genEntries(MAX_ENTRIES)), genMap(MAX_ENTRIES))
).iterator();
}
@DataProvider(name="all")
public Iterator<Object[]> all() {
List<Object[]> all = new ArrayList<>();
empty().forEachRemaining(all::add);
nonempty().forEachRemaining(all::add);
return all.iterator();
}
@Test(dataProvider="all", expectedExceptions=UnsupportedOperationException.class)
public void cannotPutNew(Map<Integer,String> act, Map<Integer,String> exp) {
act.put(-1, "xyzzy");
}
@Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class)
public void cannotPutOld(Map<Integer,String> act, Map<Integer,String> exp) {
act.put(0, "a");
}
@Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class)
public void cannotRemove(Map<Integer,String> act, Map<Integer,String> exp) {
act.remove(act.keySet().iterator().next());
}
@Test(dataProvider="all")
public void contentsMatch(Map<Integer,String> act, Map<Integer,String> exp) {
assertEquals(act, exp);
}
@Test(dataProvider="all")
public void containsAllKeys(Map<Integer,String> act, Map<Integer,String> exp) {
assertTrue(act.keySet().containsAll(exp.keySet()));
assertTrue(exp.keySet().containsAll(act.keySet()));
}
@Test(dataProvider="all")
public void containsAllValues(Map<Integer,String> act, Map<Integer,String> exp) {
assertTrue(act.values().containsAll(exp.values()));
assertTrue(exp.values().containsAll(act.values()));
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed2() {
Map<Integer, String> map = Map.of(0, "a", 0, "b");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed3() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 0, "c");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed4() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 0, "d");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed5() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 0, "e");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed6() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
0, "f");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed7() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 0, "g");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed8() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", 0, "h");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed9() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", 7, "h", 0, "i");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowed10() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", 7, "h", 8, "i", 0, "j");
}
@Test(expectedExceptions=IllegalArgumentException.class)
public void dupKeysDisallowedN() {
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
entries[MAX_ENTRIES-1] = Map.entry(0, "xxx");
Map<Integer, String> map = Map.ofEntries(entries);
}
@Test(dataProvider="all")
public void hashCodeEquals(Map<Integer,String> act, Map<Integer,String> exp) {
assertEquals(act.hashCode(), exp.hashCode());
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed1() {
Map<Integer, String> map = Map.of(null, "a");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed1() {
Map<Integer, String> map = Map.of(0, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed2() {
Map<Integer, String> map = Map.of(0, "a", null, "b");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed2() {
Map<Integer, String> map = Map.of(0, "a", 1, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed3() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", null, "c");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed3() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed4() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", null, "d");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed4() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed5() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", null, "e");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed5() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed6() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
null, "f");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed6() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed7() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", null, "g");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed7() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed8() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", null, "h");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed8() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", 7, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed9() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", 7, "h", null, "i");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed9() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", 7, "h", 8, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowed10() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", 7, "h", 8, "i", null, "j");
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowed10() {
Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
5, "f", 6, "g", 7, "h", 8, "i", 9, null);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowedVar1() {
Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
entries[0] = new AbstractMap.SimpleImmutableEntry<>(null, "a");
Map<Integer, String> map = Map.ofEntries(entries);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowedVar1() {
Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
entries[0] = new AbstractMap.SimpleImmutableEntry<>(0, null);
Map<Integer, String> map = Map.ofEntries(entries);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullEntryDisallowedVar1() {
Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
Map<Integer, String> map = Map.ofEntries(entries);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullKeyDisallowedVarN() {
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
entries[0] = new AbstractMap.SimpleImmutableEntry<>(null, "a");
Map<Integer, String> map = Map.ofEntries(entries);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullValueDisallowedVarN() {
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
entries[0] = new AbstractMap.SimpleImmutableEntry<>(0, null);
Map<Integer, String> map = Map.ofEntries(entries);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullEntryDisallowedVarN() {
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
entries[5] = null;
Map<Integer, String> map = Map.ofEntries(entries);
}
@Test(expectedExceptions=NullPointerException.class)
public void nullArrayDisallowed() {
Map.ofEntries((Map.Entry<?,?>[])null);
}
@Test(dataProvider="all", expectedExceptions=NullPointerException.class)
public void containsValueNullShouldThrowNPE(Map<Integer,String> act, Map<Integer,String> exp) {
act.containsValue(null);
}
@Test(dataProvider="all", expectedExceptions=NullPointerException.class)
public void containsKeyNullShouldThrowNPE(Map<Integer,String> act, Map<Integer,String> exp) {
act.containsKey(null);
}
@Test(dataProvider="all", expectedExceptions=NullPointerException.class)
public void getNullShouldThrowNPE(Map<Integer,String> act, Map<Integer,String> exp) {
act.get(null);
}
@Test(dataProvider="all")
public void serialEquality(Map<Integer, String> act, Map<Integer, String> exp) {
// assume that act.equals(exp) tested elsewhere
Map<Integer, String> copy = serialClone(act);
assertEquals(act, copy);
assertEquals(copy, exp);
}
@SuppressWarnings("unchecked")
static <T> T serialClone(T obj) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(obj);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new AssertionError(e);
}
}
Map<Integer, String> genMap() {
Map<Integer, String> map = new HashMap<>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
return map;
}
@Test
public void copyOfResultsEqual() {
Map<Integer, String> orig = genMap();
Map<Integer, String> copy = Map.copyOf(orig);
assertEquals(orig, copy);
assertEquals(copy, orig);
}
@Test
public void copyOfModifiedUnequal() {
Map<Integer, String> orig = genMap();
Map<Integer, String> copy = Map.copyOf(orig);
orig.put(4, "d");
assertNotEquals(orig, copy);
assertNotEquals(copy, orig);
}
@Test
public void copyOfIdentity() {
Map<Integer, String> orig = genMap();
Map<Integer, String> copy1 = Map.copyOf(orig);
Map<Integer, String> copy2 = Map.copyOf(copy1);
assertNotSame(orig, copy1);
assertSame(copy1, copy2);
}
@Test(expectedExceptions=NullPointerException.class)
public void copyOfRejectsNullMap() {
Map<Integer, String> map = Map.copyOf(null);
}
@Test(expectedExceptions=NullPointerException.class)
public void copyOfRejectsNullKey() {
Map<Integer, String> map = genMap();
map.put(null, "x");
Map<Integer, String> copy = Map.copyOf(map);
}
@Test(expectedExceptions=NullPointerException.class)
public void copyOfRejectsNullValue() {
Map<Integer, String> map = genMap();
map.put(-1, null);
Map<Integer, String> copy = Map.copyOf(map);
}
// Map::entry tests
@Test(expectedExceptions=NullPointerException.class)
public void entryWithNullKeyDisallowed() {
Map.Entry<Integer,String> e = Map.entry(null, "x");
}
@Test(expectedExceptions=NullPointerException.class)
public void entryWithNullValueDisallowed() {
Map.Entry<Integer,String> e = Map.entry(0, null);
}
@Test
public void entrySetValueDisallowed() {
var e = Map.entry("a", "b");
assertThrows(UnsupportedOperationException.class, () -> e.setValue("x"));
}
@Test
public void entryBasicTests() {
Map.Entry<String,String> kvh1 = Map.entry("xyzzy", "plugh");
Map.Entry<String,String> kvh2 = Map.entry("foobar", "blurfl");
Map.Entry<String,String> sie = new AbstractMap.SimpleImmutableEntry<>("xyzzy", "plugh");
assertTrue(kvh1.equals(sie));
assertTrue(sie.equals(kvh1));
assertFalse(kvh2.equals(sie));
assertFalse(sie.equals(kvh2));
assertEquals(kvh1.hashCode(), sie.hashCode());
assertEquals(kvh1.toString(), sie.toString());
}
// Map.Entry::copyOf tests
@Test(expectedExceptions=NullPointerException.class)
public void entryCopyNullDisallowed() {
Map.Entry.copyOf(null);
}
@Test
public void entryCopyWithNullKeyDisallowed() {
var e = new AbstractMap.SimpleEntry<>(null, "b");
assertThrows(NullPointerException.class, () -> Map.Entry.copyOf(e));
}
@Test
public void entryCopyWithNullValueDisallowed() {
var e = new AbstractMap.SimpleEntry<>("a", null);
assertThrows(NullPointerException.class, () -> Map.Entry.copyOf(e));
}
@Test
public void entryCopySetValueDisallowed() {
var e = new AbstractMap.SimpleEntry<>("a", "b");
var c = Map.Entry.copyOf(e);
assertThrows(UnsupportedOperationException.class, () -> c.setValue("x"));
}
@Test
public void entryCopyBasicTests() {
Map.Entry<String,String> orig = new AbstractMap.SimpleImmutableEntry<>("xyzzy", "plugh");
Map.Entry<String,String> copy1 = Map.Entry.copyOf(orig);
Map.Entry<String,String> copy2 = Map.Entry.copyOf(copy1);
assertEquals(orig, copy1);
assertEquals(copy1, orig);
assertEquals(orig, copy2);
assertEquals(copy2, orig);
assertEquals(copy1, copy2);
assertEquals(copy2, copy1);
assertNotSame(orig, copy1);
assertSame(copy1, copy2);
assertEquals(copy1.hashCode(), orig.hashCode());
assertEquals(copy1.toString(), orig.toString());
}
// compile-time test of wildcards
@Test
public void entryWildcardTests() {
Map.Entry<Integer,Double> e1 = Map.entry(1, 2.0);
Map.Entry<Float,Long> e2 = Map.entry(3.0f, 4L);
Map<Number,Number> map = Map.ofEntries(e1, e2);
assertEquals(map.size(), 2);
}
}

View file

@ -0,0 +1,288 @@
/*
* Copyright (c) 2016, 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.
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.Supplier;
import org.testng.annotations.DataProvider;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertEquals;
public class MapWithCollisionsProviders {
private static final int TEST_SIZE
= Boolean.valueOf(System.getProperty("test.map.collisions.shortrun"))
? 2500
: 5000;
private static final IntKey EXTRA_INTKEY_VAL
= new IntKey(TEST_SIZE, Integer.MAX_VALUE);
private static final String EXTRA_STRING_VAL = "Extra Value";
public static final class IntKey implements Comparable<IntKey> {
private final int value;
private final int hashmask; //yes duplication
IntKey(int value, int hashmask) {
this.value = value;
this.hashmask = hashmask;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof IntKey) {
IntKey other = (IntKey) obj;
return other.value == value;
}
return false;
}
@Override
public int hashCode() {
return value % hashmask;
}
@Override
public int compareTo(IntKey o) {
return value - o.value;
}
@Override
public String toString() {
return Integer.toString(value);
}
public int getValue() {
return value;
}
}
private static Object[] createUniqueObjectKeys() {
IntKey UNIQUE_OBJECTS[] = new IntKey[TEST_SIZE];
for (int i = 0; i < TEST_SIZE; i++) {
UNIQUE_OBJECTS[i] = new IntKey(i, Integer.MAX_VALUE);
}
return UNIQUE_OBJECTS;
}
private static Object[] createUniqueStringKeys() {
String UNIQUE_STRINGS[] = new String[TEST_SIZE];
for (int i = 0; i < TEST_SIZE; i++) {
UNIQUE_STRINGS[i] = unhash(i);
}
return UNIQUE_STRINGS;
}
private static Object[] createCollidingObjectKeys() {
IntKey COLLIDING_OBJECTS[] = new IntKey[TEST_SIZE];
for (int i = 0; i < TEST_SIZE; i++) {
COLLIDING_OBJECTS[i] = new IntKey(i, 10);
}
return COLLIDING_OBJECTS;
}
private static Object[] createCollidingStringKeys() {
String COLLIDING_STRINGS[] = new String[TEST_SIZE];
String UNIQUE_STRINGS[] = new String[TEST_SIZE];
for (int i = 0; i < TEST_SIZE; i++) {
UNIQUE_STRINGS[i] = unhash(i);
COLLIDING_STRINGS[i] = (0 == i % 2)
? UNIQUE_STRINGS[i / 2]
: "\u0000\u0000\u0000\u0000\u0000" + COLLIDING_STRINGS[i - 1];
}
return COLLIDING_STRINGS;
}
/**
* Returns a string with a hash equal to the argument.
*
* @return string with a hash equal to the argument.
*/
private static String unhash(int target) {
StringBuilder answer = new StringBuilder();
if (target < 0) {
// String with hash of Integer.MIN_VALUE, 0x80000000
answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");
if (target == Integer.MIN_VALUE) {
return answer.toString();
}
// Find target without sign bit set
target = target & Integer.MAX_VALUE;
}
unhash0(answer, target);
return answer.toString();
}
private static void unhash0(StringBuilder partial, int target) {
int div = target / 31;
int rem = target % 31;
if (div <= Character.MAX_VALUE) {
if (div != 0) {
partial.append((char) div);
}
partial.append((char) rem);
} else {
unhash0(partial, div);
partial.append((char) rem);
}
}
private static <T> Map<T, T> fillMap(Map<T, T> m, T[] keys) {
for (T k : keys) {
m.put(k, k);
assertTrue(m.containsKey(k));
assertTrue(m.containsValue(k));
}
assertEquals(m.size(), keys.length);
return m;
}
private static <T> Supplier<Map<T, T>> createMap(Map<T, T> m, T[] keys) {
return () -> fillMap(m, keys);
}
private static <T> Object[] createCase(String desc, Map<T, T> m, T[] keys, T val) {
return new Object[]{desc, createMap(m, keys), val};
}
private static <T> Collection<Object[]> makeMapsMoreTypes(String desc,
T[] keys,
T val) {
Collection<Object[]> cases = new ArrayList<>();
cases.add(createCase("Hashtable with " + desc,
new Hashtable<>(), keys, val));
cases.add(createCase("IdentityHashMap with " + desc,
new IdentityHashMap<>(), keys, val));
cases.add(createCase("TreeMap with " + desc,
new TreeMap<>(), keys, val));
cases.add(createCase("Descending TreeMap with " + desc,
new TreeMap<>().descendingMap(), keys, val));
cases.add(createCase("WeakHashMap with " + desc,
new WeakHashMap<>(), keys, val));
cases.add(createCase("ConcurrentHashMap with " + desc,
new ConcurrentHashMap<>(), keys, val));
cases.add(createCase("ConcurrentSkipListMap with " + desc,
new ConcurrentSkipListMap<>(), keys, val));
return cases;
}
private static <T> Collection<Object[]> makeMapsHashMap(String desc,
T[] keys,
T val) {
Collection<Object[]> cases = new ArrayList<>();
cases.add(createCase("HashMap with " + desc,
new HashMap<>(), keys, val));
cases.add(createCase("LinkedHashMap with " + desc,
new LinkedHashMap<>(), keys, val));
return cases;
}
private static <T> Collection<Object[]> makeMaps(String desc, T[] keys, T val) {
Collection<Object[]> cases = new ArrayList<>();
cases.addAll(makeMapsHashMap(desc, keys, val));
cases.addAll(makeMapsMoreTypes(desc, keys, val));
return cases;
}
private static <T> Collection<Object[]> makeObjectsCases(String desc, T[] keys) {
return makeMaps(desc, keys, EXTRA_INTKEY_VAL);
}
private static <T> Collection<Object[]> makeStringsCases(String desc,
T[] keys) {
return makeMaps(desc, keys, EXTRA_STRING_VAL);
}
private static final Collection<Object[]> mapsWithObjectsCases
= new ArrayList<>() {
{
addAll(makeObjectsCases("unique objects", createUniqueObjectKeys()));
addAll(makeObjectsCases("colliding objects", createCollidingObjectKeys()));
}
};
private static final Collection<Object[]> mapsWithStringsCases
= new ArrayList<>() {
{
addAll(makeStringsCases("unique strings", createUniqueStringKeys()));
addAll(makeStringsCases("colliding strings", createCollidingStringKeys()));
}
};
private static final Collection<Object[]> mapsWithObjectsAndStringsCases
= new ArrayList<>() {
{
addAll(mapsWithObjectsCases);
addAll(mapsWithStringsCases);
}
};
private static final Collection<Object[]> hashMapsWithObjectsCases
= new ArrayList<>() {
{
addAll(makeMapsHashMap("unique objects",
createUniqueObjectKeys(), EXTRA_INTKEY_VAL));
addAll(makeMapsHashMap("collisions objects",
createCollidingObjectKeys(), EXTRA_INTKEY_VAL));
}
};
@DataProvider
public Iterator<Object[]> mapsWithObjects() {
return mapsWithObjectsCases.iterator();
}
@DataProvider
public Iterator<Object[]> mapsWithStrings() {
return mapsWithStringsCases.iterator();
}
@DataProvider
public Iterator<Object[]> mapsWithObjectsAndStrings() {
return mapsWithObjectsAndStringsCases.iterator();
}
@DataProvider
public Iterator<Object[]> hashMapsWithObjects() {
return hashMapsWithObjectsCases.iterator();
}
}

View file

@ -0,0 +1,187 @@
/*
* Copyright (c) 2013, 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 8008785
* @summary Ensure toArray() implementations return correct results.
* @author Mike Duigou
*/
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
public class ToArray {
/**
* Number of elements per map.
*/
private static final int TEST_SIZE = 5000;
private static void realMain(String[] args) throws Throwable {
Map<Integer, Long>[] maps = (Map<Integer, Long>[]) new Map[]{
new HashMap<>(),
new Hashtable<>(),
new IdentityHashMap<>(),
new LinkedHashMap<>(),
new TreeMap<>(),
new WeakHashMap<>(),
new ConcurrentHashMap<>(),
new ConcurrentSkipListMap<>()
};
// for each map type.
for (Map<Integer, Long> map : maps) {
try {
testMap(map);
} catch(Exception all) {
unexpected("Failed for " + map.getClass().getName(), all);
}
}
}
private static final Integer[] KEYS = new Integer[TEST_SIZE];
private static final Long[] VALUES = new Long[TEST_SIZE];
static {
for (int each = 0; each < TEST_SIZE; each++) {
KEYS[each] = Integer.valueOf(each);
VALUES[each] = Long.valueOf(each + TEST_SIZE);
}
}
private static void testMap(Map<Integer, Long> map) {
System.out.println("Testing " + map.getClass());
System.out.flush();
// Fill the map
for (int each = 0; each < TEST_SIZE; each++) {
map.put(KEYS[each], VALUES[each]);
}
// check the keys
Object[] keys = map.keySet().toArray();
Arrays.sort(keys);
for(int each = 0; each < TEST_SIZE; each++) {
check( "unexpected key", keys[each] == KEYS[each]);
}
// check the values
Object[] values = map.values().toArray();
Arrays.sort(values);
for(int each = 0; each < TEST_SIZE; each++) {
check( "unexpected value", values[each] == VALUES[each]);
}
// check the entries
Map.Entry<Integer,Long>[] entries = map.entrySet().toArray(new Map.Entry[TEST_SIZE]);
Arrays.sort( entries,new Comparator<Map.Entry<Integer,Long>>() {
public int compare(Map.Entry<Integer,Long> o1, Map.Entry<Integer,Long> o2) {
return o1.getKey().compareTo(o2.getKey());
}});
for(int each = 0; each < TEST_SIZE; each++) {
check( "unexpected entry", entries[each].getKey() == KEYS[each] && entries[each].getValue() == VALUES[each]);
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {
passed++;
}
static void fail() {
failed++;
(new Error("Failure")).printStackTrace(System.err);
}
static void fail(String msg) {
failed++;
(new Error("Failure: " + msg)).printStackTrace(System.err);
}
static void abort() {
fail();
System.exit(1);
}
static void abort(String msg) {
fail(msg);
System.exit(1);
}
static void unexpected(String msg, Throwable t) {
System.err.println("Unexpected: " + msg);
unexpected(t);
}
static void unexpected(Throwable t) {
failed++;
t.printStackTrace(System.err);
}
static void check(boolean cond) {
if (cond) {
pass();
} else {
fail();
}
}
static void check(String desc, boolean cond) {
if (cond) {
pass();
} else {
fail(desc);
}
}
static void equal(Object x, Object y) {
if (Objects.equals(x, y)) {
pass();
} else {
fail(x + " not equal to " + y);
}
}
public static void main(String[] args) throws Throwable {
Thread.currentThread().setName(ToArray.class.getName());
// Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
try {
realMain(args);
} catch (Throwable t) {
unexpected(t);
}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) {
throw new Error("Some tests failed");
}
}
}