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); 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=all values=all") 198 public void testReplaceKV(String description, Map<IntegerEnum, String> map) { 199 assertTrue(map.containsKey(KEYS[1])); 200 Object expected = map.get(KEYS[1]); 201 assertTrue(null == expected || expected == VALUES[1]); 202 assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected); 203 assertSame(map.get(KEYS[1]), EXTRA_VALUE); 204 205 assertFalse(map.containsKey(EXTRA_KEY)); 206 assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE)); 207 assertFalse(map.containsKey(EXTRA_KEY)); 208 assertNull(map.get(EXTRA_KEY)); 209 assertNull(map.put(EXTRA_KEY, EXTRA_VALUE)); 210 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 211 assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE); 212 assertSame(map.get(EXTRA_KEY), expected); 213 } 214 215 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 216 public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) { 217 assertTrue(map.containsKey(null), "null key absent"); 218 assertNull(map.get(null), "value not null"); 219 assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE)); 220 assertNull(map.get(null)); 221 assertTrue(map.replace(null, null, EXTRA_VALUE)); 222 assertSame(map.get(null), EXTRA_VALUE); 223 assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE)); 224 assertSame(map.get(null), EXTRA_VALUE); 225 } 226 227 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 228 public void testReplaceKVV(String description, Map<IntegerEnum, String> map) { 229 assertTrue(map.containsKey(KEYS[1])); 230 Object expected = map.get(KEYS[1]); 231 assertTrue(null == expected || expected == VALUES[1]); 232 assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE)); 233 assertSame(map.get(KEYS[1]), expected); 234 assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE)); 235 assertSame(map.get(KEYS[1]), EXTRA_VALUE); 236 assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE)); 237 assertSame(map.get(KEYS[1]), EXTRA_VALUE); 238 239 assertFalse(map.containsKey(EXTRA_KEY)); 240 assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE)); 241 assertFalse(map.containsKey(EXTRA_KEY)); 242 assertNull(map.get(EXTRA_KEY)); 243 assertNull(map.put(EXTRA_KEY, EXTRA_VALUE)); 244 assertTrue(map.containsKey(EXTRA_KEY)); 245 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 246 assertTrue(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE)); 247 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 248 } 249 250 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 251 public void testComputeIfAbsentNulls(String description, Map<IntegerEnum, String> map) { 252 assertTrue(map.containsKey(null), "null key absent"); 253 assertNull(map.get(null), "value not null"); 254 assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, description); 255 assertSame(map.get(null), EXTRA_VALUE, description); 256 } 257 258 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 259 public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) { 260 assertTrue(map.containsKey(KEYS[1])); 261 Object expected = map.get(KEYS[1]); 262 assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected)); 263 expected = (null == expected) ? EXTRA_VALUE : expected; 264 assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description); 265 assertSame(map.get(KEYS[1]), expected, description); 266 267 assertFalse(map.containsKey(EXTRA_KEY)); 268 assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE); 269 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 270 } 271 272 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 273 public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) { 274 assertTrue(map.containsKey(null), description + ": null key absent"); 275 assertNull(map.get(null), description + ": value not null"); 276 assertSame(map.computeIfPresent(null, (k, v) -> { 277 fail(description + ": null value is not deemed present"); 278 return EXTRA_VALUE; 279 }), null, description); 280 assertTrue(map.containsKey(null)); 281 assertNull(map.get(null), description); 282 assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping"); 283 assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value"); 284 assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> { 285 fail(description + ": null value is not deemed present"); 286 return EXTRA_VALUE; 287 }), null, description); 288 assertNull(map.get(EXTRA_KEY), description + ": null mapping gone"); 289 } 290 291 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 292 public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) { 293 assertTrue(map.containsKey(KEYS[1])); 294 Object value = map.get(KEYS[1]); 295 assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); 296 Object expected = (null == value) ? null : EXTRA_VALUE; 297 assertSame(map.computeIfPresent(KEYS[1], (k, v) -> { 298 assertSame(v, value); 299 return EXTRA_VALUE; 300 }), expected, description); 301 assertSame(map.get(KEYS[1]), expected, description); 302 303 assertFalse(map.containsKey(EXTRA_KEY)); 304 assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> { 305 fail(); 306 return EXTRA_VALUE; 307 }), null); 308 assertFalse(map.containsKey(EXTRA_KEY)); 309 assertSame(map.get(EXTRA_KEY), null); 310 } 311 312 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 313 public void testComputeNulls(String description, Map<IntegerEnum, String> map) { 314 assertTrue(map.containsKey(null), "null key absent"); 315 assertNull(map.get(null), "value not null"); 316 assertSame(map.compute(null, (k, v) -> { 317 assertNull(k); 318 assertNull(v); 319 return null; 320 }), null, description); 321 assertFalse(map.containsKey(null), description + ": null key present."); 322 assertSame(map.compute(null, (k, v) -> { 323 assertSame(k, null); 324 assertNull(v); 325 return EXTRA_VALUE; 326 }), EXTRA_VALUE, description); 327 assertTrue(map.containsKey(null)); 328 assertSame(map.get(null), EXTRA_VALUE, description); 329 assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected"); 330 // no mapping before and after 331 assertFalse(map.containsKey(null), description + ": null key present"); 332 assertSame(map.compute(null, (k, v) -> { 333 assertNull(k); 334 assertNull(v); 335 return null; 336 }), null, description + ": expected null result" ); 337 assertFalse(map.containsKey(null), description + ": null key present"); 338 // compute with map not containing value 339 assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping"); 340 assertFalse(map.containsKey(EXTRA_KEY), description + ": key present"); 341 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 342 assertSame(k, EXTRA_KEY); 343 assertNull(v); 344 return null; 345 }), null, description); 346 assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present"); 347 // ensure removal. 348 assertNull(map.put(EXTRA_KEY, EXTRA_VALUE)); 349 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 350 assertSame(k, EXTRA_KEY); 351 assertSame(v, EXTRA_VALUE); 352 return null; 353 }), null, description + ": null resulted expected"); 354 assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present"); 355 // compute with map containing null value 356 assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value"); 357 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 358 assertSame(k, EXTRA_KEY); 359 assertNull(v); 360 return null; 361 }), null, description); 362 assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present"); 363 assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value"); 364 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 365 assertSame(k, EXTRA_KEY); 366 assertNull(v); 367 return EXTRA_VALUE; 368 }), EXTRA_VALUE, description); 369 assertTrue(map.containsKey(EXTRA_KEY), "null key present"); 370 } 371 372 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 373 public void testCompute(String description, Map<IntegerEnum, String> map) { 374 assertTrue(map.containsKey(KEYS[1])); 375 Object value = map.get(KEYS[1]); 376 assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); 377 assertSame(map.compute(KEYS[1], (k, v) -> { 378 assertSame(k, KEYS[1]); 379 assertSame(v, value); 380 return EXTRA_VALUE; 381 }), EXTRA_VALUE, description); 382 assertSame(map.get(KEYS[1]), EXTRA_VALUE, description); 383 assertNull(map.compute(KEYS[1], (k, v) -> { 384 assertSame(v, EXTRA_VALUE); 385 return null; 386 }), description); 387 assertFalse(map.containsKey(KEYS[1])); 388 389 assertFalse(map.containsKey(EXTRA_KEY)); 390 assertSame(map.compute(EXTRA_KEY, (k, v) -> { 391 assertNull(v); 392 return EXTRA_VALUE; 393 }), EXTRA_VALUE); 394 assertTrue(map.containsKey(EXTRA_KEY)); 395 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 396 } 397 398 399 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull") 400 public void testMergeNulls(String description, Map<IntegerEnum, String> map) { 401 assertTrue(map.containsKey(null), "null key absent"); 402 assertNull(map.get(null), "value not null"); 403 assertSame(map.merge(null, EXTRA_VALUE, (v, vv) -> { 404 assertNull(v); 405 assertSame(vv, EXTRA_VALUE); 406 return vv; 407 }), EXTRA_VALUE, description); 408 assertTrue(map.containsKey(null)); 409 assertSame(map.get(null), EXTRA_VALUE, description); 410 } 411 412 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all") 413 public void testMerge(String description, Map<IntegerEnum, String> map) { 414 assertTrue(map.containsKey(KEYS[1])); 415 Object value = map.get(KEYS[1]); 416 assertTrue(null == value || value == VALUES[1], description + String.valueOf(value)); 417 assertSame(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> { 418 assertSame(v, value); 419 assertSame(vv, EXTRA_VALUE); 420 return vv; 421 }), EXTRA_VALUE, description); 422 assertSame(map.get(KEYS[1]), EXTRA_VALUE, description); 423 assertNull(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> { 424 assertSame(v, EXTRA_VALUE); 425 assertSame(vv, EXTRA_VALUE); 426 return null; 427 }), description); 428 assertFalse(map.containsKey(KEYS[1])); 429 430 assertFalse(map.containsKey(EXTRA_KEY)); 431 assertSame(map.merge(EXTRA_KEY, EXTRA_VALUE, (v, vv) -> { 432 assertNull(v); 433 assertSame(vv, EXTRA_VALUE); 434 return EXTRA_VALUE; 435 }), EXTRA_VALUE); 436 assertTrue(map.containsKey(EXTRA_KEY)); 437 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE); 438 } 439 440 enum IntegerEnum { 441 442 e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, 443 e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, 444 e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, 445 e30, e31, e32, e33, e34, e35, e36, e37, e38, e39, 446 e40, e41, e42, e43, e44, e45, e46, e47, e48, e49, 447 e50, e51, e52, e53, e54, e55, e56, e57, e58, e59, 448 e60, e61, e62, e63, e64, e65, e66, e67, e68, e69, 449 e70, e71, e72, e73, e74, e75, e76, e77, e78, e79, 450 e80, e81, e82, e83, e84, e85, e86, e87, e88, e89, 451 e90, e91, e92, e93, e94, e95, e96, e97, e98, e99, 452 EXTRA_KEY; 453 public static final int SIZE = values().length; 454 }; 455 private static final int TEST_SIZE = IntegerEnum.SIZE - 1; 456 /** 457 * Realized keys ensure that there is always a hard ref to all test objects. 458 */ 459 private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE]; 460 /** 461 * Realized values ensure that there is always a hard ref to all test 462 * objects. 463 */ 464 private static final String[] VALUES = new String[TEST_SIZE]; 465 466 static { 467 IntegerEnum[] keys = IntegerEnum.values(); 468 for (int each = 0; each < TEST_SIZE; each++) { 469 KEYS[each] = keys[each]; 470 VALUES[each] = String.valueOf(each); 471 } 472 } 473 private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY; 474 private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE); 475 476 @DataProvider(name = "Map<IntegerEnum,String> rw=all keys=all values=all", parallel = true) 477 public static Iterator<Object[]> allMapProvider() { 478 return makeAllMaps().iterator(); 479 } 480 481 @DataProvider(name = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull", parallel = true) 482 public static Iterator<Object[]> allMapWithNullsProvider() { 483 return makeAllMapsWithNulls().iterator(); 484 } 485 486 @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull", parallel = true) 487 public static Iterator<Object[]> rwNonNullMapProvider() { 488 return makeRWNoNullsMaps().iterator(); 489 } 490 491 @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=all", parallel = true) 492 public static Iterator<Object[]> rwNonNullKeysMapProvider() { 493 return makeRWMapsNoNulls().iterator(); 494 } 495 496 @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=all values=all", parallel = true) 497 public static Iterator<Object[]> rwMapProvider() { 498 return makeAllRWMaps().iterator(); 499 } 500 501 @DataProvider(name = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull", parallel = true) 502 public static Iterator<Object[]> rwNullsMapProvider() { 503 return makeAllRWMapsWithNulls().iterator(); 504 } 505 506 private static Collection<Object[]> makeAllRWMapsWithNulls() { 507 Collection<Object[]> all = new ArrayList<>(); 508 509 all.addAll(makeRWMaps(true, true)); 510 511 return all; 512 } 513 514 515 private static Collection<Object[]> makeRWMapsNoNulls() { 516 Collection<Object[]> all = new ArrayList<>(); 517 518 all.addAll(makeRWNoNullKeysMaps(false)); 519 all.addAll(makeRWNoNullsMaps()); 520 521 return all; 522 } 523 524 private static Collection<Object[]> makeAllROMaps() { 525 Collection<Object[]> all = new ArrayList<>(); 526 527 all.addAll(makeROMaps(false)); 528 all.addAll(makeROMaps(true)); 529 530 return all; 531 } 532 533 private static Collection<Object[]> makeAllRWMaps() { 534 Collection<Object[]> all = new ArrayList<>(); 535 536 all.addAll(makeRWNoNullsMaps()); 537 all.addAll(makeRWMaps(false,true)); 538 all.addAll(makeRWMaps(true,true)); 539 all.addAll(makeRWNoNullKeysMaps(true)); 540 return all; 541 } 542 543 private static Collection<Object[]> makeAllMaps() { 544 Collection<Object[]> all = new ArrayList<>(); 545 546 all.addAll(makeAllROMaps()); 547 all.addAll(makeAllRWMaps()); 548 549 return all; 550 } 551 552 private static Collection<Object[]> makeAllMapsWithNulls() { 553 Collection<Object[]> all = new ArrayList<>(); 554 555 all.addAll(makeROMaps(true)); 556 all.addAll(makeRWMaps(true,true)); 557 558 return all; 559 } 560 /** 561 * 562 * @param nullKeys include null keys 563 * @param nullValues include null values 564 * @return 565 */ 566 private static Collection<Object[]> makeRWMaps(boolean nullKeys, boolean nullValues) { 567 return Arrays.asList( 568 new Object[]{"HashMap", makeMap(HashMap::new, nullKeys, nullValues)}, 569 new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nullKeys, nullValues)}, 570 new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nullKeys, nullValues)}, 571 new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nullKeys, nullValues)}, 572 new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nullKeys, nullValues), IntegerEnum.class, String.class)}, 573 new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nullKeys, nullValues))}, 574 new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nullKeys, nullValues)}); 575 } 576 577 /** 578 * 579 * @param nulls include null values 580 * @return 581 */ 582 private static Collection<Object[]> makeRWNoNullKeysMaps(boolean nulls) { 583 return Arrays.asList( 584 // null key hostile 585 new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls)}, 586 new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls))} 587 ); 588 } 589 590 private static Collection<Object[]> makeRWNoNullsMaps() { 591 return Arrays.asList( 592 // null key and value hostile 593 new Object[]{"Hashtable", makeMap(Hashtable::new, false, false)}, 594 new Object[]{"TreeMap", makeMap(TreeMap::new, false, false)}, 595 new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false, false)}, 596 new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false, false)}, 597 new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false, false), IntegerEnum.class, String.class)}, 598 new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false, false)} 599 ); 600 } 601 602 /** 603 * 604 * @param nulls include nulls 605 * @return 606 */ 607 private static Collection<Object[]> makeROMaps(boolean nulls) { 608 return Arrays.asList(new Object[][]{ 609 new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls, nulls))} 610 }); 611 } 612 613 /** 614 * 615 * @param supplier a supplier of mutable map instances. 616 * 617 * @param nullKeys include null keys 618 * @param nullValues include null values 619 * @return 620 */ 621 private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nullKeys, boolean nullValues) { 622 Map<IntegerEnum, String> result = supplier.get(); 623 624 for (int each = 0; each < TEST_SIZE; each++) { 625 IntegerEnum key = nullKeys ? (each == 0) ? null : KEYS[each] : KEYS[each]; 626 String value = nullValues ? (each == 0) ? null : VALUES[each] : VALUES[each]; 627 628 result.put(key, value); 629 } 630 631 return result; 632 } 633 634 public interface Thrower<T extends Throwable> { 635 636 public void run() throws T; 637 } 638 639 public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) { 640 assertThrows(thrower, throwable, null); 641 } 642 643 public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) { 644 Throwable result; 645 try { 646 thrower.run(); 647 result = null; 648 } catch (Throwable caught) { 649 result = caught; 650 } 651 652 assertInstance(result, throwable, 653 (null != message) 654 ? message 655 : "Failed to throw " + throwable.getCanonicalName()); 656 } 657 658 public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) { 659 for(Thrower<T> thrower : throwers) { 660 assertThrows(thrower, throwable, message); 661 } 662 } 663 664 public static <T> void assertInstance(T actual, Class<? extends T> expected) { 665 assertInstance(expected.isInstance(actual), null); 666 } 667 668 public static <T> void assertInstance(T actual, Class<? extends T> expected, String message) { 669 assertTrue(expected.isInstance(actual), message); 670 } 671 672 /** 673 * A simple mutable map implementation that provides only default 674 * implementations of all methods. ie. none of the Map interface default 675 * methods have overridden implementations. 676 * 677 * @param <K> Type of keys 678 * @param <V> Type of values 679 */ 680 public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K, V> { 681 682 protected final M map; 683 684 public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); } 685 686 protected ExtendsAbstractMap(M map) { this.map = map; } 687 688 public Set<Map.Entry<K, V>> entrySet() { 689 return new AbstractSet<Map.Entry<K, V>>() { 690 public int size() { 691 return map.size(); 692 } 693 694 public Iterator<Map.Entry<K,V>> iterator() { 695 final Iterator<Map.Entry<K,V>> source = map.entrySet().iterator(); 696 return new Iterator<Map.Entry<K,V>>() { 697 public boolean hasNext() { return source.hasNext(); } 698 public Map.Entry<K,V> next() { return source.next(); } 699 public void remove() { source.remove(); } 700 }; 701 } 702 703 public boolean add(Map.Entry<K,V> e) { 704 return map.entrySet().add(e); 705 } 706 }; 707 } 708 709 public V put(K key, V value) { 710 return map.put(key, value); 711 } 712 } 713 714 /** 715 * A simple mutable concurrent map implementation that provides only default 716 * implementations of all methods. ie. none of the ConcurrentMap interface 717 * default methods have overridden implementations. 718 * 719 * @param <K> Type of keys 720 * @param <V> Type of values 721 */ 722 public static class ImplementsConcurrentMap<K, V> extends ExtendsAbstractMap<ConcurrentMap<K,V>, K, V> implements ConcurrentMap<K,V> { 723 public ImplementsConcurrentMap() { super(new ConcurrentHashMap<K,V>()); } 724 725 // ConcurrentMap reabstracts these methods 726 727 public V replace(K k, V v) { return map.replace(k, v); }; 728 729 public boolean replace(K k, V v, V vv) { return map.replace(k, v, vv); }; 730 731 public boolean remove(Object k, Object v) { return map.remove(k, v); } 732 733 public V putIfAbsent(K k, V v) { return map.putIfAbsent(k, v); } 734 } 735 }