ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/ConcurrentHashMapTest.java
Revision: 1.60
Committed: Fri Oct 5 22:12:45 2018 UTC (5 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.59: +1 -3 lines
Log Message:
whitespace

File Contents

# Content
1 /*
2 * Written by Doug Lea and Martin Buchholz with assistance from
3 * members of JCP JSR-166 Expert Group and released to the public
4 * domain, as explained at
5 * http://creativecommons.org/publicdomain/zero/1.0/
6 * Other contributors include Andrew Wright, Jeffrey Hayes,
7 * Pat Fisher, Mike Judd.
8 */
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.Enumeration;
15 import java.util.Iterator;
16 import java.util.Map;
17 import java.util.Random;
18 import java.util.Set;
19 import java.util.concurrent.ConcurrentHashMap;
20
21 import junit.framework.Test;
22
23 public class ConcurrentHashMapTest extends JSR166TestCase {
24 public static void main(String[] args) {
25 main(suite(), args);
26 }
27 public static Test suite() {
28 class Implementation implements MapImplementation {
29 public Class<?> klazz() { return ConcurrentHashMap.class; }
30 public Map emptyMap() { return new ConcurrentHashMap(); }
31 public Object makeKey(int i) { return i; }
32 public Object makeValue(int i) { return i; }
33 public boolean isConcurrent() { return true; }
34 public boolean permitsNullKeys() { return false; }
35 public boolean permitsNullValues() { return false; }
36 public boolean supportsSetValue() { return true; }
37 }
38 return newTestSuite(
39 ConcurrentHashMapTest.class,
40 MapTest.testSuite(new Implementation()));
41 }
42
43 /**
44 * Returns a new map from Integers 1-5 to Strings "A"-"E".
45 */
46 private static ConcurrentHashMap<Integer, String> map5() {
47 ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>(5);
48 assertTrue(map.isEmpty());
49 map.put(one, "A");
50 map.put(two, "B");
51 map.put(three, "C");
52 map.put(four, "D");
53 map.put(five, "E");
54 assertFalse(map.isEmpty());
55 assertEquals(5, map.size());
56 return map;
57 }
58
59 // classes for testing Comparable fallbacks
60 static class BI implements Comparable<BI> {
61 private final int value;
62 BI(int value) { this.value = value; }
63 public int compareTo(BI other) {
64 return Integer.compare(value, other.value);
65 }
66 public boolean equals(Object x) {
67 return (x instanceof BI) && ((BI)x).value == value;
68 }
69 public int hashCode() { return 42; }
70 }
71 static class CI extends BI { CI(int value) { super(value); } }
72 static class DI extends BI { DI(int value) { super(value); } }
73
74 static class BS implements Comparable<BS> {
75 private final String value;
76 BS(String value) { this.value = value; }
77 public int compareTo(BS other) {
78 return value.compareTo(other.value);
79 }
80 public boolean equals(Object x) {
81 return (x instanceof BS) && value.equals(((BS)x).value);
82 }
83 public int hashCode() { return 42; }
84 }
85
86 static class LexicographicList<E extends Comparable<E>> extends ArrayList<E>
87 implements Comparable<LexicographicList<E>> {
88 LexicographicList(Collection<E> c) { super(c); }
89 LexicographicList(E e) { super(Collections.singleton(e)); }
90 public int compareTo(LexicographicList<E> other) {
91 int common = Math.min(size(), other.size());
92 int r = 0;
93 for (int i = 0; i < common; i++) {
94 if ((r = get(i).compareTo(other.get(i))) != 0)
95 break;
96 }
97 if (r == 0)
98 r = Integer.compare(size(), other.size());
99 return r;
100 }
101 private static final long serialVersionUID = 0;
102 }
103
104 static class CollidingObject {
105 final String value;
106 CollidingObject(final String value) { this.value = value; }
107 public int hashCode() { return this.value.hashCode() & 1; }
108 public boolean equals(final Object obj) {
109 return (obj instanceof CollidingObject) && ((CollidingObject)obj).value.equals(value);
110 }
111 }
112
113 static class ComparableCollidingObject extends CollidingObject implements Comparable<ComparableCollidingObject> {
114 ComparableCollidingObject(final String value) { super(value); }
115 public int compareTo(final ComparableCollidingObject o) {
116 return value.compareTo(o.value);
117 }
118 }
119
120 /**
121 * Inserted elements that are subclasses of the same Comparable
122 * class are found.
123 */
124 public void testComparableFamily() {
125 int size = 500; // makes measured test run time -> 60ms
126 ConcurrentHashMap<BI, Boolean> m = new ConcurrentHashMap<>();
127 for (int i = 0; i < size; i++) {
128 assertNull(m.put(new CI(i), true));
129 }
130 for (int i = 0; i < size; i++) {
131 assertTrue(m.containsKey(new CI(i)));
132 assertTrue(m.containsKey(new DI(i)));
133 }
134 }
135
136 /**
137 * Elements of classes with erased generic type parameters based
138 * on Comparable can be inserted and found.
139 */
140 public void testGenericComparable() {
141 int size = 120; // makes measured test run time -> 60ms
142 ConcurrentHashMap<Object, Boolean> m = new ConcurrentHashMap<>();
143 for (int i = 0; i < size; i++) {
144 BI bi = new BI(i);
145 BS bs = new BS(String.valueOf(i));
146 LexicographicList<BI> bis = new LexicographicList<>(bi);
147 LexicographicList<BS> bss = new LexicographicList<>(bs);
148 assertNull(m.putIfAbsent(bis, true));
149 assertTrue(m.containsKey(bis));
150 if (m.putIfAbsent(bss, true) == null)
151 assertTrue(m.containsKey(bss));
152 assertTrue(m.containsKey(bis));
153 }
154 for (int i = 0; i < size; i++) {
155 assertTrue(m.containsKey(Collections.singletonList(new BI(i))));
156 }
157 }
158
159 /**
160 * Elements of non-comparable classes equal to those of classes
161 * with erased generic type parameters based on Comparable can be
162 * inserted and found.
163 */
164 public void testGenericComparable2() {
165 int size = 500; // makes measured test run time -> 60ms
166 ConcurrentHashMap<Object, Boolean> m = new ConcurrentHashMap<>();
167 for (int i = 0; i < size; i++) {
168 m.put(Collections.singletonList(new BI(i)), true);
169 }
170
171 for (int i = 0; i < size; i++) {
172 LexicographicList<BI> bis = new LexicographicList<>(new BI(i));
173 assertTrue(m.containsKey(bis));
174 }
175 }
176
177 /**
178 * Mixtures of instances of comparable and non-comparable classes
179 * can be inserted and found.
180 */
181 public void testMixedComparable() {
182 int size = 1200; // makes measured test run time -> 35ms
183 ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();
184 Random rng = new Random();
185 for (int i = 0; i < size; i++) {
186 Object x;
187 switch (rng.nextInt(4)) {
188 case 0:
189 x = new Object();
190 break;
191 case 1:
192 x = new CollidingObject(Integer.toString(i));
193 break;
194 default:
195 x = new ComparableCollidingObject(Integer.toString(i));
196 }
197 assertNull(map.put(x, x));
198 }
199 int count = 0;
200 for (Object k : map.keySet()) {
201 assertEquals(map.get(k), k);
202 ++count;
203 }
204 assertEquals(count, size);
205 assertEquals(map.size(), size);
206 for (Object k : map.keySet()) {
207 assertEquals(map.put(k, k), k);
208 }
209 }
210
211 /**
212 * clear removes all pairs
213 */
214 public void testClear() {
215 ConcurrentHashMap map = map5();
216 map.clear();
217 assertEquals(0, map.size());
218 }
219
220 /**
221 * Maps with same contents are equal
222 */
223 public void testEquals() {
224 ConcurrentHashMap map1 = map5();
225 ConcurrentHashMap map2 = map5();
226 assertEquals(map1, map2);
227 assertEquals(map2, map1);
228 map1.clear();
229 assertFalse(map1.equals(map2));
230 assertFalse(map2.equals(map1));
231 }
232
233 /**
234 * hashCode() equals sum of each key.hashCode ^ value.hashCode
235 */
236 public void testHashCode() {
237 ConcurrentHashMap<Integer,String> map = map5();
238 int sum = 0;
239 for (Map.Entry<Integer,String> e : map.entrySet())
240 sum += e.getKey().hashCode() ^ e.getValue().hashCode();
241 assertEquals(sum, map.hashCode());
242 }
243
244 /**
245 * contains returns true for contained value
246 */
247 public void testContains() {
248 ConcurrentHashMap map = map5();
249 assertTrue(map.contains("A"));
250 assertFalse(map.contains("Z"));
251 }
252
253 /**
254 * containsKey returns true for contained key
255 */
256 public void testContainsKey() {
257 ConcurrentHashMap map = map5();
258 assertTrue(map.containsKey(one));
259 assertFalse(map.containsKey(zero));
260 }
261
262 /**
263 * containsValue returns true for held values
264 */
265 public void testContainsValue() {
266 ConcurrentHashMap map = map5();
267 assertTrue(map.containsValue("A"));
268 assertFalse(map.containsValue("Z"));
269 }
270
271 /**
272 * enumeration returns an enumeration containing the correct
273 * elements
274 */
275 public void testEnumeration() {
276 ConcurrentHashMap map = map5();
277 Enumeration e = map.elements();
278 int count = 0;
279 while (e.hasMoreElements()) {
280 count++;
281 e.nextElement();
282 }
283 assertEquals(5, count);
284 }
285
286 /**
287 * get returns the correct element at the given key,
288 * or null if not present
289 */
290 public void testGet() {
291 ConcurrentHashMap map = map5();
292 assertEquals("A", (String)map.get(one));
293 ConcurrentHashMap empty = new ConcurrentHashMap();
294 assertNull(map.get("anything"));
295 assertNull(empty.get("anything"));
296 }
297
298 /**
299 * isEmpty is true of empty map and false for non-empty
300 */
301 public void testIsEmpty() {
302 ConcurrentHashMap empty = new ConcurrentHashMap();
303 ConcurrentHashMap map = map5();
304 assertTrue(empty.isEmpty());
305 assertFalse(map.isEmpty());
306 }
307
308 /**
309 * keys returns an enumeration containing all the keys from the map
310 */
311 public void testKeys() {
312 ConcurrentHashMap map = map5();
313 Enumeration e = map.keys();
314 int count = 0;
315 while (e.hasMoreElements()) {
316 count++;
317 e.nextElement();
318 }
319 assertEquals(5, count);
320 }
321
322 /**
323 * keySet returns a Set containing all the keys
324 */
325 public void testKeySet() {
326 ConcurrentHashMap map = map5();
327 Set s = map.keySet();
328 assertEquals(5, s.size());
329 assertTrue(s.contains(one));
330 assertTrue(s.contains(two));
331 assertTrue(s.contains(three));
332 assertTrue(s.contains(four));
333 assertTrue(s.contains(five));
334 }
335
336 /**
337 * Test keySet().removeAll on empty map
338 */
339 public void testKeySet_empty_removeAll() {
340 ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();
341 Set<Integer> set = map.keySet();
342 set.removeAll(Collections.emptyList());
343 assertTrue(map.isEmpty());
344 assertTrue(set.isEmpty());
345 // following is test for JDK-8163353
346 set.removeAll(Collections.emptySet());
347 assertTrue(map.isEmpty());
348 assertTrue(set.isEmpty());
349 }
350
351 /**
352 * keySet.toArray returns contains all keys
353 */
354 public void testKeySetToArray() {
355 ConcurrentHashMap map = map5();
356 Set s = map.keySet();
357 Object[] ar = s.toArray();
358 assertTrue(s.containsAll(Arrays.asList(ar)));
359 assertEquals(5, ar.length);
360 ar[0] = m10;
361 assertFalse(s.containsAll(Arrays.asList(ar)));
362 }
363
364 /**
365 * Values.toArray contains all values
366 */
367 public void testValuesToArray() {
368 ConcurrentHashMap map = map5();
369 Collection v = map.values();
370 Object[] ar = v.toArray();
371 ArrayList s = new ArrayList(Arrays.asList(ar));
372 assertEquals(5, ar.length);
373 assertTrue(s.contains("A"));
374 assertTrue(s.contains("B"));
375 assertTrue(s.contains("C"));
376 assertTrue(s.contains("D"));
377 assertTrue(s.contains("E"));
378 }
379
380 /**
381 * entrySet.toArray contains all entries
382 */
383 public void testEntrySetToArray() {
384 ConcurrentHashMap map = map5();
385 Set s = map.entrySet();
386 Object[] ar = s.toArray();
387 assertEquals(5, ar.length);
388 for (int i = 0; i < 5; ++i) {
389 assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey()));
390 assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue()));
391 }
392 }
393
394 /**
395 * values collection contains all values
396 */
397 public void testValues() {
398 ConcurrentHashMap map = map5();
399 Collection s = map.values();
400 assertEquals(5, s.size());
401 assertTrue(s.contains("A"));
402 assertTrue(s.contains("B"));
403 assertTrue(s.contains("C"));
404 assertTrue(s.contains("D"));
405 assertTrue(s.contains("E"));
406 }
407
408 /**
409 * entrySet contains all pairs
410 */
411 public void testEntrySet() {
412 ConcurrentHashMap map = map5();
413 Set s = map.entrySet();
414 assertEquals(5, s.size());
415 Iterator it = s.iterator();
416 while (it.hasNext()) {
417 Map.Entry e = (Map.Entry) it.next();
418 assertTrue(
419 (e.getKey().equals(one) && e.getValue().equals("A")) ||
420 (e.getKey().equals(two) && e.getValue().equals("B")) ||
421 (e.getKey().equals(three) && e.getValue().equals("C")) ||
422 (e.getKey().equals(four) && e.getValue().equals("D")) ||
423 (e.getKey().equals(five) && e.getValue().equals("E")));
424 }
425 }
426
427 /**
428 * putAll adds all key-value pairs from the given map
429 */
430 public void testPutAll() {
431 ConcurrentHashMap empty = new ConcurrentHashMap();
432 ConcurrentHashMap map = map5();
433 empty.putAll(map);
434 assertEquals(5, empty.size());
435 assertTrue(empty.containsKey(one));
436 assertTrue(empty.containsKey(two));
437 assertTrue(empty.containsKey(three));
438 assertTrue(empty.containsKey(four));
439 assertTrue(empty.containsKey(five));
440 }
441
442 /**
443 * putIfAbsent works when the given key is not present
444 */
445 public void testPutIfAbsent() {
446 ConcurrentHashMap map = map5();
447 map.putIfAbsent(six, "Z");
448 assertTrue(map.containsKey(six));
449 }
450
451 /**
452 * putIfAbsent does not add the pair if the key is already present
453 */
454 public void testPutIfAbsent2() {
455 ConcurrentHashMap map = map5();
456 assertEquals("A", map.putIfAbsent(one, "Z"));
457 }
458
459 /**
460 * replace fails when the given key is not present
461 */
462 public void testReplace() {
463 ConcurrentHashMap map = map5();
464 assertNull(map.replace(six, "Z"));
465 assertFalse(map.containsKey(six));
466 }
467
468 /**
469 * replace succeeds if the key is already present
470 */
471 public void testReplace2() {
472 ConcurrentHashMap map = map5();
473 assertNotNull(map.replace(one, "Z"));
474 assertEquals("Z", map.get(one));
475 }
476
477 /**
478 * replace value fails when the given key not mapped to expected value
479 */
480 public void testReplaceValue() {
481 ConcurrentHashMap map = map5();
482 assertEquals("A", map.get(one));
483 assertFalse(map.replace(one, "Z", "Z"));
484 assertEquals("A", map.get(one));
485 }
486
487 /**
488 * replace value succeeds when the given key mapped to expected value
489 */
490 public void testReplaceValue2() {
491 ConcurrentHashMap map = map5();
492 assertEquals("A", map.get(one));
493 assertTrue(map.replace(one, "A", "Z"));
494 assertEquals("Z", map.get(one));
495 }
496
497 /**
498 * remove removes the correct key-value pair from the map
499 */
500 public void testRemove() {
501 ConcurrentHashMap map = map5();
502 map.remove(five);
503 assertEquals(4, map.size());
504 assertFalse(map.containsKey(five));
505 }
506
507 /**
508 * remove(key,value) removes only if pair present
509 */
510 public void testRemove2() {
511 ConcurrentHashMap map = map5();
512 map.remove(five, "E");
513 assertEquals(4, map.size());
514 assertFalse(map.containsKey(five));
515 map.remove(four, "A");
516 assertEquals(4, map.size());
517 assertTrue(map.containsKey(four));
518 }
519
520 /**
521 * size returns the correct values
522 */
523 public void testSize() {
524 ConcurrentHashMap map = map5();
525 ConcurrentHashMap empty = new ConcurrentHashMap();
526 assertEquals(0, empty.size());
527 assertEquals(5, map.size());
528 }
529
530 /**
531 * toString contains toString of elements
532 */
533 public void testToString() {
534 ConcurrentHashMap map = map5();
535 String s = map.toString();
536 for (int i = 1; i <= 5; ++i) {
537 assertTrue(s.contains(String.valueOf(i)));
538 }
539 }
540
541 // Exception tests
542
543 /**
544 * Cannot create with only negative capacity
545 */
546 public void testConstructor1() {
547 try {
548 new ConcurrentHashMap(-1);
549 shouldThrow();
550 } catch (IllegalArgumentException success) {}
551 }
552
553 /**
554 * Constructor (initialCapacity, loadFactor) throws
555 * IllegalArgumentException if either argument is negative
556 */
557 public void testConstructor2() {
558 try {
559 new ConcurrentHashMap(-1, .75f);
560 shouldThrow();
561 } catch (IllegalArgumentException success) {}
562
563 try {
564 new ConcurrentHashMap(16, -1);
565 shouldThrow();
566 } catch (IllegalArgumentException success) {}
567 }
568
569 /**
570 * Constructor (initialCapacity, loadFactor, concurrencyLevel)
571 * throws IllegalArgumentException if any argument is negative
572 */
573 public void testConstructor3() {
574 try {
575 new ConcurrentHashMap(-1, .75f, 1);
576 shouldThrow();
577 } catch (IllegalArgumentException success) {}
578
579 try {
580 new ConcurrentHashMap(16, -1, 1);
581 shouldThrow();
582 } catch (IllegalArgumentException success) {}
583
584 try {
585 new ConcurrentHashMap(16, .75f, -1);
586 shouldThrow();
587 } catch (IllegalArgumentException success) {}
588 }
589
590 /**
591 * ConcurrentHashMap(map) throws NullPointerException if the given
592 * map is null
593 */
594 public void testConstructor4() {
595 try {
596 new ConcurrentHashMap(null);
597 shouldThrow();
598 } catch (NullPointerException success) {}
599 }
600
601 /**
602 * ConcurrentHashMap(map) creates a new map with the same mappings
603 * as the given map
604 */
605 public void testConstructor5() {
606 ConcurrentHashMap map1 = map5();
607 ConcurrentHashMap map2 = new ConcurrentHashMap(map5());
608 assertTrue(map2.equals(map1));
609 map2.put(one, "F");
610 assertFalse(map2.equals(map1));
611 }
612
613 /**
614 * get(null) throws NPE
615 */
616 public void testGet_NullPointerException() {
617 ConcurrentHashMap c = new ConcurrentHashMap(5);
618 try {
619 c.get(null);
620 shouldThrow();
621 } catch (NullPointerException success) {}
622 }
623
624 /**
625 * containsKey(null) throws NPE
626 */
627 public void testContainsKey_NullPointerException() {
628 ConcurrentHashMap c = new ConcurrentHashMap(5);
629 try {
630 c.containsKey(null);
631 shouldThrow();
632 } catch (NullPointerException success) {}
633 }
634
635 /**
636 * containsValue(null) throws NPE
637 */
638 public void testContainsValue_NullPointerException() {
639 ConcurrentHashMap c = new ConcurrentHashMap(5);
640 try {
641 c.containsValue(null);
642 shouldThrow();
643 } catch (NullPointerException success) {}
644 }
645
646 /**
647 * contains(null) throws NPE
648 */
649 public void testContains_NullPointerException() {
650 ConcurrentHashMap c = new ConcurrentHashMap(5);
651 try {
652 c.contains(null);
653 shouldThrow();
654 } catch (NullPointerException success) {}
655 }
656
657 /**
658 * put(null,x) throws NPE
659 */
660 public void testPut1_NullPointerException() {
661 ConcurrentHashMap c = new ConcurrentHashMap(5);
662 try {
663 c.put(null, "whatever");
664 shouldThrow();
665 } catch (NullPointerException success) {}
666 }
667
668 /**
669 * put(x, null) throws NPE
670 */
671 public void testPut2_NullPointerException() {
672 ConcurrentHashMap c = new ConcurrentHashMap(5);
673 try {
674 c.put("whatever", null);
675 shouldThrow();
676 } catch (NullPointerException success) {}
677 }
678
679 /**
680 * putIfAbsent(null, x) throws NPE
681 */
682 public void testPutIfAbsent1_NullPointerException() {
683 ConcurrentHashMap c = new ConcurrentHashMap(5);
684 try {
685 c.putIfAbsent(null, "whatever");
686 shouldThrow();
687 } catch (NullPointerException success) {}
688 }
689
690 /**
691 * replace(null, x) throws NPE
692 */
693 public void testReplace_NullPointerException() {
694 ConcurrentHashMap c = new ConcurrentHashMap(5);
695 try {
696 c.replace(null, "whatever");
697 shouldThrow();
698 } catch (NullPointerException success) {}
699 }
700
701 /**
702 * replace(null, x, y) throws NPE
703 */
704 public void testReplaceValue_NullPointerException() {
705 ConcurrentHashMap c = new ConcurrentHashMap(5);
706 try {
707 c.replace(null, one, "whatever");
708 shouldThrow();
709 } catch (NullPointerException success) {}
710 }
711
712 /**
713 * putIfAbsent(x, null) throws NPE
714 */
715 public void testPutIfAbsent2_NullPointerException() {
716 ConcurrentHashMap c = new ConcurrentHashMap(5);
717 try {
718 c.putIfAbsent("whatever", null);
719 shouldThrow();
720 } catch (NullPointerException success) {}
721 }
722
723 /**
724 * replace(x, null) throws NPE
725 */
726 public void testReplace2_NullPointerException() {
727 ConcurrentHashMap c = new ConcurrentHashMap(5);
728 try {
729 c.replace("whatever", null);
730 shouldThrow();
731 } catch (NullPointerException success) {}
732 }
733
734 /**
735 * replace(x, null, y) throws NPE
736 */
737 public void testReplaceValue2_NullPointerException() {
738 ConcurrentHashMap c = new ConcurrentHashMap(5);
739 try {
740 c.replace("whatever", null, "A");
741 shouldThrow();
742 } catch (NullPointerException success) {}
743 }
744
745 /**
746 * replace(x, y, null) throws NPE
747 */
748 public void testReplaceValue3_NullPointerException() {
749 ConcurrentHashMap c = new ConcurrentHashMap(5);
750 try {
751 c.replace("whatever", one, null);
752 shouldThrow();
753 } catch (NullPointerException success) {}
754 }
755
756 /**
757 * remove(null) throws NPE
758 */
759 public void testRemove1_NullPointerException() {
760 ConcurrentHashMap c = new ConcurrentHashMap(5);
761 c.put("sadsdf", "asdads");
762 try {
763 c.remove(null);
764 shouldThrow();
765 } catch (NullPointerException success) {}
766 }
767
768 /**
769 * remove(null, x) throws NPE
770 */
771 public void testRemove2_NullPointerException() {
772 ConcurrentHashMap c = new ConcurrentHashMap(5);
773 c.put("sadsdf", "asdads");
774 try {
775 c.remove(null, "whatever");
776 shouldThrow();
777 } catch (NullPointerException success) {}
778 }
779
780 /**
781 * remove(x, null) returns false
782 */
783 public void testRemove3() {
784 ConcurrentHashMap c = new ConcurrentHashMap(5);
785 c.put("sadsdf", "asdads");
786 assertFalse(c.remove("sadsdf", null));
787 }
788
789 /**
790 * A deserialized/reserialized map equals original
791 */
792 public void testSerialization() throws Exception {
793 Map x = map5();
794 Map y = serialClone(x);
795
796 assertNotSame(x, y);
797 assertEquals(x.size(), y.size());
798 assertEquals(x, y);
799 assertEquals(y, x);
800 }
801
802 /**
803 * SetValue of an EntrySet entry sets value in the map.
804 */
805 public void testSetValueWriteThrough() {
806 // Adapted from a bug report by Eric Zoerner
807 ConcurrentHashMap map = new ConcurrentHashMap(2, 5.0f, 1);
808 assertTrue(map.isEmpty());
809 for (int i = 0; i < 20; i++)
810 map.put(new Integer(i), new Integer(i));
811 assertFalse(map.isEmpty());
812 Map.Entry entry1 = (Map.Entry)map.entrySet().iterator().next();
813 // Unless it happens to be first (in which case remainder of
814 // test is skipped), remove a possibly-colliding key from map
815 // which, under some implementations, may cause entry1 to be
816 // cloned in map
817 if (!entry1.getKey().equals(new Integer(16))) {
818 map.remove(new Integer(16));
819 entry1.setValue("XYZ");
820 assertTrue(map.containsValue("XYZ")); // fails if write-through broken
821 }
822 }
823
824 /**
825 * Tests performance of removeAll when the other collection is much smaller.
826 * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testRemoveAll_performance -Djsr166.expensiveTests=true tck
827 */
828 public void testRemoveAll_performance() {
829 final int mapSize = expensiveTests ? 1_000_000 : 100;
830 final int iterations = expensiveTests ? 500 : 2;
831 final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
832 for (int i = 0; i < mapSize; i++)
833 map.put(i, i);
834 Set<Integer> keySet = map.keySet();
835 Collection<Integer> removeMe = Arrays.asList(new Integer[] { -99, -86 });
836 for (int i = 0; i < iterations; i++)
837 assertFalse(keySet.removeAll(removeMe));
838 assertEquals(mapSize, map.size());
839 }
840
841 public void testReentrantComputeIfAbsent() {
842 ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>(16);
843 try {
844 for (int i = 0; i < 100; i++) { // force a resize
845 map.computeIfAbsent(i, key -> findValue(map, key));
846 }
847 fail("recursive computeIfAbsent");
848 } catch (IllegalStateException ex) {
849 }
850 }
851
852 private Integer findValue(ConcurrentHashMap<Integer, Integer> map,
853 Integer key) {
854 return (key % 5 == 0) ? key :
855 map.computeIfAbsent(key + 1, k -> findValue(map, k));
856 }
857
858 }