test/java/util/Map/Defaults.java

Print this page
rev 7360 : 8016446: Improve forEach/replaceAll for Map, HashMap, Hashtable, IdentityHashMap, WeakHashMap, TreeMap
Reviewed-by: forax, duigou, psandoz
Contributed-by: Mike Duigou <mike.duigou@oracle.com>, Remi Forax <forax@univ-mlv.fr>

@@ -34,10 +34,11 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;

@@ -45,10 +46,11 @@
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.function.BiFunction;
 import java.util.function.Supplier;
 
 import org.testng.annotations.Test;
 import org.testng.annotations.DataProvider;
 import static org.testng.Assert.fail;

@@ -58,27 +60,27 @@
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertSame;
 
 public class Defaults {
 
-    @Test(dataProvider = "Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull")
     public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) {
-        assertTrue(map.containsKey(null), "null key absent");
-        assertNull(map.get(null), "value not null");
-        assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), "values should match");
+        assertTrue(map.containsKey(null), description + ": null key absent");
+        assertNull(map.get(null), description + ": value not null");
+        assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), description + ": values should match");
     }
 
-    @Test(dataProvider = "Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
     public void testGetOrDefault(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]), "expected key missing");
         assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match");
         assertFalse(map.containsKey(EXTRA_KEY), "expected absent key");
         assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default");
         assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default");
     }
 
-    @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
     public void testPutIfAbsentNulls(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(null), "null key absent");
         assertNull(map.get(null), "value not null");
         assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
         assertTrue(map.containsKey(null), "null key absent");

@@ -94,11 +96,11 @@
         assertNull(map.get(null), "value not null");
         assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
         assertSame(map.get(null), EXTRA_VALUE, "value not expected");
     }
 
-    @Test(dataProvider = "R/W Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testPutIfAbsent(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
         Object expected = map.get(KEYS[1]);
         assertTrue(null == expected || expected == VALUES[1]);
         assertSame(map.putIfAbsent(KEYS[1], EXTRA_VALUE), expected);

@@ -107,25 +109,58 @@
         assertFalse(map.containsKey(EXTRA_KEY));
         assertSame(map.putIfAbsent(EXTRA_KEY, EXTRA_VALUE), null);
         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
     }
 
-    @Test(dataProvider = "Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
     public void testForEach(String description, Map<IntegerEnum, String> map) {
         IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()];
 
         map.forEach((k, v) -> {
             int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
             assertNull(EACH_KEY[idx]);
             EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
             assertSame(v, map.get(k));
         });
 
-        assertEquals(KEYS, EACH_KEY);
+        assertEquals(KEYS, EACH_KEY, description);
+    }
+
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
+    public static void testReplaceAll(String description, Map<IntegerEnum, String> map) {
+        IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()];
+        Set<String> EACH_REPLACE = new HashSet<>(map.size());
+
+        map.replaceAll((k,v) -> {
+            int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
+            assertNull(EACH_KEY[idx]);
+            EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
+            assertSame(v, map.get(k));
+            String replacement = v + " replaced";
+            EACH_REPLACE.add(replacement);
+            return replacement;
+        });
+
+        assertEquals(KEYS, EACH_KEY, description);
+        assertEquals(map.values().size(), EACH_REPLACE.size(), description + EACH_REPLACE);
+        assertTrue(EACH_REPLACE.containsAll(map.values()), description + " : " + EACH_REPLACE + " != " + map.values());
+        assertTrue(map.values().containsAll(EACH_REPLACE), description + " : " + EACH_REPLACE + " != " + map.values());
+    }
+
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
+    public static void testReplaceAllNoNullReplacement(String description, Map<IntegerEnum, String> map) {
+        assertThrows(
+            () -> { map.replaceAll(null); },
+            NullPointerException.class,
+            description);
+        assertThrows(
+            () -> { map.replaceAll((k,v) -> null); },
+            NullPointerException.class,
+            description);
     }
 
