Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/util/Map/Defaults.java
41149 views
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
*/
23
24
/*
25
* @test
26
* @bug 8010122 8004518 8024331 8024688
27
* @summary Test Map default methods
28
* @author Mike Duigou
29
* @run testng Defaults
30
*/
31
32
import org.testng.Assert.ThrowingRunnable;
33
import org.testng.annotations.DataProvider;
34
import org.testng.annotations.Test;
35
36
import java.util.AbstractMap;
37
import java.util.AbstractSet;
38
import java.util.ArrayList;
39
import java.util.Arrays;
40
import java.util.Collection;
41
import java.util.Collections;
42
import java.util.EnumMap;
43
import java.util.HashMap;
44
import java.util.HashSet;
45
import java.util.Hashtable;
46
import java.util.IdentityHashMap;
47
import java.util.Iterator;
48
import java.util.LinkedHashMap;
49
import java.util.Map;
50
import java.util.Set;
51
import java.util.TreeMap;
52
import java.util.WeakHashMap;
53
import java.util.concurrent.ConcurrentHashMap;
54
import java.util.concurrent.ConcurrentMap;
55
import java.util.concurrent.ConcurrentSkipListMap;
56
import java.util.concurrent.atomic.AtomicBoolean;
57
import java.util.function.BiFunction;
58
import java.util.function.Function;
59
import java.util.function.Supplier;
60
61
import static java.util.Objects.requireNonNull;
62
import static org.testng.Assert.assertEquals;
63
import static org.testng.Assert.assertFalse;
64
import static org.testng.Assert.assertNull;
65
import static org.testng.Assert.assertSame;
66
import static org.testng.Assert.assertThrows;
67
import static org.testng.Assert.assertTrue;
68
import static org.testng.Assert.fail;
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")
89
public void testPutIfAbsentNulls(String description, Map<IntegerEnum, String> map) {
90
// null -> null
91
assertTrue(map.containsKey(null), "null key absent");
92
assertNull(map.get(null), "value not null");
93
assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
94
// null -> EXTRA_VALUE
95
assertTrue(map.containsKey(null), "null key absent");
96
assertSame(map.get(null), EXTRA_VALUE, "unexpected value");
97
assertSame(map.putIfAbsent(null, null), EXTRA_VALUE, "previous not expected value");
98
assertTrue(map.containsKey(null), "null key absent");
99
assertSame(map.get(null), EXTRA_VALUE, "unexpected value");
100
assertSame(map.remove(null), EXTRA_VALUE, "removed unexpected value");
101
// null -> <absent>
102
103
assertFalse(map.containsKey(null), description + ": key present after remove");
104
assertNull(map.putIfAbsent(null, null), "previous not null");
105
// null -> null
106
assertTrue(map.containsKey(null), "null key absent");
107
assertNull(map.get(null), "value not null");
108
assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
109
assertSame(map.get(null), EXTRA_VALUE, "value not expected");
110
}
111
112
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
113
public void testPutIfAbsent(String description, Map<IntegerEnum, String> map) {
114
// 1 -> 1
115
assertTrue(map.containsKey(KEYS[1]));
116
Object expected = map.get(KEYS[1]);
117
assertTrue(null == expected || expected == VALUES[1]);
118
assertSame(map.putIfAbsent(KEYS[1], EXTRA_VALUE), expected);
119
assertSame(map.get(KEYS[1]), expected);
120
121
// EXTRA_KEY -> <absent>
122
assertFalse(map.containsKey(EXTRA_KEY));
123
assertSame(map.putIfAbsent(EXTRA_KEY, EXTRA_VALUE), null);
124
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
125
assertSame(map.putIfAbsent(EXTRA_KEY, VALUES[2]), EXTRA_VALUE);
126
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
127
}
128
129
@Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
130
public void testForEach(String description, Map<IntegerEnum, String> map) {
131
IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()];
132
133
map.forEach((k, v) -> {
134
int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
135
assertNull(EACH_KEY[idx]);
136
EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
137
assertSame(v, map.get(k));
138
});
139
140
assertEquals(KEYS, EACH_KEY, description);
141
}
142
143
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
144
public static void testReplaceAll(String description, Map<IntegerEnum, String> map) {
145
IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()];
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)); //should not allow replacement with null value
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]);
188
assertFalse(map.remove(KEYS[1], EXTRA_VALUE), description);
189
assertSame(map.get(KEYS[1]), expected);
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));
276
assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
277
assertTrue(map.containsKey(EXTRA_KEY));
278
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
279
assertTrue(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
280
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
281
}
282
283
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
284
public void testComputeIfAbsentNulls(String description, Map<IntegerEnum, String> map) {
285
// null -> null
286
assertTrue(map.containsKey(null), "null key absent");
287
assertNull(map.get(null), "value not null");
288
assertSame(map.computeIfAbsent(null, (k) -> null), null, "not expected result");
289
assertTrue(map.containsKey(null), "null key absent");
290
assertNull(map.get(null), "value not null");
291
assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, "not mapped to result");
292
// null -> EXTRA_VALUE
293
assertTrue(map.containsKey(null), "null key absent");
294
assertSame(map.get(null), EXTRA_VALUE, "not expected value");
295
assertSame(map.remove(null), EXTRA_VALUE, "removed unexpected value");
296
// null -> <absent>
297
assertFalse(map.containsKey(null), "null key present");
298
assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, "not mapped to result");
299
// null -> EXTRA_VALUE
300
assertTrue(map.containsKey(null), "null key absent");
301
assertSame(map.get(null), EXTRA_VALUE, "not expected value");
302
}
303
304
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
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
}
346
347
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
348
public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) {
349
assertTrue(map.containsKey(KEYS[1]));
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");
391
// no mapping before and after
392
assertFalse(map.containsKey(null), description + ": null key present");
393
assertSame(map.compute(null, (k, v) -> {
394
assertNull(k);
395
assertNull(v);
396
return null;
397
}), null, description + ": expected null result" );
398
assertFalse(map.containsKey(null), description + ": null key present");
399
// compute with map not containing value
400
assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
401
assertFalse(map.containsKey(EXTRA_KEY), description + ": key present");
402
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
403
assertSame(k, EXTRA_KEY);
404
assertNull(v);
405
return null;
406
}), null, description);
407
assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present");
408
// ensure removal.
409
assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
410
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
411
assertSame(k, EXTRA_KEY);
412
assertSame(v, EXTRA_VALUE);
413
return null;
414
}), null, description + ": null resulted expected");
415
assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present");
416
// compute with map containing null value
417
assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
418
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
419
assertSame(k, EXTRA_KEY);
420
assertNull(v);
421
return null;
422
}), null, description);
423
assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present");
424
assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
425
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
426
assertSame(k, EXTRA_KEY);
427
assertNull(v);
428
return EXTRA_VALUE;
429
}), EXTRA_VALUE, description);
430
assertTrue(map.containsKey(EXTRA_KEY), "null key present");
431
}
432
433
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
434
public void testCompute(String description, Map<IntegerEnum, String> map) {
435
assertTrue(map.containsKey(KEYS[1]));
436
Object value = map.get(KEYS[1]);
437
assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
438
assertSame(map.compute(KEYS[1], (k, v) -> {
439
assertSame(k, KEYS[1]);
440
assertSame(v, value);
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;
482
default:
483
fail("unexpected old value");
484
}
485
486
String returned = map.merge(EXTRA_KEY,
487
newValue == Merging.Value.NULL ? (String) null : VALUES[2],
488
merger
489
);
490
491
// check result
492
493
switch (result) {
494
case NULL :
495
assertNull(returned, "wrong value");
496
break;
497
case NEWVALUE :
498
assertSame(returned, VALUES[2], "wrong value");
499
break;
500
case RESULT :
501
assertSame(returned, VALUES[3], "wrong value");
502
break;
503
default:
504
fail("unexpected new value");
505
}
506
507
// check map
508
switch (put) {
509
case ABSENT :
510
assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
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() {
552
final ConcurrentMap<Long,Long> map = new ImplementsConcurrentMap<>();
553
final Long two = 2L;
554
Function<Long,Long> f, g;
555
556
// race not detected if function returns null
557
f = (k) -> { map.put(two, 42L); return null; };
558
assertNull(map.computeIfAbsent(two, f));
559
assertEquals(42L, (long)map.get(two));
560
561
map.clear();
562
f = (k) -> { map.put(two, 42L); return 86L; };
563
assertEquals(42L, (long)map.computeIfAbsent(two, f));
564
assertEquals(42L, (long)map.get(two));
565
566
// mapping function ignored if value already exists
567
map.put(two, 99L);
568
assertEquals(99L, (long)map.computeIfAbsent(two, f));
569
assertEquals(99L, (long)map.get(two));
570
}
571
572
/**
573
* Simulates races by modifying the map within the remapping function.
574
*/
575
@Test
576
public void testConcurrentMap_computeIfPresent_racy() {
577
final AtomicBoolean b = new AtomicBoolean(true);
578
final ConcurrentMap<Long,Long> map = new ImplementsConcurrentMap<>();
579
final Long two = 2L;
580
BiFunction<Long,Long,Long> f, g;
581
582
for (Long val : new Long[] { null, 86L }) {
583
map.clear();
584
585
// Function not invoked if no mapping exists
586
f = (k, v) -> { map.put(two, 42L); return val; };
587
assertNull(map.computeIfPresent(two, f));
588
assertNull(map.get(two));
589
590
map.put(two, 42L);
591
f = (k, v) -> { map.put(two, 86L); return val; };
592
g = (k, v) -> {
593
assertSame(two, k);
594
assertEquals(86L, (long)v);
595
return null;
596
};
597
assertNull(map.computeIfPresent(two, twoStep(b, f, g)));
598
assertFalse(map.containsKey(two));
599
assertTrue(b.get());
600
601
map.put(two, 42L);
602
f = (k, v) -> { map.put(two, 86L); return val; };
603
g = (k, v) -> {
604
assertSame(two, k);
605
assertEquals(86L, (long)v);
606
return 99L;
607
};
608
assertEquals(99L, (long)map.computeIfPresent(two, twoStep(b, f, g)));
609
assertTrue(map.containsKey(two));
610
assertTrue(b.get());
611
}
612
}
613
614
@Test
615
public void testConcurrentMap_compute_simple() {
616
final ConcurrentMap<Long,Long> map = new ImplementsConcurrentMap<>();
617
BiFunction<Long,Long,Long> fun = (k, v) -> ((v == null) ? 0L : k + v);
618
assertEquals(Long.valueOf(0L), map.compute(3L, fun));
619
assertEquals(Long.valueOf(3L), map.compute(3L, fun));
620
assertEquals(Long.valueOf(6L), map.compute(3L, fun));
621
assertNull(map.compute(3L, (k, v) -> null));
622
assertTrue(map.isEmpty());
623
624
assertEquals(Long.valueOf(0L), map.compute(new Long(3L), fun));
625
assertEquals(Long.valueOf(3L), map.compute(new Long(3L), fun));
626
assertEquals(Long.valueOf(6L), map.compute(new Long(3L), fun));
627
assertNull(map.compute(3L, (k, v) -> null));
628
assertTrue(map.isEmpty());
629
}
630
631
/**
632
* Simulates races by modifying the map within the remapping function.
633
*/
634
@Test
635
public void testConcurrentMap_compute_racy() {
636
final AtomicBoolean b = new AtomicBoolean(true);
637
final ConcurrentMap<Long,Long> map = new ImplementsConcurrentMap<>();
638
final Long two = 2L;
639
BiFunction<Long,Long,Long> f, g;
640
641
// null -> null is a no-op; race not detected
642
f = (k, v) -> { map.put(two, 42L); return null; };
643
assertNull(map.compute(two, f));
644
assertEquals(42L, (long)map.get(two));
645
646
for (Long val : new Long[] { null, 86L }) {
647
map.clear();
648
649
f = (k, v) -> { map.put(two, 42L); return 86L; };
650
g = (k, v) -> {
651
assertSame(two, k);
652
assertEquals(42L, (long)v);
653
return k + v;
654
};
655
assertEquals(44L, (long)map.compute(two, twoStep(b, f, g)));
656
assertEquals(44L, (long)map.get(two));
657
assertTrue(b.get());
658
659
f = (k, v) -> { map.remove(two); return val; };
660
g = (k, v) -> {
661
assertSame(two, k);
662
assertNull(v);
663
return 44L;
664
};
665
assertEquals(44L, (long)map.compute(two, twoStep(b, f, g)));
666
assertEquals(44L, (long)map.get(two));
667
assertTrue(map.containsKey(two));
668
assertTrue(b.get());
669
670
f = (k, v) -> { map.remove(two); return val; };
671
g = (k, v) -> {
672
assertSame(two, k);
673
assertNull(v);
674
return null;
675
};
676
assertNull(map.compute(two, twoStep(b, f, g)));
677
assertNull(map.get(two));
678
assertFalse(map.containsKey(two));
679
assertTrue(b.get());
680
}
681
}
682
683
/**
684
* Simulates races by modifying the map within the remapping function.
685
*/
686
@Test
687
public void testConcurrentMap_merge_racy() {
688
final AtomicBoolean b = new AtomicBoolean(true);
689
final ConcurrentMap<Long,Long> map = new ImplementsConcurrentMap<>();
690
final Long two = 2L;
691
BiFunction<Long,Long,Long> f, g;
692
693
for (Long val : new Long[] { null, 86L }) {
694
map.clear();
695
696
f = (v, w) -> { throw new AssertionError(); };
697
assertEquals(99L, (long)map.merge(two, 99L, f));
698
assertEquals(99L, (long)map.get(two));
699
700
f = (v, w) -> { map.put(two, 42L); return val; };
701
g = (v, w) -> {
702
assertEquals(42L, (long)v);
703
assertEquals(3L, (long)w);
704
return v + w;
705
};
706
assertEquals(45L, (long)map.merge(two, 3L, twoStep(b, f, g)));
707
assertEquals(45L, (long)map.get(two));
708
assertTrue(b.get());
709
710
f = (v, w) -> { map.remove(two); return val; };
711
g = (k, v) -> { throw new AssertionError(); };
712
assertEquals(55L, (long)map.merge(two, 55L, twoStep(b, f, g)));
713
assertEquals(55L, (long)map.get(two));
714
assertTrue(map.containsKey(two));
715
assertFalse(b.get()); b.set(true);
716
}
717
}
718
719
public enum IntegerEnum {
720
721
e0, e1, e2, e3, e4, e5, e6, e7, e8, e9,
722
e10, e11, e12, e13, e14, e15, e16, e17, e18, e19,
723
e20, e21, e22, e23, e24, e25, e26, e27, e28, e29,
724
e30, e31, e32, e33, e34, e35, e36, e37, e38, e39,
725
e40, e41, e42, e43, e44, e45, e46, e47, e48, e49,
726
e50, e51, e52, e53, e54, e55, e56, e57, e58, e59,
727
e60, e61, e62, e63, e64, e65, e66, e67, e68, e69,
728
e70, e71, e72, e73, e74, e75, e76, e77, e78, e79,
729
e80, e81, e82, e83, e84, e85, e86, e87, e88, e89,
730
e90, e91, e92, e93, e94, e95, e96, e97, e98, e99,
731
EXTRA_KEY;
732
public static final int SIZE = values().length;
733
}
734
private static final int TEST_SIZE = IntegerEnum.SIZE - 1;
735
/**
736
* Realized keys ensure that there is always a hard ref to all test objects.
737
*/
738
private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE];
739
/**
740
* Realized values ensure that there is always a hard ref to all test
741
* objects.
742
*/
743
private static final String[] VALUES = new String[TEST_SIZE];
744
745
static {
746
IntegerEnum[] keys = IntegerEnum.values();
747
for (int each = 0; each < TEST_SIZE; each++) {
748
KEYS[each] = keys[each];
749
VALUES[each] = String.valueOf(each);
750
}
751
}
752
753
private static final IntegerEnum FIRST_KEY = KEYS[0];
754
private static final String FIRST_VALUE = VALUES[0];
755
private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY;
756
private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE);
757
758
@DataProvider(name = "Map<IntegerEnum,String> rw=all keys=all values=all", parallel = true)
759
public static Iterator<Object[]> allMapProvider() {
760
return makeAllMaps().iterator();
761
}
762
763
@DataProvider(name = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull", parallel = true)
764
public static Iterator<Object[]> allMapWithNullsProvider() {
765
return makeAllMapsWithNulls().iterator();
766
}
767
768
@DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull", parallel = true)
769
public static Iterator<Object[]> rwNonNullMapProvider() {
770
return makeRWNoNullsMaps().iterator();
771
}
772
773
@DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=all", parallel = true)
774
public static Iterator<Object[]> rwNonNullKeysMapProvider() {
775
return makeRWMapsNoNulls().iterator();
776
}
777
778
@DataProvider(name = "Map<IntegerEnum,String> rw=true keys=all values=all", parallel = true)
779
public static Iterator<Object[]> rwMapProvider() {
780
return makeAllRWMaps().iterator();
781
}
782
783
@DataProvider(name = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull", parallel = true)
784
public static Iterator<Object[]> rwNullsMapProvider() {
785
return makeAllRWMapsWithNulls().iterator();
786
}
787
788
private static Collection<Object[]> makeAllRWMapsWithNulls() {
789
Collection<Object[]> all = new ArrayList<>();
790
791
all.addAll(makeRWMaps(true, true));
792
793
return all;
794
}
795
796
private static Collection<Object[]> makeRWMapsNoNulls() {
797
Collection<Object[]> all = new ArrayList<>();
798
799
all.addAll(makeRWNoNullKeysMaps(false));
800
all.addAll(makeRWNoNullsMaps());
801
802
return all;
803
}
804
805
private static Collection<Object[]> makeAllROMaps() {
806
Collection<Object[]> all = new ArrayList<>();
807
808
all.addAll(makeROMaps(false));
809
all.addAll(makeROMaps(true));
810
811
return all;
812
}
813
814
private static Collection<Object[]> makeAllRWMaps() {
815
Collection<Object[]> all = new ArrayList<>();
816
817
all.addAll(makeRWNoNullsMaps());
818
all.addAll(makeRWMaps(false,true));
819
all.addAll(makeRWMaps(true,true));
820
all.addAll(makeRWNoNullKeysMaps(true));
821
return all;
822
}
823
824
private static Collection<Object[]> makeAllMaps() {
825
Collection<Object[]> all = new ArrayList<>();
826
827
all.addAll(makeAllROMaps());
828
all.addAll(makeAllRWMaps());
829
830
return all;
831
}
832
833
private static Collection<Object[]> makeAllMapsWithNulls() {
834
Collection<Object[]> all = new ArrayList<>();
835
836
all.addAll(makeROMaps(true));
837
all.addAll(makeRWMaps(true,true));
838
839
return all;
840
}
841
842
/**
843
* @param nullKeys include null keys
844
* @param nullValues include null values
845
* @return
846
*/
847
private static Collection<Object[]> makeRWMaps(boolean nullKeys, boolean nullValues) {
848
return Arrays.asList(
849
new Object[]{"HashMap", makeMap(HashMap::new, nullKeys, nullValues)},
850
new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nullKeys, nullValues)},
851
new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nullKeys, nullValues)},
852
new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nullKeys, nullValues)},
853
new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nullKeys, nullValues), IntegerEnum.class, String.class)},
854
new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nullKeys, nullValues))},
855
new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nullKeys, nullValues)});
856
}
857
858
/**
859
* @param nulls include null values
860
* @return
861
*/
862
private static Collection<Object[]> makeRWNoNullKeysMaps(boolean nulls) {
863
return Arrays.asList(
864
// null key hostile
865
new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls)},
866
new Object[]{"TreeMap", makeMap(TreeMap::new, false, nulls)},
867
new Object[]{"ExtendsAbstractMap(TreeMap)", makeMap(() -> {return new ExtendsAbstractMap(new TreeMap());}, false, nulls)},
868
new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls))}
869
);
870
}
871
872
private static Collection<Object[]> makeRWNoNullsMaps() {
873
return Arrays.asList(
874
// null key and value hostile
875
new Object[]{"Hashtable", makeMap(Hashtable::new, false, false)},
876
new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false, false)},
877
new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false, false)},
878
new Object[]{"Collections.synchronizedMap(ConcurrentHashMap)", Collections.synchronizedMap(makeMap(ConcurrentHashMap::new, false, false))},
879
new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false, false), IntegerEnum.class, String.class)},
880
new Object[]{"ExtendsAbstractMap(ConcurrentHashMap)", makeMap(() -> {return new ExtendsAbstractMap(new ConcurrentHashMap());}, false, false)},
881
new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false, false)}
882
);
883
}
884
885
/**
886
* @param nulls include nulls
887
* @return
888
*/
889
private static Collection<Object[]> makeROMaps(boolean nulls) {
890
return Arrays.asList(new Object[][]{
891
new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls, nulls))}
892
});
893
}
894
895
/**
896
* @param supplier a supplier of mutable map instances.
897
*
898
* @param nullKeys include null keys
899
* @param nullValues include null values
900
* @return
901
*/
902
private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nullKeys, boolean nullValues) {
903
Map<IntegerEnum, String> result = supplier.get();
904
905
for (int each = 0; each < TEST_SIZE; each++) {
906
IntegerEnum key = nullKeys ? (each == 0) ? null : KEYS[each] : KEYS[each];
907
String value = nullValues ? (each == 0) ? null : VALUES[each] : VALUES[each];
908
909
result.put(key, value);
910
}
911
912
return result;
913
}
914
915
static class Merging {
916
public enum Value {
917
ABSENT,
918
NULL,
919
OLDVALUE,
920
NEWVALUE,
921
RESULT
922
}
923
924
public enum Merger implements BiFunction<String,String,String> {
925
UNUSED {
926
public String apply(String oldValue, String newValue) {
927
fail("should not be called");
928
return null;
929
}
930
},
931
NULL {
932
public String apply(String oldValue, String newValue) {
933
return null;
934
}
935
},
936
RESULT {
937
public String apply(String oldValue, String newValue) {
938
return VALUES[3];
939
}
940
},
941
}
942
}
943
944
@DataProvider(name = "MergeCases", parallel = true)
945
public Iterator<Object[]> mergeCasesProvider() {
946
Collection<Object[]> cases = new ArrayList<>();
947
948
cases.addAll(makeMergeTestCases());
949
950
return cases.iterator();
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>>() {
993
@Override public int size() {
994
return map.size();
995
}
996
997
@Override public Iterator<Map.Entry<K,V>> iterator() {
998
final Iterator<Map.Entry<K,V>> source = map.entrySet().iterator();
999
return new Iterator<Map.Entry<K,V>>() {
1000
public boolean hasNext() { return source.hasNext(); }
1001
public Map.Entry<K,V> next() { return source.next(); }
1002
public void remove() { source.remove(); }
1003
};
1004
}
1005
1006
@Override public boolean add(Map.Entry<K,V> e) {
1007
return map.entrySet().add(e);
1008
}
1009
};
1010
}
1011
1012
@Override public V put(K key, V value) {
1013
return map.put(key, value);
1014
}
1015
}
1016
1017
/**
1018
* A simple mutable concurrent map implementation that provides only default
1019
* implementations of all methods, i.e. none of the ConcurrentMap interface
1020
* default methods have overridden implementations.
1021
*
1022
* @param <K> Type of keys
1023
* @param <V> Type of values
1024
*/
1025
public static class ImplementsConcurrentMap<K,V> extends ExtendsAbstractMap<ConcurrentMap<K,V>, K, V> implements ConcurrentMap<K,V> {
1026
public ImplementsConcurrentMap() { super(new ConcurrentHashMap<K,V>()); }
1027
1028
// ConcurrentMap reabstracts these methods.
1029
//
1030
// Unlike ConcurrentHashMap, we have zero tolerance for null values.
1031
1032
@Override public V replace(K k, V v) {
1033
return map.replace(requireNonNull(k), requireNonNull(v));
1034
}
1035
1036
@Override public boolean replace(K k, V v, V vv) {
1037
return map.replace(requireNonNull(k),
1038
requireNonNull(v),
1039
requireNonNull(vv));
1040
}
1041
1042
@Override public boolean remove(Object k, Object v) {
1043
return map.remove(requireNonNull(k), requireNonNull(v));
1044
}
1045
1046
@Override public V putIfAbsent(K k, V v) {
1047
return map.putIfAbsent(requireNonNull(k), requireNonNull(v));
1048
}
1049
}
1050
}
1051
1052