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 */
36 import java.util.Collections;
37 import java.util.EnumMap;
38 import java.util.HashMap;
39 import java.util.Hashtable;
40 import java.util.HashSet;
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.concurrent.atomic.AtomicBoolean;
52 import java.util.function.BiFunction;
53 import java.util.function.Function;
54 import java.util.function.Supplier;
55
56 import org.testng.annotations.Test;
57 import org.testng.annotations.DataProvider;
58 import static java.util.Objects.requireNonNull;
59 import static org.testng.Assert.fail;
60 import static org.testng.Assert.assertEquals;
61 import static org.testng.Assert.assertTrue;
62 import static org.testng.Assert.assertFalse;
63 import static org.testng.Assert.assertNull;
64 import static org.testng.Assert.assertSame;
65
66 public class Defaults {
67
68 @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull")
69 public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) {
70 assertTrue(map.containsKey(null), description + ": null key absent");
71 assertNull(map.get(null), description + ": value not null");
72 assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), description + ": values should match");
73 }
74
75 @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
76 public void testGetOrDefault(String description, Map<IntegerEnum, String> map) {
77 assertTrue(map.containsKey(KEYS[1]), "expected key missing");
78 assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match");
79 assertFalse(map.containsKey(EXTRA_KEY), "expected absent key");
80 assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default");
81 assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default");
82 }
83
84 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
142 Set<String> EACH_REPLACE = new HashSet<>(map.size());
143
144 map.replaceAll((k,v) -> {
145 int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
146 assertNull(EACH_KEY[idx]);
147 EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
148 assertSame(v, map.get(k));
149 String replacement = v + " replaced";
150 EACH_REPLACE.add(replacement);
151 return replacement;
152 });
153
154 assertEquals(KEYS, EACH_KEY, description);
155 assertEquals(map.values().size(), EACH_REPLACE.size(), description + EACH_REPLACE);
156 assertTrue(EACH_REPLACE.containsAll(map.values()), description + " : " + EACH_REPLACE + " != " + map.values());
157 assertTrue(map.values().containsAll(EACH_REPLACE), description + " : " + EACH_REPLACE + " != " + map.values());
158 }
159
160 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
161 public static void testReplaceAllNoNullReplacement(String description, Map<IntegerEnum, String> map) {
162 assertThrows(
163 () -> { map.replaceAll(null); },
164 NullPointerException.class,
165 description);
166 assertThrows(
167 () -> { map.replaceAll((k,v) -> null); },
168 NullPointerException.class,
169 description + " should not allow replacement with null value");
170 }
171
172 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
173 public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) {
174 assertTrue(map.containsKey(null), "null key absent");
175 assertNull(map.get(null), "value not null");
176 assertFalse(map.remove(null, EXTRA_VALUE), description);
177 assertTrue(map.containsKey(null));
178 assertNull(map.get(null));
179 assertTrue(map.remove(null, null));
180 assertFalse(map.containsKey(null));
181 assertNull(map.get(null));
182 assertFalse(map.remove(null, null));
183 }
184
185 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
186 public static void testRemove(String description, Map<IntegerEnum, String> map) {
187 assertTrue(map.containsKey(KEYS[1]));
188 Object expected = map.get(KEYS[1]);
189 assertTrue(null == expected || expected == VALUES[1]);
192 assertTrue(map.remove(KEYS[1], expected));
193 assertNull(map.get(KEYS[1]));
194 assertFalse(map.remove(KEYS[1], expected));
195
196 assertFalse(map.containsKey(EXTRA_KEY));
197 assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE));
198 }
199
200 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
201 public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) {
202 assertTrue(map.containsKey(null), "null key absent");
203 assertNull(map.get(null), "value not null");
204 assertSame(map.replace(null, EXTRA_VALUE), null);
205 assertSame(map.get(null), EXTRA_VALUE);
206 }
207
208 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
209 public void testReplaceKVNoNulls(String description, Map<IntegerEnum, String> map) {
210 assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
211 assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
212 assertThrows( () -> {map.replace(FIRST_KEY, null);}, NullPointerException.class, description + ": should throw NPE");
213 assertSame(map.replace(FIRST_KEY, EXTRA_VALUE), FIRST_VALUE, description + ": replaced wrong value");
214 assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
215 }
216
217 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
218 public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
219 assertTrue(map.containsKey(KEYS[1]));
220 Object expected = map.get(KEYS[1]);
221 assertTrue(null == expected || expected == VALUES[1]);
222 assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected);
223 assertSame(map.get(KEYS[1]), EXTRA_VALUE);
224
225 assertFalse(map.containsKey(EXTRA_KEY));
226 assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE));
227 assertFalse(map.containsKey(EXTRA_KEY));
228 assertNull(map.get(EXTRA_KEY));
229 assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
230 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
231 assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE);
232 assertSame(map.get(EXTRA_KEY), expected);
233 }
234
235 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
236 public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) {
237 assertTrue(map.containsKey(null), "null key absent");
238 assertNull(map.get(null), "value not null");
239 assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
240 assertNull(map.get(null));
241 assertTrue(map.replace(null, null, EXTRA_VALUE));
242 assertSame(map.get(null), EXTRA_VALUE);
243 assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
244 assertSame(map.get(null), EXTRA_VALUE);
245 }
246
247 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
248 public void testReplaceKVVNoNulls(String description, Map<IntegerEnum, String> map) {
249 assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
250 assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
251 assertThrows( () -> {map.replace(FIRST_KEY, FIRST_VALUE, null);}, NullPointerException.class, description + ": should throw NPE");
252 assertThrows( () -> {if (!map.replace(FIRST_KEY, null, EXTRA_VALUE)) throw new NullPointerException("default returns false rather than throwing");}, NullPointerException.class, description + ": should throw NPE");
253 assertTrue(map.replace(FIRST_KEY, FIRST_VALUE, EXTRA_VALUE), description + ": replaced wrong value");
254 assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
255 }
256
257 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
258 public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
259 assertTrue(map.containsKey(KEYS[1]));
260 Object expected = map.get(KEYS[1]);
261 assertTrue(null == expected || expected == VALUES[1]);
262 assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
263 assertSame(map.get(KEYS[1]), expected);
264 assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE));
265 assertSame(map.get(KEYS[1]), EXTRA_VALUE);
266 assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
267 assertSame(map.get(KEYS[1]), EXTRA_VALUE);
268
269 assertFalse(map.containsKey(EXTRA_KEY));
270 assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
271 assertFalse(map.containsKey(EXTRA_KEY));
272 assertNull(map.get(EXTRA_KEY));
302 public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
303 // 1 -> 1
304 assertTrue(map.containsKey(KEYS[1]));
305 Object expected = map.get(KEYS[1]);
306 assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
307 expected = (null == expected) ? EXTRA_VALUE : expected;
308 assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
309 assertSame(map.get(KEYS[1]), expected, description);
310
311 // EXTRA_KEY -> <absent>
312 assertFalse(map.containsKey(EXTRA_KEY));
313 assertNull(map.computeIfAbsent(EXTRA_KEY, (k) -> null));
314 assertFalse(map.containsKey(EXTRA_KEY));
315 assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
316 // EXTRA_KEY -> EXTRA_VALUE
317 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
318 }
319
320 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
321 public void testComputeIfAbsentNullFunction(String description, Map<IntegerEnum, String> map) {
322 assertThrows( () -> { map.computeIfAbsent(KEYS[1], null);},
323 NullPointerException.class,
324 "Should throw NPE");
325 }
326
327 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
328 public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
329 assertTrue(map.containsKey(null), description + ": null key absent");
330 assertNull(map.get(null), description + ": value not null");
331 assertSame(map.computeIfPresent(null, (k, v) -> {
332 fail(description + ": null value is not deemed present");
333 return EXTRA_VALUE;
334 }), null, description);
335 assertTrue(map.containsKey(null));
336 assertNull(map.get(null), description);
337 assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
338 assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
339 assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
340 fail(description + ": null value is not deemed present");
341 return EXTRA_VALUE;
342 }), null, description);
343 assertNull(map.get(EXTRA_KEY), description + ": null mapping gone");
344 }
349 Object value = map.get(KEYS[1]);
350 assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
351 Object expected = (null == value) ? null : EXTRA_VALUE;
352 assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
353 assertSame(v, value);
354 return EXTRA_VALUE;
355 }), expected, description);
356 assertSame(map.get(KEYS[1]), expected, description);
357
358 assertFalse(map.containsKey(EXTRA_KEY));
359 assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
360 fail();
361 return EXTRA_VALUE;
362 }), null);
363 assertFalse(map.containsKey(EXTRA_KEY));
364 assertSame(map.get(EXTRA_KEY), null);
365 }
366
367 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
368 public void testComputeIfPresentNullFunction(String description, Map<IntegerEnum, String> map) {
369 assertThrows( () -> { map.computeIfPresent(KEYS[1], null);},
370 NullPointerException.class,
371 "Should throw NPE");
372 }
373
374 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
375 public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
376 assertTrue(map.containsKey(null), "null key absent");
377 assertNull(map.get(null), "value not null");
378 assertSame(map.compute(null, (k, v) -> {
379 assertNull(k);
380 assertNull(v);
381 return null;
382 }), null, description);
383 assertFalse(map.containsKey(null), description + ": null key present.");
384 assertSame(map.compute(null, (k, v) -> {
385 assertSame(k, null);
386 assertNull(v);
387 return EXTRA_VALUE;
388 }), EXTRA_VALUE, description);
389 assertTrue(map.containsKey(null));
390 assertSame(map.get(null), EXTRA_VALUE, description);
391 assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected");
442 return EXTRA_VALUE;
443 }), EXTRA_VALUE, description);
444 assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
445 assertNull(map.compute(KEYS[1], (k, v) -> {
446 assertSame(v, EXTRA_VALUE);
447 return null;
448 }), description);
449 assertFalse(map.containsKey(KEYS[1]));
450
451 assertFalse(map.containsKey(EXTRA_KEY));
452 assertSame(map.compute(EXTRA_KEY, (k, v) -> {
453 assertNull(v);
454 return EXTRA_VALUE;
455 }), EXTRA_VALUE);
456 assertTrue(map.containsKey(EXTRA_KEY));
457 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
458 }
459
460 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
461 public void testComputeNullFunction(String description, Map<IntegerEnum, String> map) {
462 assertThrows( () -> { map.compute(KEYS[1], null);},
463 NullPointerException.class,
464 "Should throw NPE");
465 }
466
467 @Test(dataProvider = "MergeCases")
468 private void testMerge(String description, Map<IntegerEnum, String> map, Merging.Value oldValue, Merging.Value newValue, Merging.Merger merger, Merging.Value put, Merging.Value result) {
469 // add and check initial conditions.
470 switch (oldValue) {
471 case ABSENT :
472 map.remove(EXTRA_KEY);
473 assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
474 break;
475 case NULL :
476 map.put(EXTRA_KEY, null);
477 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
478 assertNull(map.get(EXTRA_KEY), "wrong value");
479 break;
480 case OLDVALUE :
481 map.put(EXTRA_KEY, VALUES[1]);
482 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
483 assertSame(map.get(EXTRA_KEY), VALUES[1], "wrong value");
484 break;
514 break;
515 case NULL :
516 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
517 assertNull(map.get(EXTRA_KEY), "wrong value");
518 break;
519 case NEWVALUE :
520 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
521 assertSame(map.get(EXTRA_KEY), VALUES[2], "wrong value");
522 break;
523 case RESULT :
524 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
525 assertSame(map.get(EXTRA_KEY), VALUES[3], "wrong value");
526 break;
527 default:
528 fail("unexpected new value");
529 }
530 }
531
532 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
533 public void testMergeNullMerger(String description, Map<IntegerEnum, String> map) {
534 assertThrows( () -> { map.merge(KEYS[1], VALUES[1], null);},
535 NullPointerException.class,
536 "Should throw NPE");
537 }
538
539 /** A function that flipflops between running two other functions. */
540 static <T,U,V> BiFunction<T,U,V> twoStep(AtomicBoolean b,
541 BiFunction<T,U,V> first,
542 BiFunction<T,U,V> second) {
543 return (t, u) -> {
544 boolean bb = b.get();
545 try {
546 return (b.get() ? first : second).apply(t, u);
547 } finally {
548 b.set(!bb);
549 }};
550 }
551
552 /**
553 * Simulates races by modifying the map within the mapping function.
554 */
555 @Test
556 public void testConcurrentMap_computeIfAbsent_racy() {
956 }
957
958 static Collection<Object[]> makeMergeTestCases() {
959 Collection<Object[]> cases = new ArrayList<>();
960
961 for (Object[] mapParams : makeAllRWMaps() ) {
962 cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
963 }
964
965 for (Object[] mapParams : makeAllRWMaps() ) {
966 cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
967 }
968
969 for (Object[] mapParams : makeAllRWMaps() ) {
970 cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
971 }
972
973 return cases;
974 }
975
976 public interface Thrower<T extends Throwable> {
977
978 public void run() throws T;
979 }
980
981 public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) {
982 assertThrows(thrower, throwable, null);
983 }
984
985 public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
986 Throwable thrown;
987 try {
988 thrower.run();
989 thrown = null;
990 } catch (Throwable caught) {
991 thrown = caught;
992 }
993
994 assertInstance(thrown, throwable,
995 ((null != message) ? message : "") +
996 " Failed to throw " + throwable.getCanonicalName());
997 }
998
999 public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) {
1000 for (Thrower<T> thrower : throwers) {
1001 assertThrows(thrower, throwable, message);
1002 }
1003 }
1004
1005 public static void assertInstance(Object actual, Class<?> expected) {
1006 assertInstance(expected.isInstance(actual), null);
1007 }
1008
1009 public static void assertInstance(Object actual, Class<?> expected, String message) {
1010 assertTrue(expected.isInstance(actual), message);
1011 }
1012
1013 /**
1014 * A simple mutable map implementation that provides only default
1015 * implementations of all methods. ie. none of the Map interface default
1016 * methods have overridden implementations.
1017 *
1018 * @param <K> Type of keys
1019 * @param <V> Type of values
1020 */
1021 public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K,V> {
1022
1023 protected final M map;
1024
1025 public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); }
1026
1027 protected ExtendsAbstractMap(M map) { this.map = map; }
1028
1029 @Override public Set<Map.Entry<K,V>> entrySet() {
1030 return new AbstractSet<Map.Entry<K,V>>() {
|
1 /*
2 * Copyright (c) 2013, 2017, 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 */
36 import java.util.Collections;
37 import java.util.EnumMap;
38 import java.util.HashMap;
39 import java.util.Hashtable;
40 import java.util.HashSet;
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.concurrent.atomic.AtomicBoolean;
52 import java.util.function.BiFunction;
53 import java.util.function.Function;
54 import java.util.function.Supplier;
55
56 import org.testng.Assert.ThrowingRunnable;
57 import org.testng.annotations.Test;
58 import org.testng.annotations.DataProvider;
59
60 import static java.util.Objects.requireNonNull;
61
62 import static org.testng.Assert.fail;
63 import static org.testng.Assert.assertEquals;
64 import static org.testng.Assert.assertTrue;
65 import static org.testng.Assert.assertFalse;
66 import static org.testng.Assert.assertNull;
67 import static org.testng.Assert.assertSame;
68 import static org.testng.Assert.assertThrows;
69
70 public class Defaults {
71
72 @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull")
73 public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) {
74 assertTrue(map.containsKey(null), description + ": null key absent");
75 assertNull(map.get(null), description + ": value not null");
76 assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), description + ": values should match");
77 }
78
79 @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
80 public void testGetOrDefault(String description, Map<IntegerEnum, String> map) {
81 assertTrue(map.containsKey(KEYS[1]), "expected key missing");
82 assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match");
83 assertFalse(map.containsKey(EXTRA_KEY), "expected absent key");
84 assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default");
85 assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default");
86 }
87
88 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
146 Set<String> EACH_REPLACE = new HashSet<>(map.size());
147
148 map.replaceAll((k,v) -> {
149 int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
150 assertNull(EACH_KEY[idx]);
151 EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
152 assertSame(v, map.get(k));
153 String replacement = v + " replaced";
154 EACH_REPLACE.add(replacement);
155 return replacement;
156 });
157
158 assertEquals(KEYS, EACH_KEY, description);
159 assertEquals(map.values().size(), EACH_REPLACE.size(), description + EACH_REPLACE);
160 assertTrue(EACH_REPLACE.containsAll(map.values()), description + " : " + EACH_REPLACE + " != " + map.values());
161 assertTrue(map.values().containsAll(EACH_REPLACE), description + " : " + EACH_REPLACE + " != " + map.values());
162 }
163
164 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
165 public static void testReplaceAllNoNullReplacement(String description, Map<IntegerEnum, String> map) {
166 assertThrowsNPE(() -> map.replaceAll(null));
167 assertThrowsNPE(() -> { map.replaceAll((k,v) -> null); });
168 }
169
170 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
171 public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) {
172 assertTrue(map.containsKey(null), "null key absent");
173 assertNull(map.get(null), "value not null");
174 assertFalse(map.remove(null, EXTRA_VALUE), description);
175 assertTrue(map.containsKey(null));
176 assertNull(map.get(null));
177 assertTrue(map.remove(null, null));
178 assertFalse(map.containsKey(null));
179 assertNull(map.get(null));
180 assertFalse(map.remove(null, null));
181 }
182
183 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
184 public static void testRemove(String description, Map<IntegerEnum, String> map) {
185 assertTrue(map.containsKey(KEYS[1]));
186 Object expected = map.get(KEYS[1]);
187 assertTrue(null == expected || expected == VALUES[1]);
190 assertTrue(map.remove(KEYS[1], expected));
191 assertNull(map.get(KEYS[1]));
192 assertFalse(map.remove(KEYS[1], expected));
193
194 assertFalse(map.containsKey(EXTRA_KEY));
195 assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE));
196 }
197
198 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
199 public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) {
200 assertTrue(map.containsKey(null), "null key absent");
201 assertNull(map.get(null), "value not null");
202 assertSame(map.replace(null, EXTRA_VALUE), null);
203 assertSame(map.get(null), EXTRA_VALUE);
204 }
205
206 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
207 public void testReplaceKVNoNulls(String description, Map<IntegerEnum, String> map) {
208 assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
209 assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
210 assertThrowsNPE(() -> map.replace(FIRST_KEY, null));
211 assertSame(map.replace(FIRST_KEY, EXTRA_VALUE), FIRST_VALUE, description + ": replaced wrong value");
212 assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
213 }
214
215 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
216 public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
217 assertTrue(map.containsKey(KEYS[1]));
218 Object expected = map.get(KEYS[1]);
219 assertTrue(null == expected || expected == VALUES[1]);
220 assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected);
221 assertSame(map.get(KEYS[1]), EXTRA_VALUE);
222
223 assertFalse(map.containsKey(EXTRA_KEY));
224 assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE));
225 assertFalse(map.containsKey(EXTRA_KEY));
226 assertNull(map.get(EXTRA_KEY));
227 assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
228 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
229 assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE);
230 assertSame(map.get(EXTRA_KEY), expected);
231 }
232
233 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
234 public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) {
235 assertTrue(map.containsKey(null), "null key absent");
236 assertNull(map.get(null), "value not null");
237 assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
238 assertNull(map.get(null));
239 assertTrue(map.replace(null, null, EXTRA_VALUE));
240 assertSame(map.get(null), EXTRA_VALUE);
241 assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
242 assertSame(map.get(null), EXTRA_VALUE);
243 }
244
245 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
246 public void testReplaceKVVNoNulls(String description, Map<IntegerEnum, String> map) {
247 assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
248 assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
249 assertThrowsNPE(() -> map.replace(FIRST_KEY, FIRST_VALUE, null));
250 assertThrowsNPE(
251 () -> {
252 if (!map.replace(FIRST_KEY, null, EXTRA_VALUE)) {
253 throw new NullPointerException("default returns false rather than throwing");
254 }
255 });
256 assertTrue(map.replace(FIRST_KEY, FIRST_VALUE, EXTRA_VALUE), description + ": replaced wrong value");
257 assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
258 }
259
260 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
261 public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
262 assertTrue(map.containsKey(KEYS[1]));
263 Object expected = map.get(KEYS[1]);
264 assertTrue(null == expected || expected == VALUES[1]);
265 assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
266 assertSame(map.get(KEYS[1]), expected);
267 assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE));
268 assertSame(map.get(KEYS[1]), EXTRA_VALUE);
269 assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
270 assertSame(map.get(KEYS[1]), EXTRA_VALUE);
271
272 assertFalse(map.containsKey(EXTRA_KEY));
273 assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
274 assertFalse(map.containsKey(EXTRA_KEY));
275 assertNull(map.get(EXTRA_KEY));
305 public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
306 // 1 -> 1
307 assertTrue(map.containsKey(KEYS[1]));
308 Object expected = map.get(KEYS[1]);
309 assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
310 expected = (null == expected) ? EXTRA_VALUE : expected;
311 assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
312 assertSame(map.get(KEYS[1]), expected, description);
313
314 // EXTRA_KEY -> <absent>
315 assertFalse(map.containsKey(EXTRA_KEY));
316 assertNull(map.computeIfAbsent(EXTRA_KEY, (k) -> null));
317 assertFalse(map.containsKey(EXTRA_KEY));
318 assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
319 // EXTRA_KEY -> EXTRA_VALUE
320 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
321 }
322
323 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
324 public void testComputeIfAbsentNullFunction(String description, Map<IntegerEnum, String> map) {
325 assertThrowsNPE(() -> map.computeIfAbsent(KEYS[1], null));
326 }
327
328 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
329 public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
330 assertTrue(map.containsKey(null), description + ": null key absent");
331 assertNull(map.get(null), description + ": value not null");
332 assertSame(map.computeIfPresent(null, (k, v) -> {
333 fail(description + ": null value is not deemed present");
334 return EXTRA_VALUE;
335 }), null, description);
336 assertTrue(map.containsKey(null));
337 assertNull(map.get(null), description);
338 assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
339 assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
340 assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
341 fail(description + ": null value is not deemed present");
342 return EXTRA_VALUE;
343 }), null, description);
344 assertNull(map.get(EXTRA_KEY), description + ": null mapping gone");
345 }
350 Object value = map.get(KEYS[1]);
351 assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
352 Object expected = (null == value) ? null : EXTRA_VALUE;
353 assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
354 assertSame(v, value);
355 return EXTRA_VALUE;
356 }), expected, description);
357 assertSame(map.get(KEYS[1]), expected, description);
358
359 assertFalse(map.containsKey(EXTRA_KEY));
360 assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
361 fail();
362 return EXTRA_VALUE;
363 }), null);
364 assertFalse(map.containsKey(EXTRA_KEY));
365 assertSame(map.get(EXTRA_KEY), null);
366 }
367
368 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
369 public void testComputeIfPresentNullFunction(String description, Map<IntegerEnum, String> map) {
370 assertThrowsNPE(() -> map.computeIfPresent(KEYS[1], null));
371 }
372
373 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
374 public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
375 assertTrue(map.containsKey(null), "null key absent");
376 assertNull(map.get(null), "value not null");
377 assertSame(map.compute(null, (k, v) -> {
378 assertNull(k);
379 assertNull(v);
380 return null;
381 }), null, description);
382 assertFalse(map.containsKey(null), description + ": null key present.");
383 assertSame(map.compute(null, (k, v) -> {
384 assertSame(k, null);
385 assertNull(v);
386 return EXTRA_VALUE;
387 }), EXTRA_VALUE, description);
388 assertTrue(map.containsKey(null));
389 assertSame(map.get(null), EXTRA_VALUE, description);
390 assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected");
441 return EXTRA_VALUE;
442 }), EXTRA_VALUE, description);
443 assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
444 assertNull(map.compute(KEYS[1], (k, v) -> {
445 assertSame(v, EXTRA_VALUE);
446 return null;
447 }), description);
448 assertFalse(map.containsKey(KEYS[1]));
449
450 assertFalse(map.containsKey(EXTRA_KEY));
451 assertSame(map.compute(EXTRA_KEY, (k, v) -> {
452 assertNull(v);
453 return EXTRA_VALUE;
454 }), EXTRA_VALUE);
455 assertTrue(map.containsKey(EXTRA_KEY));
456 assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
457 }
458
459 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
460 public void testComputeNullFunction(String description, Map<IntegerEnum, String> map) {
461 assertThrowsNPE(() -> map.compute(KEYS[1], null));
462 }
463
464 @Test(dataProvider = "MergeCases")
465 private void testMerge(String description, Map<IntegerEnum, String> map, Merging.Value oldValue, Merging.Value newValue, Merging.Merger merger, Merging.Value put, Merging.Value result) {
466 // add and check initial conditions.
467 switch (oldValue) {
468 case ABSENT :
469 map.remove(EXTRA_KEY);
470 assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
471 break;
472 case NULL :
473 map.put(EXTRA_KEY, null);
474 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
475 assertNull(map.get(EXTRA_KEY), "wrong value");
476 break;
477 case OLDVALUE :
478 map.put(EXTRA_KEY, VALUES[1]);
479 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
480 assertSame(map.get(EXTRA_KEY), VALUES[1], "wrong value");
481 break;
511 break;
512 case NULL :
513 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
514 assertNull(map.get(EXTRA_KEY), "wrong value");
515 break;
516 case NEWVALUE :
517 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
518 assertSame(map.get(EXTRA_KEY), VALUES[2], "wrong value");
519 break;
520 case RESULT :
521 assertTrue(map.containsKey(EXTRA_KEY), "key absent");
522 assertSame(map.get(EXTRA_KEY), VALUES[3], "wrong value");
523 break;
524 default:
525 fail("unexpected new value");
526 }
527 }
528
529 @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
530 public void testMergeNullMerger(String description, Map<IntegerEnum, String> map) {
531 assertThrowsNPE(() -> map.merge(KEYS[1], VALUES[1], null));
532 }
533
534 /** A function that flipflops between running two other functions. */
535 static <T,U,V> BiFunction<T,U,V> twoStep(AtomicBoolean b,
536 BiFunction<T,U,V> first,
537 BiFunction<T,U,V> second) {
538 return (t, u) -> {
539 boolean bb = b.get();
540 try {
541 return (b.get() ? first : second).apply(t, u);
542 } finally {
543 b.set(!bb);
544 }};
545 }
546
547 /**
548 * Simulates races by modifying the map within the mapping function.
549 */
550 @Test
551 public void testConcurrentMap_computeIfAbsent_racy() {
951 }
952
953 static Collection<Object[]> makeMergeTestCases() {
954 Collection<Object[]> cases = new ArrayList<>();
955
956 for (Object[] mapParams : makeAllRWMaps() ) {
957 cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
958 }
959
960 for (Object[] mapParams : makeAllRWMaps() ) {
961 cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
962 }
963
964 for (Object[] mapParams : makeAllRWMaps() ) {
965 cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
966 }
967
968 return cases;
969 }
970
971 public static void assertThrowsNPE(ThrowingRunnable r) {
972 assertThrows(NullPointerException.class, r);
973 }
974
975 /**
976 * A simple mutable map implementation that provides only default
977 * implementations of all methods. ie. none of the Map interface default
978 * methods have overridden implementations.
979 *
980 * @param <K> Type of keys
981 * @param <V> Type of values
982 */
983 public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K,V> {
984
985 protected final M map;
986
987 public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); }
988
989 protected ExtendsAbstractMap(M map) { this.map = map; }
990
991 @Override public Set<Map.Entry<K,V>> entrySet() {
992 return new AbstractSet<Map.Entry<K,V>>() {
|