-    @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
     public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(null), "null key absent");
         assertNull(map.get(null), "value not null");
         assertFalse(map.remove(null, EXTRA_VALUE), description);
         assertTrue(map.containsKey(null));

@@ -134,11 +169,11 @@
         assertFalse(map.containsKey(null));
         assertNull(map.get(null));
         assertFalse(map.remove(null, null));
     }
 
-    @Test(dataProvider = "R/W Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public static void testRemove(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
         Object expected = map.get(KEYS[1]);
         assertTrue(null == expected || expected == VALUES[1]);
         assertFalse(map.remove(KEYS[1], EXTRA_VALUE), description);

@@ -149,19 +184,19 @@
 
         assertFalse(map.containsKey(EXTRA_KEY));
         assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE));
     }
 
-    @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
     public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(null), "null key absent");
         assertNull(map.get(null), "value not null");
         assertSame(map.replace(null, EXTRA_VALUE), null);
         assertSame(map.get(null), EXTRA_VALUE);
     }
 
-    @Test(dataProvider = "R/W Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
         Object expected = map.get(KEYS[1]);
         assertTrue(null == expected || expected == VALUES[1]);
         assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected);

@@ -175,11 +210,11 @@
         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
         assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE);
         assertSame(map.get(EXTRA_KEY), expected);
     }
 
-    @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
     public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(null), "null key absent");
         assertNull(map.get(null), "value not null");
         assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
         assertNull(map.get(null));

@@ -187,11 +222,11 @@
         assertSame(map.get(null), EXTRA_VALUE);
         assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
         assertSame(map.get(null), EXTRA_VALUE);
     }
 
-    @Test(dataProvider = "R/W Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
         Object expected = map.get(KEYS[1]);
         assertTrue(null == expected || expected == VALUES[1]);
         assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));

@@ -210,19 +245,19 @@
         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
         assertTrue(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
     }
 
-    @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
     public void testComputeIfAbsentNulls(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(null), "null key absent");
         assertNull(map.get(null), "value not null");
         assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, description);
         assertSame(map.get(null), EXTRA_VALUE, description);
     }
 
-    @Test(dataProvider = "R/W Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
         Object expected = map.get(KEYS[1]);
         assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
         expected = (null == expected) ? EXTRA_VALUE : expected;

@@ -232,11 +267,11 @@
         assertFalse(map.containsKey(EXTRA_KEY));
         assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
     }
 
-    @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
     public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(null));
         assertNull(map.get(null));
         assertSame(map.computeIfPresent(null, (k, v) -> {
             fail();

@@ -244,11 +279,11 @@
         }), null, description);
         assertTrue(map.containsKey(null));
         assertSame(map.get(null), null, description);
     }
 
-    @Test(dataProvider = "R/W Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
         Object value = map.get(KEYS[1]);
         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
         Object expected = (null == value) ? null : EXTRA_VALUE;

@@ -265,11 +300,11 @@
         }), null);
         assertFalse(map.containsKey(EXTRA_KEY));
         assertSame(map.get(EXTRA_KEY), null);
     }
 
-    @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
     public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(null), "null key absent");
         assertNull(map.get(null), "value not null");
         assertSame(map.compute(null, (k, v) -> {
             assertSame(k, null);

@@ -285,11 +320,11 @@
             assertNull(v);
             return null;
         }), null, description);
     }
 
