View Javadoc
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  
17  package com.google.common.collect.testing;
18  
19  import static java.util.Collections.singleton;
20  
21  import com.google.common.annotations.GwtCompatible;
22  
23  import junit.framework.TestCase;
24  
25  import java.util.Arrays;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.HashSet;
29  import java.util.Iterator;
30  import java.util.Map;
31  import java.util.Map.Entry;
32  import java.util.Set;
33  
34  /**
35   * Tests representing the contract of {@link Map}. Concrete subclasses of this
36   * base class test conformance of concrete {@link Map} subclasses to that
37   * contract.
38   *
39   * TODO: Descriptive assertion messages, with hints as to probable
40   * fixes.
41   * TODO: Add another constructor parameter indicating whether the
42   * class under test is ordered, and check the order if so.
43   * TODO: Refactor to share code with SetTestBuilder &c.
44   *
45   * @param <K> the type of keys used by the maps under test
46   * @param <V> the type of mapped values used the maps under test
47   *
48   * @author George van den Driessche
49   */
50  @GwtCompatible
51  public abstract class MapInterfaceTest<K, V> extends TestCase {
52  
53    /** A key type that is not assignable to any classes but Object. */
54    private static final class IncompatibleKeyType {
55      @Override public String toString() {
56        return "IncompatibleKeyType";
57      }
58    }
59  
60    protected final boolean supportsPut;
61    protected final boolean supportsRemove;
62    protected final boolean supportsClear;
63    protected final boolean allowsNullKeys;
64    protected final boolean allowsNullValues;
65    protected final boolean supportsIteratorRemove;
66  
67    /**
68     * Creates a new, empty instance of the class under test.
69     *
70     * @return a new, empty map instance.
71     * @throws UnsupportedOperationException if it's not possible to make an
72     * empty instance of the class under test.
73     */
74    protected abstract Map<K, V> makeEmptyMap()
75        throws UnsupportedOperationException;
76  
77    /**
78     * Creates a new, non-empty instance of the class under test.
79     *
80     * @return a new, non-empty map instance.
81     * @throws UnsupportedOperationException if it's not possible to make a
82     * non-empty instance of the class under test.
83     */
84    protected abstract Map<K, V> makePopulatedMap()
85        throws UnsupportedOperationException;
86  
87    /**
88     * Creates a new key that is not expected to be found
89     * in {@link #makePopulatedMap()}.
90     *
91     * @return a key.
92     * @throws UnsupportedOperationException if it's not possible to make a key
93     * that will not be found in the map.
94     */
95    protected abstract K getKeyNotInPopulatedMap()
96        throws UnsupportedOperationException;
97  
98    /**
99     * Creates a new value that is not expected to be found
100    * in {@link #makePopulatedMap()}.
101    *
102    * @return a value.
103    * @throws UnsupportedOperationException if it's not possible to make a value
104    * that will not be found in the map.
105    */
106   protected abstract V getValueNotInPopulatedMap()
107       throws UnsupportedOperationException;
108 
109   /**
110    * Constructor that assigns {@code supportsIteratorRemove} the same value as
111    * {@code supportsRemove}.
112    */
113   protected MapInterfaceTest(
114       boolean allowsNullKeys,
115       boolean allowsNullValues,
116       boolean supportsPut,
117       boolean supportsRemove,
118       boolean supportsClear) {
119     this(allowsNullKeys, allowsNullValues, supportsPut, supportsRemove,
120         supportsClear, supportsRemove);
121   }
122 
123   /**
124    * Constructor with an explicit {@code supportsIteratorRemove} parameter.
125    */
126   protected MapInterfaceTest(
127       boolean allowsNullKeys,
128       boolean allowsNullValues,
129       boolean supportsPut,
130       boolean supportsRemove,
131       boolean supportsClear,
132       boolean supportsIteratorRemove) {
133     this.supportsPut = supportsPut;
134     this.supportsRemove = supportsRemove;
135     this.supportsClear = supportsClear;
136     this.allowsNullKeys = allowsNullKeys;
137     this.allowsNullValues = allowsNullValues;
138     this.supportsIteratorRemove = supportsIteratorRemove;
139   }
140 
141   /**
142    * Used by tests that require a map, but don't care whether it's
143    * populated or not.
144    *
145    * @return a new map instance.
146    */
147   protected Map<K, V> makeEitherMap() {
148     try {
149       return makePopulatedMap();
150     } catch (UnsupportedOperationException e) {
151       return makeEmptyMap();
152     }
153   }
154 
155   protected final boolean supportsValuesHashCode(Map<K, V> map) {
156     // get the first non-null value
157     Collection<V> values = map.values();
158     for (V value : values) {
159       if (value != null) {
160         try {
161           value.hashCode();
162         } catch (Exception e) {
163           return false;
164         }
165         return true;
166       }
167     }
168     return true;
169   }
170 
171   /**
172    * Checks all the properties that should always hold of a map. Also calls
173    * {@link #assertMoreInvariants} to check invariants that are peculiar to
174    * specific implementations.
175    *
176    * @see #assertMoreInvariants
177    * @param map the map to check.
178    */
179   protected final void assertInvariants(Map<K, V> map) {
180     Set<K> keySet = map.keySet();
181     Collection<V> valueCollection = map.values();
182     Set<Entry<K, V>> entrySet = map.entrySet();
183 
184     assertEquals(map.size() == 0, map.isEmpty());
185     assertEquals(map.size(), keySet.size());
186     assertEquals(keySet.size() == 0, keySet.isEmpty());
187     assertEquals(!keySet.isEmpty(), keySet.iterator().hasNext());
188 
189     int expectedKeySetHash = 0;
190     for (K key : keySet) {
191       V value = map.get(key);
192       expectedKeySetHash += key != null ? key.hashCode() : 0;
193       assertTrue(map.containsKey(key));
194       assertTrue(map.containsValue(value));
195       assertTrue(valueCollection.contains(value));
196       assertTrue(valueCollection.containsAll(Collections.singleton(value)));
197       assertTrue(entrySet.contains(mapEntry(key, value)));
198       assertTrue(allowsNullKeys || (key != null));
199     }
200     assertEquals(expectedKeySetHash, keySet.hashCode());
201 
202     assertEquals(map.size(), valueCollection.size());
203     assertEquals(valueCollection.size() == 0, valueCollection.isEmpty());
204     assertEquals(
205         !valueCollection.isEmpty(), valueCollection.iterator().hasNext());
206     for (V value : valueCollection) {
207       assertTrue(map.containsValue(value));
208       assertTrue(allowsNullValues || (value != null));
209     }
210 
211     assertEquals(map.size(), entrySet.size());
212     assertEquals(entrySet.size() == 0, entrySet.isEmpty());
213     assertEquals(!entrySet.isEmpty(), entrySet.iterator().hasNext());
214     assertFalse(entrySet.contains("foo"));
215 
216     boolean supportsValuesHashCode = supportsValuesHashCode(map);
217     if (supportsValuesHashCode) {
218       int expectedEntrySetHash = 0;
219       for (Entry<K, V> entry : entrySet) {
220         assertTrue(map.containsKey(entry.getKey()));
221         assertTrue(map.containsValue(entry.getValue()));
222         int expectedHash =
223             (entry.getKey() == null ? 0 : entry.getKey().hashCode()) ^
224             (entry.getValue() == null ? 0 : entry.getValue().hashCode());
225         assertEquals(expectedHash, entry.hashCode());
226         expectedEntrySetHash += expectedHash;
227       }
228       assertEquals(expectedEntrySetHash, entrySet.hashCode());
229       assertTrue(entrySet.containsAll(new HashSet<Entry<K, V>>(entrySet)));
230       assertTrue(entrySet.equals(new HashSet<Entry<K, V>>(entrySet)));
231     }
232 
233     Object[] entrySetToArray1 = entrySet.toArray();
234     assertEquals(map.size(), entrySetToArray1.length);
235     assertTrue(Arrays.asList(entrySetToArray1).containsAll(entrySet));
236 
237     Entry<?, ?>[] entrySetToArray2 = new Entry<?, ?>[map.size() + 2];
238     entrySetToArray2[map.size()] = mapEntry("foo", 1);
239     assertSame(entrySetToArray2, entrySet.toArray(entrySetToArray2));
240     assertNull(entrySetToArray2[map.size()]);
241     assertTrue(Arrays.asList(entrySetToArray2).containsAll(entrySet));
242 
243     Object[] valuesToArray1 = valueCollection.toArray();
244     assertEquals(map.size(), valuesToArray1.length);
245     assertTrue(Arrays.asList(valuesToArray1).containsAll(valueCollection));
246 
247     Object[] valuesToArray2 = new Object[map.size() + 2];
248     valuesToArray2[map.size()] = "foo";
249     assertSame(valuesToArray2, valueCollection.toArray(valuesToArray2));
250     assertNull(valuesToArray2[map.size()]);
251     assertTrue(Arrays.asList(valuesToArray2).containsAll(valueCollection));
252 
253     if (supportsValuesHashCode) {
254       int expectedHash = 0;
255       for (Entry<K, V> entry : entrySet) {
256         expectedHash += entry.hashCode();
257       }
258       assertEquals(expectedHash, map.hashCode());
259     }
260 
261     assertMoreInvariants(map);
262   }
263 
264   /**
265    * Override this to check invariants which should hold true for a particular
266    * implementation, but which are not generally applicable to every instance
267    * of Map.
268    *
269    * @param map the map whose additional invariants to check.
270    */
271   protected void assertMoreInvariants(Map<K, V> map) {
272   }
273 
274   public void testClear() {
275     final Map<K, V> map;
276     try {
277       map = makePopulatedMap();
278     } catch (UnsupportedOperationException e) {
279       return;
280     }
281 
282     if (supportsClear) {
283       map.clear();
284       assertTrue(map.isEmpty());
285     } else {
286       try {
287         map.clear();
288         fail("Expected UnsupportedOperationException.");
289       } catch (UnsupportedOperationException e) {
290         // Expected.
291       }
292     }
293     assertInvariants(map);
294   }
295 
296   public void testContainsKey() {
297     final Map<K, V> map;
298     final K unmappedKey;
299     try {
300       map = makePopulatedMap();
301       unmappedKey = getKeyNotInPopulatedMap();
302     } catch (UnsupportedOperationException e) {
303       return;
304     }
305     assertFalse(map.containsKey(unmappedKey));
306     try {
307       assertFalse(map.containsKey(new IncompatibleKeyType()));
308     } catch (ClassCastException tolerated) {}
309     assertTrue(map.containsKey(map.keySet().iterator().next()));
310     if (allowsNullKeys) {
311       map.containsKey(null);
312     } else {
313       try {
314         map.containsKey(null);
315       } catch (NullPointerException optional) {
316       }
317     }
318     assertInvariants(map);
319   }
320 
321   public void testContainsValue() {
322     final Map<K, V> map;
323     final V unmappedValue;
324     try {
325       map = makePopulatedMap();
326       unmappedValue = getValueNotInPopulatedMap();
327     } catch (UnsupportedOperationException e) {
328       return;
329     }
330     assertFalse(map.containsValue(unmappedValue));
331     assertTrue(map.containsValue(map.values().iterator().next()));
332     if (allowsNullValues) {
333       map.containsValue(null);
334     } else {
335       try {
336         map.containsKey(null);
337       } catch (NullPointerException optional) {
338       }
339     }
340     assertInvariants(map);
341   }
342 
343   public void testEntrySet() {
344     final Map<K, V> map;
345     final Set<Entry<K, V>> entrySet;
346     try {
347       map = makePopulatedMap();
348     } catch (UnsupportedOperationException e) {
349       return;
350     }
351     assertInvariants(map);
352 
353     entrySet = map.entrySet();
354     final K unmappedKey;
355     final V unmappedValue;
356     try {
357       unmappedKey = getKeyNotInPopulatedMap();
358       unmappedValue = getValueNotInPopulatedMap();
359     } catch (UnsupportedOperationException e) {
360       return;
361     }
362     for (Entry<K, V> entry : entrySet) {
363       assertFalse(unmappedKey.equals(entry.getKey()));
364       assertFalse(unmappedValue.equals(entry.getValue()));
365     }
366   }
367 
368   public void testEntrySetForEmptyMap() {
369     final Map<K, V> map;
370     try {
371       map = makeEmptyMap();
372     } catch (UnsupportedOperationException e) {
373       return;
374     }
375     assertInvariants(map);
376   }
377 
378   public void testEntrySetContainsEntryIncompatibleKey() {
379     final Map<K, V> map;
380     final Set<Entry<K, V>> entrySet;
381     try {
382       map = makeEitherMap();
383     } catch (UnsupportedOperationException e) {
384       return;
385     }
386     assertInvariants(map);
387 
388     entrySet = map.entrySet();
389     final V unmappedValue;
390     try {
391       unmappedValue = getValueNotInPopulatedMap();
392     } catch (UnsupportedOperationException e) {
393       return;
394     }
395     Entry<IncompatibleKeyType, V> entry
396         = mapEntry(new IncompatibleKeyType(), unmappedValue);
397     try {
398       assertFalse(entrySet.contains(entry));
399     } catch (ClassCastException tolerated) {}
400   }
401 
402   public void testEntrySetContainsEntryNullKeyPresent() {
403     if (!allowsNullKeys || !supportsPut) {
404       return;
405     }
406     final Map<K, V> map;
407     final Set<Entry<K, V>> entrySet;
408     try {
409       map = makeEitherMap();
410     } catch (UnsupportedOperationException e) {
411       return;
412     }
413     assertInvariants(map);
414 
415     entrySet = map.entrySet();
416     final V unmappedValue;
417     try {
418       unmappedValue = getValueNotInPopulatedMap();
419     } catch (UnsupportedOperationException e) {
420       return;
421     }
422 
423     map.put(null, unmappedValue);
424     Entry<K, V> entry = mapEntry(null, unmappedValue);
425     assertTrue(entrySet.contains(entry));
426     assertFalse(entrySet.contains(mapEntry(null, null)));
427   }
428 
429   public void testEntrySetContainsEntryNullKeyMissing() {
430     final Map<K, V> map;
431     final Set<Entry<K, V>> entrySet;
432     try {
433       map = makeEitherMap();
434     } catch (UnsupportedOperationException e) {
435       return;
436     }
437     assertInvariants(map);
438 
439     entrySet = map.entrySet();
440     final V unmappedValue;
441     try {
442       unmappedValue = getValueNotInPopulatedMap();
443     } catch (UnsupportedOperationException e) {
444       return;
445     }
446     Entry<K, V> entry = mapEntry(null, unmappedValue);
447     try {
448       assertFalse(entrySet.contains(entry));
449     } catch (NullPointerException e) {
450       assertFalse(allowsNullKeys);
451     }
452     try {
453       assertFalse(entrySet.contains(mapEntry(null, null)));
454     } catch (NullPointerException e) {
455       assertFalse(allowsNullKeys && allowsNullValues);
456     }
457   }
458 
459   public void testEntrySetIteratorRemove() {
460     final Map<K, V> map;
461     try {
462       map = makePopulatedMap();
463     } catch (UnsupportedOperationException e) {
464       return;
465     }
466 
467     Set<Entry<K, V>> entrySet = map.entrySet();
468     Iterator<Entry<K, V>> iterator = entrySet.iterator();
469     if (supportsIteratorRemove) {
470       int initialSize = map.size();
471       Entry<K, V> entry = iterator.next();
472       Entry<K, V> entryCopy = Helpers.mapEntry(
473           entry.getKey(), entry.getValue());
474 
475       iterator.remove();
476       assertEquals(initialSize - 1, map.size());
477 
478       // Use "entryCopy" instead of "entry" because "entry" might be invalidated after
479       // iterator.remove().
480       assertFalse(entrySet.contains(entryCopy));
481       assertInvariants(map);
482       try {
483         iterator.remove();
484         fail("Expected IllegalStateException.");
485       } catch (IllegalStateException e) {
486         // Expected.
487       }
488     } else {
489       try {
490         iterator.next();
491         iterator.remove();
492         fail("Expected UnsupportedOperationException.");
493       } catch (UnsupportedOperationException e) {
494         // Expected.
495       }
496     }
497     assertInvariants(map);
498   }
499 
500   public void testEntrySetRemove() {
501     final Map<K, V> map;
502     try {
503       map = makePopulatedMap();
504     } catch (UnsupportedOperationException e) {
505       return;
506     }
507 
508     Set<Entry<K, V>> entrySet = map.entrySet();
509     if (supportsRemove) {
510       int initialSize = map.size();
511       boolean didRemove = entrySet.remove(entrySet.iterator().next());
512       assertTrue(didRemove);
513       assertEquals(initialSize - 1, map.size());
514     } else {
515       try {
516         entrySet.remove(entrySet.iterator().next());
517         fail("Expected UnsupportedOperationException.");
518       } catch (UnsupportedOperationException e) {
519         // Expected.
520       }
521     }
522     assertInvariants(map);
523   }
524 
525   public void testEntrySetRemoveMissingKey() {
526     final Map<K, V> map;
527     final K key;
528     try {
529       map = makeEitherMap();
530       key = getKeyNotInPopulatedMap();
531     } catch (UnsupportedOperationException e) {
532       return;
533     }
534 
535     Set<Entry<K, V>> entrySet = map.entrySet();
536     Entry<K, V> entry
537         = mapEntry(key, getValueNotInPopulatedMap());
538     int initialSize = map.size();
539     if (supportsRemove) {
540       boolean didRemove = entrySet.remove(entry);
541       assertFalse(didRemove);
542     } else {
543       try {
544         boolean didRemove = entrySet.remove(entry);
545         assertFalse(didRemove);
546       } catch (UnsupportedOperationException optional) {}
547     }
548     assertEquals(initialSize, map.size());
549     assertFalse(map.containsKey(key));
550     assertInvariants(map);
551   }
552 
553   public void testEntrySetRemoveDifferentValue() {
554     final Map<K, V> map;
555     try {
556       map = makePopulatedMap();
557     } catch (UnsupportedOperationException e) {
558       return;
559     }
560 
561     Set<Entry<K, V>> entrySet = map.entrySet();
562     K key = map.keySet().iterator().next();
563     Entry<K, V> entry
564         = mapEntry(key, getValueNotInPopulatedMap());
565     int initialSize = map.size();
566     if (supportsRemove) {
567       boolean didRemove = entrySet.remove(entry);
568       assertFalse(didRemove);
569     } else {
570       try {
571         boolean didRemove = entrySet.remove(entry);
572         assertFalse(didRemove);
573       } catch (UnsupportedOperationException optional) {}
574     }
575     assertEquals(initialSize, map.size());
576     assertTrue(map.containsKey(key));
577     assertInvariants(map);
578   }
579 
580   public void testEntrySetRemoveNullKeyPresent() {
581     if (!allowsNullKeys || !supportsPut || !supportsRemove) {
582       return;
583     }
584     final Map<K, V> map;
585     final Set<Entry<K, V>> entrySet;
586     try {
587       map = makeEitherMap();
588     } catch (UnsupportedOperationException e) {
589       return;
590     }
591     assertInvariants(map);
592 
593     entrySet = map.entrySet();
594     final V unmappedValue;
595     try {
596       unmappedValue = getValueNotInPopulatedMap();
597     } catch (UnsupportedOperationException e) {
598       return;
599     }
600 
601     map.put(null, unmappedValue);
602     assertEquals(unmappedValue, map.get(null));
603     assertTrue(map.containsKey(null));
604     Entry<K, V> entry = mapEntry(null, unmappedValue);
605     assertTrue(entrySet.remove(entry));
606     assertNull(map.get(null));
607     assertFalse(map.containsKey(null));
608   }
609 
610   public void testEntrySetRemoveNullKeyMissing() {
611     final Map<K, V> map;
612     try {
613       map = makeEitherMap();
614     } catch (UnsupportedOperationException e) {
615       return;
616     }
617 
618     Set<Entry<K, V>> entrySet = map.entrySet();
619     Entry<K, V> entry
620         = mapEntry(null, getValueNotInPopulatedMap());
621     int initialSize = map.size();
622     if (supportsRemove) {
623       try {
624         boolean didRemove = entrySet.remove(entry);
625         assertFalse(didRemove);
626       } catch (NullPointerException e) {
627         assertFalse(allowsNullKeys);
628       }
629     } else {
630       try {
631         boolean didRemove = entrySet.remove(entry);
632         assertFalse(didRemove);
633       } catch (UnsupportedOperationException optional) {}
634     }
635     assertEquals(initialSize, map.size());
636     assertInvariants(map);
637   }
638 
639   public void testEntrySetRemoveAll() {
640     final Map<K, V> map;
641     try {
642       map = makePopulatedMap();
643     } catch (UnsupportedOperationException e) {
644       return;
645     }
646 
647     Set<Entry<K, V>> entrySet = map.entrySet();
648 
649     Entry<K, V> entryToRemove = entrySet.iterator().next();
650     Set<Entry<K, V>> entriesToRemove = singleton(entryToRemove);
651     if (supportsRemove) {
652       // We use a copy of "entryToRemove" in the assertion because "entryToRemove" might be
653       // invalidated and have undefined behavior after entrySet.removeAll(entriesToRemove),
654       // for example entryToRemove.getValue() might be null.
655       Entry<K, V> entryToRemoveCopy = Helpers.mapEntry(
656           entryToRemove.getKey(), entryToRemove.getValue());
657 
658       int initialSize = map.size();
659       boolean didRemove = entrySet.removeAll(entriesToRemove);
660       assertTrue(didRemove);
661       assertEquals(initialSize - entriesToRemove.size(), map.size());
662 
663       // Use "entryToRemoveCopy" instead of "entryToRemove" because it might be invalidated and
664       // have undefined behavior after entrySet.removeAll(entriesToRemove),
665       assertFalse(entrySet.contains(entryToRemoveCopy));
666     } else {
667       try {
668         entrySet.removeAll(entriesToRemove);
669         fail("Expected UnsupportedOperationException.");
670       } catch (UnsupportedOperationException e) {
671         // Expected.
672       }
673     }
674     assertInvariants(map);
675   }
676 
677   public void testEntrySetRemoveAllNullFromEmpty() {
678     final Map<K, V> map;
679     try {
680       map = makeEmptyMap();
681     } catch (UnsupportedOperationException e) {
682       return;
683     }
684 
685     Set<Entry<K, V>> entrySet = map.entrySet();
686     if (supportsRemove) {
687       try {
688         entrySet.removeAll(null);
689         fail("Expected NullPointerException.");
690       } catch (NullPointerException e) {
691         // Expected.
692       }
693     } else {
694       try {
695         entrySet.removeAll(null);
696         fail("Expected UnsupportedOperationException or NullPointerException.");
697       } catch (UnsupportedOperationException e) {
698         // Expected.
699       } catch (NullPointerException e) {
700         // Expected.
701       }
702     }
703     assertInvariants(map);
704   }
705 
706   public void testEntrySetRetainAll() {
707     final Map<K, V> map;
708     try {
709       map = makePopulatedMap();
710     } catch (UnsupportedOperationException e) {
711       return;
712     }
713 
714     Set<Entry<K, V>> entrySet = map.entrySet();
715     Set<Entry<K, V>> entriesToRetain =
716         singleton(entrySet.iterator().next());
717     if (supportsRemove) {
718       boolean shouldRemove = (entrySet.size() > entriesToRetain.size());
719       boolean didRemove = entrySet.retainAll(entriesToRetain);
720       assertEquals(shouldRemove, didRemove);
721       assertEquals(entriesToRetain.size(), map.size());
722       for (Entry<K, V> entry : entriesToRetain) {
723         assertTrue(entrySet.contains(entry));
724       }
725     } else {
726       try {
727         entrySet.retainAll(entriesToRetain);
728         fail("Expected UnsupportedOperationException.");
729       } catch (UnsupportedOperationException e) {
730         // Expected.
731       }
732     }
733     assertInvariants(map);
734   }
735 
736   public void testEntrySetRetainAllNullFromEmpty() {
737     final Map<K, V> map;
738     try {
739       map = makeEmptyMap();
740     } catch (UnsupportedOperationException e) {
741       return;
742     }
743 
744     Set<Entry<K, V>> entrySet = map.entrySet();
745     if (supportsRemove) {
746       try {
747         entrySet.retainAll(null);
748         // Returning successfully is not ideal, but tolerated.
749       } catch (NullPointerException e) {
750         // Expected.
751       }
752     } else {
753       try {
754         entrySet.retainAll(null);
755         // We have to tolerate a successful return (Sun bug 4802647)
756       } catch (UnsupportedOperationException e) {
757         // Expected.
758       } catch (NullPointerException e) {
759         // Expected.
760       }
761     }
762     assertInvariants(map);
763   }
764 
765   public void testEntrySetClear() {
766     final Map<K, V> map;
767     try {
768       map = makePopulatedMap();
769     } catch (UnsupportedOperationException e) {
770       return;
771     }
772 
773     Set<Entry<K, V>> entrySet = map.entrySet();
774     if (supportsClear) {
775       entrySet.clear();
776       assertTrue(entrySet.isEmpty());
777     } else {
778       try {
779         entrySet.clear();
780         fail("Expected UnsupportedOperationException.");
781       } catch (UnsupportedOperationException e) {
782         // Expected.
783       }
784     }
785     assertInvariants(map);
786   }
787 
788   public void testEntrySetAddAndAddAll() {
789     final Map<K, V> map = makeEitherMap();
790 
791     Set<Entry<K, V>> entrySet = map.entrySet();
792     final Entry<K, V> entryToAdd = mapEntry(null, null);
793     try {
794       entrySet.add(entryToAdd);
795       fail("Expected UnsupportedOperationException or NullPointerException.");
796     } catch (UnsupportedOperationException e) {
797       // Expected.
798     } catch (NullPointerException e) {
799       // Expected.
800     }
801     assertInvariants(map);
802 
803     try {
804       entrySet.addAll(singleton(entryToAdd));
805       fail("Expected UnsupportedOperationException or NullPointerException.");
806     } catch (UnsupportedOperationException e) {
807       // Expected.
808     } catch (NullPointerException e) {
809       // Expected.
810     }
811     assertInvariants(map);
812   }
813 
814   public void testEntrySetSetValue() {
815     // TODO: Investigate the extent to which, in practice, maps that support
816     // put() also support Entry.setValue().
817     if (!supportsPut) {
818       return;
819     }
820 
821     final Map<K, V> map;
822     final V valueToSet;
823     try {
824       map = makePopulatedMap();
825       valueToSet = getValueNotInPopulatedMap();
826     } catch (UnsupportedOperationException e) {
827       return;
828     }
829 
830     Set<Entry<K, V>> entrySet = map.entrySet();
831     Entry<K, V> entry = entrySet.iterator().next();
832     final V oldValue = entry.getValue();
833     final V returnedValue = entry.setValue(valueToSet);
834     assertEquals(oldValue, returnedValue);
835     assertTrue(entrySet.contains(
836         mapEntry(entry.getKey(), valueToSet)));
837     assertEquals(valueToSet, map.get(entry.getKey()));
838     assertInvariants(map);
839   }
840 
841   public void testEntrySetSetValueSameValue() {
842     // TODO: Investigate the extent to which, in practice, maps that support
843     // put() also support Entry.setValue().
844     if (!supportsPut) {
845       return;
846     }
847 
848     final Map<K, V> map;
849     try {
850       map = makePopulatedMap();
851     } catch (UnsupportedOperationException e) {
852       return;
853     }
854 
855     Set<Entry<K, V>> entrySet = map.entrySet();
856     Entry<K, V> entry = entrySet.iterator().next();
857     final V oldValue = entry.getValue();
858     final V returnedValue = entry.setValue(oldValue);
859     assertEquals(oldValue, returnedValue);
860     assertTrue(entrySet.contains(
861         mapEntry(entry.getKey(), oldValue)));
862     assertEquals(oldValue, map.get(entry.getKey()));
863     assertInvariants(map);
864   }
865 
866   public void testEqualsForEqualMap() {
867     final Map<K, V> map;
868     try {
869       map = makePopulatedMap();
870     } catch (UnsupportedOperationException e) {
871       return;
872     }
873 
874     assertEquals(map, map);
875     assertEquals(makePopulatedMap(), map);
876     assertFalse(map.equals(Collections.emptyMap()));
877     //no-inspection ObjectEqualsNull
878     assertFalse(map.equals(null));
879   }
880 
881   public void testEqualsForLargerMap() {
882     if (!supportsPut) {
883       return;
884     }
885 
886     final Map<K, V> map;
887     final Map<K, V> largerMap;
888     try {
889       map = makePopulatedMap();
890       largerMap = makePopulatedMap();
891       largerMap.put(getKeyNotInPopulatedMap(), getValueNotInPopulatedMap());
892     } catch (UnsupportedOperationException e) {
893       return;
894     }
895 
896     assertFalse(map.equals(largerMap));
897   }
898 
899   public void testEqualsForSmallerMap() {
900     if (!supportsRemove) {
901       return;
902     }
903 
904     final Map<K, V> map;
905     final Map<K, V> smallerMap;
906     try {
907       map = makePopulatedMap();
908       smallerMap = makePopulatedMap();
909       smallerMap.remove(smallerMap.keySet().iterator().next());
910     } catch (UnsupportedOperationException e) {
911       return;
912     }
913 
914     assertFalse(map.equals(smallerMap));
915   }
916 
917   public void testEqualsForEmptyMap() {
918     final Map<K, V> map;
919     try {
920       map = makeEmptyMap();
921     } catch (UnsupportedOperationException e) {
922       return;
923     }
924 
925     assertEquals(map, map);
926     assertEquals(makeEmptyMap(), map);
927     assertEquals(Collections.emptyMap(), map);
928     assertFalse(map.equals(Collections.emptySet()));
929     //noinspection ObjectEqualsNull
930     assertFalse(map.equals(null));
931   }
932 
933   public void testGet() {
934     final Map<K, V> map;
935     try {
936       map = makePopulatedMap();
937     } catch (UnsupportedOperationException e) {
938       return;
939     }
940 
941     for (Entry<K, V> entry : map.entrySet()) {
942       assertEquals(entry.getValue(), map.get(entry.getKey()));
943     }
944 
945     K unmappedKey = null;
946     try {
947       unmappedKey = getKeyNotInPopulatedMap();
948     } catch (UnsupportedOperationException e) {
949       return;
950     }
951     assertNull(map.get(unmappedKey));
952   }
953 
954   public void testGetForEmptyMap() {
955     final Map<K, V> map;
956     K unmappedKey = null;
957     try {
958       map = makeEmptyMap();
959       unmappedKey = getKeyNotInPopulatedMap();
960     } catch (UnsupportedOperationException e) {
961       return;
962     }
963     assertNull(map.get(unmappedKey));
964   }
965 
966   public void testGetNull() {
967     Map<K, V> map = makeEitherMap();
968     if (allowsNullKeys) {
969       if (allowsNullValues) {
970         // TODO: decide what to test here.
971       } else {
972         assertEquals(map.containsKey(null), map.get(null) != null);
973       }
974     } else {
975       try {
976         map.get(null);
977       } catch (NullPointerException optional) {
978       }
979     }
980     assertInvariants(map);
981   }
982 
983   public void testHashCode() {
984     final Map<K, V> map;
985     try {
986       map = makePopulatedMap();
987     } catch (UnsupportedOperationException e) {
988       return;
989     }
990     assertInvariants(map);
991   }
992 
993   public void testHashCodeForEmptyMap() {
994     final Map<K, V> map;
995     try {
996       map = makeEmptyMap();
997     } catch (UnsupportedOperationException e) {
998       return;
999     }
1000     assertInvariants(map);
1001   }
1002 
1003   public void testPutNewKey() {
1004     final Map<K, V> map = makeEitherMap();
1005     final K keyToPut;
1006     final V valueToPut;
1007     try {
1008       keyToPut = getKeyNotInPopulatedMap();
1009       valueToPut = getValueNotInPopulatedMap();
1010     } catch (UnsupportedOperationException e) {
1011       return;
1012     }
1013     if (supportsPut) {
1014       int initialSize = map.size();
1015       V oldValue = map.put(keyToPut, valueToPut);
1016       assertEquals(valueToPut, map.get(keyToPut));
1017       assertTrue(map.containsKey(keyToPut));
1018       assertTrue(map.containsValue(valueToPut));
1019       assertEquals(initialSize + 1, map.size());
1020       assertNull(oldValue);
1021     } else {
1022       try {
1023         map.put(keyToPut, valueToPut);
1024         fail("Expected UnsupportedOperationException.");
1025       } catch (UnsupportedOperationException e) {
1026         // Expected.
1027       }
1028     }
1029     assertInvariants(map);
1030   }
1031 
1032   public void testPutExistingKey() {
1033     final Map<K, V> map;
1034     final K keyToPut;
1035     final V valueToPut;
1036     try {
1037       map = makePopulatedMap();
1038       valueToPut = getValueNotInPopulatedMap();
1039     } catch (UnsupportedOperationException e) {
1040       return;
1041     }
1042     keyToPut = map.keySet().iterator().next();
1043     if (supportsPut) {
1044       int initialSize = map.size();
1045       map.put(keyToPut, valueToPut);
1046       assertEquals(valueToPut, map.get(keyToPut));
1047       assertTrue(map.containsKey(keyToPut));
1048       assertTrue(map.containsValue(valueToPut));
1049       assertEquals(initialSize, map.size());
1050     } else {
1051       try {
1052         map.put(keyToPut, valueToPut);
1053         fail("Expected UnsupportedOperationException.");
1054       } catch (UnsupportedOperationException e) {
1055         // Expected.
1056       }
1057     }
1058     assertInvariants(map);
1059   }
1060 
1061   public void testPutNullKey() {
1062     if (!supportsPut) {
1063       return;
1064     }
1065     final Map<K, V> map = makeEitherMap();
1066     final V valueToPut;
1067     try {
1068       valueToPut = getValueNotInPopulatedMap();
1069     } catch (UnsupportedOperationException e) {
1070       return;
1071     }
1072     if (allowsNullKeys) {
1073       final V oldValue = map.get(null);
1074       final V returnedValue = map.put(null, valueToPut);
1075       assertEquals(oldValue, returnedValue);
1076       assertEquals(valueToPut, map.get(null));
1077       assertTrue(map.containsKey(null));
1078       assertTrue(map.containsValue(valueToPut));
1079     } else {
1080       try {
1081         map.put(null, valueToPut);
1082         fail("Expected RuntimeException");
1083       } catch (RuntimeException e) {
1084         // Expected.
1085       }
1086     }
1087     assertInvariants(map);
1088   }
1089 
1090   public void testPutNullValue() {
1091     if (!supportsPut) {
1092       return;
1093     }
1094     final Map<K, V> map = makeEitherMap();
1095     final K keyToPut;
1096     try {
1097       keyToPut = getKeyNotInPopulatedMap();
1098     } catch (UnsupportedOperationException e) {
1099       return;
1100     }
1101     if (allowsNullValues) {
1102       int initialSize = map.size();
1103       final V oldValue = map.get(keyToPut);
1104       final V returnedValue = map.put(keyToPut, null);
1105       assertEquals(oldValue, returnedValue);
1106       assertNull(map.get(keyToPut));
1107       assertTrue(map.containsKey(keyToPut));
1108       assertTrue(map.containsValue(null));
1109       assertEquals(initialSize + 1, map.size());
1110     } else {
1111       try {
1112         map.put(keyToPut, null);
1113         fail("Expected RuntimeException");
1114       } catch (RuntimeException e) {
1115         // Expected.
1116       }
1117     }
1118     assertInvariants(map);
1119   }
1120 
1121   public void testPutNullValueForExistingKey() {
1122     if (!supportsPut) {
1123       return;
1124     }
1125     final Map<K, V> map;
1126     final K keyToPut;
1127     try {
1128       map = makePopulatedMap();
1129       keyToPut = map.keySet().iterator().next();
1130     } catch (UnsupportedOperationException e) {
1131       return;
1132     }
1133     if (allowsNullValues) {
1134       int initialSize = map.size();
1135       final V oldValue = map.get(keyToPut);
1136       final V returnedValue = map.put(keyToPut, null);
1137       assertEquals(oldValue, returnedValue);
1138       assertNull(map.get(keyToPut));
1139       assertTrue(map.containsKey(keyToPut));
1140       assertTrue(map.containsValue(null));
1141       assertEquals(initialSize, map.size());
1142     } else {
1143       try {
1144         map.put(keyToPut, null);
1145         fail("Expected RuntimeException");
1146       } catch (RuntimeException e) {
1147         // Expected.
1148       }
1149     }
1150     assertInvariants(map);
1151   }
1152 
1153   public void testPutAllNewKey() {
1154     final Map<K, V> map = makeEitherMap();
1155     final K keyToPut;
1156     final V valueToPut;
1157     try {
1158       keyToPut = getKeyNotInPopulatedMap();
1159       valueToPut = getValueNotInPopulatedMap();
1160     } catch (UnsupportedOperationException e) {
1161       return;
1162     }
1163     final Map<K, V> mapToPut = Collections.singletonMap(keyToPut, valueToPut);
1164     if (supportsPut) {
1165       int initialSize = map.size();
1166       map.putAll(mapToPut);
1167       assertEquals(valueToPut, map.get(keyToPut));
1168       assertTrue(map.containsKey(keyToPut));
1169       assertTrue(map.containsValue(valueToPut));
1170       assertEquals(initialSize + 1, map.size());
1171     } else {
1172       try {
1173         map.putAll(mapToPut);
1174         fail("Expected UnsupportedOperationException.");
1175       } catch (UnsupportedOperationException e) {
1176         // Expected.
1177       }
1178     }
1179     assertInvariants(map);
1180   }
1181 
1182   public void testPutAllExistingKey() {
1183     final Map<K, V> map;
1184     final K keyToPut;
1185     final V valueToPut;
1186     try {
1187       map = makePopulatedMap();
1188       valueToPut = getValueNotInPopulatedMap();
1189     } catch (UnsupportedOperationException e) {
1190       return;
1191     }
1192     keyToPut = map.keySet().iterator().next();
1193     final Map<K, V> mapToPut = Collections.singletonMap(keyToPut, valueToPut);
1194     int initialSize = map.size();
1195     if (supportsPut) {
1196       map.putAll(mapToPut);
1197       assertEquals(valueToPut, map.get(keyToPut));
1198       assertTrue(map.containsKey(keyToPut));
1199       assertTrue(map.containsValue(valueToPut));
1200     } else {
1201       try {
1202         map.putAll(mapToPut);
1203         fail("Expected UnsupportedOperationException.");
1204       } catch (UnsupportedOperationException e) {
1205         // Expected.
1206       }
1207     }
1208     assertEquals(initialSize, map.size());
1209     assertInvariants(map);
1210   }
1211 
1212   public void testRemove() {
1213     final Map<K, V> map;
1214     final K keyToRemove;
1215     try {
1216       map = makePopulatedMap();
1217     } catch (UnsupportedOperationException e) {
1218       return;
1219     }
1220     keyToRemove = map.keySet().iterator().next();
1221     if (supportsRemove) {
1222       int initialSize = map.size();
1223       V expectedValue = map.get(keyToRemove);
1224       V oldValue = map.remove(keyToRemove);
1225       assertEquals(expectedValue, oldValue);
1226       assertFalse(map.containsKey(keyToRemove));
1227       assertEquals(initialSize - 1, map.size());
1228     } else {
1229       try {
1230         map.remove(keyToRemove);
1231         fail("Expected UnsupportedOperationException.");
1232       } catch (UnsupportedOperationException e) {
1233         // Expected.
1234       }
1235     }
1236     assertInvariants(map);
1237   }
1238 
1239   public void testRemoveMissingKey() {
1240     final Map<K, V> map;
1241     final K keyToRemove;
1242     try {
1243       map = makePopulatedMap();
1244       keyToRemove = getKeyNotInPopulatedMap();
1245     } catch (UnsupportedOperationException e) {
1246       return;
1247     }
1248     if (supportsRemove) {
1249       int initialSize = map.size();
1250       assertNull(map.remove(keyToRemove));
1251       assertEquals(initialSize, map.size());
1252     } else {
1253       try {
1254         map.remove(keyToRemove);
1255         fail("Expected UnsupportedOperationException.");
1256       } catch (UnsupportedOperationException e) {
1257         // Expected.
1258       }
1259     }
1260     assertInvariants(map);
1261   }
1262 
1263   public void testSize() {
1264     assertInvariants(makeEitherMap());
1265   }
1266 
1267   public void testKeySetRemove() {
1268     final Map<K, V> map;
1269     try {
1270       map = makePopulatedMap();
1271     } catch (UnsupportedOperationException e) {
1272       return;
1273     }
1274 
1275     Set<K> keys = map.keySet();
1276     K key = keys.iterator().next();
1277     if (supportsRemove) {
1278       int initialSize = map.size();
1279       keys.remove(key);
1280       assertEquals(initialSize - 1, map.size());
1281       assertFalse(map.containsKey(key));
1282     } else {
1283       try {
1284         keys.remove(key);
1285         fail("Expected UnsupportedOperationException.");
1286       } catch (UnsupportedOperationException e) {
1287         // Expected.
1288       }
1289     }
1290     assertInvariants(map);
1291   }
1292 
1293   public void testKeySetRemoveAll() {
1294     final Map<K, V> map;
1295     try {
1296       map = makePopulatedMap();
1297     } catch (UnsupportedOperationException e) {
1298       return;
1299     }
1300 
1301     Set<K> keys = map.keySet();
1302     K key = keys.iterator().next();
1303     if (supportsRemove) {
1304       int initialSize = map.size();
1305       assertTrue(keys.removeAll(Collections.singleton(key)));
1306       assertEquals(initialSize - 1, map.size());
1307       assertFalse(map.containsKey(key));
1308     } else {
1309       try {
1310         keys.removeAll(Collections.singleton(key));
1311         fail("Expected UnsupportedOperationException.");
1312       } catch (UnsupportedOperationException e) {
1313         // Expected.
1314       }
1315     }
1316     assertInvariants(map);
1317   }
1318 
1319   public void testKeySetRetainAll() {
1320     final Map<K, V> map;
1321     try {
1322       map = makePopulatedMap();
1323     } catch (UnsupportedOperationException e) {
1324       return;
1325     }
1326 
1327     Set<K> keys = map.keySet();
1328     K key = keys.iterator().next();
1329     if (supportsRemove) {
1330       keys.retainAll(Collections.singleton(key));
1331       assertEquals(1, map.size());
1332       assertTrue(map.containsKey(key));
1333     } else {
1334       try {
1335         keys.retainAll(Collections.singleton(key));
1336         fail("Expected UnsupportedOperationException.");
1337       } catch (UnsupportedOperationException e) {
1338         // Expected.
1339       }
1340     }
1341     assertInvariants(map);
1342   }
1343 
1344   public void testKeySetClear() {
1345     final Map<K, V> map;
1346     try {
1347       map = makeEitherMap();
1348     } catch (UnsupportedOperationException e) {
1349       return;
1350     }
1351 
1352     Set<K> keySet = map.keySet();
1353     if (supportsClear) {
1354       keySet.clear();
1355       assertTrue(keySet.isEmpty());
1356     } else {
1357       try {
1358         keySet.clear();
1359         fail("Expected UnsupportedOperationException.");
1360       } catch (UnsupportedOperationException e) {
1361         // Expected.
1362       }
1363     }
1364     assertInvariants(map);
1365   }
1366 
1367   public void testKeySetRemoveAllNullFromEmpty() {
1368     final Map<K, V> map;
1369     try {
1370       map = makeEmptyMap();
1371     } catch (UnsupportedOperationException e) {
1372       return;
1373     }
1374 
1375     Set<K> keySet = map.keySet();
1376     if (supportsRemove) {
1377       try {
1378         keySet.removeAll(null);
1379         fail("Expected NullPointerException.");
1380       } catch (NullPointerException e) {
1381         // Expected.
1382       }
1383     } else {
1384       try {
1385         keySet.removeAll(null);
1386         fail("Expected UnsupportedOperationException or NullPointerException.");
1387       } catch (UnsupportedOperationException e) {
1388         // Expected.
1389       } catch (NullPointerException e) {
1390         // Expected.
1391       }
1392     }
1393     assertInvariants(map);
1394   }
1395 
1396   public void testKeySetRetainAllNullFromEmpty() {
1397     final Map<K, V> map;
1398     try {
1399       map = makeEmptyMap();
1400     } catch (UnsupportedOperationException e) {
1401       return;
1402     }
1403 
1404     Set<K> keySet = map.keySet();
1405     if (supportsRemove) {
1406       try {
1407         keySet.retainAll(null);
1408         // Returning successfully is not ideal, but tolerated.
1409       } catch (NullPointerException e) {
1410         // Expected.
1411       }
1412     } else {
1413       try {
1414         keySet.retainAll(null);
1415         // We have to tolerate a successful return (Sun bug 4802647)
1416       } catch (UnsupportedOperationException e) {
1417         // Expected.
1418       } catch (NullPointerException e) {
1419         // Expected.
1420       }
1421     }
1422     assertInvariants(map);
1423   }
1424 
1425   public void testValues() {
1426     final Map<K, V> map;
1427     final Collection<V> valueCollection;
1428     try {
1429       map = makePopulatedMap();
1430     } catch (UnsupportedOperationException e) {
1431       return;
1432     }
1433     assertInvariants(map);
1434 
1435     valueCollection = map.values();
1436     final V unmappedValue;
1437     try {
1438       unmappedValue = getValueNotInPopulatedMap();
1439     } catch (UnsupportedOperationException e) {
1440       return;
1441     }
1442     for (V value : valueCollection) {
1443       assertFalse(unmappedValue.equals(value));
1444     }
1445   }
1446 
1447   public void testValuesIteratorRemove() {
1448     final Map<K, V> map;
1449     try {
1450       map = makePopulatedMap();
1451     } catch (UnsupportedOperationException e) {
1452       return;
1453     }
1454 
1455     Collection<V> valueCollection = map.values();
1456     Iterator<V> iterator = valueCollection.iterator();
1457     if (supportsIteratorRemove) {
1458       int initialSize = map.size();
1459       iterator.next();
1460       iterator.remove();
1461       assertEquals(initialSize - 1, map.size());
1462       // (We can't assert that the values collection no longer contains the
1463       // removed value, because the underlying map can have multiple mappings
1464       // to the same value.)
1465       assertInvariants(map);
1466       try {
1467         iterator.remove();
1468         fail("Expected IllegalStateException.");
1469       } catch (IllegalStateException e) {
1470         // Expected.
1471       }
1472     } else {
1473       try {
1474         iterator.next();
1475         iterator.remove();
1476         fail("Expected UnsupportedOperationException.");
1477       } catch (UnsupportedOperationException e) {
1478         // Expected.
1479       }
1480     }
1481     assertInvariants(map);
1482   }
1483 
1484   public void testValuesRemove() {
1485     final Map<K, V> map;
1486     try {
1487       map = makePopulatedMap();
1488     } catch (UnsupportedOperationException e) {
1489       return;
1490     }
1491 
1492     Collection<V> valueCollection = map.values();
1493     if (supportsRemove) {
1494       int initialSize = map.size();
1495       valueCollection.remove(valueCollection.iterator().next());
1496       assertEquals(initialSize - 1, map.size());
1497       // (We can't assert that the values collection no longer contains the
1498       // removed value, because the underlying map can have multiple mappings
1499       // to the same value.)
1500     } else {
1501       try {
1502         valueCollection.remove(valueCollection.iterator().next());
1503         fail("Expected UnsupportedOperationException.");
1504       } catch (UnsupportedOperationException e) {
1505         // Expected.
1506       }
1507     }
1508     assertInvariants(map);
1509   }
1510 
1511   public void testValuesRemoveMissing() {
1512     final Map<K, V> map;
1513     final V valueToRemove;
1514     try {
1515       map = makeEitherMap();
1516       valueToRemove = getValueNotInPopulatedMap();
1517     } catch (UnsupportedOperationException e) {
1518       return;
1519     }
1520 
1521     Collection<V> valueCollection = map.values();
1522     int initialSize = map.size();
1523     if (supportsRemove) {
1524       assertFalse(valueCollection.remove(valueToRemove));
1525     } else {
1526       try {
1527         assertFalse(valueCollection.remove(valueToRemove));
1528       } catch (UnsupportedOperationException e) {
1529         // Tolerated.
1530       }
1531     }
1532     assertEquals(initialSize, map.size());
1533     assertInvariants(map);
1534   }
1535 
1536   public void testValuesRemoveAll() {
1537     final Map<K, V> map;
1538     try {
1539       map = makePopulatedMap();
1540     } catch (UnsupportedOperationException e) {
1541       return;
1542     }
1543 
1544     Collection<V> valueCollection = map.values();
1545     Set<V> valuesToRemove = singleton(valueCollection.iterator().next());
1546     if (supportsRemove) {
1547       valueCollection.removeAll(valuesToRemove);
1548       for (V value : valuesToRemove) {
1549         assertFalse(valueCollection.contains(value));
1550       }
1551       for (V value : valueCollection) {
1552         assertFalse(valuesToRemove.contains(value));
1553       }
1554     } else {
1555       try {
1556         valueCollection.removeAll(valuesToRemove);
1557         fail("Expected UnsupportedOperationException.");
1558       } catch (UnsupportedOperationException e) {
1559         // Expected.
1560       }
1561     }
1562     assertInvariants(map);
1563   }
1564 
1565   public void testValuesRemoveAllNullFromEmpty() {
1566     final Map<K, V> map;
1567     try {
1568       map = makeEmptyMap();
1569     } catch (UnsupportedOperationException e) {
1570       return;
1571     }
1572 
1573     Collection<V> values = map.values();
1574     if (supportsRemove) {
1575       try {
1576         values.removeAll(null);
1577         // Returning successfully is not ideal, but tolerated.
1578       } catch (NullPointerException e) {
1579         // Expected.
1580       }
1581     } else {
1582       try {
1583         values.removeAll(null);
1584         // We have to tolerate a successful return (Sun bug 4802647)
1585       } catch (UnsupportedOperationException e) {
1586         // Expected.
1587       } catch (NullPointerException e) {
1588         // Expected.
1589       }
1590     }
1591     assertInvariants(map);
1592   }
1593 
1594   public void testValuesRetainAll() {
1595     final Map<K, V> map;
1596     try {
1597       map = makePopulatedMap();
1598     } catch (UnsupportedOperationException e) {
1599       return;
1600     }
1601 
1602     Collection<V> valueCollection = map.values();
1603     Set<V> valuesToRetain = singleton(valueCollection.iterator().next());
1604     if (supportsRemove) {
1605       valueCollection.retainAll(valuesToRetain);
1606       for (V value : valuesToRetain) {
1607         assertTrue(valueCollection.contains(value));
1608       }
1609       for (V value : valueCollection) {
1610         assertTrue(valuesToRetain.contains(value));
1611       }
1612     } else {
1613       try {
1614         valueCollection.retainAll(valuesToRetain);
1615         fail("Expected UnsupportedOperationException.");
1616       } catch (UnsupportedOperationException e) {
1617         // Expected.
1618       }
1619     }
1620     assertInvariants(map);
1621   }
1622 
1623   public void testValuesRetainAllNullFromEmpty() {
1624     final Map<K, V> map;
1625     try {
1626       map = makeEmptyMap();
1627     } catch (UnsupportedOperationException e) {
1628       return;
1629     }
1630 
1631     Collection<V> values = map.values();
1632     if (supportsRemove) {
1633       try {
1634         values.retainAll(null);
1635         // Returning successfully is not ideal, but tolerated.
1636       } catch (NullPointerException e) {
1637         // Expected.
1638       }
1639     } else {
1640       try {
1641         values.retainAll(null);
1642         // We have to tolerate a successful return (Sun bug 4802647)
1643       } catch (UnsupportedOperationException e) {
1644         // Expected.
1645       } catch (NullPointerException e) {
1646         // Expected.
1647       }
1648     }
1649     assertInvariants(map);
1650   }
1651 
1652   public void testValuesClear() {
1653     final Map<K, V> map;
1654     try {
1655       map = makePopulatedMap();
1656     } catch (UnsupportedOperationException e) {
1657       return;
1658     }
1659 
1660     Collection<V> valueCollection = map.values();
1661     if (supportsClear) {
1662       valueCollection.clear();
1663       assertTrue(valueCollection.isEmpty());
1664     } else {
1665       try {
1666         valueCollection.clear();
1667         fail("Expected UnsupportedOperationException.");
1668       } catch (UnsupportedOperationException e) {
1669         // Expected.
1670       }
1671     }
1672     assertInvariants(map);
1673   }
1674 
1675   static <K, V> Entry<K, V> mapEntry(K key, V value) {
1676     return Collections.singletonMap(key, value).entrySet().iterator().next();
1677   }
1678 }