test/java/util/Map/Defaults.java

Print this page
rev 6858 : 8004518: Add in-place operations to Map
8010122: Add defaults for ConcurrentMap operations to Map
Reviewed-by: darcy, briangoetz, mduigou, dholmes, ulfzibis
Contributed-by: Doug Lea <dl at cs.oswego.edu>, Henry Jen <henry.jen@oracle.com>, Akhil Arora <akhil.arora@oracle.com>, Peter Levart <peter.levart@gmail.com>


   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 8008785
  27  * @summary Ensure toArray() implementations return correct results.
  28  * @author Mike Duigou

  29  */
  30 import java.util.*;
















  31 import java.util.concurrent.ConcurrentHashMap;
  32 import java.util.concurrent.ConcurrentSkipListMap;

  33 
  34 public class ToArray {















































































































































































































  35 

















































































































  36     /**
  37      * Number of elements per map.
  38      */
  39     private static final int TEST_SIZE = 5000;
  40 
  41     private static void realMain(String[] args) throws Throwable {
  42         Map<Integer, Long>[] maps = (Map<Integer, Long>[]) new Map[]{
  43                     new HashMap<>(),
  44                     new Hashtable<>(),
  45                     new IdentityHashMap<>(),
  46                     new LinkedHashMap<>(),
  47                     new TreeMap<>(),
  48                     new WeakHashMap<>(),
  49                     new ConcurrentHashMap<>(),
  50                     new ConcurrentSkipListMap<>()
  51                 };
  52 
  53         // for each map type.
  54         for (Map<Integer, Long> map : maps) {
  55              try {
  56                 testMap(map);
  57              } catch(Exception all) {
  58                 unexpected("Failed for " + map.getClass().getName(), all);
  59              }
  60         }
  61     }


  62 
  63     private static final Integer[] KEYS = new Integer[TEST_SIZE];



  64 
  65     private static final Long[] VALUES = new Long[TEST_SIZE];



  66 
  67     static {
  68         for (int each = 0; each < TEST_SIZE; each++) {
  69             KEYS[each]   = Integer.valueOf(each);
  70             VALUES[each] = Long.valueOf(each + TEST_SIZE);
  71         }




  72     }
  73 


  74 
  75     private static void testMap(Map<Integer, Long> map) {
  76         System.out.println("Testing " + map.getClass());
  77         System.out.flush();
  78 
  79         // Fill the map
  80         for (int each = 0; each < TEST_SIZE; each++) {
  81             map.put(KEYS[each], VALUES[each]);
  82         }
  83 
  84         // check the keys
  85         Object[] keys = map.keySet().toArray();
  86         Arrays.sort(keys);


  87 
  88         for(int each = 0; each < TEST_SIZE; each++) {
  89             check( "unexpected key", keys[each] == KEYS[each]);
  90         }
  91 
  92         // check the values
  93         Object[] values = map.values().toArray();
  94         Arrays.sort(values);
  95 
  96         for(int each = 0; each < TEST_SIZE; each++) {
  97             check( "unexpected value", values[each] == VALUES[each]);





  98         }
  99 
 100         // check the entries
 101         Map.Entry<Integer,Long>[] entries = map.entrySet().toArray(new Map.Entry[TEST_SIZE]);
 102         Arrays.sort( entries,new Comparator<Map.Entry<Integer,Long>>() {
 103                 public int compare(Map.Entry<Integer,Long> o1, Map.Entry<Integer,Long> o2) {
 104                         return o1.getKey().compareTo(o2.getKey());
 105                 }});
 106 
 107         for(int each = 0; each < TEST_SIZE; each++) {
 108             check( "unexpected entry", entries[each].getKey() == KEYS[each] && entries[each].getValue() == VALUES[each]);
 109         }










 110     }
 111 
 112     //--------------------- Infrastructure ---------------------------
 113     static volatile int passed = 0, failed = 0;










 114 
 115     static void pass() {
 116         passed++;


 117     }
 118 
 119     static void fail() {
 120         failed++;
 121         (new Error("Failure")).printStackTrace(System.err);






 122     }
 123 
 124     static void fail(String msg) {
 125         failed++;
 126         (new Error("Failure: " + msg)).printStackTrace(System.err);
 127     }
 128 
 129     static void abort() {
 130         fail();
 131         System.exit(1);
 132     }
 133 
 134     static void abort(String msg) {
 135         fail(msg);
 136         System.exit(1);
 137     }
 138 
 139     static void unexpected(String msg, Throwable t) {
 140         System.err.println("Unexpected: " + msg);
 141         unexpected(t);




 142     }
 143 
 144     static void unexpected(Throwable t) {
 145         failed++;
 146         t.printStackTrace(System.err);

 147     }
 148 
 149     static void check(boolean cond) {
 150         if (cond) {
 151             pass();
 152         } else {
 153             fail();
 154         }



 155     }
 156 
 157     static void check(String desc, boolean cond) {
 158         if (cond) {
 159             pass();
 160         } else {
 161             fail(desc);















 162         }








 163     }
 164 
 165     static void equal(Object x, Object y) {
 166         if (Objects.equals(x, y)) {
 167             pass();
 168         } else {
 169             fail(x + " not equal to " + y);
 170         }

 171     }
 172 
 173     public static void main(String[] args) throws Throwable {
 174         Thread.currentThread().setName(ToArray.class.getName());
 175 //        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
 176         try {
 177             realMain(args);
 178         } catch (Throwable t) {
 179             unexpected(t);
 180         }
 181 
 182         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
 183         if (failed > 0) {
 184             throw new Error("Some tests failed");
 185         }





















 186     }
 187 }


   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 8010122 8004518
  27  * @summary Test Map default methods
  28  * @author Mike Duigou
  29  * @run testng Defaults
  30  */
  31 import java.util.AbstractMap;
  32 import java.util.AbstractSet;
  33 import java.util.ArrayList;
  34 import java.util.Arrays;
  35 import java.util.Collection;
  36 import java.util.Collections;
  37 import java.util.EnumMap;
  38 import java.util.HashMap;
  39 import java.util.Hashtable;
  40 import java.util.IdentityHashMap;
  41 import java.util.Iterator;
  42 import java.util.LinkedHashMap;
  43 import java.util.Map;
  44 import java.util.TreeMap;
  45 import java.util.Set;
  46 import java.util.WeakHashMap;
  47 import java.util.concurrent.ConcurrentMap;
  48 import java.util.concurrent.ConcurrentHashMap;
  49 import java.util.concurrent.ConcurrentSkipListMap;
  50 import java.util.function.Supplier;
  51 
  52 import org.testng.annotations.Test;
  53 import org.testng.annotations.DataProvider;
  54 import static org.testng.Assert.fail;
  55 import static org.testng.Assert.assertEquals;
  56 import static org.testng.Assert.assertTrue;
  57 import static org.testng.Assert.assertFalse;
  58 import static org.testng.Assert.assertNull;
  59 import static org.testng.Assert.assertSame;
  60 
  61 public class Defaults {
  62 
  63     @Test(dataProvider = "Nulls Map<IntegerEnum,String>")
  64     public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) {
  65         assertTrue(map.containsKey(null), "null key absent");
  66         assertNull(map.get(null), "value not null");
  67         assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), "values should match");
  68     }
  69 
  70     @Test(dataProvider = "Map<IntegerEnum,String>")
  71     public void testGetOrDefault(String description, Map<IntegerEnum, String> map) {
  72         assertTrue(map.containsKey(KEYS[1]), "expected key missing");
  73         assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match");
  74         assertFalse(map.containsKey(EXTRA_KEY), "expected absent key");
  75         assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default");
  76         assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default");
  77     }
  78 
  79     @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
  80     public void testPutIfAbsentNulls(String description, Map<IntegerEnum, String> map) {
  81         assertTrue(map.containsKey(null), "null key absent");
  82         assertNull(map.get(null), "value not null");
  83         assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
  84         assertTrue(map.containsKey(null), "null key absent");
  85         assertSame(map.get(null), EXTRA_VALUE, "unexpected value");
  86         assertSame(map.putIfAbsent(null, null), EXTRA_VALUE, "previous not expected value");
  87         assertTrue(map.containsKey(null), "null key absent");
  88         assertSame(map.get(null), EXTRA_VALUE, "unexpected value");
  89         assertSame(map.remove(null), EXTRA_VALUE, "removed unexpected value");
  90 
  91         assertFalse(map.containsKey(null), description + ": key present after remove");
  92         assertNull(map.putIfAbsent(null, null), "previous not null");
  93         assertTrue(map.containsKey(null), "null key absent");
  94         assertNull(map.get(null), "value not null");
  95         assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
  96         assertSame(map.get(null), EXTRA_VALUE, "value not expected");
  97     }
  98 
  99     @Test(dataProvider = "R/W Map<IntegerEnum,String>")
 100     public void testPutIfAbsent(String description, Map<IntegerEnum, String> map) {
 101         assertTrue(map.containsKey(KEYS[1]));
 102         Object expected = map.get(KEYS[1]);
 103         assertTrue(null == expected || expected == VALUES[1]);
 104         assertSame(map.putIfAbsent(KEYS[1], EXTRA_VALUE), expected);
 105         assertSame(map.get(KEYS[1]), expected);
 106 
 107         assertFalse(map.containsKey(EXTRA_KEY));
 108         assertSame(map.putIfAbsent(EXTRA_KEY, EXTRA_VALUE), null);
 109         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 110     }
 111 
 112     @Test(dataProvider = "Nulls Map<IntegerEnum,String>")
 113     public void testForEach(String description, Map<IntegerEnum, String> map) {
 114         IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()];
 115 
 116         map.forEach((k, v) -> {
 117             int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
 118             assertNull(EACH_KEY[idx]);
 119             EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
 120             assertSame(v, map.get(k));
 121         });
 122 
 123         assertEquals(KEYS, EACH_KEY);
 124     }
 125 
 126     @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
 127     public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) {
 128         assertTrue(map.containsKey(null), "null key absent");
 129         assertNull(map.get(null), "value not null");
 130         assertFalse(map.remove(null, EXTRA_VALUE), description);
 131         assertTrue(map.containsKey(null));
 132         assertNull(map.get(null));
 133         assertTrue(map.remove(null, null));
 134         assertFalse(map.containsKey(null));
 135         assertNull(map.get(null));
 136         assertFalse(map.remove(null, null));
 137     }
 138 
 139     @Test(dataProvider = "R/W Map<IntegerEnum,String>")
 140     public static void testRemove(String description, Map<IntegerEnum, String> map) {
 141         assertTrue(map.containsKey(KEYS[1]));
 142         Object expected = map.get(KEYS[1]);
 143         assertTrue(null == expected || expected == VALUES[1]);
 144         assertFalse(map.remove(KEYS[1], EXTRA_VALUE), description);
 145         assertSame(map.get(KEYS[1]), expected);
 146         assertTrue(map.remove(KEYS[1], expected));
 147         assertNull(map.get(KEYS[1]));
 148         assertFalse(map.remove(KEYS[1], expected));
 149 
 150         assertFalse(map.containsKey(EXTRA_KEY));
 151         assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE));
 152     }
 153 
 154     @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
 155     public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) {
 156         assertTrue(map.containsKey(null), "null key absent");
 157         assertNull(map.get(null), "value not null");
 158         assertSame(map.replace(null, EXTRA_VALUE), null);
 159         assertSame(map.get(null), EXTRA_VALUE);
 160     }
 161 
 162     @Test(dataProvider = "R/W Map<IntegerEnum,String>")
 163     public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
 164         assertTrue(map.containsKey(KEYS[1]));
 165         Object expected = map.get(KEYS[1]);
 166         assertTrue(null == expected || expected == VALUES[1]);
 167         assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected);
 168         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 169 
 170         assertFalse(map.containsKey(EXTRA_KEY));
 171         assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE));
 172         assertFalse(map.containsKey(EXTRA_KEY));
 173         assertNull(map.get(EXTRA_KEY));
 174         assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
 175         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 176         assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE);
 177         assertSame(map.get(EXTRA_KEY), expected);
 178     }
 179 
 180     @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
 181     public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) {
 182         assertTrue(map.containsKey(null), "null key absent");
 183         assertNull(map.get(null), "value not null");
 184         assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
 185         assertNull(map.get(null));
 186         assertTrue(map.replace(null, null, EXTRA_VALUE));
 187         assertSame(map.get(null), EXTRA_VALUE);
 188         assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
 189         assertSame(map.get(null), EXTRA_VALUE);
 190     }
 191 
 192     @Test(dataProvider = "R/W Map<IntegerEnum,String>")
 193     public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
 194         assertTrue(map.containsKey(KEYS[1]));
 195         Object expected = map.get(KEYS[1]);
 196         assertTrue(null == expected || expected == VALUES[1]);
 197         assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
 198         assertSame(map.get(KEYS[1]), expected);
 199         assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE));
 200         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 201         assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
 202         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 203 
 204         assertFalse(map.containsKey(EXTRA_KEY));
 205         assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
 206         assertFalse(map.containsKey(EXTRA_KEY));
 207         assertNull(map.get(EXTRA_KEY));
 208         assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
 209         assertTrue(map.containsKey(EXTRA_KEY));
 210         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 211         assertTrue(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
 212         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 213     }
 214 
 215     @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
 216     public void testComputeIfAbsentNulls(String description, Map<IntegerEnum, String> map) {
 217         assertTrue(map.containsKey(null), "null key absent");
 218         assertNull(map.get(null), "value not null");
 219         assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, description);
 220         assertSame(map.get(null), EXTRA_VALUE, description);
 221     }
 222 
 223     @Test(dataProvider = "R/W Map<IntegerEnum,String>")
 224     public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
 225         assertTrue(map.containsKey(KEYS[1]));
 226         Object expected = map.get(KEYS[1]);
 227         assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
 228         expected = (null == expected) ? EXTRA_VALUE : expected;
 229         assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
 230         assertSame(map.get(KEYS[1]), expected, description);
 231 
 232         assertFalse(map.containsKey(EXTRA_KEY));
 233         assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
 234         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 235     }
 236 
 237     @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
 238     public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
 239         assertTrue(map.containsKey(null));
 240         assertNull(map.get(null));
 241         assertSame(map.computeIfPresent(null, (k, v) -> {
 242             fail();
 243             return EXTRA_VALUE;
 244         }), null, description);
 245         assertTrue(map.containsKey(null));
 246         assertSame(map.get(null), null, description);
 247     }
 248 
 249     @Test(dataProvider = "R/W Map<IntegerEnum,String>")
 250     public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) {
 251         assertTrue(map.containsKey(KEYS[1]));
 252         Object value = map.get(KEYS[1]);
 253         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
 254         Object expected = (null == value) ? null : EXTRA_VALUE;
 255         assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
 256             assertSame(v, value);
 257             return EXTRA_VALUE;
 258         }), expected, description);
 259         assertSame(map.get(KEYS[1]), expected, description);
 260 
 261         assertFalse(map.containsKey(EXTRA_KEY));
 262         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 263             fail();
 264             return EXTRA_VALUE;
 265         }), null);
 266         assertFalse(map.containsKey(EXTRA_KEY));
 267         assertSame(map.get(EXTRA_KEY), null);
 268     }
 269 
 270     @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
 271     public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
 272         assertTrue(map.containsKey(null), "null key absent");
 273         assertNull(map.get(null), "value not null");
 274         assertSame(map.compute(null, (k, v) -> {
 275             assertSame(k, null);
 276             assertNull(v);
 277             return EXTRA_VALUE;
 278         }), EXTRA_VALUE, description);
 279         assertTrue(map.containsKey(null));
 280         assertSame(map.get(null), EXTRA_VALUE, description);
 281         assertSame(map.remove(null), EXTRA_VALUE, "removed value not expected");
 282         assertFalse(map.containsKey(null), "null key present");
 283         assertSame(map.compute(null, (k, v) -> {
 284             assertSame(k, null);
 285             assertNull(v);
 286             return null;
 287         }), null, description);
 288     }
 289 
 290     @Test(dataProvider = "R/W Map<IntegerEnum,String>")
 291     public void testCompute(String description, Map<IntegerEnum, String> map) {
 292         assertTrue(map.containsKey(KEYS[1]));
 293         Object value = map.get(KEYS[1]);
 294         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
 295         assertSame(map.compute(KEYS[1], (k, v) -> {
 296             assertSame(k, KEYS[1]);
 297             assertSame(v, value);
 298             return EXTRA_VALUE;
 299         }), EXTRA_VALUE, description);
 300         assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
 301         assertNull(map.compute(KEYS[1], (k, v) -> {
 302             assertSame(v, EXTRA_VALUE);
 303             return null;
 304         }), description);
 305         assertFalse(map.containsKey(KEYS[1]));
 306 
 307         assertFalse(map.containsKey(EXTRA_KEY));
 308         assertSame(map.compute(EXTRA_KEY, (k, v) -> {
 309             assertNull(v);
 310             return EXTRA_VALUE;
 311         }), EXTRA_VALUE);
 312         assertTrue(map.containsKey(EXTRA_KEY));
 313         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 314     }
 315 
 316 
 317     @Test(dataProvider = "R/W Nulls Map<IntegerEnum,String>")
 318     public void testMergeNulls(String description, Map<IntegerEnum, String> map) {
 319         assertTrue(map.containsKey(null), "null key absent");
 320         assertNull(map.get(null), "value not null");
 321         assertSame(map.merge(null, EXTRA_VALUE, (v, vv) -> {
 322             assertNull(v);
 323             assertSame(vv, EXTRA_VALUE);
 324             return vv;
 325         }), EXTRA_VALUE, description);
 326         assertTrue(map.containsKey(null));
 327         assertSame(map.get(null), EXTRA_VALUE, description);
 328     }
 329 
 330     @Test(dataProvider = "R/W Map<IntegerEnum,String>")
 331     public void testMerge(String description, Map<IntegerEnum, String> map) {
 332         assertTrue(map.containsKey(KEYS[1]));
 333         Object value = map.get(KEYS[1]);
 334         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
 335         assertSame(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> {
 336             assertSame(v, value);
 337             assertSame(vv, EXTRA_VALUE);
 338             return vv;
 339         }), EXTRA_VALUE, description);
 340         assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
 341         assertNull(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> {
 342             assertSame(v, EXTRA_VALUE);
 343             assertSame(vv, EXTRA_VALUE);
 344             return null;
 345         }), description);
 346         assertFalse(map.containsKey(KEYS[1]));
 347 
 348         assertFalse(map.containsKey(EXTRA_KEY));
 349         assertSame(map.merge(EXTRA_KEY, EXTRA_VALUE, (v, vv) -> {
 350             assertNull(v);
 351             assertSame(vv, EXTRA_VALUE);
 352             return EXTRA_VALUE;
 353         }), EXTRA_VALUE);
 354         assertTrue(map.containsKey(EXTRA_KEY));
 355         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 356     }
 357 
 358     enum IntegerEnum {
 359 
 360         e0, e1, e2, e3, e4, e5, e6, e7, e8, e9,
 361         e10, e11, e12, e13, e14, e15, e16, e17, e18, e19,
 362         e20, e21, e22, e23, e24, e25, e26, e27, e28, e29,
 363         e30, e31, e32, e33, e34, e35, e36, e37, e38, e39,
 364         e40, e41, e42, e43, e44, e45, e46, e47, e48, e49,
 365         e50, e51, e52, e53, e54, e55, e56, e57, e58, e59,
 366         e60, e61, e62, e63, e64, e65, e66, e67, e68, e69,
 367         e70, e71, e72, e73, e74, e75, e76, e77, e78, e79,
 368         e80, e81, e82, e83, e84, e85, e86, e87, e88, e89,
 369         e90, e91, e92, e93, e94, e95, e96, e97, e98, e99,
 370         EXTRA_KEY;
 371         public static final int SIZE = values().length;
 372     };
 373     private static final int TEST_SIZE = IntegerEnum.SIZE - 1;
 374     /**
 375      * Realized keys ensure that there is always a hard ref to all test objects.
 376      */
 377     private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE];
 378     /**
 379      * Realized values ensure that there is always a hard ref to all test
 380      * objects.
 381      */
 382     private static final String[] VALUES = new String[TEST_SIZE];







 383 
 384     static {
 385         IntegerEnum[] keys = IntegerEnum.values();
 386         for (int each = 0; each < TEST_SIZE; each++) {
 387             KEYS[each] = keys[each];
 388             VALUES[each] = String.valueOf(each);


 389         }
 390     }
 391     private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY;
 392     private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE);
 393 
 394     @DataProvider(name = "Map<IntegerEnum,String>", parallel = true)
 395     public static Iterator<Object[]> allNullsMapProvider() {
 396         return makeAllMaps().iterator();
 397     }
 398 
 399     @DataProvider(name = "Nulls Map<IntegerEnum,String>", parallel = true)
 400     public static Iterator<Object[]> allMapProvider() {
 401         return makeRWMaps(true).iterator();
 402     }
 403 
 404     @DataProvider(name = "R/W Map<IntegerEnum,String>", parallel = true)
 405     public static Iterator<Object[]> rwMapProvider() {
 406         return makeRWMapsNoNulls().iterator();

 407     }
 408 
 409     @DataProvider(name = "R/W Nulls Map<IntegerEnum,String>", parallel = true)
 410     public static Iterator<Object[]> rwNullsMapProvider() {
 411         return makeRWMaps(true).iterator();
 412     }
 413 
 414     private static Collection<Object[]> makeAllMapsNoNulls() {
 415         Collection<Object[]> all = new ArrayList<>();
 416 
 417         all.addAll(makeRWMaps(false));
 418         all.addAll(makeRWNoNullsMaps());
 419         all.addAll(makeROMaps(false));
 420 
 421         return all;


 422     }
 423 
 424     private static Collection<Object[]> makeRWMapsNoNulls() {
 425         Collection<Object[]> all = new ArrayList<>();
 426 
 427         all.addAll(makeRWMaps(false));
 428         all.addAll(makeRWNoNullsMaps());
 429 
 430         return all;

 431     }
 432 
 433     private static Collection<Object[]> makeAllMaps() {
 434         Collection<Object[]> all = new ArrayList<>();

 435 
 436         all.addAll(makeROMaps(false));
 437         all.addAll(makeRWMaps(false));
 438         all.addAll(makeRWNoNullsMaps());
 439         all.addAll(makeRWMaps(true));
 440         all.addAll(makeROMaps(true));
 441 
 442         return all;
 443     }
 444 
 445     private static Collection<Object[]> makeAllRWMaps() {
 446         Collection<Object[]> all = new ArrayList<>();
 447 
 448         all.addAll(makeRWMaps(false));
 449         all.addAll(makeRWNoNullsMaps());
 450         all.addAll(makeRWMaps(true));
 451 
 452         return all;

 453     }
 454 
 455     private static Collection<Object[]> makeRWMaps(boolean nulls) {
 456         return Arrays.asList(
 457             new Object[]{"HashMap", makeMap(HashMap::new, nulls)},
 458             new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nulls)},
 459             new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nulls)},
 460             new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nulls)},
 461             new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nulls), IntegerEnum.class, String.class)},
 462             new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nulls))},
 463             new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nulls)});
 464     }
 465 
 466     private static Collection<Object[]> makeRWNoNullsMaps() {
 467         return Arrays.asList(
 468             // null hostile
 469             new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false)},
 470             new Object[]{"Hashtable", makeMap(Hashtable::new, false)},
 471             new Object[]{"TreeMap", makeMap(TreeMap::new, false)},
 472             new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false)},
 473             new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false)},
 474             new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false), IntegerEnum.class, String.class)},
 475             new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false))},
 476             new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false)});
 477     }
 478 
 479     private static Collection<Object[]> makeROMaps(boolean nulls) {
 480         return Arrays.asList(new Object[][]{
 481             new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls))}
 482         });
 483     }
 484 
 485     private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nulls) {
 486         Map<IntegerEnum, String> result = supplier.get();
 487 
 488         for (int each = 0; each < TEST_SIZE; each++) {
 489             if (nulls) {
 490                 result.put((each == 0) ? null : KEYS[each], null);
 491             } else {
 492                 result.put(KEYS[each], VALUES[each]);
 493             }
 494         }
 495 
 496         return result;


 497     }
 498 
 499     public interface Thrower<T extends Throwable> {
 500 
 501         public void run() throws T;
 502     }
 503 
 504     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) {
 505         assertThrows(thrower, throwable, null);

 506     }
 507 
 508     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
 509         Throwable result;
 510         try {
 511             thrower.run();
 512             result = null;
 513         } catch (Throwable caught) {
 514             result = caught;
 515         }
 516 
 517         assertInstance(result, throwable,
 518             (null != message)
 519             ? message
 520             : "Failed to throw " + throwable.getCanonicalName());
 521     }
 522 
 523     public static <T> void assertInstance(T actual, Class<? extends T> expected) {
 524         assertInstance(expected.isInstance(actual), null);



 525     }
 526 
 527     public static <T> void assertInstance(T actual, Class<? extends T> expected, String message) {
 528         assertTrue(expected.isInstance(actual), message);
 529     }
 530 
 531     /**
 532      * A simple mutable map implementation that provides only default
 533      * implementations of all methods. ie. none of the Map interface default
 534      * methods have overridden implementations.
 535      *
 536      * @param <K> Type of keys
 537      * @param <V> Type of values
 538      */
 539     public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K, V> {
 540 
 541         protected final M map;
 542 
 543         public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); }
 544 
 545         protected ExtendsAbstractMap(M map) { this.map = map; }
 546 
 547         public Set<Map.Entry<K, V>> entrySet() {
 548             return new AbstractSet<Map.Entry<K, V>>() {
 549                 public int size() {
 550                     return map.size();
 551                 }
 552 
 553                 public Iterator<Map.Entry<K,V>> iterator() {
 554                     final Iterator<Map.Entry<K,V>> source = map.entrySet().iterator();
 555                     return new Iterator<Map.Entry<K,V>>() {
 556                        public boolean hasNext() { return source.hasNext(); }
 557                        public Map.Entry<K,V> next() { return source.next(); }
 558                        public void remove() { source.remove(); }
 559                     };
 560                 }
 561 
 562                 public boolean add(Map.Entry<K,V> e) {
 563                     return map.entrySet().add(e);



 564                 }
 565             };
 566         }
 567 
 568         public V put(K key, V value) {
 569             return map.put(key, value);





 570         }




 571     }
 572 
 573     /**
 574      * A simple mutable concurrent map implementation that provides only default
 575      * implementations of all methods. ie. none of the ConcurrentMap interface
 576      * default methods have overridden implementations.
 577      *
 578      * @param <K> Type of keys
 579      * @param <V> Type of values
 580      */
 581     public static class ImplementsConcurrentMap<K, V> extends ExtendsAbstractMap<ConcurrentMap<K,V>, K, V> implements ConcurrentMap<K,V> {
 582         public ImplementsConcurrentMap() { super(new ConcurrentHashMap<K,V>()); }
 583 
 584         // ConcurrentMap reabstracts these methods
 585 
 586         public V replace(K k, V v) { return map.replace(k, v); };
 587 
 588         public boolean replace(K k, V v, V vv) { return map.replace(k, v, vv); };
 589 
 590         public boolean remove(Object k, Object v) { return map.remove(k, v); }
 591 
 592         public V putIfAbsent(K k, V v) { return map.putIfAbsent(k, v); }
 593     }
 594 }