-    @Test(dataProvider = "R/W Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testCompute(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
         Object value = map.get(KEYS[1]);
         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
         assertSame(map.compute(KEYS[1], (k, v) -> {

@@ -312,11 +347,11 @@
         assertTrue(map.containsKey(EXTRA_KEY));
         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
     }
 
 
-    @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
     public void testMergeNulls(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(null), "null key absent");
         assertNull(map.get(null), "value not null");
         assertSame(map.merge(null, EXTRA_VALUE, (v, vv) -> {
             assertNull(v);

@@ -325,11 +360,11 @@
         }), EXTRA_VALUE, description);
         assertTrue(map.containsKey(null));
         assertSame(map.get(null), EXTRA_VALUE, description);
     }
 
-    @Test(dataProvider = "R/W Map<IntegerEnum,String>")
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testMerge(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
         Object value = map.get(KEYS[1]);
         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
         assertSame(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> {

@@ -389,110 +424,163 @@
         }
     }
     private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY;
     private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE);
 
-    @DataProvider(name = "Map<IntegerEnum,String>", parallel = true)
-    public static Iterator<Object[]> allNullsMapProvider() {
+    @DataProvider(name = "Map<IntegerEnum,String> rw=all keys=all values=all", parallel = true)
+    public static Iterator<Object[]> allMapProvider() {
         return makeAllMaps().iterator();
     }
 
-    @DataProvider(name = "Nulls Map<IntegerEnum,String>", parallel = true)
-    public static Iterator<Object[]> allMapProvider() {
-        return makeRWMaps(true).iterator();
+    @DataProvider(name = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull", parallel = true)
+    public static Iterator<Object[]> allMapWithNullsProvider() {
+        return makeAllMapsWithNulls().iterator();
     }
 
-    @DataProvider(name = "R/W Map<IntegerEnum,String>", parallel = true)
-    public static Iterator<Object[]> rwMapProvider() {
+    @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull", parallel = true)
+    public static Iterator<Object[]> rwNonNullMapProvider() {
+        return makeRWNoNullsMaps().iterator();
+    }
+
+    @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=all", parallel = true)
+    public static Iterator<Object[]> rwNonNullKeysMapProvider() {
         return makeRWMapsNoNulls().iterator();
     }
 
-    @DataProvider(name = "R/W Nulls Map<IntegerEnum,String>", parallel = true)
+    @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=all values=all", parallel = true)
+    public static Iterator<Object[]> rwMapProvider() {
+        return makeAllRWMaps().iterator();
+    }
+
+    @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull", parallel = true)
     public static Iterator<Object[]> rwNullsMapProvider() {
-        return makeRWMaps(true).iterator();
+        return makeAllRWMapsWithNulls().iterator();
     }
 
-    private static Collection<Object[]> makeAllMapsNoNulls() {
+    private static Collection<Object[]> makeAllRWMapsWithNulls() {
         Collection<Object[]> all = new ArrayList<>();
 
-        all.addAll(makeRWMaps(false));
-        all.addAll(makeRWNoNullsMaps());
-        all.addAll(makeROMaps(false));
+        all.addAll(makeRWMaps(true, true));
 
         return all;
     }
 
+
     private static Collection<Object[]> makeRWMapsNoNulls() {
         Collection<Object[]> all = new ArrayList<>();
 
-        all.addAll(makeRWMaps(false));
+        all.addAll(makeRWNoNullKeysMaps(false));
         all.addAll(makeRWNoNullsMaps());
 
         return all;
     }
 
-    private static Collection<Object[]> makeAllMaps() {
+    private static Collection<Object[]> makeAllROMaps() {
         Collection<Object[]> all = new ArrayList<>();
 
         all.addAll(makeROMaps(false));
-        all.addAll(makeRWMaps(false));
-        all.addAll(makeRWNoNullsMaps());
-        all.addAll(makeRWMaps(true));
         all.addAll(makeROMaps(true));
 
         return all;
     }
 
     private static Collection<Object[]> makeAllRWMaps() {
         Collection<Object[]> all = new ArrayList<>();
 
-        all.addAll(makeRWMaps(false));
         all.addAll(makeRWNoNullsMaps());
-        all.addAll(makeRWMaps(true));
+        all.addAll(makeRWMaps(false,true));
+        all.addAll(makeRWMaps(true,true));
+        all.addAll(makeRWNoNullKeysMaps(true));
+        return all;
+    }
+
+    private static Collection<Object[]> makeAllMaps() {
+        Collection<Object[]> all = new ArrayList<>();
+
+        all.addAll(makeAllROMaps());
+        all.addAll(makeAllRWMaps());
 
         return all;
     }
 
-    private static Collection<Object[]> makeRWMaps(boolean nulls) {
+    private static Collection<Object[]> makeAllMapsWithNulls() {
+        Collection<Object[]> all = new ArrayList<>();
+
+        all.addAll(makeROMaps(true));
+        all.addAll(makeRWMaps(true,true));
+
+        return all;
+    }
+    /**
+     *
+     * @param nullKeys include null keys
+     * @param nullValues include null values
+     * @return
+     */
+    private static Collection<Object[]> makeRWMaps(boolean nullKeys, boolean nullValues) {
+        return Arrays.asList(
+            new Object[]{"HashMap", makeMap(HashMap::new, nullKeys, nullValues)},
+            new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nullKeys, nullValues)},
+            new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nullKeys, nullValues)},
+            new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nullKeys, nullValues)},
+            new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nullKeys, nullValues), IntegerEnum.class, String.class)},
+            new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nullKeys, nullValues))},
+            new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nullKeys, nullValues)});
+    }
+
+    /**
+     *
+     * @param nulls include null values
+     * @return
+     */
+    private static Collection<Object[]> makeRWNoNullKeysMaps(boolean nulls) {
         return Arrays.asList(
-            new Object[]{"HashMap", makeMap(HashMap::new, nulls)},
-            new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nulls)},
-            new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nulls)},
-            new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nulls)},
-            new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nulls), IntegerEnum.class, String.class)},
-            new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nulls))},
-            new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nulls)});
+                // null key hostile
+                new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls)},
+                new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls))}
+                );
     }
 
     private static Collection<Object[]> makeRWNoNullsMaps() {
         return Arrays.asList(
-            // null hostile
-            new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false)},
-            new Object[]{"Hashtable", makeMap(Hashtable::new, false)},
-            new Object[]{"TreeMap", makeMap(TreeMap::new, false)},
-            new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false)},
-            new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false)},
-            new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false), IntegerEnum.class, String.class)},
-            new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false))},
-            new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false)});
+            // null key and value hostile
+            new Object[]{"Hashtable", makeMap(Hashtable::new, false, false)},
+            new Object[]{"TreeMap", makeMap(TreeMap::new, false, false)},
+            new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false, false)},
+            new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false, false)},
+            new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false, false), IntegerEnum.class, String.class)},
+            new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false, false)}
+            );
     }
 
