53905e600a
Reviewed-by: smarks
768 lines
24 KiB
Java
768 lines
24 KiB
Java
/*
|
|
* 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);
|
|
}
|
|
}
|