Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2007 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;
     18 
     19 import static java.util.Arrays.asList;
     20 import static org.junit.contrib.truth.Truth.ASSERT;
     21 
     22 import com.google.common.annotations.GwtCompatible;
     23 import com.google.common.annotations.GwtIncompatible;
     24 import com.google.common.testing.SerializableTester;
     25 
     26 import junit.framework.TestCase;
     27 
     28 import java.util.ArrayList;
     29 import java.util.Arrays;
     30 import java.util.Collection;
     31 import java.util.Collections;
     32 import java.util.ConcurrentModificationException;
     33 import java.util.Iterator;
     34 import java.util.Map;
     35 import java.util.Map.Entry;
     36 import java.util.NoSuchElementException;
     37 import java.util.Set;
     38 
     39 /**
     40  * Tests for {@code Multimap} implementations. Caution: when subclassing avoid
     41  * accidental naming collisions with tests in this class!
     42  *
     43  * @author Jared Levy
     44  */
     45 @GwtCompatible(emulated = true)
     46 public abstract class AbstractMultimapTest extends TestCase {
     47 
     48   private Multimap<String, Integer> multimap;
     49 
     50   protected abstract Multimap<String, Integer> create();
     51 
     52   protected Multimap<String, Integer> createSample() {
     53     Multimap<String, Integer> sample = create();
     54     sample.putAll("foo", asList(3, -1, 2, 4, 1));
     55     sample.putAll("bar", asList(1, 2, 3, 1));
     56     return sample;
     57   }
     58 
     59   // public for GWT
     60   @Override public void setUp() throws Exception {
     61     super.setUp();
     62     multimap = create();
     63   }
     64 
     65   protected Multimap<String, Integer> getMultimap() {
     66     return multimap;
     67   }
     68 
     69   /**
     70    * Returns the key to use as a null placeholder in tests. The default
     71    * implementation returns {@code null}, but tests for multimaps that don't
     72    * support null keys should override it.
     73    */
     74   protected String nullKey() {
     75     return null;
     76   }
     77 
     78   /**
     79    * Returns the value to use as a null placeholder in tests. The default
     80    * implementation returns {@code null}, but tests for multimaps that don't
     81    * support null values should override it.
     82    */
     83   protected Integer nullValue() {
     84     return null;
     85   }
     86 
     87   /**
     88    * Validate multimap size by calling {@code size()} and also by iterating
     89    * through the entries. This tests cases where the {@code entries()} list is
     90    * stored separately, such as the {@link LinkedHashMultimap}. It also
     91    * verifies that the multimap contains every multimap entry.
     92    */
     93   protected void assertSize(int expectedSize) {
     94     assertEquals(expectedSize, multimap.size());
     95 
     96     int size = 0;
     97     for (Entry<String, Integer> entry : multimap.entries()) {
     98       assertTrue(multimap.containsEntry(entry.getKey(), entry.getValue()));
     99       size++;
    100     }
    101     assertEquals(expectedSize, size);
    102 
    103     int size2 = 0;
    104     for (Entry<String, Collection<Integer>> entry2 :
    105         multimap.asMap().entrySet()) {
    106       size2 += entry2.getValue().size();
    107     }
    108     assertEquals(expectedSize, size2);
    109   }
    110 
    111   protected boolean removedCollectionsAreModifiable() {
    112     return false;
    113   }
    114 
    115   public void testSize0() {
    116     assertSize(0);
    117   }
    118 
    119   public void testSize1() {
    120     multimap.put("foo", 1);
    121     assertSize(1);
    122   }
    123 
    124   public void testSize2Keys() {
    125     multimap.put("foo", 1);
    126     multimap.put("bar", 5);
    127     assertSize(2);
    128   }
    129 
    130   public void testSize2Values() {
    131     multimap.put("foo", 1);
    132     multimap.put("foo", 7);
    133     assertSize(2);
    134   }
    135 
    136   public void testSizeNull() {
    137     multimap.put("foo", 1);
    138     multimap.put("bar", 5);
    139     multimap.put(nullKey(), nullValue());
    140     multimap.put("foo", nullValue());
    141     multimap.put(nullKey(), 5);
    142     assertSize(5);
    143   }
    144 
    145   public void testIsEmptyYes() {
    146     assertTrue(multimap.isEmpty());
    147   }
    148 
    149   public void testIsEmptyNo() {
    150     multimap.put("foo", 1);
    151     assertFalse(multimap.isEmpty());
    152   }
    153 
    154   public void testIsEmptyNull() {
    155     multimap.put(nullKey(), nullValue());
    156     assertFalse(multimap.isEmpty());
    157   }
    158 
    159   public void testIsEmptyRemoved() {
    160     multimap.put("foo", 1);
    161     multimap.remove("foo", 1);
    162     assertTrue(multimap.isEmpty());
    163   }
    164 
    165   public void testContainsKeyTrue() {
    166     multimap.put("foo", 1);
    167     assertTrue(multimap.containsKey("foo"));
    168   }
    169 
    170   public void testContainsKeyFalse() {
    171     multimap.put("foo", 1);
    172     assertFalse(multimap.containsKey("bar"));
    173     assertFalse(multimap.containsKey(nullKey()));
    174   }
    175 
    176   public void testContainsKeyNull() {
    177     multimap.put(nullKey(), 1);
    178     assertTrue(multimap.containsKey(nullKey()));
    179   }
    180 
    181   public void testContainsValueTrue() {
    182     multimap.put("foo", 1);
    183     assertTrue(multimap.containsValue(1));
    184   }
    185 
    186   public void testContainsValueFalse() {
    187     multimap.put("foo", 1);
    188     assertFalse(multimap.containsValue(2));
    189     assertFalse(multimap.containsValue(nullValue()));
    190   }
    191 
    192   public void testContainsValueNull() {
    193     multimap.put("foo", nullValue());
    194     assertTrue(multimap.containsValue(nullValue()));
    195   }
    196 
    197   public void testContainsKeyValueTrue() {
    198     multimap.put("foo", 1);
    199     assertTrue(multimap.containsEntry("foo", 1));
    200   }
    201 
    202   public void testContainsKeyValueRemoved() {
    203     multimap.put("foo", 1);
    204     multimap.remove("foo", 1);
    205     assertFalse(multimap.containsEntry("foo", 1));
    206   }
    207 
    208   public void testGet0() {
    209     multimap.put("foo", 1);
    210     Collection<Integer> values = multimap.get("bar");
    211     assertEquals(0, values.size());
    212   }
    213 
    214   public void testGet1() {
    215     multimap.put("foo", 1);
    216     multimap.put("bar", 3);
    217     Collection<Integer> values = multimap.get("bar");
    218     assertEquals(1, values.size());
    219     assertTrue(values.contains(3));
    220     assertFalse(values.contains(5));
    221   }
    222 
    223   public void testGet2() {
    224     multimap.put("foo", 1);
    225     multimap.put("foo", 3);
    226     Collection<Integer> values = multimap.get("foo");
    227     assertEquals(2, values.size());
    228     assertTrue(values.contains(1));
    229     assertTrue(values.contains(3));
    230   }
    231 
    232   public void testGetNull() {
    233     multimap.put(nullKey(), nullValue());
    234     multimap.put(nullKey(), 3);
    235     Collection<Integer> values = multimap.get(nullKey());
    236     assertEquals(2, values.size());
    237     assertTrue(values.contains(nullValue()));
    238     assertTrue(values.contains(3));
    239   }
    240 
    241   public void testPutAllIterable() {
    242     Iterable<Integer> iterable = new Iterable<Integer>() {
    243       @Override
    244       public Iterator<Integer> iterator() {
    245         return Lists.newArrayList(1, 3).iterator();
    246       }
    247     };
    248     multimap.putAll("foo", iterable);
    249     assertTrue(multimap.containsEntry("foo", 1));
    250     assertTrue(multimap.containsEntry("foo", 3));
    251     assertSize(2);
    252 
    253     Iterable<Integer> emptyIterable = new Iterable<Integer>() {
    254       @Override
    255       public Iterator<Integer> iterator() {
    256         return Iterators.emptyIterator();
    257       }
    258     };
    259     multimap.putAll("bar", emptyIterable);
    260     assertSize(2);
    261     assertEquals(Collections.singleton("foo"), multimap.keySet());
    262   }
    263 
    264   public void testPutAllCollection() {
    265     Collection<Integer> collection = Lists.newArrayList(1, 3);
    266     multimap.putAll("foo", collection);
    267     assertTrue(multimap.containsEntry("foo", 1));
    268     assertTrue(multimap.containsEntry("foo", 3));
    269     assertSize(2);
    270 
    271     Collection<Integer> emptyCollection = Lists.newArrayList();
    272     multimap.putAll("bar", emptyCollection);
    273     assertSize(2);
    274     assertEquals(Collections.singleton("foo"), multimap.keySet());
    275   }
    276 
    277   public void testPutAllCollectionNull() {
    278     Collection<Integer> collection = Lists.newArrayList(1, nullValue());
    279     multimap.putAll(nullKey(), collection);
    280     assertTrue(multimap.containsEntry(nullKey(), 1));
    281     assertTrue(multimap.containsEntry(nullKey(), nullValue()));
    282     assertSize(2);
    283   }
    284 
    285   public void testPutAllEmptyCollection() {
    286     Collection<Integer> collection = Lists.newArrayList();
    287     multimap.putAll("foo", collection);
    288     assertSize(0);
    289     assertTrue(multimap.isEmpty());
    290   }
    291 
    292   public void testPutAllMultimap() {
    293     multimap.put("foo", 2);
    294     multimap.put("cow", 5);
    295     multimap.put(nullKey(), 2);
    296     Multimap<String, Integer> multimap2 = create();
    297     multimap2.put("foo", 1);
    298     multimap2.put("bar", 3);
    299     multimap2.put(nullKey(), nullValue());
    300     multimap.putAll(multimap2);
    301     assertTrue(multimap.containsEntry("foo", 2));
    302     assertTrue(multimap.containsEntry("cow", 5));
    303     assertTrue(multimap.containsEntry("foo", 1));
    304     assertTrue(multimap.containsEntry("bar", 3));
    305     assertTrue(multimap.containsEntry(nullKey(), nullValue()));
    306     assertTrue(multimap.containsEntry(nullKey(), 2));
    307     assertSize(6);
    308   }
    309 
    310   public void testPutAllReturn_emptyCollection() {
    311     assertFalse(multimap.putAll("foo", new ArrayList<Integer>()));
    312     assertFalse(multimap.putAll(create()));
    313   }
    314 
    315   public void testPutAllReturn_nonEmptyCollection() {
    316     assertTrue(multimap.putAll("foo", asList(1, 2, 3)));
    317     assertTrue(multimap.putAll("foo", asList(4, 5, 6)));
    318     assertFalse(multimap.putAll(create()));
    319 
    320     Multimap<String, Integer> other = create();
    321     other.putAll("bar", asList(7, 8, 9));
    322     assertTrue(multimap.putAll(other));
    323   }
    324 
    325   private void checkRemovedCollection(Collection<Integer> collection) {
    326     if (removedCollectionsAreModifiable()) {
    327       collection.add(9876);
    328       collection.remove(9876);
    329       assertFalse(collection.contains(9876));
    330     } else {
    331       try {
    332         collection.add(9876);
    333         fail();
    334       } catch (UnsupportedOperationException expected) {
    335       }
    336     }
    337   }
    338 
    339   public void testReplaceValues() {
    340     multimap.put("foo", 1);
    341     multimap.put("bar", 3);
    342     Collection<Integer> values = asList(2, nullValue());
    343     Collection<Integer> oldValues = multimap.replaceValues("foo", values);
    344     assertTrue(multimap.containsEntry("foo", 2));
    345     assertTrue(multimap.containsEntry("foo", nullValue()));
    346     assertTrue(multimap.containsEntry("bar", 3));
    347     assertSize(3);
    348     assertTrue(oldValues.contains(1));
    349     assertEquals(1, oldValues.size());
    350     checkRemovedCollection(oldValues);
    351   }
    352 
    353   public void testReplaceValuesEmpty() {
    354     multimap.put("foo", 1);
    355     multimap.put("bar", 3);
    356     Collection<Integer> values = asList();
    357     Collection<Integer> oldValues = multimap.replaceValues("foo", values);
    358     assertFalse(multimap.containsKey("foo"));
    359     assertTrue(multimap.containsEntry("bar", 3));
    360     assertSize(1);
    361     assertTrue(oldValues.contains(1));
    362     assertEquals(1, oldValues.size());
    363     checkRemovedCollection(oldValues);
    364   }
    365 
    366   public void testReplaceValuesNull() {
    367     multimap.put(nullKey(), 1);
    368     multimap.put("bar", 3);
    369     Collection<Integer> values = asList(2, nullValue());
    370     Collection<Integer> oldValues = multimap.replaceValues(nullKey(), values);
    371     assertTrue(multimap.containsEntry(nullKey(), 2));
    372     assertTrue(multimap.containsEntry(nullKey(), nullValue()));
    373     assertTrue(multimap.containsEntry("bar", 3));
    374     assertSize(3);
    375     assertTrue(oldValues.contains(1));
    376     assertEquals(1, oldValues.size());
    377     checkRemovedCollection(oldValues);
    378   }
    379 
    380   public void testReplaceValuesNotPresent() {
    381     multimap.put("bar", 3);
    382     Collection<Integer> values = asList(2, 4);
    383     Collection<Integer> oldValues = multimap.replaceValues("foo", values);
    384     assertTrue(multimap.containsEntry("foo", 2));
    385     assertTrue(multimap.containsEntry("foo", 4));
    386     assertTrue(multimap.containsEntry("bar", 3));
    387     assertSize(3);
    388     assertNotNull(oldValues);
    389     assertTrue(oldValues.isEmpty());
    390     checkRemovedCollection(oldValues);
    391   }
    392 
    393   public void testReplaceValuesDuplicates() {
    394     Collection<Integer> values = Lists.newArrayList(1, 2, 3, 2, 1);
    395     multimap.put("bar", 3);
    396     Collection<Integer> oldValues = multimap.replaceValues("bar", values);
    397     Collection<Integer> replacedValues = multimap.get("bar");
    398     assertSize(multimap.size());
    399     assertEquals(replacedValues.size(), multimap.size());
    400     assertEquals(1, oldValues.size());
    401     assertTrue(oldValues.contains(3));
    402     checkRemovedCollection(oldValues);
    403   }
    404 
    405   public void testRemove() {
    406     multimap.put("foo", 1);
    407     multimap.put("foo", 3);
    408 
    409     assertTrue(multimap.remove("foo", 1));
    410     assertFalse(multimap.containsEntry("foo", 1));
    411     assertTrue(multimap.containsEntry("foo", 3));
    412     assertSize(1);
    413 
    414     assertFalse(multimap.remove("bar", 3));
    415     assertTrue(multimap.containsEntry("foo", 3));
    416     assertSize(1);
    417 
    418     assertFalse(multimap.remove("foo", 2));
    419     assertTrue(multimap.containsEntry("foo", 3));
    420     assertSize(1);
    421 
    422     assertTrue(multimap.remove("foo", 3));
    423     assertFalse(multimap.containsKey("foo"));
    424     assertSize(0);
    425   }
    426 
    427   public void testRemoveNull() {
    428     multimap.put(nullKey(), 1);
    429     multimap.put(nullKey(), 3);
    430     multimap.put(nullKey(), nullValue());
    431 
    432     assertTrue(multimap.remove(nullKey(), 1));
    433     assertFalse(multimap.containsEntry(nullKey(), 1));
    434     assertTrue(multimap.containsEntry(nullKey(), 3));
    435     assertTrue(multimap.containsEntry(nullKey(), nullValue()));
    436     assertSize(2);
    437 
    438     assertTrue(multimap.remove(nullKey(), nullValue()));
    439     assertFalse(multimap.containsEntry(nullKey(), 1));
    440     assertTrue(multimap.containsEntry(nullKey(), 3));
    441     assertFalse(multimap.containsEntry(nullKey(), nullValue()));
    442     assertSize(1);
    443   }
    444 
    445   public void testRemoveAll() {
    446     multimap.put("foo", 1);
    447     multimap.put("foo", 3);
    448     Collection<Integer> removed = multimap.removeAll("foo");
    449     assertFalse(multimap.containsKey("foo"));
    450     assertSize(0);
    451     assertTrue(removed.contains(1));
    452     assertTrue(removed.contains(3));
    453     assertEquals(2, removed.size());
    454     checkRemovedCollection(removed);
    455   }
    456 
    457   public void testRemoveAllNull() {
    458     multimap.put(nullKey(), 1);
    459     multimap.put(nullKey(), nullValue());
    460     Collection<Integer> removed = multimap.removeAll(nullKey());
    461     assertFalse(multimap.containsKey(nullKey()));
    462     assertSize(0);
    463     assertTrue(removed.contains(1));
    464     assertTrue(removed.contains(nullValue()));
    465     assertEquals(2, removed.size());
    466     checkRemovedCollection(removed);
    467   }
    468 
    469   public void testRemoveAllNotPresent() {
    470     multimap.put("foo", 1);
    471     multimap.put("foo", 3);
    472     Collection<Integer> removed = multimap.removeAll("bar");
    473     assertSize(2);
    474     assertNotNull(removed);
    475     assertTrue(removed.isEmpty());
    476     checkRemovedCollection(removed);
    477   }
    478 
    479   public void testClear() {
    480     multimap.put("foo", 1);
    481     multimap.put("bar", 3);
    482     multimap.clear();
    483     assertEquals(0, multimap.keySet().size());
    484     assertSize(0);
    485   }
    486 
    487   public void testKeySet() {
    488     multimap.put("foo", 1);
    489     multimap.put("foo", nullValue());
    490     multimap.put(nullKey(), 3);
    491     Set<String> keys = multimap.keySet();
    492     assertEquals(2, keys.size());
    493     assertTrue(keys.contains("foo"));
    494     assertTrue(keys.contains(nullKey()));
    495     assertTrue(keys.containsAll(Lists.newArrayList("foo", nullKey())));
    496     assertFalse(keys.containsAll(Lists.newArrayList("foo", "bar")));
    497   }
    498 
    499   public void testValues() {
    500     multimap.put("foo", 1);
    501     multimap.put("foo", nullValue());
    502     multimap.put(nullKey(), 3);
    503     Collection<Integer> values = multimap.values();
    504     assertEquals(3, values.size());
    505     assertTrue(values.contains(1));
    506     assertTrue(values.contains(3));
    507     assertTrue(values.contains(nullValue()));
    508     assertFalse(values.contains(5));
    509   }
    510 
    511   public void testValuesClear() {
    512     multimap.put("foo", 1);
    513     multimap.put("foo", nullValue());
    514     multimap.put(nullKey(), 3);
    515     Collection<Integer> values = multimap.values();
    516     values.clear();
    517     assertTrue(multimap.isEmpty());
    518     assertTrue(values.isEmpty());
    519     assertFalse(multimap.containsEntry("foo", 1));
    520   }
    521 
    522   public void testValuesRemoveAllNullFromEmpty() {
    523     try {
    524       multimap.values().removeAll(null);
    525       // Returning successfully is not ideal, but tolerated.
    526     } catch (NullPointerException expected) {}
    527   }
    528 
    529   public void testValuesRetainAllNullFromEmpty() {
    530     try {
    531       multimap.values().retainAll(null);
    532       // Returning successfully is not ideal, but tolerated.
    533     } catch (NullPointerException expected) {}
    534   }
    535 
    536   // the entries collection is more thoroughly tested in MultimapCollectionTest
    537   @SuppressWarnings("unchecked") // varargs
    538   public void testEntries() {
    539     multimap.put("foo", 1);
    540     multimap.put("foo", nullValue());
    541     multimap.put(nullKey(), 3);
    542     Collection<Entry<String, Integer>> entries = multimap.entries();
    543     ASSERT.that(entries).hasContentsAnyOrder(
    544         Maps.immutableEntry("foo", 1),
    545         Maps.immutableEntry("foo", nullValue()),
    546         Maps.immutableEntry(nullKey(), 3));
    547   }
    548 
    549   public void testNoSuchElementException() {
    550     Iterator<Entry<String, Integer>> entries =
    551         multimap.entries().iterator();
    552     try {
    553       entries.next();
    554       fail();
    555     } catch (NoSuchElementException expected) {}
    556   }
    557 
    558   public void testAsMap() {
    559     multimap.put("foo", 1);
    560     multimap.put("foo", nullValue());
    561     multimap.put(nullKey(), 3);
    562     Map<String, Collection<Integer>> map = multimap.asMap();
    563 
    564     assertEquals(2, map.size());
    565     ASSERT.that(map.get("foo")).hasContentsAnyOrder(1, nullValue());
    566     ASSERT.that(map.get(nullKey())).hasContentsAnyOrder(3);
    567     assertNull(map.get("bar"));
    568     assertTrue(map.containsKey("foo"));
    569     assertTrue(map.containsKey(nullKey()));
    570     assertFalse(multimap.containsKey("bar"));
    571 
    572     ASSERT.that(map.remove("foo")).hasContentsAnyOrder(1, nullValue());
    573     assertFalse(multimap.containsKey("foo"));
    574     assertEquals(1, multimap.size());
    575     assertNull(map.remove("bar"));
    576     multimap.get(nullKey()).add(5);
    577     assertTrue(multimap.containsEntry(nullKey(), 5));
    578     assertEquals(2, multimap.size());
    579     multimap.get(nullKey()).clear();
    580     assertTrue(multimap.isEmpty());
    581     assertEquals(0, multimap.size());
    582 
    583     try {
    584       map.put("bar", asList(4, 8));
    585       fail("Expected UnsupportedOperationException");
    586     } catch (UnsupportedOperationException expected) {}
    587 
    588     multimap.put("bar", 5);
    589     assertSize(1);
    590     map.clear();
    591     assertSize(0);
    592   }
    593 
    594   public void testAsMapEntries() {
    595     multimap.put("foo", 1);
    596     multimap.put("foo", nullValue());
    597     multimap.put(nullKey(), 3);
    598     Collection<Entry<String, Collection<Integer>>> entries =
    599         multimap.asMap().entrySet();
    600     assertEquals(2, entries.size());
    601 
    602     assertTrue(entries.contains(
    603         Maps.immutableEntry("foo", multimap.get("foo"))));
    604     assertFalse(entries.contains(
    605         Maps.immutableEntry("bar", multimap.get("foo"))));
    606     assertFalse(entries.contains(
    607         Maps.immutableEntry("bar", null)));
    608     assertFalse(entries.contains(
    609         Maps.immutableEntry("foo", null)));
    610     assertFalse(entries.contains(
    611         Maps.immutableEntry("foo", asList(1, 4))));
    612     assertFalse(entries.contains("foo"));
    613 
    614     Iterator<Entry<String, Collection<Integer>>> iterator =
    615         entries.iterator();
    616     for (int i = 0; i < 2; i++) {
    617       assertTrue(iterator.hasNext());
    618       Entry<String, Collection<Integer>> entry = iterator.next();
    619       if ("foo".equals(entry.getKey())) {
    620         assertEquals(2, entry.getValue().size());
    621         assertTrue(entry.getValue().contains(1));
    622         assertTrue(entry.getValue().contains(nullValue()));
    623       } else {
    624         assertEquals(nullKey(), entry.getKey());
    625         assertEquals(1, entry.getValue().size());
    626         assertTrue(entry.getValue().contains(3));
    627       }
    628     }
    629     assertFalse(iterator.hasNext());
    630   }
    631 
    632   public void testAsMapToString() {
    633     multimap.put("foo", 1);
    634     assertEquals("{foo=[1]}", multimap.asMap().toString());
    635   }
    636 
    637   public void testKeys() {
    638     multimap.put("foo", 1);
    639     multimap.put("foo", 5);
    640     multimap.put("foo", nullValue());
    641     multimap.put(nullKey(), 3);
    642     Multiset<String> multiset = multimap.keys();
    643     assertEquals(3, multiset.count("foo"));
    644     assertEquals(1, multiset.count(nullKey()));
    645     ASSERT.that(multiset.elementSet()).hasContentsAnyOrder("foo", nullKey());
    646     assertEquals(2, multiset.entrySet().size());
    647     assertEquals(4, multiset.size());
    648 
    649     Set<Multiset.Entry<String>> entries = multimap.keys().entrySet();
    650     assertTrue(entries.contains(Multisets.immutableEntry("foo", 3)));
    651     assertFalse(entries.contains(Multisets.immutableEntry("foo", 2)));
    652     assertFalse(entries.contains(Maps.immutableEntry("foo", 3)));
    653 
    654     Multiset<String> foo3null1 =
    655         HashMultiset.create(asList("foo", "foo", nullKey(), "foo"));
    656     assertEquals(foo3null1, multiset);
    657     assertEquals(multiset, foo3null1);
    658     assertFalse(multiset.equals(
    659         HashMultiset.create(asList("foo", "foo", nullKey(), nullKey()))));
    660     assertEquals(foo3null1.hashCode(), multiset.hashCode());
    661     assertEquals(foo3null1.entrySet(), multiset.entrySet());
    662     assertEquals(multiset.entrySet(), foo3null1.entrySet());
    663     assertEquals(foo3null1.entrySet().hashCode(),
    664         multiset.entrySet().hashCode());
    665 
    666     assertEquals(0, multiset.remove("bar", 1));
    667     assertEquals(1, multiset.remove(nullKey(), 4));
    668     assertFalse(multimap.containsKey(nullKey()));
    669     assertSize(3);
    670     assertEquals("foo", entries.iterator().next().getElement());
    671 
    672     assertEquals(3, multiset.remove("foo", 1));
    673     assertTrue(multimap.containsKey("foo"));
    674     assertSize(2);
    675     assertEquals(2, multiset.setCount("foo", 0));
    676     assertEquals(0, multiset.setCount("bar", 0));
    677   }
    678 
    679   public void testKeysAdd() {
    680     multimap.put("foo", 1);
    681     Multiset<String> multiset = multimap.keys();
    682 
    683     try {
    684       multiset.add("bar");
    685       fail();
    686     } catch (UnsupportedOperationException expected) {}
    687 
    688     try {
    689       multiset.add("bar", 2);
    690       fail();
    691     } catch (UnsupportedOperationException expected) {}
    692   }
    693 
    694   public void testKeysContainsAll() {
    695     multimap.put("foo", 1);
    696     multimap.put("foo", 5);
    697     multimap.put("foo", nullValue());
    698     multimap.put(nullKey(), 3);
    699     Multiset<String> multiset = multimap.keys();
    700 
    701     assertTrue(multiset.containsAll(asList("foo", nullKey())));
    702     assertFalse(multiset.containsAll(asList("foo", "bar")));
    703   }
    704 
    705   public void testKeysClear() {
    706     multimap.put("foo", 1);
    707     multimap.put("foo", 5);
    708     multimap.put("foo", nullValue());
    709     multimap.put(nullKey(), 3);
    710     Multiset<String> multiset = multimap.keys();
    711 
    712     multiset.clear();
    713     assertTrue(multiset.isEmpty());
    714     assertTrue(multimap.isEmpty());
    715     assertSize(0);
    716     assertFalse(multimap.containsKey("foo"));
    717     assertFalse(multimap.containsKey(nullKey()));
    718   }
    719 
    720   public void testKeysToString() {
    721     multimap.put("foo", 7);
    722     multimap.put("foo", 8);
    723     assertEquals("[foo x 2]", multimap.keys().toString());
    724   }
    725 
    726   public void testKeysEntrySetIterator() {
    727     multimap.put("foo", 7);
    728     multimap.put("foo", 8);
    729     Iterator<Multiset.Entry<String>> iterator
    730         = multimap.keys().entrySet().iterator();
    731     assertTrue(iterator.hasNext());
    732     assertEquals(Multisets.immutableEntry("foo", 2), iterator.next());
    733     iterator.remove();
    734     assertFalse(iterator.hasNext());
    735     assertSize(0);
    736   }
    737 
    738   public void testKeysEntrySetToString() {
    739     multimap.put("foo", 7);
    740     multimap.put("foo", 8);
    741     assertEquals("[foo x 2]", multimap.keys().entrySet().toString());
    742   }
    743 
    744   public void testKeysEntrySetRemove() {
    745     multimap.putAll("foo", asList(1, 2, 3));
    746     multimap.putAll("bar", asList(4, 5));
    747     Set<Multiset.Entry<String>> entries = multimap.keys().entrySet();
    748     assertTrue(entries.remove(Multisets.immutableEntry("bar", 2)));
    749     assertEquals("[foo x 3]", multimap.keys().entrySet().toString());
    750 
    751     // doesn't exist in entries, should have no effect
    752     assertFalse(entries.remove(Multisets.immutableEntry("foo", 2)));
    753     assertEquals("[foo x 3]", multimap.keys().entrySet().toString());
    754     assertEquals("Multimap size after keys().entrySet().remove(entry)",
    755         3, multimap.size());
    756   }
    757 
    758   public void testEqualsTrue() {
    759     multimap.put("foo", 1);
    760     multimap.put("foo", nullValue());
    761     multimap.put(nullKey(), 3);
    762     assertEquals(multimap, multimap);
    763 
    764     Multimap<String, Integer> multimap2 = create();
    765     multimap2.put(nullKey(), 3);
    766     multimap2.put("foo", 1);
    767     multimap2.put("foo", nullValue());
    768 
    769     assertEquals(multimap, multimap2);
    770     assertEquals(multimap.hashCode(), multimap2.hashCode());
    771   }
    772 
    773   public void testEqualsFalse() {
    774     multimap.put("foo", 1);
    775     multimap.put("foo", 3);
    776     multimap.put("bar", 3);
    777 
    778     Multimap<String, Integer> multimap2 = create();
    779     multimap2.put("bar", 3);
    780     multimap2.put("bar", 1);
    781     assertFalse(multimap.equals(multimap2));
    782 
    783     multimap2.put("foo", 3);
    784     assertFalse(multimap.equals(multimap2));
    785 
    786     assertFalse(multimap.equals(nullValue()));
    787     assertFalse(multimap.equals("foo"));
    788   }
    789 
    790   public void testValuesIterator() {
    791     multimap.put("foo", 1);
    792     multimap.put("foo", 2);
    793     multimap.put(nullKey(), 4);
    794     int sum = 0;
    795     for (int i : multimap.values()) {
    796       sum += i;
    797     }
    798     assertEquals(7, sum);
    799   }
    800 
    801   public void testValuesIteratorEmpty() {
    802     int sum = 0;
    803     for (int i : multimap.values()) {
    804       sum += i;
    805     }
    806     assertEquals(0, sum);
    807   }
    808 
    809   public void testGetAddQuery() {
    810     multimap.put("foo", 1);
    811     multimap.put("foo", 3);
    812     multimap.put("bar", 4);
    813     Collection<Integer> values = multimap.get("foo");
    814     multimap.put("foo", 5);
    815     multimap.put("bar", 6);
    816 
    817     /* Verify that values includes effect of put. */
    818     assertEquals(3, values.size());
    819     assertTrue(values.contains(1));
    820     assertTrue(values.contains(5));
    821     assertFalse(values.contains(6));
    822     ASSERT.that(values).hasContentsAnyOrder(1, 3, 5);
    823     assertTrue(values.containsAll(asList(3, 5)));
    824     assertFalse(values.isEmpty());
    825     assertEquals(multimap.get("foo"), values);
    826     assertEquals(multimap.get("foo").hashCode(), values.hashCode());
    827     assertEquals(multimap.get("foo").toString(), values.toString());
    828   }
    829 
    830   public void testGetAddAll() {
    831     multimap.put("foo", 1);
    832     multimap.put("foo", 3);
    833     multimap.get("foo").addAll(asList(5, 7));
    834     multimap.get("bar").addAll(asList(6, 8));
    835     multimap.get("cow").addAll(Arrays.<Integer>asList());
    836     assertSize(6);
    837     ASSERT.that(multimap.get("foo")).hasContentsAnyOrder(1, 3, 5, 7);
    838     ASSERT.that(multimap.get("bar")).hasContentsAnyOrder(6, 8);
    839     ASSERT.that(multimap.get("cow")).isEmpty();
    840   }
    841 
    842   public void testGetRemoveAddQuery() {
    843     multimap.put("foo", 1);
    844     multimap.put("foo", 3);
    845     multimap.put("bar", 4);
    846     Collection<Integer> values = multimap.get("foo");
    847     Iterator<Integer> iterator = values.iterator();
    848     multimap.remove("foo", 1);
    849     multimap.remove("foo", 3);
    850 
    851     /* Verify that values includes effect of remove */
    852     assertEquals(0, values.size());
    853     assertFalse(values.contains(1));
    854     assertFalse(values.contains(6));
    855     assertTrue(values.isEmpty());
    856     assertEquals(multimap.get("foo"), values);
    857     assertEquals(multimap.get("foo").hashCode(), values.hashCode());
    858     assertEquals(multimap.get("foo").toString(), values.toString());
    859 
    860     multimap.put("foo", 5);
    861 
    862     /* Verify that values includes effect of put. */
    863     assertEquals(1, values.size());
    864     assertFalse(values.contains(1));
    865     assertTrue(values.contains(5));
    866     assertFalse(values.contains(6));
    867     assertEquals(5, values.iterator().next().intValue());
    868     assertFalse(values.isEmpty());
    869     assertEquals(multimap.get("foo"), values);
    870     assertEquals(multimap.get("foo").hashCode(), values.hashCode());
    871     assertEquals(multimap.get("foo").toString(), values.toString());
    872 
    873     try {
    874       iterator.hasNext();
    875     } catch (ConcurrentModificationException expected) {}
    876   }
    877 
    878   public void testModifyCollectionFromGet() {
    879     multimap.put("foo", 1);
    880     multimap.put("foo", 3);
    881     multimap.put("bar", 4);
    882     Collection<Integer> values = multimap.get("foo");
    883 
    884     assertTrue(values.add(5));
    885     assertSize(4);
    886     assertEquals(3, multimap.get("foo").size());
    887     assertTrue(multimap.containsEntry("foo", 5));
    888 
    889     values.clear();
    890     assertSize(1);
    891     assertFalse(multimap.containsKey("foo"));
    892 
    893     assertTrue(values.addAll(asList(7, 9)));
    894     assertSize(3);
    895     assertEquals(2, multimap.get("foo").size());
    896     assertTrue(multimap.containsEntry("foo", 7));
    897     assertTrue(multimap.containsEntry("foo", 9));
    898     assertFalse(values.addAll(Collections.<Integer>emptyList()));
    899     assertSize(3);
    900 
    901     assertTrue(values.remove(7));
    902     assertSize(2);
    903     assertEquals(1, multimap.get("foo").size());
    904     assertFalse(multimap.containsEntry("foo", 7));
    905     assertTrue(multimap.containsEntry("foo", 9));
    906     assertFalse(values.remove(77));
    907     assertSize(2);
    908 
    909     assertTrue(values.add(11));
    910     assertTrue(values.add(13));
    911     assertTrue(values.add(15));
    912     assertTrue(values.add(17));
    913 
    914     assertTrue(values.removeAll(asList(11, 15)));
    915     assertSize(4);
    916     ASSERT.that(multimap.get("foo")).hasContentsAnyOrder(9, 13, 17);
    917     assertFalse(values.removeAll(asList(21, 25)));
    918     assertSize(4);
    919 
    920     assertTrue(values.retainAll(asList(13, 17, 19)));
    921     assertSize(3);
    922     ASSERT.that(multimap.get("foo")).hasContentsAnyOrder(13, 17);
    923     assertFalse(values.retainAll(asList(13, 17, 19)));
    924     assertSize(3);
    925 
    926     values.remove(13);
    927     values.remove(17);
    928     assertTrue(multimap.get("foo").isEmpty());
    929     assertSize(1);
    930     assertFalse(multimap.containsKey("foo"));
    931   }
    932 
    933   public void testGetIterator() {
    934     multimap.put("foo", 1);
    935     multimap.put("foo", 3);
    936     multimap.put("foo", 5);
    937     multimap.put("bar", 4);
    938     Collection<Integer> values = multimap.get("foo");
    939 
    940     Iterator<Integer> iterator = values.iterator();
    941     assertTrue(iterator.hasNext());
    942     Integer v1 = iterator.next();
    943     assertTrue(iterator.hasNext());
    944     Integer v2 = iterator.next();
    945     iterator.remove();
    946     assertTrue(iterator.hasNext());
    947     Integer v3 = iterator.next();
    948     assertFalse(iterator.hasNext());
    949 
    950     ASSERT.that(asList(v1, v2, v3)).hasContentsAnyOrder(1, 3, 5);
    951     assertSize(3);
    952     assertTrue(multimap.containsEntry("foo", v1));
    953     assertFalse(multimap.containsEntry("foo", v2));
    954     assertTrue(multimap.containsEntry("foo", v3));
    955 
    956     iterator = values.iterator();
    957     assertTrue(iterator.hasNext());
    958     Integer n1 = iterator.next();
    959     iterator.remove();
    960     assertTrue(iterator.hasNext());
    961     Integer n3 = iterator.next();
    962     iterator.remove();
    963     assertFalse(iterator.hasNext());
    964 
    965     ASSERT.that(asList(n1, n3)).hasContentsAnyOrder(v1, v3);
    966     assertSize(1);
    967     assertFalse(multimap.containsKey("foo"));
    968   }
    969 
    970   public void testGetClear() {
    971     multimap.put("foo", 1);
    972     multimap.put("bar", 3);
    973     Collection<Integer> values = multimap.get("foo");
    974     multimap.clear();
    975     assertTrue(values.isEmpty());
    976   }
    977 
    978   public void testGetPutAllCollection() {
    979     Collection<Integer> values = multimap.get("foo");
    980     Collection<Integer> collection = Lists.newArrayList(1, 3);
    981     multimap.putAll("foo", collection);
    982     ASSERT.that(values).hasContentsAnyOrder(1, 3);
    983   }
    984 
    985   public void testGetPutAllMultimap() {
    986     multimap.put("foo", 2);
    987     multimap.put("cow", 5);
    988     multimap.put(nullKey(), 2);
    989     Collection<Integer> valuesFoo = multimap.get("foo");
    990     Collection<Integer> valuesBar = multimap.get("bar");
    991     Collection<Integer> valuesCow = multimap.get("cow");
    992     Collection<Integer> valuesNull = multimap.get(nullKey());
    993     Multimap<String, Integer> multimap2 = create();
    994     multimap2.put("foo", 1);
    995     multimap2.put("bar", 3);
    996     multimap2.put(nullKey(), nullValue());
    997     multimap.putAll(multimap2);
    998 
    999     ASSERT.that(valuesFoo).hasContentsAnyOrder(1, 2);
   1000     ASSERT.that(valuesBar).hasContentsAnyOrder(3);
   1001     ASSERT.that(valuesCow).hasContentsAnyOrder(5);
   1002     ASSERT.that(valuesNull).hasContentsAnyOrder(nullValue(), 2);
   1003   }
   1004 
   1005   public void testGetRemove() {
   1006     multimap.put("foo", 1);
   1007     multimap.put("foo", 3);
   1008     Collection<Integer> values = multimap.get("foo");
   1009     multimap.remove("foo", 1);
   1010     ASSERT.that(values).hasContentsAnyOrder(3);
   1011   }
   1012 
   1013   public void testGetRemoveAll() {
   1014     multimap.put("foo", 1);
   1015     multimap.put("foo", 3);
   1016     Collection<Integer> values = multimap.get("foo");
   1017     multimap.removeAll("foo");
   1018     assertTrue(values.isEmpty());
   1019   }
   1020 
   1021   public void testGetReplaceValues() {
   1022     multimap.put("foo", 1);
   1023     multimap.put("foo", 3);
   1024     Collection<Integer> values = multimap.get("foo");
   1025     multimap.replaceValues("foo", asList(1, 5));
   1026     ASSERT.that(values).hasContentsAnyOrder(1, 5);
   1027 
   1028     multimap.replaceValues("foo", new ArrayList<Integer>());
   1029     assertTrue(multimap.isEmpty());
   1030     assertSize(0);
   1031     assertTrue(values.isEmpty());
   1032   }
   1033 
   1034   public void testEntriesUpdate() {
   1035     multimap.put("foo", 1);
   1036     Collection<Entry<String, Integer>> entries = multimap.entries();
   1037     Iterator<Entry<String, Integer>> iterator = entries.iterator();
   1038 
   1039     assertTrue(iterator.hasNext());
   1040     Entry<String, Integer> entry = iterator.next();
   1041     assertEquals("foo", entry.getKey());
   1042     assertEquals(1, entry.getValue().intValue());
   1043     iterator.remove();
   1044     assertFalse(iterator.hasNext());
   1045     assertTrue(multimap.isEmpty());
   1046     assertSize(0);
   1047 
   1048     try {
   1049       entries.add(Maps.immutableEntry("bar", 2));
   1050       fail("UnsupportedOperationException expected");
   1051     } catch (UnsupportedOperationException expected) {}
   1052     assertSize(0);
   1053     assertFalse(multimap.containsEntry("bar", 2));
   1054 
   1055     multimap.put("bar", 2);
   1056     assertSize(1);
   1057     assertTrue(entries.contains(Maps.immutableEntry("bar", 2)));
   1058 
   1059     entries.clear();
   1060     assertTrue(multimap.isEmpty());
   1061     assertSize(0);
   1062   }
   1063 
   1064   public void testEntriesRemove() {
   1065     multimap.put("foo", 1);
   1066     multimap.put("foo", nullValue());
   1067     multimap.put(nullKey(), 3);
   1068     Collection<Entry<String, Integer>> entries = multimap.entries();
   1069 
   1070     assertTrue(entries.remove(Maps.immutableEntry("foo", nullValue())));
   1071     assertSize(2);
   1072     assertFalse(multimap.containsEntry("foo", nullValue()));
   1073 
   1074     assertFalse(entries.remove(Maps.immutableEntry("foo", 3)));
   1075     assertFalse(entries.remove(3.5));
   1076     assertSize(2);
   1077   }
   1078 
   1079   @SuppressWarnings("unchecked")
   1080   public void testEntriesRemoveAll() {
   1081     multimap.put("foo", 1);
   1082     multimap.put("foo", 2);
   1083     multimap.put("bar", 3);
   1084 
   1085     assertFalse(multimap.entries().removeAll(
   1086         Collections.singleton(Maps.immutableEntry("foo", 3))));
   1087     assertSize(3);
   1088 
   1089     assertTrue(multimap.entries().removeAll(asList(
   1090         Maps.immutableEntry("foo", 3), Maps.immutableEntry("bar", 3))));
   1091     assertSize(2);
   1092     assertFalse(multimap.containsKey("bar"));
   1093   }
   1094 
   1095   public void testEntriesRemoveAllNullFromEmpty() {
   1096     try {
   1097       multimap.entries().removeAll(null);
   1098       // Returning successfully is not ideal, but tolerated.
   1099     } catch (NullPointerException expected) {}
   1100   }
   1101 
   1102   @SuppressWarnings("unchecked")
   1103   public void testEntriesRetainAll() {
   1104     multimap.put("foo", 1);
   1105     multimap.put("foo", 2);
   1106     multimap.put("bar", 3);
   1107 
   1108     assertFalse(multimap.entries().retainAll(asList(
   1109         Maps.immutableEntry("foo", 1), Maps.immutableEntry("foo", 2),
   1110         Maps.immutableEntry("foo", 3), Maps.immutableEntry("bar", 3))));
   1111     assertSize(3);
   1112 
   1113     assertTrue(multimap.entries().retainAll(asList(
   1114         Maps.immutableEntry("foo", 3), Maps.immutableEntry("bar", 3))));
   1115     assertSize(1);
   1116     assertTrue(multimap.containsEntry("bar", 3));
   1117   }
   1118 
   1119   public void testEntriesRetainAllNullFromEmpty() {
   1120     try {
   1121       multimap.entries().retainAll(null);
   1122       // Returning successfully is not ideal, but tolerated.
   1123     } catch (NullPointerException expected) {}
   1124   }
   1125 
   1126   public void testEntriesIterator() {
   1127     multimap.put("foo", 3);
   1128     Iterator<Entry<String, Integer>> iterator
   1129         = multimap.entries().iterator();
   1130     assertTrue(iterator.hasNext());
   1131     assertEquals(Maps.immutableEntry("foo", 3), iterator.next());
   1132     iterator.remove();
   1133     assertFalse(iterator.hasNext());
   1134     assertSize(0);
   1135   }
   1136 
   1137   public void testEntriesToString() {
   1138     multimap.put("foo", 3);
   1139     Collection<Entry<String, Integer>> entries = multimap.entries();
   1140     assertEquals("[foo=3]", entries.toString());
   1141   }
   1142 
   1143   public void testEntriesToArray() {
   1144     multimap.put("foo", 3);
   1145     Collection<Entry<String, Integer>> entries = multimap.entries();
   1146     Entry<?, ?>[] array = new Entry<?, ?>[3];
   1147     assertSame(array, entries.toArray(array));
   1148     assertEquals(Maps.immutableEntry("foo", 3), array[0]);
   1149     assertNull(array[1]);
   1150   }
   1151 
   1152   /**
   1153    * Test calling setValue() on an entry returned by multimap.entries().
   1154    */
   1155   public void testEntrySetValue() {
   1156     multimap.put("foo", 1);
   1157     multimap.put("bar", 1);
   1158     Collection<Entry<String, Integer>> entries = multimap.entries();
   1159     Iterator<Entry<String, Integer>> iterator = entries.iterator();
   1160     Entry<String, Integer> entrya = iterator.next();
   1161     Entry<String, Integer> entryb = iterator.next();
   1162     try {
   1163       entrya.setValue(3);
   1164       fail();
   1165     } catch (UnsupportedOperationException expected) {}
   1166     assertTrue(multimap.containsEntry("foo", 1));
   1167     assertTrue(multimap.containsEntry("bar", 1));
   1168     assertFalse(multimap.containsEntry("foo", 2));
   1169     assertFalse(multimap.containsEntry("bar", 2));
   1170     assertEquals(1, (int) entrya.getValue());
   1171     assertEquals(1, (int) entryb.getValue());
   1172   }
   1173 
   1174   /** Verify that the entries remain valid after iterating past them. */
   1175   public void testEntriesCopy() {
   1176     multimap.put("foo", 1);
   1177     multimap.put("foo", 2);
   1178     multimap.put("bar", 3);
   1179 
   1180     Set<Entry<String, Integer>> copy = Sets.newHashSet(multimap.entries());
   1181     assertEquals(3, copy.size());
   1182     assertTrue(copy.contains(Maps.immutableEntry("foo", 1)));
   1183     assertTrue(copy.contains(Maps.immutableEntry("foo", 2)));
   1184     assertTrue(copy.contains(Maps.immutableEntry("bar", 3)));
   1185     assertFalse(copy.contains(Maps.immutableEntry("bar", 1)));
   1186 
   1187     multimap.removeAll("foo");
   1188     assertEquals(3, copy.size());
   1189     assertTrue(copy.contains(Maps.immutableEntry("foo", 1)));
   1190     assertTrue(copy.contains(Maps.immutableEntry("foo", 2)));
   1191     assertTrue(copy.contains(Maps.immutableEntry("bar", 3)));
   1192     assertFalse(copy.contains(Maps.immutableEntry("bar", 1)));
   1193   }
   1194 
   1195   public void testKeySetRemove() {
   1196     multimap.put("foo", 1);
   1197     multimap.put("foo", nullValue());
   1198     multimap.put(nullKey(), 3);
   1199     Set<String> keys = multimap.keySet();
   1200     assertTrue(keys.remove("foo"));
   1201     assertFalse(keys.remove("bar"));
   1202     assertSize(1);
   1203     assertFalse(multimap.containsKey("foo"));
   1204     assertTrue(multimap.containsEntry(nullKey(), 3));
   1205   }
   1206 
   1207   public void testKeySetRemoveAllNullFromEmpty() {
   1208     try {
   1209       multimap.keySet().removeAll(null);
   1210       fail();
   1211     } catch (NullPointerException expected) {}
   1212   }
   1213 
   1214   public void testKeySetRetainAllNullFromEmpty() {
   1215     try {
   1216       multimap.keySet().retainAll(null);
   1217       // Returning successfully is not ideal, but tolerated.
   1218     } catch (NullPointerException expected) {}
   1219   }
   1220 
   1221   public void testKeySetIterator() {
   1222     multimap.put("foo", 1);
   1223     multimap.put("foo", nullValue());
   1224     multimap.put(nullKey(), 3);
   1225 
   1226     Iterator<String> iterator = multimap.keySet().iterator();
   1227     while (iterator.hasNext()) {
   1228       String key = iterator.next();
   1229       if ("foo".equals(key)) {
   1230         iterator.remove();
   1231       }
   1232     }
   1233     assertSize(1);
   1234     assertFalse(multimap.containsKey("foo"));
   1235     assertTrue(multimap.containsEntry(nullKey(), 3));
   1236 
   1237     iterator = multimap.keySet().iterator();
   1238     assertEquals(nullKey(), iterator.next());
   1239     iterator.remove();
   1240     assertTrue(multimap.isEmpty());
   1241     assertSize(0);
   1242   }
   1243 
   1244   public void testKeySetClear() {
   1245     multimap.put("foo", 1);
   1246     multimap.put("foo", nullValue());
   1247     multimap.put(nullKey(), 3);
   1248 
   1249     multimap.keySet().clear();
   1250     assertTrue(multimap.isEmpty());
   1251     assertSize(0);
   1252   }
   1253 
   1254   public void testValuesIteratorRemove() {
   1255     multimap.put("foo", 1);
   1256     multimap.put("foo", 2);
   1257     multimap.put(nullKey(), 4);
   1258 
   1259     Iterator<Integer> iterator = multimap.values().iterator();
   1260     while (iterator.hasNext()) {
   1261       int value = iterator.next();
   1262       if ((value % 2) == 0) {
   1263         iterator.remove();
   1264       }
   1265     }
   1266 
   1267     assertSize(1);
   1268     assertTrue(multimap.containsEntry("foo", 1));
   1269   }
   1270 
   1271   public void testAsMapEntriesUpdate() {
   1272     multimap.put("foo", 1);
   1273     multimap.put("foo", 3);
   1274     Collection<Entry<String, Collection<Integer>>> entries =
   1275         multimap.asMap().entrySet();
   1276     Entry<String, Collection<Integer>> entry = entries.iterator().next();
   1277     Collection<Integer> values = entry.getValue();
   1278 
   1279     multimap.put("foo", 5);
   1280     assertEquals(3, values.size());
   1281     assertTrue(values.contains(5));
   1282 
   1283     values.add(7);
   1284     assertSize(4);
   1285     assertTrue(multimap.containsValue(7));
   1286 
   1287     multimap.put("bar", 4);
   1288     assertEquals(2, entries.size());
   1289     assertSize(5);
   1290 
   1291     assertTrue(entries.remove(entry));
   1292     assertSize(1);
   1293     assertFalse(multimap.containsKey("foo"));
   1294     assertTrue(multimap.containsKey("bar"));
   1295     assertFalse(entries.remove("foo"));
   1296     assertFalse(entries.remove(
   1297         Maps.immutableEntry("foo", Collections.singleton(2))));
   1298     assertSize(1);
   1299 
   1300     Iterator<Entry<String, Collection<Integer>>> iterator =
   1301         entries.iterator();
   1302     assertTrue(iterator.hasNext());
   1303     iterator.next();
   1304     iterator.remove();
   1305     assertFalse(iterator.hasNext());
   1306     assertSize(0);
   1307     assertTrue(multimap.isEmpty());
   1308 
   1309     multimap.put("bar", 8);
   1310     assertSize(1);
   1311     entries.clear();
   1312     assertSize(0);
   1313   }
   1314 
   1315   public void testToStringNull() {
   1316     multimap.put("foo", 3);
   1317     multimap.put("foo", -1);
   1318     multimap.put(nullKey(), nullValue());
   1319     multimap.put("bar", 1);
   1320     multimap.put("foo", 2);
   1321     multimap.put(nullKey(), 0);
   1322     multimap.put("bar", 2);
   1323     multimap.put("bar", nullValue());
   1324     multimap.put("foo", nullValue());
   1325     multimap.put("foo", 4);
   1326     multimap.put(nullKey(), -1);
   1327     multimap.put("bar", 3);
   1328     multimap.put("bar", 1);
   1329     multimap.put("foo", 1);
   1330 
   1331     // This test is brittle. The original test was meant to validate the
   1332     // contents of the string itself, but key and value ordering tend
   1333     // to change under unpredictable circumstances. Instead, we're just ensuring
   1334     // that the string not return null and, implicitly, not throw an exception.
   1335     assertNotNull(multimap.toString());
   1336   }
   1337 
   1338   @GwtIncompatible("SerializableTester")
   1339   public void testSerializable() {
   1340     multimap = createSample();
   1341     assertEquals(multimap, SerializableTester.reserialize(multimap));
   1342   }
   1343 
   1344   public void testEmptyToString() {
   1345     Multimap<String, Integer> map = create();
   1346     assertEquals("{}", map.toString());
   1347     assertEquals("[]", map.entries().toString());
   1348   }
   1349 
   1350   public void testEmptyGetToString() {
   1351     Multimap<String, Integer> map = create();
   1352     map.get("foo"); // shouldn't have any side-effect
   1353     assertEquals("{}", map.toString());
   1354     assertEquals("[]", map.entries().toString());
   1355   }
   1356 
   1357   public void testGetRemoveToString() {
   1358     Multimap<String, Integer> map = create();
   1359     map.put("bar", 1);
   1360     map.put("foo", 2);
   1361     map.put("bar", 3);
   1362     map.get("foo").remove(2);
   1363     map.get("bar").remove(1);
   1364     assertEquals("{bar=[3]}", map.toString());
   1365     assertEquals("[bar=3]", map.entries().toString());
   1366   }
   1367 
   1368   public void testRemoveToString() {
   1369     Multimap<String, Integer> map = create();
   1370     map.put("foo", 1);
   1371     map.put("foo", 2);
   1372     map.remove("foo", 1);
   1373     assertEquals("[foo=2]", map.entries().toString());
   1374   }
   1375 }
   1376