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