Home | History | Annotate | Download | only in testing
      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 }
   1679