Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/util/Map/Defaults.java
38812 views
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
*/
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
import java.util.AbstractMap;
32
import java.util.AbstractSet;
33
import java.util.ArrayList;
34
import java.util.Arrays;
35
import java.util.Collection;
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.function.BiFunction;
52
import java.util.function.Supplier;
53
54
import org.testng.annotations.Test;
55
import org.testng.annotations.DataProvider;
56
import static org.testng.Assert.fail;
57
import static org.testng.Assert.assertEquals;
58
import static org.testng.Assert.assertTrue;
59
import static org.testng.Assert.assertFalse;
60
import static org.testng.Assert.assertNull;
61
import static org.testng.Assert.assertSame;
62
63
public class Defaults {
64
65
@Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull")
66
public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) {
67
assertTrue(map.containsKey(null), description + ": null key absent");
68
assertNull(map.get(null), description + ": value not null");
69
assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), description + ": values should match");
70
}
71
72
@Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
73
public void testGetOrDefault(String description, Map<IntegerEnum, String> map) {
74
assertTrue(map.containsKey(KEYS[1]), "expected key missing");
75
assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match");
76
assertFalse(map.containsKey(EXTRA_KEY), "expected absent key");
77
assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default");
78
assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default");
79
}
80
81
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
82
public void testPutIfAbsentNulls(String description, Map<IntegerEnum, String> map) {
83
// null -> null
84
assertTrue(map.containsKey(null), "null key absent");
85
assertNull(map.get(null), "value not null");
86
assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
87
// null -> EXTRA_VALUE
88
assertTrue(map.containsKey(null), "null key absent");
89
assertSame(map.get(null), EXTRA_VALUE, "unexpected value");
90
assertSame(map.putIfAbsent(null, null), EXTRA_VALUE, "previous not expected value");
91
assertTrue(map.containsKey(null), "null key absent");
92
assertSame(map.get(null), EXTRA_VALUE, "unexpected value");
93
assertSame(map.remove(null), EXTRA_VALUE, "removed unexpected value");
94
// null -> <absent>
95
96
assertFalse(map.containsKey(null), description + ": key present after remove");
97
assertNull(map.putIfAbsent(null, null), "previous not null");
98
// null -> null
99
assertTrue(map.containsKey(null), "null key absent");
100
assertNull(map.get(null), "value not null");
101
assertNull(map.putIfAbsent(null, EXTRA_VALUE), "previous not null");
102
assertSame(map.get(null), EXTRA_VALUE, "value not expected");
103
}
104
105
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
106
public void testPutIfAbsent(String description, Map<IntegerEnum, String> map) {
107
// 1 -> 1
108
assertTrue(map.containsKey(KEYS[1]));
109
Object expected = map.get(KEYS[1]);
110
assertTrue(null == expected || expected == VALUES[1]);
111
assertSame(map.putIfAbsent(KEYS[1], EXTRA_VALUE), expected);
112
assertSame(map.get(KEYS[1]), expected);
113
114
// EXTRA_KEY -> <absent>
115
assertFalse(map.containsKey(EXTRA_KEY));
116
assertSame(map.putIfAbsent(EXTRA_KEY, EXTRA_VALUE), null);
117
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
118
assertSame(map.putIfAbsent(EXTRA_KEY, VALUES[2]), EXTRA_VALUE);
119
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
120
}
121
122
@Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
123
public void testForEach(String description, Map<IntegerEnum, String> map) {
124
IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()];
125
126
map.forEach((k, v) -> {
127
int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
128
assertNull(EACH_KEY[idx]);
129
EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
130
assertSame(v, map.get(k));
131
});
132
133
assertEquals(KEYS, EACH_KEY, description);
134
}
135
136
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
137
public static void testReplaceAll(String description, Map<IntegerEnum, String> map) {
138
IntegerEnum[] EACH_KEY = new IntegerEnum[map.size()];
139
Set<String> EACH_REPLACE = new HashSet<>(map.size());
140
141
map.replaceAll((k,v) -> {
142
int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
143
assertNull(EACH_KEY[idx]);
144
EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
145
assertSame(v, map.get(k));
146
String replacement = v + " replaced";
147
EACH_REPLACE.add(replacement);
148
return replacement;
149
});
150
151
assertEquals(KEYS, EACH_KEY, description);
152
assertEquals(map.values().size(), EACH_REPLACE.size(), description + EACH_REPLACE);
153
assertTrue(EACH_REPLACE.containsAll(map.values()), description + " : " + EACH_REPLACE + " != " + map.values());
154
assertTrue(map.values().containsAll(EACH_REPLACE), description + " : " + EACH_REPLACE + " != " + map.values());
155
}
156
157
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
158
public static void testReplaceAllNoNullReplacement(String description, Map<IntegerEnum, String> map) {
159
assertThrows(
160
() -> { map.replaceAll(null); },
161
NullPointerException.class,
162
description);
163
assertThrows(
164
() -> { map.replaceAll((k,v) -> null); },
165
NullPointerException.class,
166
description + " should not allow replacement with null value");
167
}
168
169
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
170
public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) {
171
assertTrue(map.containsKey(null), "null key absent");
172
assertNull(map.get(null), "value not null");
173
assertFalse(map.remove(null, EXTRA_VALUE), description);
174
assertTrue(map.containsKey(null));
175
assertNull(map.get(null));
176
assertTrue(map.remove(null, null));
177
assertFalse(map.containsKey(null));
178
assertNull(map.get(null));
179
assertFalse(map.remove(null, null));
180
}
181
182
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
183
public static void testRemove(String description, Map<IntegerEnum, String> map) {
184
assertTrue(map.containsKey(KEYS[1]));
185
Object expected = map.get(KEYS[1]);
186
assertTrue(null == expected || expected == VALUES[1]);
187
assertFalse(map.remove(KEYS[1], EXTRA_VALUE), description);
188
assertSame(map.get(KEYS[1]), expected);
189
assertTrue(map.remove(KEYS[1], expected));
190
assertNull(map.get(KEYS[1]));
191
assertFalse(map.remove(KEYS[1], expected));
192
193
assertFalse(map.containsKey(EXTRA_KEY));
194
assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE));
195
}
196
197
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
198
public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) {
199
assertTrue(map.containsKey(null), "null key absent");
200
assertNull(map.get(null), "value not null");
201
assertSame(map.replace(null, EXTRA_VALUE), null);
202
assertSame(map.get(null), EXTRA_VALUE);
203
}
204
205
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
206
public void testReplaceKVNoNulls(String description, Map<IntegerEnum, String> map) {
207
assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
208
assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
209
assertThrows( () -> {map.replace(FIRST_KEY, null);}, NullPointerException.class, description + ": should throw NPE");
210
assertSame(map.replace(FIRST_KEY, EXTRA_VALUE), FIRST_VALUE, description + ": replaced wrong value");
211
assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
212
}
213
214
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
215
public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
216
assertTrue(map.containsKey(KEYS[1]));
217
Object expected = map.get(KEYS[1]);
218
assertTrue(null == expected || expected == VALUES[1]);
219
assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected);
220
assertSame(map.get(KEYS[1]), EXTRA_VALUE);
221
222
assertFalse(map.containsKey(EXTRA_KEY));
223
assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE));
224
assertFalse(map.containsKey(EXTRA_KEY));
225
assertNull(map.get(EXTRA_KEY));
226
assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
227
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
228
assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE);
229
assertSame(map.get(EXTRA_KEY), expected);
230
}
231
232
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
233
public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) {
234
assertTrue(map.containsKey(null), "null key absent");
235
assertNull(map.get(null), "value not null");
236
assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
237
assertNull(map.get(null));
238
assertTrue(map.replace(null, null, EXTRA_VALUE));
239
assertSame(map.get(null), EXTRA_VALUE);
240
assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
241
assertSame(map.get(null), EXTRA_VALUE);
242
}
243
244
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
245
public void testReplaceKVVNoNulls(String description, Map<IntegerEnum, String> map) {
246
assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
247
assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
248
assertThrows( () -> {map.replace(FIRST_KEY, FIRST_VALUE, null);}, NullPointerException.class, description + ": should throw NPE");
249
assertThrows( () -> {if (!map.replace(FIRST_KEY, null, EXTRA_VALUE)) throw new NullPointerException("default returns false rather than throwing");}, NullPointerException.class, description + ": should throw NPE");
250
assertTrue(map.replace(FIRST_KEY, FIRST_VALUE, EXTRA_VALUE), description + ": replaced wrong value");
251
assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
252
}
253
254
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
255
public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
256
assertTrue(map.containsKey(KEYS[1]));
257
Object expected = map.get(KEYS[1]);
258
assertTrue(null == expected || expected == VALUES[1]);
259
assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
260
assertSame(map.get(KEYS[1]), expected);
261
assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE));
262
assertSame(map.get(KEYS[1]), EXTRA_VALUE);
263
assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
264
assertSame(map.get(KEYS[1]), EXTRA_VALUE);
265
266
assertFalse(map.containsKey(EXTRA_KEY));
267
assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
268
assertFalse(map.containsKey(EXTRA_KEY));
269
assertNull(map.get(EXTRA_KEY));
270
assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
271
assertTrue(map.containsKey(EXTRA_KEY));
272
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
273
assertTrue(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
274
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
275
}
276
277
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
278
public void testComputeIfAbsentNulls(String description, Map<IntegerEnum, String> map) {
279
// null -> null
280
assertTrue(map.containsKey(null), "null key absent");
281
assertNull(map.get(null), "value not null");
282
assertSame(map.computeIfAbsent(null, (k) -> null), null, "not expected result");
283
assertTrue(map.containsKey(null), "null key absent");
284
assertNull(map.get(null), "value not null");
285
assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, "not mapped to result");
286
// null -> EXTRA_VALUE
287
assertTrue(map.containsKey(null), "null key absent");
288
assertSame(map.get(null), EXTRA_VALUE, "not expected value");
289
assertSame(map.remove(null), EXTRA_VALUE, "removed unexpected value");
290
// null -> <absent>
291
assertFalse(map.containsKey(null), "null key present");
292
assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, "not mapped to result");
293
// null -> EXTRA_VALUE
294
assertTrue(map.containsKey(null), "null key absent");
295
assertSame(map.get(null), EXTRA_VALUE, "not expected value");
296
}
297
298
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
299
public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
300
// 1 -> 1
301
assertTrue(map.containsKey(KEYS[1]));
302
Object expected = map.get(KEYS[1]);
303
assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
304
expected = (null == expected) ? EXTRA_VALUE : expected;
305
assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
306
assertSame(map.get(KEYS[1]), expected, description);
307
308
// EXTRA_KEY -> <absent>
309
assertFalse(map.containsKey(EXTRA_KEY));
310
assertNull(map.computeIfAbsent(EXTRA_KEY, (k) -> null));
311
assertFalse(map.containsKey(EXTRA_KEY));
312
assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
313
// EXTRA_KEY -> EXTRA_VALUE
314
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
315
}
316
317
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
318
public void testComputeIfAbsentNullFunction(String description, Map<IntegerEnum, String> map) {
319
assertThrows( () -> { map.computeIfAbsent(KEYS[1], null);},
320
NullPointerException.class,
321
"Should throw NPE");
322
}
323
324
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
325
public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
326
assertTrue(map.containsKey(null), description + ": null key absent");
327
assertNull(map.get(null), description + ": value not null");
328
assertSame(map.computeIfPresent(null, (k, v) -> {
329
fail(description + ": null value is not deemed present");
330
return EXTRA_VALUE;
331
}), null, description);
332
assertTrue(map.containsKey(null));
333
assertNull(map.get(null), description);
334
assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
335
assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
336
assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
337
fail(description + ": null value is not deemed present");
338
return EXTRA_VALUE;
339
}), null, description);
340
assertNull(map.get(EXTRA_KEY), description + ": null mapping gone");
341
}
342
343
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
344
public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) {
345
assertTrue(map.containsKey(KEYS[1]));
346
Object value = map.get(KEYS[1]);
347
assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
348
Object expected = (null == value) ? null : EXTRA_VALUE;
349
assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
350
assertSame(v, value);
351
return EXTRA_VALUE;
352
}), expected, description);
353
assertSame(map.get(KEYS[1]), expected, description);
354
355
assertFalse(map.containsKey(EXTRA_KEY));
356
assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
357
fail();
358
return EXTRA_VALUE;
359
}), null);
360
assertFalse(map.containsKey(EXTRA_KEY));
361
assertSame(map.get(EXTRA_KEY), null);
362
}
363
364
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
365
public void testComputeIfPresentNullFunction(String description, Map<IntegerEnum, String> map) {
366
assertThrows( () -> { map.computeIfPresent(KEYS[1], null);},
367
NullPointerException.class,
368
"Should throw NPE");
369
}
370
371
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
372
public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
373
assertTrue(map.containsKey(null), "null key absent");
374
assertNull(map.get(null), "value not null");
375
assertSame(map.compute(null, (k, v) -> {
376
assertNull(k);
377
assertNull(v);
378
return null;
379
}), null, description);
380
assertFalse(map.containsKey(null), description + ": null key present.");
381
assertSame(map.compute(null, (k, v) -> {
382
assertSame(k, null);
383
assertNull(v);
384
return EXTRA_VALUE;
385
}), EXTRA_VALUE, description);
386
assertTrue(map.containsKey(null));
387
assertSame(map.get(null), EXTRA_VALUE, description);
388
assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected");
389
// no mapping before and after
390
assertFalse(map.containsKey(null), description + ": null key present");
391
assertSame(map.compute(null, (k, v) -> {
392
assertNull(k);
393
assertNull(v);
394
return null;
395
}), null, description + ": expected null result" );
396
assertFalse(map.containsKey(null), description + ": null key present");
397
// compute with map not containing value
398
assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
399
assertFalse(map.containsKey(EXTRA_KEY), description + ": key present");
400
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
401
assertSame(k, EXTRA_KEY);
402
assertNull(v);
403
return null;
404
}), null, description);
405
assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present");
406
// ensure removal.
407
assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
408
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
409
assertSame(k, EXTRA_KEY);
410
assertSame(v, EXTRA_VALUE);
411
return null;
412
}), null, description + ": null resulted expected");
413
assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present");
414
// compute with map containing null value
415
assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
416
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
417
assertSame(k, EXTRA_KEY);
418
assertNull(v);
419
return null;
420
}), null, description);
421
assertFalse(map.containsKey(EXTRA_KEY), description + ": null key present");
422
assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
423
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
424
assertSame(k, EXTRA_KEY);
425
assertNull(v);
426
return EXTRA_VALUE;
427
}), EXTRA_VALUE, description);
428
assertTrue(map.containsKey(EXTRA_KEY), "null key present");
429
}
430
431
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
432
public void testCompute(String description, Map<IntegerEnum, String> map) {
433
assertTrue(map.containsKey(KEYS[1]));
434
Object value = map.get(KEYS[1]);
435
assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
436
assertSame(map.compute(KEYS[1], (k, v) -> {
437
assertSame(k, KEYS[1]);
438
assertSame(v, value);
439
return EXTRA_VALUE;
440
}), EXTRA_VALUE, description);
441
assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
442
assertNull(map.compute(KEYS[1], (k, v) -> {
443
assertSame(v, EXTRA_VALUE);
444
return null;
445
}), description);
446
assertFalse(map.containsKey(KEYS[1]));
447
448
assertFalse(map.containsKey(EXTRA_KEY));
449
assertSame(map.compute(EXTRA_KEY, (k, v) -> {
450
assertNull(v);
451
return EXTRA_VALUE;
452
}), EXTRA_VALUE);
453
assertTrue(map.containsKey(EXTRA_KEY));
454
assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
455
}
456
457
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
458
public void testComputeNullFunction(String description, Map<IntegerEnum, String> map) {
459
assertThrows( () -> { map.compute(KEYS[1], null);},
460
NullPointerException.class,
461
"Should throw NPE");
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
assertThrows( () -> { map.merge(KEYS[1], VALUES[1], null);},
532
NullPointerException.class,
533
"Should throw NPE");
534
}
535
536
public enum IntegerEnum {
537
538
e0, e1, e2, e3, e4, e5, e6, e7, e8, e9,
539
e10, e11, e12, e13, e14, e15, e16, e17, e18, e19,
540
e20, e21, e22, e23, e24, e25, e26, e27, e28, e29,
541
e30, e31, e32, e33, e34, e35, e36, e37, e38, e39,
542
e40, e41, e42, e43, e44, e45, e46, e47, e48, e49,
543
e50, e51, e52, e53, e54, e55, e56, e57, e58, e59,
544
e60, e61, e62, e63, e64, e65, e66, e67, e68, e69,
545
e70, e71, e72, e73, e74, e75, e76, e77, e78, e79,
546
e80, e81, e82, e83, e84, e85, e86, e87, e88, e89,
547
e90, e91, e92, e93, e94, e95, e96, e97, e98, e99,
548
EXTRA_KEY;
549
public static final int SIZE = values().length;
550
};
551
private static final int TEST_SIZE = IntegerEnum.SIZE - 1;
552
/**
553
* Realized keys ensure that there is always a hard ref to all test objects.
554
*/
555
private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE];
556
/**
557
* Realized values ensure that there is always a hard ref to all test
558
* objects.
559
*/
560
private static final String[] VALUES = new String[TEST_SIZE];
561
562
static {
563
IntegerEnum[] keys = IntegerEnum.values();
564
for (int each = 0; each < TEST_SIZE; each++) {
565
KEYS[each] = keys[each];
566
VALUES[each] = String.valueOf(each);
567
}
568
}
569
570
private static final IntegerEnum FIRST_KEY = KEYS[0];
571
private static final String FIRST_VALUE = VALUES[0];
572
private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY;
573
private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE);
574
575
@DataProvider(name = "Map<IntegerEnum,String> rw=all keys=all values=all", parallel = true)
576
public static Iterator<Object[]> allMapProvider() {
577
return makeAllMaps().iterator();
578
}
579
580
@DataProvider(name = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull", parallel = true)
581
public static Iterator<Object[]> allMapWithNullsProvider() {
582
return makeAllMapsWithNulls().iterator();
583
}
584
585
@DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull", parallel = true)
586
public static Iterator<Object[]> rwNonNullMapProvider() {
587
return makeRWNoNullsMaps().iterator();
588
}
589
590
@DataProvider(name = "Map<IntegerEnum,String> rw=true keys=nonNull values=all", parallel = true)
591
public static Iterator<Object[]> rwNonNullKeysMapProvider() {
592
return makeRWMapsNoNulls().iterator();
593
}
594
595
@DataProvider(name = "Map<IntegerEnum,String> rw=true keys=all values=all", parallel = true)
596
public static Iterator<Object[]> rwMapProvider() {
597
return makeAllRWMaps().iterator();
598
}
599
600
@DataProvider(name = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull", parallel = true)
601
public static Iterator<Object[]> rwNullsMapProvider() {
602
return makeAllRWMapsWithNulls().iterator();
603
}
604
605
private static Collection<Object[]> makeAllRWMapsWithNulls() {
606
Collection<Object[]> all = new ArrayList<>();
607
608
all.addAll(makeRWMaps(true, true));
609
610
return all;
611
}
612
613
614
private static Collection<Object[]> makeRWMapsNoNulls() {
615
Collection<Object[]> all = new ArrayList<>();
616
617
all.addAll(makeRWNoNullKeysMaps(false));
618
all.addAll(makeRWNoNullsMaps());
619
620
return all;
621
}
622
623
private static Collection<Object[]> makeAllROMaps() {
624
Collection<Object[]> all = new ArrayList<>();
625
626
all.addAll(makeROMaps(false));
627
all.addAll(makeROMaps(true));
628
629
return all;
630
}
631
632
private static Collection<Object[]> makeAllRWMaps() {
633
Collection<Object[]> all = new ArrayList<>();
634
635
all.addAll(makeRWNoNullsMaps());
636
all.addAll(makeRWMaps(false,true));
637
all.addAll(makeRWMaps(true,true));
638
all.addAll(makeRWNoNullKeysMaps(true));
639
return all;
640
}
641
642
private static Collection<Object[]> makeAllMaps() {
643
Collection<Object[]> all = new ArrayList<>();
644
645
all.addAll(makeAllROMaps());
646
all.addAll(makeAllRWMaps());
647
648
return all;
649
}
650
651
private static Collection<Object[]> makeAllMapsWithNulls() {
652
Collection<Object[]> all = new ArrayList<>();
653
654
all.addAll(makeROMaps(true));
655
all.addAll(makeRWMaps(true,true));
656
657
return all;
658
}
659
/**
660
*
661
* @param nullKeys include null keys
662
* @param nullValues include null values
663
* @return
664
*/
665
private static Collection<Object[]> makeRWMaps(boolean nullKeys, boolean nullValues) {
666
return Arrays.asList(
667
new Object[]{"HashMap", makeMap(HashMap::new, nullKeys, nullValues)},
668
new Object[]{"IdentityHashMap", makeMap(IdentityHashMap::new, nullKeys, nullValues)},
669
new Object[]{"LinkedHashMap", makeMap(LinkedHashMap::new, nullKeys, nullValues)},
670
new Object[]{"WeakHashMap", makeMap(WeakHashMap::new, nullKeys, nullValues)},
671
new Object[]{"Collections.checkedMap(HashMap)", Collections.checkedMap(makeMap(HashMap::new, nullKeys, nullValues), IntegerEnum.class, String.class)},
672
new Object[]{"Collections.synchronizedMap(HashMap)", Collections.synchronizedMap(makeMap(HashMap::new, nullKeys, nullValues))},
673
new Object[]{"ExtendsAbstractMap", makeMap(ExtendsAbstractMap::new, nullKeys, nullValues)});
674
}
675
676
/**
677
*
678
* @param nulls include null values
679
* @return
680
*/
681
private static Collection<Object[]> makeRWNoNullKeysMaps(boolean nulls) {
682
return Arrays.asList(
683
// null key hostile
684
new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls)},
685
new Object[]{"TreeMap", makeMap(TreeMap::new, false, nulls)},
686
new Object[]{"ExtendsAbstractMap(TreeMap)", makeMap(() -> {return new ExtendsAbstractMap(new TreeMap());}, false, nulls)},
687
new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls))}
688
);
689
}
690
691
private static Collection<Object[]> makeRWNoNullsMaps() {
692
return Arrays.asList(
693
// null key and value hostile
694
new Object[]{"Hashtable", makeMap(Hashtable::new, false, false)},
695
new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false, false)},
696
new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false, false)},
697
new Object[]{"Collections.synchronizedMap(ConcurrentHashMap)", Collections.synchronizedMap(makeMap(ConcurrentHashMap::new, false, false))},
698
new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false, false), IntegerEnum.class, String.class)},
699
new Object[]{"ExtendsAbstractMap(ConcurrentHashMap)", makeMap(() -> {return new ExtendsAbstractMap(new ConcurrentHashMap());}, false, false)},
700
new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false, false)}
701
);
702
}
703
704
/**
705
*
706
* @param nulls include nulls
707
* @return
708
*/
709
private static Collection<Object[]> makeROMaps(boolean nulls) {
710
return Arrays.asList(new Object[][]{
711
new Object[]{"Collections.unmodifiableMap(HashMap)", Collections.unmodifiableMap(makeMap(HashMap::new, nulls, nulls))}
712
});
713
}
714
715
/**
716
*
717
* @param supplier a supplier of mutable map instances.
718
*
719
* @param nullKeys include null keys
720
* @param nullValues include null values
721
* @return
722
*/
723
private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nullKeys, boolean nullValues) {
724
Map<IntegerEnum, String> result = supplier.get();
725
726
for (int each = 0; each < TEST_SIZE; each++) {
727
IntegerEnum key = nullKeys ? (each == 0) ? null : KEYS[each] : KEYS[each];
728
String value = nullValues ? (each == 0) ? null : VALUES[each] : VALUES[each];
729
730
result.put(key, value);
731
}
732
733
return result;
734
}
735
736
static class Merging {
737
public enum Value {
738
ABSENT,
739
NULL,
740
OLDVALUE,
741
NEWVALUE,
742
RESULT
743
}
744
745
public enum Merger implements BiFunction<String,String,String> {
746
UNUSED {
747
public String apply(String oldValue, String newValue) {
748
fail("should not be called");
749
return null;
750
}
751
},
752
NULL {
753
public String apply(String oldValue, String newValue) {
754
return null;
755
}
756
},
757
RESULT {
758
public String apply(String oldValue, String newValue) {
759
return VALUES[3];
760
}
761
},
762
}
763
}
764
765
@DataProvider(name = "MergeCases", parallel = true)
766
public Iterator<Object[]> mergeCasesProvider() {
767
Collection<Object[]> cases = new ArrayList<>();
768
769
cases.addAll(makeMergeTestCases());
770
771
return cases.iterator();
772
}
773
774
static Collection<Object[]> makeMergeTestCases() {
775
Collection<Object[]> cases = new ArrayList<>();
776
777
for( Object[] mapParams : makeAllRWMaps() ) {
778
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
779
}
780
781
for( Object[] mapParams : makeAllRWMaps() ) {
782
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
783
}
784
785
for( Object[] mapParams : makeAllRWMaps() ) {
786
cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
787
}
788
789
return cases;
790
}
791
792
public interface Thrower<T extends Throwable> {
793
794
public void run() throws T;
795
}
796
797
public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) {
798
assertThrows(thrower, throwable, null);
799
}
800
801
public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
802
Throwable thrown;
803
try {
804
thrower.run();
805
thrown = null;
806
} catch (Throwable caught) {
807
thrown = caught;
808
}
809
810
assertInstance(thrown, throwable,
811
((null != message) ? message : "") +
812
" Failed to throw " + throwable.getCanonicalName());
813
}
814
815
public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) {
816
for(Thrower<T> thrower : throwers) {
817
assertThrows(thrower, throwable, message);
818
}
819
}
820
821
public static void assertInstance(Object actual, Class<?> expected) {
822
assertInstance(expected.isInstance(actual), null);
823
}
824
825
public static void assertInstance(Object actual, Class<?> expected, String message) {
826
assertTrue(expected.isInstance(actual), message);
827
}
828
829
/**
830
* A simple mutable map implementation that provides only default
831
* implementations of all methods. ie. none of the Map interface default
832
* methods have overridden implementations.
833
*
834
* @param <K> Type of keys
835
* @param <V> Type of values
836
*/
837
public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K, V> {
838
839
protected final M map;
840
841
public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); }
842
843
protected ExtendsAbstractMap(M map) { this.map = map; }
844
845
public Set<Map.Entry<K, V>> entrySet() {
846
return new AbstractSet<Map.Entry<K, V>>() {
847
public int size() {
848
return map.size();
849
}
850
851
public Iterator<Map.Entry<K,V>> iterator() {
852
final Iterator<Map.Entry<K,V>> source = map.entrySet().iterator();
853
return new Iterator<Map.Entry<K,V>>() {
854
public boolean hasNext() { return source.hasNext(); }
855
public Map.Entry<K,V> next() { return source.next(); }
856
public void remove() { source.remove(); }
857
};
858
}
859
860
public boolean add(Map.Entry<K,V> e) {
861
return map.entrySet().add(e);
862
}
863
};
864
}
865
866
public V put(K key, V value) {
867
return map.put(key, value);
868
}
869
}
870
871
/**
872
* A simple mutable concurrent map implementation that provides only default
873
* implementations of all methods. ie. none of the ConcurrentMap interface
874
* default methods have overridden implementations.
875
*
876
* @param <K> Type of keys
877
* @param <V> Type of values
878
*/
879
public static class ImplementsConcurrentMap<K, V> extends ExtendsAbstractMap<ConcurrentMap<K,V>, K, V> implements ConcurrentMap<K,V> {
880
public ImplementsConcurrentMap() { super(new ConcurrentHashMap<K,V>()); }
881
882
// ConcurrentMap reabstracts these methods
883
884
public V replace(K k, V v) { return map.replace(k, v); };
885
886
public boolean replace(K k, V v, V vv) { return map.replace(k, v, vv); };
887
888
public boolean remove(Object k, Object v) { return map.remove(k, v); }
889
890
public V putIfAbsent(K k, V v) { return map.putIfAbsent(k, v); }
891
}
892
}
893
894