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 {
toString()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    */
makeEmptyMap()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    */
makePopulatedMap()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    */
getKeyNotInPopulatedMap()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    */
getValueNotInPopulatedMap()106   protected abstract V getValueNotInPopulatedMap()
107       throws UnsupportedOperationException;
108 
109   /**
110    * Constructor that assigns {@code supportsIteratorRemove} the same value as
111    * {@code supportsRemove}.
112    */
MapInterfaceTest( boolean allowsNullKeys, boolean allowsNullValues, boolean supportsPut, boolean supportsRemove, boolean supportsClear)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    */
MapInterfaceTest( boolean allowsNullKeys, boolean allowsNullValues, boolean supportsPut, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)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    */
makeEitherMap()147   protected Map<K, V> makeEitherMap() {
148     try {
149       return makePopulatedMap();
150     } catch (UnsupportedOperationException e) {
151       return makeEmptyMap();
152     }
153   }
154 
supportsValuesHashCode(Map<K, V> map)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    */
assertInvariants(Map<K, V> map)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    */
assertMoreInvariants(Map<K, V> map)271   protected void assertMoreInvariants(Map<K, V> map) {
272   }
273 
testClear()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 
testContainsKey()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 
testContainsValue()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 
testEntrySet()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 
testEntrySetForEmptyMap()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 
testEntrySetContainsEntryIncompatibleKey()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 
testEntrySetContainsEntryNullKeyPresent()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 
testEntrySetContainsEntryNullKeyMissing()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 
testEntrySetIteratorRemove()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 
testEntrySetRemove()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 
testEntrySetRemoveMissingKey()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 
testEntrySetRemoveDifferentValue()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 
testEntrySetRemoveNullKeyPresent()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 
testEntrySetRemoveNullKeyMissing()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 
testEntrySetRemoveAll()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 
testEntrySetRemoveAllNullFromEmpty()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 
testEntrySetRetainAll()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 
testEntrySetRetainAllNullFromEmpty()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 
testEntrySetClear()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 
testEntrySetAddAndAddAll()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 
testEntrySetSetValue()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 
testEntrySetSetValueSameValue()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 
testEqualsForEqualMap()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 
testEqualsForLargerMap()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 
testEqualsForSmallerMap()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 
testEqualsForEmptyMap()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 
testGet()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 
testGetForEmptyMap()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 
testGetNull()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 
testHashCode()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 
testHashCodeForEmptyMap()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 
testPutNewKey()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 
testPutExistingKey()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 
testPutNullKey()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 
testPutNullValue()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 
testPutNullValueForExistingKey()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 
testPutAllNewKey()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 
testPutAllExistingKey()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 
testRemove()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 
testRemoveMissingKey()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 
testSize()1263   public void testSize() {
1264     assertInvariants(makeEitherMap());
1265   }
1266 
testKeySetRemove()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 
testKeySetRemoveAll()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 
testKeySetRetainAll()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 
testKeySetClear()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 
testKeySetRemoveAllNullFromEmpty()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 
testKeySetRetainAllNullFromEmpty()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 
testValues()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 
testValuesIteratorRemove()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 
testValuesRemove()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 
testValuesRemoveMissing()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 
testValuesRemoveAll()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 
testValuesRemoveAllNullFromEmpty()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 
testValuesRetainAll()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 
testValuesRetainAllNullFromEmpty()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 
testValuesClear()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 
mapEntry(K key, V value)1675   static <K, V> Entry<K, V> mapEntry(K key, V value) {
1676     return Collections.singletonMap(key, value).entrySet().iterator().next();
1677   }
1678 }
1679