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