1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 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.HashSet; 40 import java.util.Hashtable; 41 import java.util.IdentityHashMap; 42 import java.util.Iterator; 43 import java.util.LinkedHashMap; 44 import java.util.Map; 45 import java.util.TreeMap; 46 import java.util.Set; 47 import java.util.WeakHashMap; 48 import java.util.concurrent.ConcurrentMap; 49 import java.util.concurrent.ConcurrentHashMap; 50 import java.util.concurrent.ConcurrentSkipListMap; 51 import java.util.function.BiFunction; 52 import java.util.function.Supplier; 53 54 import org.testng.annotations.Test; 55 import org.testng.annotations.DataProvider; 56 import static org.testng.Assert.fail; 57 import static org.testng.Assert.assertEquals; 58 import static org.testng.Assert.assertTrue; 59 import static org.testng.Assert.assertFalse; 60 import static org.testng.Assert.assertNull; 61 import static org.testng.Assert.assertSame; 62 63 public class Defaults { 64 65 @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull") 66 public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) { 67 assertTrue(map.containsKey(null), description + ": null key absent"); 68 assertNull(map.get(null), description + ": value not null"); 69 assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), description + ": values should match"); 70 } 71 72 @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all") 73 public void testGetOrDefault(String description, Map<IntegerEnum, String> map) { 74 assertTrue(map.containsKey(KEYS[1]), "expected key missing"); 75 assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match"); 76 assertFalse(map.containsKey(EXTRA_KEY), "expected absent key"); 77 assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default"); 78 assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default"); 79 } 80 81 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 82 public void testPutIfAbsentNulls(String description, Map<IntegerEnum, String> map) { 83 assertTrue(map.containsKey(null), "null key absent"); 84 assertNull(map.get(null), "value not null"); 85 assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null"); 86 assertTrue(map.containsKey(null), "null key absent"); 87 assertSame(map.get(null), EXTRA_VALUE, "unexpected value"); 88 assertSame(map.putIfAbsent(null, null), EXTRA_VALUE, "previous not expected value"); 89 assertTrue(map.containsKey(null), "null key absent"); 90 assertSame(map.get(null), EXTRA_VALUE, "unexpected value"); 91 assertSame(map.remove(null), EXTRA_VALUE, "removed unexpected value"); 92 93 assertFalse(map.containsKey(null), description + ": key present after remove"); 94 assertNull(map.putIfAbsent(null, null), "previous not null"); 95 assertTrue(map.containsKey(null), "null key absent"); 96 assertNull(map.get(null), "value not null"); 97 assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null"); 98 assertSame(map.get(null), EXTRA_VALUE, "value not expected"); 99 } 100 101 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 102 public void testPutIfAbsent(String description, Map<IntegerEnum, String> map) { 103 assertTrue(map.containsKey(KEYS[1])); 104 Object expected = map.get(KEYS[1]); 105 assertTrue(null == expected || expected == VALUES[1]); 106 assertSame(map.putIfAbsent(KEYS[1], EXTRA_VALUE), expected); 107 assertSame(map.get(KEYS[1]), expected); 108 109 assertFalse(map.containsKey(EXTRA_KEY)); 110 assertSame(map.putIfAbsent(EXTRA_KEY, EXTRA_VALUE), null); 111 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 112 } 113 114 @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all") 115 public void testForEach(String description, Map<IntegerEnum, String> map) { 116 IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()]; 117 118 map.forEach((k, v) -> { 119 int idx = (null == k) ? 0 : k.ordinal(); // substitute for index. 120 assertNull(EACH_KEY[idx]); 121 EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison. 122 assertSame(v, map.get(k)); 123 }); 124 125 assertEquals(KEYS, EACH_KEY, description); 126 } 127 128 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 129 public static void testReplaceAll(String description, Map<IntegerEnum, String> map) { 130 IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()]; 131 Set<String> EACH_REPLACE = new HashSet<>(map.size()); 132 133 map.replaceAll((k,v) -> { 134 int idx = (null == k) ? 0 : k.ordinal(); // substitute for index. 135 assertNull(EACH_KEY[idx]); 136 EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison. 137 assertSame(v, map.get(k)); 138 String replacement = v + " replaced"; 139 EACH_REPLACE.add(replacement); 140 return replacement; 141 }); 142 143 assertEquals(KEYS, EACH_KEY, description); 144 assertEquals(map.values().size(), EACH_REPLACE.size(), description + EACH_REPLACE); 145 assertTrue(EACH_REPLACE.containsAll(map.values()), description + " : " + EACH_REPLACE + " != " + map.values()); 146 assertTrue(map.values().containsAll(EACH_REPLACE), description + " : " + EACH_REPLACE + " != " + map.values()); 147 } 148 149 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull") 150 public static void testReplaceAllNoNullReplacement(String description, Map<IntegerEnum, String> map) { 151 assertThrows( 152 () -> { map.replaceAll(null); }, 153 NullPointerException.class, 154 description); 155 assertThrows( 156 () -> { map.replaceAll((k,v) -> null); }, 157 NullPointerException.class, 158 description + " should not allow replacement with null value"); 159 } 160 161 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 162 public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) { 163 assertTrue(map.containsKey(null), "null key absent"); 164 assertNull(map.get(null), "value not null"); 165 assertFalse(map.remove(null, EXTRA_VALUE), description); 166 assertTrue(map.containsKey(null)); 167 assertNull(map.get(null)); 168 assertTrue(map.remove(null, null)); 169 assertFalse(map.containsKey(null)); 170 assertNull(map.get(null)); 171 assertFalse(map.remove(null, null)); 172 } 173 174 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 175 public static void testRemove(String description, Map<IntegerEnum, String> map) { 176 assertTrue(map.containsKey(KEYS[1])); 177 Object expected = map.get(KEYS[1]); 178 assertTrue(null == expected || expected == VALUES[1]); 179 assertFalse(map.remove(KEYS[1], EXTRA_VALUE), description); 180 assertSame(map.get(KEYS[1]), expected); 181 assertTrue(map.remove(KEYS[1], expected)); 182 assertNull(map.get(KEYS[1])); 183 assertFalse(map.remove(KEYS[1], expected)); 184 185 assertFalse(map.containsKey(EXTRA_KEY)); 186 assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE)); 187 } 188 189 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 190 public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) { 191 assertTrue(map.containsKey(null), "null key absent"); 192 assertNull(map.get(null), "value not null"); 193 assertSame(map.replace(null, EXTRA_VALUE), null); 194 assertSame(map.get(null), EXTRA_VALUE); 195 } 196 197 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull") 198 public void testReplaceKVNoNulls(String description, Map<IntegerEnum, String> map) { 199 assertTrue(map.containsKey(FIRST_KEY), "expected key missing"); 200 assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value"); 201 assertThrows( () -> {map.replace(FIRST_KEY, null);}, NullPointerException.class, description + ": should throw NPE"); 202 assertSame(map.replace(FIRST_KEY, EXTRA_VALUE), FIRST_VALUE, description + ": replaced wrong value"); 203 assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value"); 204 } 205 206 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 207 public void testReplaceKV(String description, Map<IntegerEnum, String> map) { 208 assertTrue(map.containsKey(KEYS[1])); 209 Object expected = map.get(KEYS[1]); 210 assertTrue(null == expected || expected == VALUES[1]); 211 assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected); 212 assertSame(map.get(KEYS[1]), EXTRA_VALUE); 213 214 assertFalse(map.containsKey(EXTRA_KEY)); 215 assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE)); 216 assertFalse(map.containsKey(EXTRA_KEY)); 217 assertNull(map.get(EXTRA_KEY)); 218 assertNull(map.put(EXTRA_KEY, EXTRA_VALUE)); 219 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 220 assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE); 221 assertSame(map.get(EXTRA_KEY), expected); 222 } 223 224 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 225 public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) { 226 assertTrue(map.containsKey(null), "null key absent"); 227 assertNull(map.get(null), "value not null"); 228 assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE)); 229 assertNull(map.get(null)); 230 assertTrue(map.replace(null, null, EXTRA_VALUE)); 231 assertSame(map.get(null), EXTRA_VALUE); 232 assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE)); 233 assertSame(map.get(null), EXTRA_VALUE); 234 } 235 236 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull") 237 public void testReplaceKVVNoNulls(String description, Map<IntegerEnum, String> map) { 238 assertTrue(map.containsKey(FIRST_KEY), "expected key missing"); 239 assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value"); 240 assertThrows( () -> {map.replace(FIRST_KEY, FIRST_VALUE, null);}, NullPointerException.class, description + ": should throw NPE"); 241 assertThrows( () -> {if (!map.replace(FIRST_KEY, null, EXTRA_VALUE)) throw new NullPointerException("default returns false rather than throwing");}, NullPointerException.class, description + ": should throw NPE"); 242 assertTrue(map.replace(FIRST_KEY, FIRST_VALUE, EXTRA_VALUE), description + ": replaced wrong value"); 243 assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value"); 244 } 245 246 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 247 public void testReplaceKVV(String description, Map<IntegerEnum, String> map) { 248 assertTrue(map.containsKey(KEYS[1])); 249 Object expected = map.get(KEYS[1]); 250 assertTrue(null == expected || expected == VALUES[1]); 251 assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE)); 252 assertSame(map.get(KEYS[1]), expected); 253 assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE)); 254 assertSame(map.get(KEYS[1]), EXTRA_VALUE); 255 assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE)); 256 assertSame(map.get(KEYS[1]), EXTRA_VALUE); 257 258 assertFalse(map.containsKey(EXTRA_KEY)); 259 assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE)); 260 assertFalse(map.containsKey(EXTRA_KEY)); 261 assertNull(map.get(EXTRA_KEY)); 262 assertNull(map.put(EXTRA_KEY, EXTRA_VALUE)); 263 assertTrue(map.containsKey(EXTRA_KEY)); 264 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 265 assertTrue(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE)); 266 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 267 } 268 269 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 270 public void testComputeIfAbsentNulls(String description, Map<IntegerEnum, String> map) { 271 assertTrue(map.containsKey(null), "null key absent"); 272 assertNull(map.get(null), "value not null"); 273 assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, description); 274 assertSame(map.get(null), EXTRA_VALUE, description); 275 } 276 277 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 278 public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) { 279 assertTrue(map.containsKey(KEYS[1])); 280 Object expected = map.get(KEYS[1]); 281 assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected)); 282 expected = (null == expected) ? EXTRA_VALUE : expected; 283 assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description); 284 assertSame(map.get(KEYS[1]), expected, description); 285 286 assertFalse(map.containsKey(EXTRA_KEY)); 287 assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE); 288 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 289 } 290 291 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 292 public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) { 293 assertTrue(map.containsKey(null), description + ": null key absent"); 294 assertNull(map.get(null), description + ": value not null"); 295 assertSame(map.computeIfPresent(null, (k, v) -> { 296 fail(description + ": null value is not deemed present"); 297 return EXTRA_VALUE; 298 }), null, description); 299 assertTrue(map.containsKey(null)); 300 assertNull(map.get(null), description); 301 assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping"); 302 assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value"); 303 assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> { 304 fail(description + ": null value is not deemed present"); 305 return EXTRA_VALUE; 306 }), null, description); 307 assertNull(map.get(EXTRA_KEY), description + ": null mapping gone"); 308 } 309 310 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 311 public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) { 312 assertTrue(map.containsKey(KEYS[1])); 313 Object value = map.get(KEYS[1]); 314 assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); 315 Object expected = (null == value) ? null : EXTRA_VALUE; 316 assertSame(map.computeIfPresent(KEYS[1], (k, v) -> { 317 assertSame(v, value); 318 return EXTRA_VALUE; 319 }), expected, description); 320 assertSame(map.get(KEYS[1]), expected, description); 321 322 assertFalse(map.containsKey(EXTRA_KEY)); 323 assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> { 324 fail(); 325 return EXTRA_VALUE; 326 }), null); 327 assertFalse(map.containsKey(EXTRA_KEY)); 328 assertSame(map.get(EXTRA_KEY), null); 329 } 330 331 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 332 public void testComputeNulls(String description, Map<IntegerEnum, String> map) { 333 assertTrue(map.containsKey(null), "null key absent"); 334 assertNull(map.get(null), "value not null"); 335 assertSame(map.compute(null, (k, v) -> { 336 assertNull(k); 337 assertNull(v); 338 return null; 339 }), null, description); 340 assertFalse(map.containsKey(null), description + ": null key present."); 341 assertSame(map.compute(null, (k, v) -> { 342 assertSame(k, null); 343 assertNull(v); 344 return EXTRA_VALUE; 345 }), EXTRA_VALUE, description); 346 assertTrue(map.containsKey(null)); 347 assertSame(map.get(null), EXTRA_VALUE, description); 348 assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected"); 349 // no mapping before and after 350 assertFalse(map.containsKey(null), description + ": null key present"); 351 assertSame(map.compute(null, (k, v) -> { 352 assertNull(k); 353 assertNull(v); 354 return null; 355 }), null, description + ": expected null result" ); 356 assertFalse(map.containsKey(null), description + ": null key present"); 357 // compute with map not containing value 358 assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping"); 359 assertFalse(map.containsKey(EXTRA_KEY), description + ": key present"); 360 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 361 assertSame(k, EXTRA_KEY); 362 assertNull(v); 363 return null; 364 }), null, description); 365 assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present"); 366 // ensure removal. 367 assertNull(map.put(EXTRA_KEY, EXTRA_VALUE)); 368 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 369 assertSame(k, EXTRA_KEY); 370 assertSame(v, EXTRA_VALUE); 371 return null; 372 }), null, description + ": null resulted expected"); 373 assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present"); 374 // compute with map containing null value 375 assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value"); 376 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 377 assertSame(k, EXTRA_KEY); 378 assertNull(v); 379 return null; 380 }), null, description); 381 assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present"); 382 assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value"); 383 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 384 assertSame(k, EXTRA_KEY); 385 assertNull(v); 386 return EXTRA_VALUE; 387 }), EXTRA_VALUE, description); 388 assertTrue(map.containsKey(EXTRA_KEY), "null key present"); 389 } 390 391 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 392 public void testCompute(String description, Map<IntegerEnum, String> map) { 393 assertTrue(map.containsKey(KEYS[1])); 394 Object value = map.get(KEYS[1]); 395 assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); 396 assertSame(map.compute(KEYS[1], (k, v) -> { 397 assertSame(k, KEYS[1]); 398 assertSame(v, value); 399 return EXTRA_VALUE; 400 }), EXTRA_VALUE, description); 401 assertSame(map.get(KEYS[1]), EXTRA_VALUE, description); 402 assertNull(map.compute(KEYS[1], (k, v) -> { 403 assertSame(v, EXTRA_VALUE); 404 return null; 405 }), description); 406 assertFalse(map.containsKey(KEYS[1])); 407 408 assertFalse(map.containsKey(EXTRA_KEY)); 409 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 410 assertNull(v); 411 return EXTRA_VALUE; 412 }), EXTRA_VALUE); 413 assertTrue(map.containsKey(EXTRA_KEY)); 414 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 415 } 416 417 418 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 419 public void testMergeNulls(String description, Map<IntegerEnum, String> map) { 420 assertTrue(map.containsKey(null), "null key absent"); 421 assertNull(map.get(null), "value not null"); 422 assertSame(map.merge(null, EXTRA_VALUE, (v, vv) -> { 423 assertNull(v); 424 assertSame(vv, EXTRA_VALUE); 425 return vv; 426 }), EXTRA_VALUE, description); 427 assertTrue(map.containsKey(null)); 428 assertSame(map.get(null), EXTRA_VALUE, description); 429 } 430 431 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 432 public void testMerge(String description, Map<IntegerEnum, String> map) { 433 assertTrue(map.containsKey(KEYS[1])); 434 Object value = map.get(KEYS[1]); 435 assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); 436 assertSame(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> { 437 assertSame(v, value); 438 assertSame(vv, EXTRA_VALUE); 439 return vv; 440 }), EXTRA_VALUE, description); 441 assertSame(map.get(KEYS[1]), EXTRA_VALUE, description); 442 assertNull(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> { 443 assertSame(v, EXTRA_VALUE); 444 assertSame(vv, EXTRA_VALUE); 445 return null; 446 }), description); 447 assertFalse(map.containsKey(KEYS[1])); 448 449 assertFalse(map.containsKey(EXTRA_KEY)); 450 assertSame(map.merge(EXTRA_KEY, EXTRA_VALUE, (v, vv) -> { 451 assertNull(v); 452 assertSame(vv, EXTRA_VALUE); 453 return EXTRA_VALUE; 454 }), EXTRA_VALUE); 455 assertTrue(map.containsKey(EXTRA_KEY)); 456 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 457 } 458 459 enum IntegerEnum { 460 461 e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, 462 e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, 463 e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, 464 e30, e31, e32, e33, e34, e35, e36, e37, e38, e39, 465 e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, 466 e50, e51, e52, e53, e54, e55, e56, e57, e58, e59, 467 e60, e61, e62, e63, e64, e65, e66, e67, e68, e69, 468 e70, e71, e72, e73, e74, e75, e76, e77, e78, e79, 469 e80, e81, e82, e83, e84, e85, e86, e87, e88, e89, 470 e90, e91, e92, e93, e94, e95, e96, e97, e98, e99, 471 EXTRA_KEY; 472 public static final int SIZE = values().length; 473 }; 474 private static final int TEST_SIZE = IntegerEnum.SIZE - 1; 475 /** 476 * Realized keys ensure that there is always a hard ref to all test objects. 477 */ 478 private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE]; 479 /** 480 * Realized values ensure that there is always a hard ref to all test 481 * objects. 482 */ 483 private static final String[] VALUES = new String[TEST_SIZE]; 484 485 static { 486 IntegerEnum[] keys = IntegerEnum.values(); 487 for (int each = 0; each < TEST_SIZE; each++) { 488 KEYS[each] = keys[each]; 489 VALUES[each] = String.valueOf(each); 490 } 491 } 492 493 private static final IntegerEnum FIRST_KEY = KEYS[0]; 494 private static final String FIRST_VALUE = VALUES[0]; 495 private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY; 496 private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE); 497 498 @DataProvider(name = "Map<IntegerEnum,String> rw=all keys=all values=all", parallel = true) 499 public static Iterator<Object[]> allMapProvider() { 500 return makeAllMaps().iterator(); 501 } 502 503 @DataProvider(name = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull", parallel = true) 504 public static Iterator<Object[]> allMapWithNullsProvider() { 505 return makeAllMapsWithNulls().iterator(); 506 } 507 508 @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull", parallel = true) 509 public static Iterator<Object[]> rwNonNullMapProvider() { 510 return makeRWNoNullsMaps().iterator(); 511 } 512 513 @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=all", parallel = true) 514 public static Iterator<Object[]> rwNonNullKeysMapProvider() { 515 return makeRWMapsNoNulls().iterator(); 516 } 517 518 @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=all values=all", parallel = true) 519 public static Iterator<Object[]> rwMapProvider() { 520 return makeAllRWMaps().iterator(); 521 } 522 523 @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull", parallel = true) 524 public static Iterator<Object[]> rwNullsMapProvider() { 525 return makeAllRWMapsWithNulls().iterator(); 526 } 527 528 private static Collection<Object[]> makeAllRWMapsWithNulls() { 529 Collection<Object[]> all = new ArrayList<>(); 530 531 all.addAll(makeRWMaps(true, true)); 532 533 return all; 534 } 535 536 537 private static Collection<Object[]> makeRWMapsNoNulls() { 538 Collection<Object[]> all = new ArrayList<>(); 539 540 all.addAll(makeRWNoNullKeysMaps(false)); 541 all.addAll(makeRWNoNullsMaps()); 542 543 return all; 544 } 545 546 private static Collection<Object[]> makeAllROMaps() { 547 Collection<Object[]> all = new ArrayList<>(); 548 549 all.addAll(makeROMaps(false)); 550 all.addAll(makeROMaps(true)); 551 552 return all; 553 } 554 555 private static Collection<Object[]> makeAllRWMaps() { 556 Collection<Object[]> all = new ArrayList<>(); 557 558 all.addAll(makeRWNoNullsMaps()); 559 all.addAll(makeRWMaps(false,true)); 560 all.addAll(makeRWMaps(true,true)); 561 all.addAll(makeRWNoNullKeysMaps(true)); 562 return all; 563 } 564 565 private static Collection<Object[]> makeAllMaps() { 566 Collection<Object[]> all = new ArrayList<>(); 567 568 all.addAll(makeAllROMaps()); 569 all.addAll(makeAllRWMaps()); 570 571 return all; 572 } 573 574 private static Collection<Object[]> makeAllMapsWithNulls() { 575 Collection<Object[]> all = new ArrayList<>(); 576 577 all.addAll(makeROMaps(true)); 578 all.addAll(makeRWMaps(true,true)); 579 580 return all; 581 } 582 /** 583 * 584 * @param nullKeys include null keys 585 * @param nullValues include null values 586 * @return 587 */ 588 private static Collection<Object[]> makeRWMaps(boolean nullKeys, boolean nullValues) { 589 return Arrays.asList( 590 new Object[]{"HashMap", makeMap(HashMap::new, nullKeys, nullValues)}, 591 new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nullKeys, nullValues)}, 592 new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nullKeys, nullValues)}, 593 new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nullKeys, nullValues)}, 594 new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nullKeys, nullValues), IntegerEnum.class, String.class)}, 595 new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nullKeys, nullValues))}, 596 new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nullKeys, nullValues)}); 597 } 598 599 /** 600 * 601 * @param nulls include null values 602 * @return 603 */ 604 private static Collection<Object[]> makeRWNoNullKeysMaps(boolean nulls) { 605 return Arrays.asList( 606 // null key hostile 607 new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls)}, 608 new Object[]{"TreeMap", makeMap(TreeMap::new, false, nulls)}, 609 new Object[]{"ExtendsAbstractMap(TreeMap)", makeMap(() -> {return new ExtendsAbstractMap(new TreeMap());}, false, nulls)}, 610 new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls))} 611 ); 612 } 613 614 private static Collection<Object[]> makeRWNoNullsMaps() { 615 return Arrays.asList( 616 // null key and value hostile 617 new Object[]{"Hashtable", makeMap(Hashtable::new, false, false)}, 618 new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false, false)}, 619 new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false, false)}, 620 new Object[]{"Collections.synchronizedMap(ConcurrentHashMap)", Collections.synchronizedMap(makeMap(ConcurrentHashMap::new, false, false))}, 621 new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false, false), IntegerEnum.class, String.class)}, 622 new Object[]{"ExtendsAbstractMap(ConcurrentHashMap)", makeMap(() -> {return new ExtendsAbstractMap(new ConcurrentHashMap());}, false, false)}, 623 new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false, false)} 624 ); 625 } 626 627 /** 628 * 629 * @param nulls include nulls 630 * @return 631 */ 632 private static Collection<Object[]> makeROMaps(boolean nulls) { 633 return Arrays.asList(new Object[][]{ 634 new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls, nulls))} 635 }); 636 } 637 638 /** 639 * 640 * @param supplier a supplier of mutable map instances. 641 * 642 * @param nullKeys include null keys 643 * @param nullValues include null values 644 * @return 645 */ 646 private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nullKeys, boolean nullValues) { 647 Map<IntegerEnum, String> result = supplier.get(); 648 649 for (int each = 0; each < TEST_SIZE; each++) { 650 IntegerEnum key = nullKeys ? (each == 0) ? null : KEYS[each] : KEYS[each]; 651 String value = nullValues ? (each == 0) ? null : VALUES[each] : VALUES[each]; 652 653 result.put(key, value); 654 } 655 656 return result; 657 } 658 659 public interface Thrower<T extends Throwable> { 660 661 public void run() throws T; 662 } 663 664 public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) { 665 assertThrows(thrower, throwable, null); 666 } 667 668 public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) { 669 Throwable thrown; 670 try { 671 thrower.run(); 672 thrown = null; 673 } catch (Throwable caught) { 674 thrown = caught; 675 } 676 677 assertInstance(thrown, throwable, 678 ((null != message) ? message : "") + 679 " Failed to throw " + throwable.getCanonicalName()); 680 } 681 682 public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) { 683 for(Thrower<T> thrower : throwers) { 684 assertThrows(thrower, throwable, message); 685 } 686 } 687 688 public static void assertInstance(Object actual, Class<?> expected) { 689 assertInstance(expected.isInstance(actual), null); 690 } 691 692 public static void assertInstance(Object actual, Class<?> expected, String message) { 693 assertTrue(expected.isInstance(actual), message); 694 } 695 696 /** 697 * A simple mutable map implementation that provides only default 698 * implementations of all methods. ie. none of the Map interface default 699 * methods have overridden implementations. 700 * 701 * @param <K> Type of keys 702 * @param <V> Type of values 703 */ 704 public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K, V> { 705 706 protected final M map; 707 708 public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); } 709 710 protected ExtendsAbstractMap(M map) { this.map = map; } 711 712 public Set<Map.Entry<K, V>> entrySet() { 713 return new AbstractSet<Map.Entry<K, V>>() { 714 public int size() { 715 return map.size(); 716 } 717 718 public Iterator<Map.Entry<K,V>> iterator() { 719 final Iterator<Map.Entry<K,V>> source = map.entrySet().iterator(); 720 return new Iterator<Map.Entry<K,V>>() { 721 public boolean hasNext() { return source.hasNext(); } 722 public Map.Entry<K,V> next() { return source.next(); } 723 public void remove() { source.remove(); } 724 }; 725 } 726 727 public boolean add(Map.Entry<K,V> e) { 728 return map.entrySet().add(e); 729 } 730 }; 731 } 732 733 public V put(K key, V value) { 734 return map.put(key, value); 735 } 736 } 737 738 /** 739 * A simple mutable concurrent map implementation that provides only default 740 * implementations of all methods. ie. none of the ConcurrentMap interface 741 * default methods have overridden implementations. 742 * 743 * @param <K> Type of keys 744 * @param <V> Type of values 745 */ 746 public static class ImplementsConcurrentMap<K, V> extends ExtendsAbstractMap<ConcurrentMap<K,V>, K, V> implements ConcurrentMap<K,V> { 747 public ImplementsConcurrentMap() { super(new ConcurrentHashMap<K,V>()); } 748 749 // ConcurrentMap reabstracts these methods 750 751 public V replace(K k, V v) { return map.replace(k, v); }; 752 753 public boolean replace(K k, V v, V vv) { return map.replace(k, v, vv); }; 754 755 public boolean remove(Object k, Object v) { return map.remove(k, v); } 756 757 public V putIfAbsent(K k, V v) { return map.putIfAbsent(k, v); } 758 } 759 }