| /* | |
| * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.IdentityHashMap; | |
| import java.util.Set; | |
| import java.util.function.BiPredicate; | |
| import java.util.stream.IntStream; | |
| import org.testng.annotations.BeforeMethod; | |
| import org.testng.annotations.Test; | |
| import static java.util.Map.entry; | |
| import static org.testng.Assert.*; | |
| /* | |
| * @test | |
| * @bug 8285295 8178355 | |
| * @summary Basic tests for IdentityHashMap | |
| * @run testng Basic | |
| */ | |
| // NOTE: avoid using TestNG's assertEquals/assertNotEquals directly on two IDHM instances, | |
| // as its logic for testing collections equality is suspect. Use checkEntries() to assert | |
| // that a map's entrySet contains exactly the expected mappings. There are no guarantees about | |
| // the identities of Map.Entry instances obtained from the entrySet; however, the keys and | |
| // values they contain are guaranteed to have the right identity. | |
| // TODO add tests using null keys and values | |
| // TODO deeper testing of view collections including iterators, equals, contains, etc. | |
| // TODO Map.Entry::setValue | |
| public class Basic { | |
| /* | |
| * Helpers | |
| */ | |
| record Box(int i) { | |
| Box(Box other) { | |
| this(other.i()); | |
| } | |
| } | |
| // Checks that a collection contains exactly the given elements and no others, using the | |
| // provided predicate for equivalence. Checking is performed both using contains() on the | |
| // collection and by simple array searching. The latter is O(N^2) so is suitable only for | |
| // small arrays. No two of the given elements can be equivalent according to the predicate. | |
| // TODO: read out the elements using iterator and stream and check them too | |
| @SafeVarargs | |
| private <E> void checkContents(Collection<E> c, BiPredicate<E,E> p, E... given) { | |
| @SuppressWarnings("unchecked") | |
| E[] contents = (E[]) c.toArray(); | |
| assertEquals(c.size(), given.length); | |
| assertEquals(contents.length, given.length); | |
| final int LEN = given.length; | |
| for (E e : given) { | |
| assertTrue(c.contains(e)); | |
| } | |
| // Fill indexes array with position of a given element in the contents array, | |
| // or -1 if the given element cannot be found. | |
| int[] indexes = new int[LEN]; | |
| outer: | |
| for (int i = 0; i < LEN; i++) { | |
| for (int j = 0; j < LEN; j++) { | |
| if (p.test(given[i], contents[j])) { | |
| indexes[i] = j; | |
| continue outer; | |
| } | |
| } | |
| indexes[i] = -1; | |
| } | |
| // If every given element matches a distinct element in the contents array, | |
| // the sorted indexes array will be the sequence [0..LEN-1]. | |
| Arrays.sort(indexes); | |
| assertEquals(indexes, IntStream.range(0, LEN).toArray()); | |
| } | |
| // Checks that the collection contains the given boxes, by identity. | |
| private void checkElements(Collection<Box> c, Box... given) { | |
| checkContents(c, (b1, b2) -> b1 == b2, given); | |
| } | |
| // Checks that the collection contains entries that have identical keys and values. | |
| // The entries themselves are not checked for identity. | |
| @SafeVarargs | |
| private void checkEntries(Collection<Map.Entry<Box, Box>> c, Map.Entry<Box, Box>... given) { | |
| checkContents(c, (e1, e2) -> e1.getKey() == e2.getKey() && e1.getValue() == e2.getValue(), given); | |
| } | |
| /* | |
| * Setup | |
| */ | |
| final Box k1a = new Box(17); | |
| final Box k1b = new Box(17); // equals but != k1a | |
| final Box k2 = new Box(42); | |
| final Box v1a = new Box(30); | |
| final Box v1b = new Box(30); // equals but != v1a | |
| final Box v2 = new Box(99); | |
| IdentityHashMap<Box, Box> map; | |
| IdentityHashMap<Box, Box> map2; | |
| @BeforeMethod | |
| public void setup() { | |
| map = new IdentityHashMap<>(); | |
| map.put(k1a, v1a); | |
| map.put(k1b, v1b); | |
| map.put(k2, v2); | |
| map2 = new IdentityHashMap<>(); | |
| map2.put(k1a, v1a); | |
| map2.put(k1b, v1b); | |
| map2.put(k2, v2); | |
| } | |
| /* | |
| * Tests | |
| */ | |
| // containsKey | |
| // containsValue | |
| // size | |
| @Test | |
| public void testSizeContainsKeyValue() { | |
| assertEquals(map.size(), 3); | |
| assertTrue(map.containsKey(k1a)); | |
| assertTrue(map.containsKey(k1b)); | |
| assertTrue(map.containsKey(k2)); | |
| assertFalse(map.containsKey(new Box(k1a))); | |
| assertTrue(map.containsValue(v1a)); | |
| assertTrue(map.containsValue(v1b)); | |
| assertFalse(map.containsValue(new Box(v1a))); | |
| assertTrue(map.containsValue(v2)); | |
| } | |
| // get | |
| @Test | |
| public void testGet() { | |
| assertSame(map.get(k1a), v1a); | |
| assertSame(map.get(k1b), v1b); | |
| assertSame(map.get(k2), v2); | |
| assertNull(map.get(new Box(k1a))); | |
| } | |
| // getOrDefault | |
| @Test | |
| public void testGetOrDefault() { | |
| Box other = new Box(22); | |
| assertSame(map.getOrDefault(k1a, other), v1a); | |
| assertSame(map.getOrDefault(k1b, other), v1b); | |
| assertSame(map.getOrDefault(new Box(k1a), other), other); | |
| assertSame(map.getOrDefault(k2, other), v2); | |
| } | |
| // clear | |
| // isEmpty | |
| @Test | |
| public void testClearEmpty() { | |
| assertFalse(map.isEmpty()); | |
| map.clear(); | |
| assertTrue(map.isEmpty()); | |
| } | |
| // hashCode | |
| @Test | |
| public void testHashCode() { | |
| int expected = (System.identityHashCode(k1a) ^ System.identityHashCode(v1a)) + | |
| (System.identityHashCode(k1b) ^ System.identityHashCode(v1b)) + | |
| (System.identityHashCode(k2) ^ System.identityHashCode(v2)); | |
| assertEquals(map.hashCode(), expected); | |
| assertEquals(map.entrySet().hashCode(), expected); | |
| } | |
| // equals | |
| @Test | |
| public void testEquals() { | |
| assertTrue(map.equals(map)); | |
| assertTrue(map.equals(map2)); | |
| assertTrue(map2.equals(map)); | |
| assertTrue(map.keySet().equals(map.keySet())); | |
| assertTrue(map.keySet().equals(map2.keySet())); | |
| assertTrue(map2.keySet().equals(map.keySet())); | |
| assertTrue(map.entrySet().equals(map.entrySet())); | |
| assertTrue(map.entrySet().equals(map2.entrySet())); | |
| assertTrue(map2.entrySet().equals(map.entrySet())); | |
| } | |
| // equals | |
| @Test | |
| public void testEqualsDifferentKey() { | |
| map2.remove(k1a); | |
| map2.put(new Box(k1a), v1a); | |
| assertFalse(map.equals(map2)); | |
| assertFalse(map2.equals(map)); | |
| assertFalse(map.keySet().equals(map2.keySet())); | |
| assertFalse(map2.keySet().equals(map.keySet())); | |
| assertFalse(map.entrySet().equals(map2.entrySet())); | |
| assertFalse(map2.entrySet().equals(map.entrySet())); | |
| } | |
| // equals | |
| @Test | |
| public void testEqualsDifferentValue() { | |
| map2.put(k1a, new Box(v1a)); | |
| assertFalse(map.equals(map2)); | |
| assertFalse(map2.equals(map)); | |
| assertTrue(map.keySet().equals(map2.keySet())); | |
| assertTrue(map2.keySet().equals(map.keySet())); | |
| assertFalse(map.entrySet().equals(map2.entrySet())); | |
| assertFalse(map2.entrySet().equals(map.entrySet())); | |
| } | |
| // equals | |
| @Test | |
| public void testEqualsNewMapping() { | |
| map.put(new Box(k1a), new Box(v1a)); | |
| assertFalse(map.equals(map2)); | |
| assertFalse(map2.equals(map)); | |
| assertFalse(map.keySet().equals(map2.keySet())); | |
| assertFalse(map2.keySet().equals(map.keySet())); | |
| assertFalse(map.entrySet().equals(map2.entrySet())); | |
| assertFalse(map2.entrySet().equals(map.entrySet())); | |
| } | |
| // equals | |
| @Test | |
| public void testEqualsMissingMapping() { | |
| var tmp = new IdentityHashMap<Box, Box>(); | |
| tmp.put(k1a, v1a); | |
| tmp.put(k1b, v1b); | |
| assertFalse(map.equals(tmp)); | |
| assertFalse(tmp.equals(map)); | |
| assertFalse(map.keySet().equals(tmp.keySet())); | |
| assertFalse(tmp.keySet().equals(map.keySet())); | |
| assertFalse(map.entrySet().equals(tmp.entrySet())); | |
| assertFalse(tmp.entrySet().equals(map.entrySet())); | |
| } | |
| // keySet equals, contains | |
| @Test | |
| public void testKeySet() { | |
| Set<Box> keySet = map.keySet(); | |
| checkElements(keySet, k1a, k1b, k2); | |
| assertFalse(keySet.contains(new Box(k1a))); | |
| assertTrue(map.keySet().equals(map2.keySet())); | |
| assertTrue(map2.keySet().equals(map.keySet())); | |
| } | |
| // keySet remove | |
| @Test | |
| public void testKeySetNoRemove() { | |
| Set<Box> keySet = map.keySet(); | |
| boolean r = keySet.remove(new Box(k1a)); | |
| assertFalse(r); | |
| checkElements(keySet, k1a, k1b, k2); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| assertTrue(map.keySet().equals(map2.keySet())); | |
| assertTrue(map2.keySet().equals(map.keySet())); | |
| } | |
| // keySet remove | |
| @Test | |
| public void testKeySetRemove() { | |
| Set<Box> keySet = map.keySet(); | |
| boolean r = keySet.remove(k1a); | |
| assertTrue(r); | |
| checkElements(keySet, k1b, k2); | |
| checkEntries(map.entrySet(), entry(k1b, v1b), | |
| entry(k2, v2)); | |
| assertFalse(map.keySet().equals(map2.keySet())); | |
| assertFalse(map2.keySet().equals(map.keySet())); | |
| } | |
| // values | |
| @Test | |
| public void testValues() { | |
| Collection<Box> values = map.values(); | |
| checkElements(values, v1a, v1b, v2); | |
| assertFalse(values.contains(new Box(v1a))); | |
| } | |
| // values remove | |
| @Test | |
| public void testValuesNoRemove() { | |
| Collection<Box> values = map.values(); | |
| boolean r = values.remove(new Box(v1a)); | |
| assertFalse(r); | |
| checkElements(values, v1a, v1b, v2); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // values remove | |
| @Test | |
| public void testValuesRemove() { | |
| Collection<Box> values = map.values(); | |
| boolean r = values.remove(v1a); | |
| assertTrue(r); | |
| checkElements(values, v1b, v2); | |
| checkEntries(map.entrySet(), entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // entrySet equals, contains | |
| @Test | |
| public void testEntrySet() { | |
| Set<Map.Entry<Box,Box>> entrySet = map.entrySet(); | |
| assertFalse(entrySet.contains(entry(new Box(k1a), v1a))); | |
| assertFalse(entrySet.contains(entry(k1b, new Box(v1b)))); | |
| assertFalse(entrySet.contains(entry(new Box(k2), new Box(v2)))); | |
| assertTrue(map.entrySet().equals(map2.entrySet())); | |
| checkEntries(entrySet, entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // entrySet remove | |
| @Test | |
| public void testEntrySetNoRemove() { | |
| Set<Map.Entry<Box, Box>> entrySet = map.entrySet(); | |
| boolean r1 = entrySet.remove(entry(new Box(k1a), v1a)); | |
| boolean r2 = entrySet.remove(entry(k1a, new Box(v1a))); | |
| assertFalse(r1); | |
| assertFalse(r2); | |
| assertTrue(entrySet.equals(map2.entrySet())); | |
| checkEntries(entrySet, entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // entrySet remove | |
| @Test | |
| public void testEntrySetRemove() { | |
| Set<Map.Entry<Box, Box>> entrySet = map.entrySet(); | |
| boolean r = entrySet.remove(Map.entry(k1a, v1a)); | |
| assertTrue(r); | |
| assertFalse(entrySet.equals(map2.entrySet())); | |
| assertFalse(map.entrySet().equals(map2.entrySet())); | |
| checkEntries(entrySet, entry(k1b, v1b), | |
| entry(k2, v2)); | |
| checkEntries(map.entrySet(), entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // put | |
| @Test | |
| public void testPutNew() { | |
| Box newKey = new Box(k1a); | |
| Box newVal = new Box(v1a); | |
| Box r = map.put(newKey, newVal); | |
| assertNull(r); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2), | |
| entry(newKey, newVal)); | |
| } | |
| // put | |
| @Test | |
| public void testPutOverwrite() { | |
| Box newVal = new Box(v1a); | |
| Box r = map.put(k1a, newVal); | |
| assertSame(r, v1a); | |
| checkEntries(map.entrySet(), entry(k1a, newVal), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // putAll | |
| @Test | |
| public void testPutAll() { | |
| Box newKey = new Box(k1a); | |
| Box newVal = new Box(v1a); | |
| Box newValB = new Box(v1b); | |
| var argMap = new IdentityHashMap<Box, Box>(); | |
| argMap.put(newKey, newVal); // new entry | |
| argMap.put(k1b, newValB); // will overwrite value | |
| map.putAll(argMap); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, newValB), | |
| entry(k2, v2), | |
| entry(newKey, newVal)); | |
| } | |
| // putIfAbsent | |
| @Test | |
| public void testPutIfAbsentNoop() { | |
| Box r = map.putIfAbsent(k1a, new Box(v1a)); // no-op | |
| assertSame(r, v1a); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // putIfAbsent | |
| @Test | |
| public void testPutIfAbsentAddsNew() { | |
| Box newKey = new Box(k1a); | |
| Box newVal = new Box(v1a); | |
| Box r = map.putIfAbsent(newKey, newVal); // adds new entry | |
| assertNull(r); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2), | |
| entry(newKey, newVal)); | |
| } | |
| // remove(Object) | |
| @Test | |
| public void testRemoveKey() { | |
| Box r = map.remove(k1b); | |
| assertSame(r, v1b); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k2, v2)); | |
| } | |
| // remove(Object, Object) absent key, absent value | |
| @Test | |
| public void testRemoveAA() { | |
| Box k1c = new Box(k1a); | |
| Box v1c = new Box(v1a); | |
| assertFalse(map.remove(k1c, v1c)); | |
| checkEntries(map.entrySet(), | |
| entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // remove(Object, Object) absent key, present value | |
| @Test | |
| public void testRemoveAV() { | |
| Box k1c = new Box(k1a); | |
| assertFalse(map.remove(k1c, v1a)); | |
| checkEntries(map.entrySet(), | |
| entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // remove(Object, Object) present key, absent value | |
| @Test | |
| public void testRemoveKA() { | |
| Box v1c = new Box(v1a); | |
| assertFalse(map.remove(k1a, v1c)); | |
| checkEntries(map.entrySet(), | |
| entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // remove(Object, Object) present key, present value | |
| @Test | |
| public void testRemoveKV() { | |
| assertTrue(map.remove(k1a, v1a)); | |
| checkEntries(map.entrySet(), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // replace(K, V, V) absent key, absent oldValue | |
| @Test | |
| public void testReplaceAA() { | |
| Box k1c = new Box(k1a); | |
| Box v1c = new Box(v1a); | |
| Box newVal = new Box(v2); | |
| assertFalse(map.replace(k1c, v1c, newVal)); | |
| checkEntries(map.entrySet(), | |
| entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // replace(K, V, V) absent key, present oldValue | |
| @Test | |
| public void testReplaceAV() { | |
| Box k1c = new Box(k1a); | |
| Box newVal = new Box(v2); | |
| assertFalse(map.replace(k1c, v1a, newVal)); | |
| checkEntries(map.entrySet(), | |
| entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // replace(K, V, V) present key, absent oldValue | |
| @Test | |
| public void testReplaceKA() { | |
| Box v1c = new Box(v1a); | |
| Box newVal = new Box(v2); | |
| assertFalse(map.replace(k1a, v1c, newVal)); | |
| checkEntries(map.entrySet(), | |
| entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // replace(K, V, V) present key, present oldValue | |
| @Test | |
| public void testReplaceKV() { | |
| Box newVal = new Box(v2); | |
| assertTrue(map.replace(k1a, v1a, newVal)); | |
| checkEntries(map.entrySet(), | |
| entry(k1a, newVal), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // AN: key absent, remappingFunction returns null | |
| @Test | |
| public void testComputeAN() { | |
| Box newKey = new Box(k1a); | |
| Box r = map.compute(newKey, (k, v) -> null); | |
| assertNull(r); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // AV: key absent, remappingFunction returns non-null value | |
| @Test | |
| public void testComputeAV() { | |
| Box newKey = new Box(k1a); | |
| Box newVal = new Box(v1a); | |
| Box r = map.compute(newKey, (k, v) -> newVal); | |
| assertSame(r, newVal); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2), | |
| entry(newKey, newVal)); | |
| } | |
| // PN: key present, remappingFunction returns null | |
| @Test | |
| public void testComputePN() { | |
| Box r = map.compute(k1a, (k, v) -> null); | |
| assertNull(r); | |
| checkEntries(map.entrySet(), entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // PV: key present, remappingFunction returns non-null value | |
| @Test | |
| public void testComputePV() { | |
| Box newVal = new Box(v1a); | |
| Box r = map.compute(k1a, (k, v) -> newVal); | |
| assertSame(r, newVal); | |
| checkEntries(map.entrySet(), entry(k1a, newVal), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // computeIfAbsent | |
| @Test | |
| public void testComputeIfAbsentIsCalled() { | |
| boolean[] called = new boolean[1]; | |
| Box newKey = new Box(k1a); | |
| Box newVal = new Box(v1a); | |
| Box r = map.computeIfAbsent(newKey, k -> { called[0] = true; return newVal; }); | |
| assertSame(r, newVal); | |
| assertTrue(called[0]); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2), | |
| entry(newKey, newVal)); | |
| } | |
| // computeIfAbsent | |
| @Test | |
| public void testComputeIfAbsentNotCalled() { | |
| boolean[] called = new boolean[1]; | |
| Box r = map.computeIfAbsent(k1a, k -> { called[0] = true; return null; }); | |
| assertSame(r, v1a); | |
| assertFalse(called[0]); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // computeIfAbsent | |
| @Test | |
| public void testComputeIfAbsentNullReturn() { | |
| boolean[] called = new boolean[1]; | |
| Box newKey = new Box(k1a); | |
| Box r = map.computeIfAbsent(newKey, k -> { called[0] = true; return null; }); | |
| assertNull(r); | |
| assertTrue(called[0]); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // computeIfPresent | |
| @Test | |
| public void testComputeIfPresentIsCalled() { | |
| boolean[] called = new boolean[1]; | |
| Box newVal = new Box(v1a); | |
| Box r = map.computeIfPresent(k1a, (k, v) -> { called[0] = true; return newVal; }); | |
| assertSame(r, newVal); | |
| assertTrue(called[0]); | |
| checkEntries(map.entrySet(), entry(k1a, newVal), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // computeIfPresent | |
| @Test | |
| public void testComputeIfPresentNotCalled() { | |
| boolean[] called = new boolean[1]; | |
| Box r = map.computeIfPresent(new Box(k1a), (k, v) -> { called[0] = true; return null; }); | |
| assertNull(r); | |
| assertFalse(called[0]); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // computeIfPresent | |
| @Test | |
| public void testComputeIfPresentNullReturn() { | |
| boolean[] called = new boolean[1]; | |
| Box r = map.computeIfPresent(k1a, (k, v) -> { called[0] = true; return null; }); | |
| assertNull(r); | |
| assertTrue(called[0]); | |
| checkEntries(map.entrySet(), entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // merge | |
| @Test | |
| public void testMergeAbsent() { | |
| boolean[] called = new boolean[1]; | |
| Box newKey = new Box(k1a); | |
| Box newVal = new Box(v1a); | |
| Box r = map.merge(newKey, newVal, (v1, v2) -> { called[0] = true; return newVal; }); | |
| assertSame(r, newVal); | |
| assertFalse(called[0]); | |
| checkEntries(map.entrySet(), entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2), | |
| entry(newKey, newVal)); | |
| } | |
| // merge | |
| @Test | |
| public void testMergePresent() { | |
| boolean[] called = new boolean[1]; | |
| Box val2 = new Box(47); | |
| Box[] mergedVal = new Box[1]; | |
| Box r = map.merge(k1a, val2, (v1, v2) -> { | |
| called[0] = true; | |
| mergedVal[0] = new Box(v1.i + v2.i); | |
| return mergedVal[0]; | |
| }); | |
| assertSame(r, mergedVal[0]); | |
| assertTrue(called[0]); | |
| checkEntries(map.entrySet(), entry(k1a, mergedVal[0]), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // forEach | |
| @Test | |
| public void testForEach() { | |
| @SuppressWarnings("unchecked") | |
| List<Map.Entry<Box, Box>> entries = new ArrayList<>(); | |
| map.forEach((k, v) -> entries.add(entry(k, v))); | |
| checkEntries(entries, entry(k1a, v1a), | |
| entry(k1b, v1b), | |
| entry(k2, v2)); | |
| } | |
| // replaceAll | |
| @Test | |
| public void testReplaceAll() { | |
| List<Map.Entry<Box, Box>> replacements = new ArrayList<>(); | |
| map.replaceAll((k, v) -> { | |
| Box v1 = new Box(v); | |
| replacements.add(entry(k, v1)); | |
| return v1; | |
| }); | |
| @SuppressWarnings("unchecked") | |
| var replacementArray = (Map.Entry<Box, Box>[]) replacements.toArray(Map.Entry[]::new); | |
| checkEntries(map.entrySet(), replacementArray); | |
| } | |
| } |