1 /* 2 * Copyright (c) 2022, 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 package test.java.util.IdentityHashMap; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Collection; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.IdentityHashMap; 32 import java.util.Set; 33 import java.util.function.BiPredicate; 34 import java.util.stream.IntStream; 35 import org.testng.annotations.BeforeMethod; 36 import org.testng.annotations.Test; 37 38 import static java.util.Map.entry; 39 import static org.testng.Assert.*; 40 41 /* 42 * @test 43 * @bug 8285295 8178355 44 * @summary Basic tests for IdentityHashMap 45 * @run testng Basic 46 */ 47 48 // NOTE: avoid using TestNG's assertEquals/assertNotEquals directly on two IDHM instances, 49 // as its logic for testing collections equality is suspect. Use checkEntries() to assert 50 // that a map's entrySet contains exactly the expected mappings. There are no guarantees about 51 // the identities of Map.Entry instances obtained from the entrySet; however, the keys and 52 // values they contain are guaranteed to have the right identity. 53 54 // TODO add tests using null keys and values 55 // TODO deeper testing of view collections including iterators, equals, contains, etc. 56 // TODO Map.Entry::setValue 57 58 public class Basic { 59 /* 60 * Helpers 61 */ 62 Box(int i)63 record Box(int i) { 64 Box(Box other) { 65 this(other.i()); 66 } 67 } 68 69 // Checks that a collection contains exactly the given elements and no others, using the 70 // provided predicate for equivalence. Checking is performed both using contains() on the 71 // collection and by simple array searching. The latter is O(N^2) so is suitable only for 72 // small arrays. No two of the given elements can be equivalent according to the predicate. 73 74 // TODO: read out the elements using iterator and stream and check them too 75 76 @SafeVarargs checkContents(Collection<E> c, BiPredicate<E,E> p, E... given)77 private <E> void checkContents(Collection<E> c, BiPredicate<E,E> p, E... given) { 78 @SuppressWarnings("unchecked") 79 E[] contents = (E[]) c.toArray(); 80 81 assertEquals(c.size(), given.length); 82 assertEquals(contents.length, given.length); 83 final int LEN = given.length; 84 85 for (E e : given) { 86 assertTrue(c.contains(e)); 87 } 88 89 // Fill indexes array with position of a given element in the contents array, 90 // or -1 if the given element cannot be found. 91 92 int[] indexes = new int[LEN]; 93 94 outer: 95 for (int i = 0; i < LEN; i++) { 96 for (int j = 0; j < LEN; j++) { 97 if (p.test(given[i], contents[j])) { 98 indexes[i] = j; 99 continue outer; 100 } 101 } 102 indexes[i] = -1; 103 } 104 105 // If every given element matches a distinct element in the contents array, 106 // the sorted indexes array will be the sequence [0..LEN-1]. 107 108 Arrays.sort(indexes); 109 assertEquals(indexes, IntStream.range(0, LEN).toArray()); 110 } 111 112 // Checks that the collection contains the given boxes, by identity. checkElements(Collection<Box> c, Box... given)113 private void checkElements(Collection<Box> c, Box... given) { 114 checkContents(c, (b1, b2) -> b1 == b2, given); 115 } 116 117 // Checks that the collection contains entries that have identical keys and values. 118 // The entries themselves are not checked for identity. 119 @SafeVarargs checkEntries(Collection<Map.Entry<Box, Box>> c, Map.Entry<Box, Box>... given)120 private void checkEntries(Collection<Map.Entry<Box, Box>> c, Map.Entry<Box, Box>... given) { 121 checkContents(c, (e1, e2) -> e1.getKey() == e2.getKey() && e1.getValue() == e2.getValue(), given); 122 } 123 124 /* 125 * Setup 126 */ 127 128 final Box k1a = new Box(17); 129 final Box k1b = new Box(17); // equals but != k1a 130 final Box k2 = new Box(42); 131 132 final Box v1a = new Box(30); 133 final Box v1b = new Box(30); // equals but != v1a 134 final Box v2 = new Box(99); 135 136 IdentityHashMap<Box, Box> map; 137 IdentityHashMap<Box, Box> map2; 138 139 @BeforeMethod setup()140 public void setup() { 141 map = new IdentityHashMap<>(); 142 map.put(k1a, v1a); 143 map.put(k1b, v1b); 144 map.put(k2, v2); 145 146 map2 = new IdentityHashMap<>(); 147 map2.put(k1a, v1a); 148 map2.put(k1b, v1b); 149 map2.put(k2, v2); 150 } 151 152 /* 153 * Tests 154 */ 155 156 // containsKey 157 // containsValue 158 // size 159 @Test testSizeContainsKeyValue()160 public void testSizeContainsKeyValue() { 161 assertEquals(map.size(), 3); 162 163 assertTrue(map.containsKey(k1a)); 164 assertTrue(map.containsKey(k1b)); 165 assertTrue(map.containsKey(k2)); 166 assertFalse(map.containsKey(new Box(k1a))); 167 168 assertTrue(map.containsValue(v1a)); 169 assertTrue(map.containsValue(v1b)); 170 assertFalse(map.containsValue(new Box(v1a))); 171 assertTrue(map.containsValue(v2)); 172 } 173 174 // get 175 @Test testGet()176 public void testGet() { 177 assertSame(map.get(k1a), v1a); 178 assertSame(map.get(k1b), v1b); 179 assertSame(map.get(k2), v2); 180 assertNull(map.get(new Box(k1a))); 181 } 182 183 // getOrDefault 184 @Test testGetOrDefault()185 public void testGetOrDefault() { 186 Box other = new Box(22); 187 188 assertSame(map.getOrDefault(k1a, other), v1a); 189 assertSame(map.getOrDefault(k1b, other), v1b); 190 assertSame(map.getOrDefault(new Box(k1a), other), other); 191 assertSame(map.getOrDefault(k2, other), v2); 192 } 193 194 // clear 195 // isEmpty 196 @Test testClearEmpty()197 public void testClearEmpty() { 198 assertFalse(map.isEmpty()); 199 map.clear(); 200 assertTrue(map.isEmpty()); 201 } 202 203 // hashCode 204 @Test testHashCode()205 public void testHashCode() { 206 int expected = (System.identityHashCode(k1a) ^ System.identityHashCode(v1a)) + 207 (System.identityHashCode(k1b) ^ System.identityHashCode(v1b)) + 208 (System.identityHashCode(k2) ^ System.identityHashCode(v2)); 209 assertEquals(map.hashCode(), expected); 210 assertEquals(map.entrySet().hashCode(), expected); 211 } 212 213 // equals 214 @Test testEquals()215 public void testEquals() { 216 assertTrue(map.equals(map)); 217 assertTrue(map.equals(map2)); 218 assertTrue(map2.equals(map)); 219 220 assertTrue(map.keySet().equals(map.keySet())); 221 assertTrue(map.keySet().equals(map2.keySet())); 222 assertTrue(map2.keySet().equals(map.keySet())); 223 224 assertTrue(map.entrySet().equals(map.entrySet())); 225 assertTrue(map.entrySet().equals(map2.entrySet())); 226 assertTrue(map2.entrySet().equals(map.entrySet())); 227 } 228 229 // equals 230 @Test testEqualsDifferentKey()231 public void testEqualsDifferentKey() { 232 map2.remove(k1a); 233 map2.put(new Box(k1a), v1a); 234 235 assertFalse(map.equals(map2)); 236 assertFalse(map2.equals(map)); 237 238 assertFalse(map.keySet().equals(map2.keySet())); 239 assertFalse(map2.keySet().equals(map.keySet())); 240 241 assertFalse(map.entrySet().equals(map2.entrySet())); 242 assertFalse(map2.entrySet().equals(map.entrySet())); 243 } 244 245 // equals 246 @Test testEqualsDifferentValue()247 public void testEqualsDifferentValue() { 248 map2.put(k1a, new Box(v1a)); 249 250 assertFalse(map.equals(map2)); 251 assertFalse(map2.equals(map)); 252 253 assertTrue(map.keySet().equals(map2.keySet())); 254 assertTrue(map2.keySet().equals(map.keySet())); 255 256 assertFalse(map.entrySet().equals(map2.entrySet())); 257 assertFalse(map2.entrySet().equals(map.entrySet())); 258 } 259 260 // equals 261 @Test testEqualsNewMapping()262 public void testEqualsNewMapping() { 263 map.put(new Box(k1a), new Box(v1a)); 264 265 assertFalse(map.equals(map2)); 266 assertFalse(map2.equals(map)); 267 268 assertFalse(map.keySet().equals(map2.keySet())); 269 assertFalse(map2.keySet().equals(map.keySet())); 270 271 assertFalse(map.entrySet().equals(map2.entrySet())); 272 assertFalse(map2.entrySet().equals(map.entrySet())); 273 } 274 275 // equals 276 @Test testEqualsMissingMapping()277 public void testEqualsMissingMapping() { 278 var tmp = new IdentityHashMap<Box, Box>(); 279 tmp.put(k1a, v1a); 280 tmp.put(k1b, v1b); 281 282 assertFalse(map.equals(tmp)); 283 assertFalse(tmp.equals(map)); 284 285 assertFalse(map.keySet().equals(tmp.keySet())); 286 assertFalse(tmp.keySet().equals(map.keySet())); 287 288 assertFalse(map.entrySet().equals(tmp.entrySet())); 289 assertFalse(tmp.entrySet().equals(map.entrySet())); 290 } 291 292 // keySet equals, contains 293 @Test testKeySet()294 public void testKeySet() { 295 Set<Box> keySet = map.keySet(); 296 297 checkElements(keySet, k1a, k1b, k2); 298 assertFalse(keySet.contains(new Box(k1a))); 299 assertTrue(map.keySet().equals(map2.keySet())); 300 assertTrue(map2.keySet().equals(map.keySet())); 301 } 302 303 // keySet remove 304 @Test testKeySetNoRemove()305 public void testKeySetNoRemove() { 306 Set<Box> keySet = map.keySet(); 307 boolean r = keySet.remove(new Box(k1a)); 308 309 assertFalse(r); 310 checkElements(keySet, k1a, k1b, k2); 311 checkEntries(map.entrySet(), entry(k1a, v1a), 312 entry(k1b, v1b), 313 entry(k2, v2)); 314 assertTrue(map.keySet().equals(map2.keySet())); 315 assertTrue(map2.keySet().equals(map.keySet())); 316 } 317 318 // keySet remove 319 @Test testKeySetRemove()320 public void testKeySetRemove() { 321 Set<Box> keySet = map.keySet(); 322 boolean r = keySet.remove(k1a); 323 324 assertTrue(r); 325 checkElements(keySet, k1b, k2); 326 checkEntries(map.entrySet(), entry(k1b, v1b), 327 entry(k2, v2)); 328 assertFalse(map.keySet().equals(map2.keySet())); 329 assertFalse(map2.keySet().equals(map.keySet())); 330 } 331 332 // values 333 @Test testValues()334 public void testValues() { 335 Collection<Box> values = map.values(); 336 checkElements(values, v1a, v1b, v2); 337 assertFalse(values.contains(new Box(v1a))); 338 } 339 340 // values remove 341 @Test testValuesNoRemove()342 public void testValuesNoRemove() { 343 Collection<Box> values = map.values(); 344 boolean r = values.remove(new Box(v1a)); 345 346 assertFalse(r); 347 checkElements(values, v1a, v1b, v2); 348 checkEntries(map.entrySet(), entry(k1a, v1a), 349 entry(k1b, v1b), 350 entry(k2, v2)); 351 } 352 353 // values remove 354 @Test testValuesRemove()355 public void testValuesRemove() { 356 Collection<Box> values = map.values(); 357 boolean r = values.remove(v1a); 358 359 assertTrue(r); 360 checkElements(values, v1b, v2); 361 checkEntries(map.entrySet(), entry(k1b, v1b), 362 entry(k2, v2)); 363 } 364 365 // entrySet equals, contains 366 @Test testEntrySet()367 public void testEntrySet() { 368 Set<Map.Entry<Box,Box>> entrySet = map.entrySet(); 369 370 assertFalse(entrySet.contains(entry(new Box(k1a), v1a))); 371 assertFalse(entrySet.contains(entry(k1b, new Box(v1b)))); 372 assertFalse(entrySet.contains(entry(new Box(k2), new Box(v2)))); 373 assertTrue(map.entrySet().equals(map2.entrySet())); 374 checkEntries(entrySet, entry(k1a, v1a), 375 entry(k1b, v1b), 376 entry(k2, v2)); 377 } 378 379 // entrySet remove 380 @Test testEntrySetNoRemove()381 public void testEntrySetNoRemove() { 382 Set<Map.Entry<Box, Box>> entrySet = map.entrySet(); 383 boolean r1 = entrySet.remove(entry(new Box(k1a), v1a)); 384 boolean r2 = entrySet.remove(entry(k1a, new Box(v1a))); 385 386 assertFalse(r1); 387 assertFalse(r2); 388 assertTrue(entrySet.equals(map2.entrySet())); 389 checkEntries(entrySet, entry(k1a, v1a), 390 entry(k1b, v1b), 391 entry(k2, v2)); 392 } 393 394 // entrySet remove 395 @Test testEntrySetRemove()396 public void testEntrySetRemove() { 397 Set<Map.Entry<Box, Box>> entrySet = map.entrySet(); 398 boolean r = entrySet.remove(Map.entry(k1a, v1a)); 399 400 assertTrue(r); 401 assertFalse(entrySet.equals(map2.entrySet())); 402 assertFalse(map.entrySet().equals(map2.entrySet())); 403 checkEntries(entrySet, entry(k1b, v1b), 404 entry(k2, v2)); 405 checkEntries(map.entrySet(), entry(k1b, v1b), 406 entry(k2, v2)); 407 } 408 409 // put 410 @Test testPutNew()411 public void testPutNew() { 412 Box newKey = new Box(k1a); 413 Box newVal = new Box(v1a); 414 Box r = map.put(newKey, newVal); 415 416 assertNull(r); 417 checkEntries(map.entrySet(), entry(k1a, v1a), 418 entry(k1b, v1b), 419 entry(k2, v2), 420 entry(newKey, newVal)); 421 } 422 423 // put 424 @Test testPutOverwrite()425 public void testPutOverwrite() { 426 Box newVal = new Box(v1a); 427 Box r = map.put(k1a, newVal); 428 429 assertSame(r, v1a); 430 checkEntries(map.entrySet(), entry(k1a, newVal), 431 entry(k1b, v1b), 432 entry(k2, v2)); 433 } 434 435 // putAll 436 @Test testPutAll()437 public void testPutAll() { 438 Box newKey = new Box(k1a); 439 Box newVal = new Box(v1a); 440 Box newValB = new Box(v1b); 441 var argMap = new IdentityHashMap<Box, Box>(); 442 argMap.put(newKey, newVal); // new entry 443 argMap.put(k1b, newValB); // will overwrite value 444 map.putAll(argMap); 445 446 checkEntries(map.entrySet(), entry(k1a, v1a), 447 entry(k1b, newValB), 448 entry(k2, v2), 449 entry(newKey, newVal)); 450 } 451 452 // putIfAbsent 453 @Test testPutIfAbsentNoop()454 public void testPutIfAbsentNoop() { 455 Box r = map.putIfAbsent(k1a, new Box(v1a)); // no-op 456 457 assertSame(r, v1a); 458 checkEntries(map.entrySet(), entry(k1a, v1a), 459 entry(k1b, v1b), 460 entry(k2, v2)); 461 } 462 463 // putIfAbsent 464 @Test testPutIfAbsentAddsNew()465 public void testPutIfAbsentAddsNew() { 466 Box newKey = new Box(k1a); 467 Box newVal = new Box(v1a); 468 Box r = map.putIfAbsent(newKey, newVal); // adds new entry 469 470 assertNull(r); 471 checkEntries(map.entrySet(), entry(k1a, v1a), 472 entry(k1b, v1b), 473 entry(k2, v2), 474 entry(newKey, newVal)); 475 } 476 477 // remove(Object) 478 @Test testRemoveKey()479 public void testRemoveKey() { 480 Box r = map.remove(k1b); 481 482 assertSame(r, v1b); 483 checkEntries(map.entrySet(), entry(k1a, v1a), 484 entry(k2, v2)); 485 } 486 487 // remove(Object, Object) absent key, absent value 488 @Test testRemoveAA()489 public void testRemoveAA() { 490 Box k1c = new Box(k1a); 491 Box v1c = new Box(v1a); 492 assertFalse(map.remove(k1c, v1c)); 493 checkEntries(map.entrySet(), 494 entry(k1a, v1a), 495 entry(k1b, v1b), 496 entry(k2, v2)); 497 } 498 499 // remove(Object, Object) absent key, present value 500 @Test testRemoveAV()501 public void testRemoveAV() { 502 Box k1c = new Box(k1a); 503 assertFalse(map.remove(k1c, v1a)); 504 checkEntries(map.entrySet(), 505 entry(k1a, v1a), 506 entry(k1b, v1b), 507 entry(k2, v2)); 508 } 509 510 // remove(Object, Object) present key, absent value 511 @Test testRemoveKA()512 public void testRemoveKA() { 513 Box v1c = new Box(v1a); 514 assertFalse(map.remove(k1a, v1c)); 515 checkEntries(map.entrySet(), 516 entry(k1a, v1a), 517 entry(k1b, v1b), 518 entry(k2, v2)); 519 } 520 521 // remove(Object, Object) present key, present value 522 @Test testRemoveKV()523 public void testRemoveKV() { 524 assertTrue(map.remove(k1a, v1a)); 525 checkEntries(map.entrySet(), 526 entry(k1b, v1b), 527 entry(k2, v2)); 528 } 529 530 // replace(K, V, V) absent key, absent oldValue 531 @Test testReplaceAA()532 public void testReplaceAA() { 533 Box k1c = new Box(k1a); 534 Box v1c = new Box(v1a); 535 Box newVal = new Box(v2); 536 assertFalse(map.replace(k1c, v1c, newVal)); 537 checkEntries(map.entrySet(), 538 entry(k1a, v1a), 539 entry(k1b, v1b), 540 entry(k2, v2)); 541 } 542 543 // replace(K, V, V) absent key, present oldValue 544 @Test testReplaceAV()545 public void testReplaceAV() { 546 Box k1c = new Box(k1a); 547 Box newVal = new Box(v2); 548 assertFalse(map.replace(k1c, v1a, newVal)); 549 checkEntries(map.entrySet(), 550 entry(k1a, v1a), 551 entry(k1b, v1b), 552 entry(k2, v2)); 553 } 554 555 // replace(K, V, V) present key, absent oldValue 556 @Test testReplaceKA()557 public void testReplaceKA() { 558 Box v1c = new Box(v1a); 559 Box newVal = new Box(v2); 560 assertFalse(map.replace(k1a, v1c, newVal)); 561 checkEntries(map.entrySet(), 562 entry(k1a, v1a), 563 entry(k1b, v1b), 564 entry(k2, v2)); 565 } 566 567 // replace(K, V, V) present key, present oldValue 568 @Test testReplaceKV()569 public void testReplaceKV() { 570 Box newVal = new Box(v2); 571 assertTrue(map.replace(k1a, v1a, newVal)); 572 checkEntries(map.entrySet(), 573 entry(k1a, newVal), 574 entry(k1b, v1b), 575 entry(k2, v2)); 576 } 577 578 // AN: key absent, remappingFunction returns null 579 @Test testComputeAN()580 public void testComputeAN() { 581 Box newKey = new Box(k1a); 582 Box r = map.compute(newKey, (k, v) -> null); 583 584 assertNull(r); 585 checkEntries(map.entrySet(), entry(k1a, v1a), 586 entry(k1b, v1b), 587 entry(k2, v2)); 588 } 589 590 // AV: key absent, remappingFunction returns non-null value 591 @Test testComputeAV()592 public void testComputeAV() { 593 Box newKey = new Box(k1a); 594 Box newVal = new Box(v1a); 595 Box r = map.compute(newKey, (k, v) -> newVal); 596 597 assertSame(r, newVal); 598 checkEntries(map.entrySet(), entry(k1a, v1a), 599 entry(k1b, v1b), 600 entry(k2, v2), 601 entry(newKey, newVal)); 602 } 603 604 // PN: key present, remappingFunction returns null 605 @Test testComputePN()606 public void testComputePN() { 607 Box r = map.compute(k1a, (k, v) -> null); 608 609 assertNull(r); 610 checkEntries(map.entrySet(), entry(k1b, v1b), 611 entry(k2, v2)); 612 } 613 614 // PV: key present, remappingFunction returns non-null value 615 @Test testComputePV()616 public void testComputePV() { 617 Box newVal = new Box(v1a); 618 Box r = map.compute(k1a, (k, v) -> newVal); 619 620 assertSame(r, newVal); 621 checkEntries(map.entrySet(), entry(k1a, newVal), 622 entry(k1b, v1b), 623 entry(k2, v2)); 624 } 625 626 // computeIfAbsent 627 @Test testComputeIfAbsentIsCalled()628 public void testComputeIfAbsentIsCalled() { 629 boolean[] called = new boolean[1]; 630 Box newKey = new Box(k1a); 631 Box newVal = new Box(v1a); 632 Box r = map.computeIfAbsent(newKey, k -> { called[0] = true; return newVal; }); 633 634 assertSame(r, newVal); 635 assertTrue(called[0]); 636 checkEntries(map.entrySet(), entry(k1a, v1a), 637 entry(k1b, v1b), 638 entry(k2, v2), 639 entry(newKey, newVal)); 640 } 641 642 // computeIfAbsent 643 @Test testComputeIfAbsentNotCalled()644 public void testComputeIfAbsentNotCalled() { 645 boolean[] called = new boolean[1]; 646 Box r = map.computeIfAbsent(k1a, k -> { called[0] = true; return null; }); 647 648 assertSame(r, v1a); 649 assertFalse(called[0]); 650 checkEntries(map.entrySet(), entry(k1a, v1a), 651 entry(k1b, v1b), 652 entry(k2, v2)); 653 } 654 655 // computeIfAbsent 656 @Test testComputeIfAbsentNullReturn()657 public void testComputeIfAbsentNullReturn() { 658 boolean[] called = new boolean[1]; 659 Box newKey = new Box(k1a); 660 Box r = map.computeIfAbsent(newKey, k -> { called[0] = true; return null; }); 661 662 assertNull(r); 663 assertTrue(called[0]); 664 checkEntries(map.entrySet(), entry(k1a, v1a), 665 entry(k1b, v1b), 666 entry(k2, v2)); 667 } 668 669 // computeIfPresent 670 @Test testComputeIfPresentIsCalled()671 public void testComputeIfPresentIsCalled() { 672 boolean[] called = new boolean[1]; 673 Box newVal = new Box(v1a); 674 Box r = map.computeIfPresent(k1a, (k, v) -> { called[0] = true; return newVal; }); 675 676 assertSame(r, newVal); 677 assertTrue(called[0]); 678 checkEntries(map.entrySet(), entry(k1a, newVal), 679 entry(k1b, v1b), 680 entry(k2, v2)); 681 } 682 683 // computeIfPresent 684 @Test testComputeIfPresentNotCalled()685 public void testComputeIfPresentNotCalled() { 686 boolean[] called = new boolean[1]; 687 Box r = map.computeIfPresent(new Box(k1a), (k, v) -> { called[0] = true; return null; }); 688 689 assertNull(r); 690 assertFalse(called[0]); 691 checkEntries(map.entrySet(), entry(k1a, v1a), 692 entry(k1b, v1b), 693 entry(k2, v2)); 694 } 695 696 // computeIfPresent 697 @Test testComputeIfPresentNullReturn()698 public void testComputeIfPresentNullReturn() { 699 boolean[] called = new boolean[1]; 700 Box r = map.computeIfPresent(k1a, (k, v) -> { called[0] = true; return null; }); 701 702 assertNull(r); 703 assertTrue(called[0]); 704 checkEntries(map.entrySet(), entry(k1b, v1b), 705 entry(k2, v2)); 706 } 707 708 // merge 709 @Test testMergeAbsent()710 public void testMergeAbsent() { 711 boolean[] called = new boolean[1]; 712 Box newKey = new Box(k1a); 713 Box newVal = new Box(v1a); 714 Box r = map.merge(newKey, newVal, (v1, v2) -> { called[0] = true; return newVal; }); 715 716 assertSame(r, newVal); 717 assertFalse(called[0]); 718 checkEntries(map.entrySet(), entry(k1a, v1a), 719 entry(k1b, v1b), 720 entry(k2, v2), 721 entry(newKey, newVal)); 722 } 723 724 // merge 725 @Test testMergePresent()726 public void testMergePresent() { 727 boolean[] called = new boolean[1]; 728 Box val2 = new Box(47); 729 Box[] mergedVal = new Box[1]; 730 Box r = map.merge(k1a, val2, (v1, v2) -> { 731 called[0] = true; 732 mergedVal[0] = new Box(v1.i + v2.i); 733 return mergedVal[0]; 734 }); 735 736 assertSame(r, mergedVal[0]); 737 assertTrue(called[0]); 738 checkEntries(map.entrySet(), entry(k1a, mergedVal[0]), 739 entry(k1b, v1b), 740 entry(k2, v2)); 741 } 742 743 // forEach 744 @Test testForEach()745 public void testForEach() { 746 @SuppressWarnings("unchecked") 747 List<Map.Entry<Box, Box>> entries = new ArrayList<>(); 748 map.forEach((k, v) -> entries.add(entry(k, v))); 749 checkEntries(entries, entry(k1a, v1a), 750 entry(k1b, v1b), 751 entry(k2, v2)); 752 } 753 754 // replaceAll 755 @Test testReplaceAll()756 public void testReplaceAll() { 757 List<Map.Entry<Box, Box>> replacements = new ArrayList<>(); 758 759 map.replaceAll((k, v) -> { 760 Box v1 = new Box(v); 761 replacements.add(entry(k, v1)); 762 return v1; 763 }); 764 765 @SuppressWarnings("unchecked") 766 var replacementArray = (Map.Entry<Box, Box>[]) replacements.toArray(Map.Entry[]::new); 767 checkEntries(map.entrySet(), replacementArray); 768 } 769 } 770