+    /**
+     *
+     * @param nulls include nulls
+     * @return
+     */
     private static Collection<Object[]> makeROMaps(boolean nulls) {
         return Arrays.asList(new Object[][]{
-            new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls))}
+            new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls, nulls))}
         });
     }
 
-    private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nulls) {
+     /**
+     *
+     * @param supplier a supplier of mutable map instances.
+     *
+     * @param nullKeys   include null keys
+     * @param nullValues include null values
+     * @return
+     */
+    private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nullKeys, boolean nullValues) {
         Map<IntegerEnum, String> result = supplier.get();
 
         for (int each = 0; each < TEST_SIZE; each++) {
-            if (nulls) {
-                result.put((each == 0) ? null : KEYS[each], null);
-            } else {
-                result.put(KEYS[each], VALUES[each]);
-            }
+            IntegerEnum key = nullKeys ? (each == 0) ? null : KEYS[each] : KEYS[each];
+            String value = nullValues ? (each == 0) ? null : VALUES[each] : VALUES[each];
+
+            result.put(key, value);
         }
 
         return result;
     }
 

@@ -518,10 +606,16 @@
             (null != message)
             ? message
             : "Failed to throw " + throwable.getCanonicalName());
     }
 
+    public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) {
+        for(Thrower<T> thrower : throwers) {
+            assertThrows(thrower, throwable, message);
+        }
+    }
+
     public static <T> void assertInstance(T actual, Class<? extends T> expected) {
         assertInstance(expected.isInstance(actual), null);
     }
 
     public static <T> void assertInstance(T actual, Class<? extends T> expected, String message) {