1/*
2 * Copyright (C) 2008 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.collect.testing;
18
19import java.util.concurrent.ConcurrentMap;
20
21/**
22 * Tests representing the contract of {@link ConcurrentMap}. Concrete
23 * subclasses of this base class test conformance of concrete
24 * {@link ConcurrentMap} subclasses to that contract.
25 *
26 * <p>This class is GWT compatible.
27 *
28 * <p>The tests in this class for null keys and values only check maps for
29 * which null keys and values are not allowed. There are currently no
30 * {@link ConcurrentMap} implementations that support nulls.
31 *
32 * @author Jared Levy
33 */
34public abstract class ConcurrentMapInterfaceTest<K, V>
35    extends MapInterfaceTest<K, V> {
36
37  protected ConcurrentMapInterfaceTest(boolean allowsNullKeys,
38      boolean allowsNullValues, boolean supportsPut, boolean supportsRemove,
39      boolean supportsClear) {
40    super(allowsNullKeys, allowsNullValues, supportsPut, supportsRemove,
41        supportsClear);
42  }
43
44  /**
45   * Creates a new value that is not expected to be found in
46   * {@link #makePopulatedMap()} and differs from the value returned by
47   * {@link #getValueNotInPopulatedMap()}.
48   *
49   * @return a value
50   * @throws UnsupportedOperationException if it's not possible to make a value
51   * that will not be found in the map
52   */
53  protected abstract V getSecondValueNotInPopulatedMap()
54      throws UnsupportedOperationException;
55
56  @Override protected abstract ConcurrentMap<K, V> makeEmptyMap()
57      throws UnsupportedOperationException;
58
59  @Override protected abstract ConcurrentMap<K, V> makePopulatedMap()
60      throws UnsupportedOperationException;
61
62  @Override protected ConcurrentMap<K, V> makeEitherMap() {
63    try {
64      return makePopulatedMap();
65    } catch (UnsupportedOperationException e) {
66      return makeEmptyMap();
67    }
68  }
69
70  public void testPutIfAbsentNewKey() {
71    final ConcurrentMap<K, V> map;
72    final K keyToPut;
73    final V valueToPut;
74    try {
75      map = makeEitherMap();
76      keyToPut = getKeyNotInPopulatedMap();
77      valueToPut = getValueNotInPopulatedMap();
78    } catch (UnsupportedOperationException e) {
79      return;
80    }
81    if (supportsPut) {
82      int initialSize = map.size();
83      V oldValue = map.putIfAbsent(keyToPut, valueToPut);
84      assertEquals(valueToPut, map.get(keyToPut));
85      assertTrue(map.containsKey(keyToPut));
86      assertTrue(map.containsValue(valueToPut));
87      assertEquals(initialSize + 1, map.size());
88      assertNull(oldValue);
89    } else {
90      try {
91        map.putIfAbsent(keyToPut, valueToPut);
92        fail("Expected UnsupportedOperationException.");
93      } catch (UnsupportedOperationException e) {
94        // Expected.
95      }
96    }
97    assertInvariants(map);
98  }
99
100  public void testPutIfAbsentExistingKey() {
101    final ConcurrentMap<K, V> map;
102    final K keyToPut;
103    final V valueToPut;
104    try {
105      map = makePopulatedMap();
106      valueToPut = getValueNotInPopulatedMap();
107    } catch (UnsupportedOperationException e) {
108      return;
109    }
110    keyToPut = map.keySet().iterator().next();
111    if (supportsPut) {
112      V oldValue = map.get(keyToPut);
113      int initialSize = map.size();
114      assertEquals(oldValue, map.putIfAbsent(keyToPut, valueToPut));
115      assertEquals(oldValue, map.get(keyToPut));
116      assertTrue(map.containsKey(keyToPut));
117      assertTrue(map.containsValue(oldValue));
118      assertFalse(map.containsValue(valueToPut));
119      assertEquals(initialSize, map.size());
120    } else {
121      try {
122        map.putIfAbsent(keyToPut, valueToPut);
123        fail("Expected UnsupportedOperationException.");
124      } catch (UnsupportedOperationException e) {
125        // Expected.
126      }
127    }
128    assertInvariants(map);
129  }
130
131  public void testPutIfAbsentNullKey() {
132    if (allowsNullKeys) {
133      return;   // Not yet implemented
134    }
135    final ConcurrentMap<K, V> map;
136    final V valueToPut;
137    try {
138      map = makeEitherMap();
139      valueToPut = getValueNotInPopulatedMap();
140    } catch (UnsupportedOperationException e) {
141      return;
142    }
143    int initialSize = map.size();
144    if (supportsPut) {
145      try {
146        map.putIfAbsent(null, valueToPut);
147        fail("Expected NullPointerException");
148      } catch (NullPointerException e) {
149        // Expected.
150      }
151    } else {
152      try {
153        map.putIfAbsent(null, valueToPut);
154        fail("Expected UnsupportedOperationException or NullPointerException");
155      } catch (UnsupportedOperationException e) {
156        // Expected.
157      } catch (NullPointerException e) {
158        // Expected.
159      }
160    }
161    assertEquals(initialSize, map.size());
162    assertInvariants(map);
163  }
164
165  public void testPutIfAbsentNewKeyNullValue() {
166    if (allowsNullValues) {
167      return;   // Not yet implemented
168    }
169    final ConcurrentMap<K, V> map;
170    final K keyToPut;
171    try {
172      map = makeEitherMap();
173      keyToPut = getKeyNotInPopulatedMap();
174    } catch (UnsupportedOperationException e) {
175      return;
176    }
177    int initialSize = map.size();
178    if (supportsPut) {
179      try {
180        map.putIfAbsent(keyToPut, null);
181        fail("Expected NullPointerException");
182      } catch (NullPointerException e) {
183        // Expected.
184      }
185    } else {
186      try {
187        map.putIfAbsent(keyToPut, null);
188        fail("Expected UnsupportedOperationException or NullPointerException");
189      } catch (UnsupportedOperationException e) {
190        // Expected.
191      } catch (NullPointerException e) {
192        // Expected.
193      }
194    }
195    assertEquals(initialSize, map.size());
196    assertInvariants(map);
197  }
198
199  public void testPutIfAbsentExistingKeyNullValue() {
200    if (allowsNullValues) {
201      return;   // Not yet implemented
202    }
203    final ConcurrentMap<K, V> map;
204    final K keyToPut;
205    try {
206      map = makePopulatedMap();
207    } catch (UnsupportedOperationException e) {
208      return;
209    }
210    keyToPut = map.keySet().iterator().next();
211    int initialSize = map.size();
212    if (supportsPut) {
213      try {
214        assertNull(map.putIfAbsent(keyToPut, null));
215      } catch (NullPointerException e) {
216        // Optional.
217      }
218    } else {
219      try {
220        map.putIfAbsent(keyToPut, null);
221        fail("Expected UnsupportedOperationException or NullPointerException");
222      } catch (UnsupportedOperationException e) {
223        // Expected.
224      } catch (NullPointerException e) {
225        // Expected.
226      }
227    }
228    assertEquals(initialSize, map.size());
229    assertInvariants(map);
230  }
231
232  public void testRemoveKeyValueExisting() {
233    final ConcurrentMap<K, V> map;
234    final K keyToRemove;
235    try {
236      map = makePopulatedMap();
237    } catch (UnsupportedOperationException e) {
238      return;
239    }
240    keyToRemove = map.keySet().iterator().next();
241    V oldValue = map.get(keyToRemove);
242    if (supportsRemove) {
243      int initialSize = map.size();
244      assertTrue(map.remove(keyToRemove, oldValue));
245      assertFalse(map.containsKey(keyToRemove));
246      assertEquals(initialSize - 1, map.size());
247    } else {
248      try {
249        map.remove(keyToRemove, oldValue);
250        fail("Expected UnsupportedOperationException.");
251      } catch (UnsupportedOperationException e) {
252        // Expected.
253      }
254    }
255    assertInvariants(map);
256  }
257
258  public void testRemoveKeyValueMissingKey() {
259    final ConcurrentMap<K, V> map;
260    final K keyToRemove;
261    final V valueToRemove;
262    try {
263      map = makePopulatedMap();
264      keyToRemove = getKeyNotInPopulatedMap();
265      valueToRemove = getValueNotInPopulatedMap();
266    } catch (UnsupportedOperationException e) {
267      return;
268    }
269    if (supportsRemove) {
270      int initialSize = map.size();
271      assertFalse(map.remove(keyToRemove, valueToRemove));
272      assertEquals(initialSize, map.size());
273    } else {
274      try {
275        map.remove(keyToRemove, valueToRemove);
276        fail("Expected UnsupportedOperationException.");
277      } catch (UnsupportedOperationException e) {
278        // Expected.
279      }
280    }
281    assertInvariants(map);
282  }
283
284  public void testRemoveKeyValueDifferentValue() {
285    final ConcurrentMap<K, V> map;
286    final K keyToRemove;
287    final V valueToRemove;
288    try {
289      map = makePopulatedMap();
290      valueToRemove = getValueNotInPopulatedMap();
291    } catch (UnsupportedOperationException e) {
292      return;
293    }
294    keyToRemove = map.keySet().iterator().next();
295    if (supportsRemove) {
296      int initialSize = map.size();
297      V oldValue = map.get(keyToRemove);
298      assertFalse(map.remove(keyToRemove, valueToRemove));
299      assertEquals(oldValue, map.get(keyToRemove));
300      assertTrue(map.containsKey(keyToRemove));
301      assertEquals(initialSize, map.size());
302    } else {
303      try {
304        map.remove(keyToRemove, valueToRemove);
305        fail("Expected UnsupportedOperationException.");
306      } catch (UnsupportedOperationException e) {
307        // Expected.
308      }
309    }
310    assertInvariants(map);
311  }
312
313  public void testRemoveKeyValueNullKey() {
314    if (allowsNullKeys) {
315      return;   // Not yet implemented
316    }
317    final ConcurrentMap<K, V> map;
318    final V valueToRemove;
319    try {
320      map = makeEitherMap();
321      valueToRemove = getValueNotInPopulatedMap();
322    } catch (UnsupportedOperationException e) {
323      return;
324    }
325    int initialSize = map.size();
326    if (supportsRemove) {
327      try {
328        assertFalse(map.remove(null, valueToRemove));
329      } catch (NullPointerException e) {
330        // Optional.
331      }
332    } else {
333      try {
334        assertFalse(map.remove(null, valueToRemove));
335      } catch (UnsupportedOperationException e) {
336        // Optional.
337      } catch (NullPointerException e) {
338        // Optional.
339      }
340    }
341    assertEquals(initialSize, map.size());
342    assertInvariants(map);
343  }
344
345  public void testRemoveKeyValueExistingKeyNullValue() {
346    if (allowsNullValues) {
347      return;   // Not yet implemented
348    }
349    final ConcurrentMap<K, V> map;
350    final K keyToRemove;
351    try {
352      map = makePopulatedMap();
353    } catch (UnsupportedOperationException e) {
354      return;
355    }
356    keyToRemove = map.keySet().iterator().next();
357    int initialSize = map.size();
358    if (supportsRemove) {
359      try {
360        assertFalse(map.remove(keyToRemove, null));
361      } catch (NullPointerException e) {
362        // Optional.
363      }
364    } else {
365      try {
366        assertFalse(map.remove(keyToRemove, null));
367      } catch (UnsupportedOperationException e) {
368        // Optional.
369      } catch (NullPointerException e) {
370        // Optional.
371      }
372    }
373    assertEquals(initialSize, map.size());
374    assertInvariants(map);
375  }
376
377  public void testRemoveKeyValueMissingKeyNullValue() {
378    if (allowsNullValues) {
379      return;   // Not yet implemented
380    }
381    final ConcurrentMap<K, V> map;
382    final K keyToRemove;
383    try {
384      map = makeEitherMap();
385      keyToRemove = getKeyNotInPopulatedMap();
386    } catch (UnsupportedOperationException e) {
387      return;
388    }
389    int initialSize = map.size();
390    if (supportsRemove) {
391      try {
392        assertFalse(map.remove(keyToRemove, null));
393      } catch (NullPointerException e) {
394        // Optional.
395      }
396    } else {
397      try {
398        assertFalse(map.remove(keyToRemove, null));
399      } catch (UnsupportedOperationException e) {
400        // Optional.
401      } catch (NullPointerException e) {
402        // Optional.
403      }
404    }
405    assertEquals(initialSize, map.size());
406    assertInvariants(map);
407  }
408
409  /* Replace2 tests call 2-parameter replace(key, value) */
410
411  public void testReplace2ExistingKey() {
412    final ConcurrentMap<K, V> map;
413    final K keyToReplace;
414    final V newValue;
415    try {
416      map = makePopulatedMap();
417      newValue = getValueNotInPopulatedMap();
418    } catch (UnsupportedOperationException e) {
419      return;
420    }
421    keyToReplace = map.keySet().iterator().next();
422    if (supportsPut) {
423      V oldValue = map.get(keyToReplace);
424      int initialSize = map.size();
425      assertEquals(oldValue, map.replace(keyToReplace, newValue));
426      assertEquals(newValue, map.get(keyToReplace));
427      assertTrue(map.containsKey(keyToReplace));
428      assertTrue(map.containsValue(newValue));
429      assertEquals(initialSize, map.size());
430    } else {
431      try {
432        map.replace(keyToReplace, newValue);
433        fail("Expected UnsupportedOperationException.");
434      } catch (UnsupportedOperationException e) {
435        // Expected.
436      }
437    }
438    assertInvariants(map);
439  }
440
441  public void testReplace2MissingKey() {
442    final ConcurrentMap<K, V> map;
443    final K keyToReplace;
444    final V newValue;
445    try {
446      map = makeEitherMap();
447      keyToReplace = getKeyNotInPopulatedMap();
448      newValue = getValueNotInPopulatedMap();
449    } catch (UnsupportedOperationException e) {
450      return;
451    }
452    if (supportsPut) {
453      int initialSize = map.size();
454      assertNull(map.replace(keyToReplace, newValue));
455      assertNull(map.get(keyToReplace));
456      assertFalse(map.containsKey(keyToReplace));
457      assertFalse(map.containsValue(newValue));
458      assertEquals(initialSize, map.size());
459    } else {
460      try {
461        map.replace(keyToReplace, newValue);
462        fail("Expected UnsupportedOperationException.");
463      } catch (UnsupportedOperationException e) {
464        // Expected.
465      }
466    }
467    assertInvariants(map);
468  }
469
470  public void testReplace2NullKey() {
471    if (allowsNullKeys) {
472      return;   // Not yet implemented
473    }
474    final ConcurrentMap<K, V> map;
475    final V valueToReplace;
476    try {
477      map = makeEitherMap();
478      valueToReplace = getValueNotInPopulatedMap();
479    } catch (UnsupportedOperationException e) {
480      return;
481    }
482    int initialSize = map.size();
483    if (supportsPut) {
484      try {
485        assertNull(map.replace(null, valueToReplace));
486      } catch (NullPointerException e) {
487        // Optional.
488      }
489    } else {
490      try {
491        assertNull(map.replace(null, valueToReplace));
492      } catch (UnsupportedOperationException e) {
493        // Optional.
494      } catch (NullPointerException e) {
495        // Optional.
496      }
497    }
498    assertEquals(initialSize, map.size());
499    assertInvariants(map);
500  }
501
502  public void testReplace2ExistingKeyNullValue() {
503    if (allowsNullValues) {
504      return;   // Not yet implemented
505    }
506    final ConcurrentMap<K, V> map;
507    final K keyToReplace;
508    try {
509      map = makePopulatedMap();
510    } catch (UnsupportedOperationException e) {
511      return;
512    }
513    keyToReplace = map.keySet().iterator().next();
514    int initialSize = map.size();
515    if (supportsPut) {
516      try {
517        map.replace(keyToReplace, null);
518        fail("Expected NullPointerException");
519      } catch (NullPointerException e) {
520        // Expected.
521      }
522    } else {
523      try {
524        map.replace(keyToReplace, null);
525        fail("Expected UnsupportedOperationException or NullPointerException");
526      } catch (UnsupportedOperationException e) {
527        // Expected.
528      } catch (NullPointerException e) {
529        // Expected.
530      }
531    }
532    assertEquals(initialSize, map.size());
533    assertInvariants(map);
534  }
535
536  public void testReplace2MissingKeyNullValue() {
537    if (allowsNullValues) {
538      return;   // Not yet implemented
539    }
540    final ConcurrentMap<K, V> map;
541    final K keyToReplace;
542    try {
543      map = makeEitherMap();
544      keyToReplace = getKeyNotInPopulatedMap();
545    } catch (UnsupportedOperationException e) {
546      return;
547    }
548    int initialSize = map.size();
549    if (supportsPut) {
550      try {
551        assertNull(map.replace(keyToReplace, null));
552      } catch (NullPointerException e) {
553        // Optional.
554      }
555    } else {
556      try {
557        assertNull(map.replace(keyToReplace, null));
558      } catch (UnsupportedOperationException e) {
559        // Optional.
560      } catch (NullPointerException e) {
561        // Optional.
562      }
563    }
564    assertEquals(initialSize, map.size());
565    assertInvariants(map);
566  }
567
568  /*
569   * Replace3 tests call 3-parameter replace(key, oldValue, newValue)
570   */
571
572  public void testReplace3ExistingKeyValue() {
573    final ConcurrentMap<K, V> map;
574    final K keyToReplace;
575    final V oldValue;
576    final V newValue;
577    try {
578      map = makePopulatedMap();
579      newValue = getValueNotInPopulatedMap();
580    } catch (UnsupportedOperationException e) {
581      return;
582    }
583    keyToReplace = map.keySet().iterator().next();
584    oldValue = map.get(keyToReplace);
585    if (supportsPut) {
586      int initialSize = map.size();
587      assertTrue(map.replace(keyToReplace, oldValue, newValue));
588      assertEquals(newValue, map.get(keyToReplace));
589      assertTrue(map.containsKey(keyToReplace));
590      assertTrue(map.containsValue(newValue));
591      assertFalse(map.containsValue(oldValue));
592      assertEquals(initialSize, map.size());
593    } else {
594      try {
595        map.replace(keyToReplace, oldValue, newValue);
596        fail("Expected UnsupportedOperationException.");
597      } catch (UnsupportedOperationException e) {
598        // Expected.
599      }
600    }
601    assertInvariants(map);
602  }
603
604  public void testReplace3ExistingKeyDifferentValue() {
605    final ConcurrentMap<K, V> map;
606    final K keyToReplace;
607    final V oldValue;
608    final V newValue;
609    try {
610      map = makePopulatedMap();
611      oldValue = getValueNotInPopulatedMap();
612      newValue = getSecondValueNotInPopulatedMap();
613    } catch (UnsupportedOperationException e) {
614      return;
615    }
616    keyToReplace = map.keySet().iterator().next();
617    final V originalValue = map.get(keyToReplace);
618    int initialSize = map.size();
619    if (supportsPut) {
620      assertFalse(map.replace(keyToReplace, oldValue, newValue));
621    } else {
622      try {
623        map.replace(keyToReplace, oldValue, newValue);
624        fail("Expected UnsupportedOperationException.");
625      } catch (UnsupportedOperationException e) {
626        // Expected.
627      }
628    }
629    assertTrue(map.containsKey(keyToReplace));
630    assertFalse(map.containsValue(newValue));
631    assertFalse(map.containsValue(oldValue));
632    assertEquals(originalValue, map.get(keyToReplace));
633    assertEquals(initialSize, map.size());
634    assertInvariants(map);
635  }
636
637  public void testReplace3MissingKey() {
638    final ConcurrentMap<K, V> map;
639    final K keyToReplace;
640    final V oldValue;
641    final V newValue;
642    try {
643      map = makeEitherMap();
644      keyToReplace = getKeyNotInPopulatedMap();
645      oldValue = getValueNotInPopulatedMap();
646      newValue = getSecondValueNotInPopulatedMap();
647    } catch (UnsupportedOperationException e) {
648      return;
649    }
650    int initialSize = map.size();
651    if (supportsPut) {
652      assertFalse(map.replace(keyToReplace, oldValue, newValue));
653    } else {
654      try {
655        map.replace(keyToReplace, oldValue, newValue);
656        fail("Expected UnsupportedOperationException.");
657      } catch (UnsupportedOperationException e) {
658        // Expected.
659      }
660    }
661    assertFalse(map.containsKey(keyToReplace));
662    assertFalse(map.containsValue(newValue));
663    assertFalse(map.containsValue(oldValue));
664    assertEquals(initialSize, map.size());
665    assertInvariants(map);
666  }
667
668  public void testReplace3NullKey() {
669    if (allowsNullKeys) {
670      return;   // Not yet implemented
671    }
672    final ConcurrentMap<K, V> map;
673    final V oldValue;
674    final V newValue;
675    try {
676      map = makeEitherMap();
677      oldValue = getValueNotInPopulatedMap();
678      newValue = getSecondValueNotInPopulatedMap();
679    } catch (UnsupportedOperationException e) {
680      return;
681    }
682    int initialSize = map.size();
683    if (supportsPut) {
684      try {
685        assertFalse(map.replace(null, oldValue, newValue));
686      } catch (NullPointerException e) {
687        // Optional.
688      }
689    } else {
690      try {
691        assertFalse(map.replace(null, oldValue, newValue));
692      } catch (UnsupportedOperationException e) {
693        // Optional.
694      } catch (NullPointerException e) {
695        // Optional.
696      }
697    }
698    assertEquals(initialSize, map.size());
699    assertInvariants(map);
700  }
701
702  public void testReplace3ExistingKeyNullOldValue() {
703    if (allowsNullValues) {
704      return;   // Not yet implemented
705    }
706    final ConcurrentMap<K, V> map;
707    final K keyToReplace;
708    final V newValue;
709    try {
710      map = makePopulatedMap();
711      newValue = getValueNotInPopulatedMap();
712    } catch (UnsupportedOperationException e) {
713      return;
714    }
715    keyToReplace = map.keySet().iterator().next();
716    final V originalValue = map.get(keyToReplace);
717    int initialSize = map.size();
718    if (supportsPut) {
719      try {
720        assertFalse(map.replace(keyToReplace, null, newValue));
721      } catch (NullPointerException e) {
722        // Optional.
723      }
724    } else {
725      try {
726        assertFalse(map.replace(keyToReplace, null, newValue));
727      } catch (UnsupportedOperationException e) {
728        // Optional.
729      } catch (NullPointerException e) {
730        // Optional.
731      }
732    }
733    assertEquals(initialSize, map.size());
734    assertEquals(originalValue, map.get(keyToReplace));
735    assertInvariants(map);
736  }
737
738  public void testReplace3MissingKeyNullOldValue() {
739    if (allowsNullValues) {
740      return;   // Not yet implemented
741    }
742    final ConcurrentMap<K, V> map;
743    final K keyToReplace;
744    final V newValue;
745    try {
746      map = makeEitherMap();
747      keyToReplace = getKeyNotInPopulatedMap();
748      newValue = getValueNotInPopulatedMap();
749    } catch (UnsupportedOperationException e) {
750      return;
751    }
752    int initialSize = map.size();
753    if (supportsPut) {
754      try {
755        assertFalse(map.replace(keyToReplace, null, newValue));
756      } catch (NullPointerException e) {
757        // Optional.
758      }
759    } else {
760      try {
761        assertFalse(map.replace(keyToReplace, null, newValue));
762      } catch (UnsupportedOperationException e) {
763        // Optional.
764      } catch (NullPointerException e) {
765        // Optional.
766      }
767    }
768    assertEquals(initialSize, map.size());
769    assertInvariants(map);
770  }
771
772  public void testReplace3MissingKeyNullNewValue() {
773    if (allowsNullValues) {
774      return;   // Not yet implemented
775    }
776    final ConcurrentMap<K, V> map;
777    final K keyToReplace;
778    final V oldValue;
779    try {
780      map = makeEitherMap();
781      keyToReplace = getKeyNotInPopulatedMap();
782      oldValue = getValueNotInPopulatedMap();
783    } catch (UnsupportedOperationException e) {
784      return;
785    }
786    int initialSize = map.size();
787    if (supportsPut) {
788      try {
789        map.replace(keyToReplace, oldValue, null);
790      } catch (NullPointerException e) {
791        // Optional.
792      }
793    } else {
794      try {
795        map.replace(keyToReplace, oldValue, null);
796      } catch (UnsupportedOperationException e) {
797        // Optional.
798      } catch (NullPointerException e) {
799        // Optional.
800      }
801    }
802    assertEquals(initialSize, map.size());
803    assertInvariants(map);
804  }
805
806  public void testReplace3ExistingKeyValueNullNewValue() {
807    if (allowsNullValues) {
808      return;   // Not yet implemented
809    }
810    final ConcurrentMap<K, V> map;
811    final K keyToReplace;
812    final V oldValue;
813    try {
814      map = makePopulatedMap();
815    } catch (UnsupportedOperationException e) {
816      return;
817    }
818    keyToReplace = map.keySet().iterator().next();
819    oldValue = map.get(keyToReplace);
820    int initialSize = map.size();
821    if (supportsPut) {
822      try {
823        map.replace(keyToReplace, oldValue, null);
824        fail("Expected NullPointerException");
825      } catch (NullPointerException e) {
826        // Expected.
827      }
828    } else {
829      try {
830        map.replace(keyToReplace, oldValue, null);
831        fail("Expected UnsupportedOperationException or NullPointerException");
832      } catch (UnsupportedOperationException e) {
833        // Expected.
834      } catch (NullPointerException e) {
835        // Expected.
836      }
837    }
838    assertEquals(initialSize, map.size());
839    assertEquals(oldValue, map.get(keyToReplace));
840    assertInvariants(map);
841  }
842}
843