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 com.google.common.collect.Maps.immutableEntry;
     20 import static com.google.common.collect.Sets.newHashSet;
     21 import static com.google.common.collect.testing.Helpers.nefariousMapEntry;
     22 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
     23 import static java.util.Arrays.asList;
     24 import static org.junit.contrib.truth.Truth.ASSERT;
     25 
     26 import com.google.common.annotations.GwtCompatible;
     27 import com.google.common.annotations.GwtIncompatible;
     28 import com.google.common.base.Function;
     29 import com.google.common.base.Functions;
     30 import com.google.common.base.Supplier;
     31 import com.google.common.collect.Maps.EntryTransformer;
     32 import com.google.common.collect.testing.IteratorTester;
     33 import com.google.common.collect.testing.google.UnmodifiableCollectionTests;
     34 import com.google.common.testing.NullPointerTester;
     35 import com.google.common.testing.SerializableTester;
     36 
     37 import java.io.Serializable;
     38 import java.util.Arrays;
     39 import java.util.Collection;
     40 import java.util.Collections;
     41 import java.util.Comparator;
     42 import java.util.HashSet;
     43 import java.util.Iterator;
     44 import java.util.LinkedList;
     45 import java.util.List;
     46 import java.util.Map;
     47 import java.util.Map.Entry;
     48 import java.util.Queue;
     49 import java.util.RandomAccess;
     50 import java.util.Set;
     51 import java.util.SortedMap;
     52 import java.util.SortedSet;
     53 import java.util.TreeSet;
     54 
     55 import javax.annotation.Nullable;
     56 
     57 /**
     58  * Unit test for {@code Multimaps}.
     59  *
     60  * @author Jared Levy
     61  */
     62 @GwtCompatible(emulated = true)
     63 public class MultimapsTest extends AbstractMultimapTest {
     64   private static final Comparator<Integer> INT_COMPARATOR =
     65       Ordering.<Integer>natural().reverse().nullsFirst();
     66 
     67   private static final EntryTransformer<Object, Object, Object> ALWAYS_NULL =
     68       new EntryTransformer<Object, Object, Object>() {
     69         @Override
     70         public Object transformEntry(Object k, Object v1) {
     71           return null;
     72         }
     73       };
     74 
     75   @Override protected Multimap<String, Integer> create() {
     76     return Multimaps.synchronizedSetMultimap(
     77         HashMultimap.<String, Integer>create());
     78   }
     79 
     80   @SuppressWarnings("deprecation")
     81   public void testUnmodifiableListMultimapShortCircuit(){
     82     ListMultimap<String, Integer> mod = ArrayListMultimap.create();
     83     ListMultimap<String, Integer> unmod = Multimaps.unmodifiableListMultimap(mod);
     84     assertNotSame(mod, unmod);
     85     assertSame(unmod, Multimaps.unmodifiableListMultimap(unmod));
     86     ImmutableListMultimap<String, Integer> immutable =
     87         ImmutableListMultimap.of("a", 1, "b", 2, "a", 3);
     88     assertSame(immutable, Multimaps.unmodifiableListMultimap(immutable));
     89     assertSame(
     90         immutable, Multimaps.unmodifiableListMultimap((ListMultimap<String, Integer>) immutable));
     91   }
     92 
     93   @SuppressWarnings("deprecation")
     94   public void testUnmodifiableSetMultimapShortCircuit(){
     95     SetMultimap<String, Integer> mod = HashMultimap.create();
     96     SetMultimap<String, Integer> unmod = Multimaps.unmodifiableSetMultimap(mod);
     97     assertNotSame(mod, unmod);
     98     assertSame(unmod, Multimaps.unmodifiableSetMultimap(unmod));
     99     ImmutableSetMultimap<String, Integer> immutable =
    100         ImmutableSetMultimap.of("a", 1, "b", 2, "a", 3);
    101     assertSame(immutable, Multimaps.unmodifiableSetMultimap(immutable));
    102     assertSame(
    103         immutable, Multimaps.unmodifiableSetMultimap((SetMultimap<String, Integer>) immutable));
    104   }
    105 
    106   @SuppressWarnings("deprecation")
    107   public void testUnmodifiableMultimapShortCircuit(){
    108     Multimap<String, Integer> mod = HashMultimap.create();
    109     Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod);
    110     assertNotSame(mod, unmod);
    111     assertSame(unmod, Multimaps.unmodifiableMultimap(unmod));
    112     ImmutableMultimap<String, Integer> immutable = ImmutableMultimap.of("a", 1, "b", 2, "a", 3);
    113     assertSame(immutable, Multimaps.unmodifiableMultimap(immutable));
    114     assertSame(immutable, Multimaps.unmodifiableMultimap((Multimap<String, Integer>) immutable));
    115   }
    116 
    117   @GwtIncompatible("slow (~10s)")
    118   public void testUnmodifiableArrayListMultimap() {
    119     checkUnmodifiableMultimap(
    120         ArrayListMultimap.<String, Integer>create(), true);
    121   }
    122 
    123   @GwtIncompatible("SerializableTester")
    124   public void testSerializingUnmodifiableArrayListMultimap() {
    125     Multimap<String, Integer> unmodifiable =
    126         prepareUnmodifiableTests(ArrayListMultimap.<String, Integer>create(), true, null, null);
    127     SerializableTester.reserializeAndAssert(unmodifiable);
    128   }
    129 
    130   public void testUnmodifiableArrayListMultimapRandomAccess() {
    131     ListMultimap<String, Integer> delegate = ArrayListMultimap.create();
    132     delegate.put("foo", 1);
    133     delegate.put("foo", 3);
    134     ListMultimap<String, Integer> multimap
    135         = Multimaps.unmodifiableListMultimap(delegate);
    136     assertTrue(multimap.get("foo") instanceof RandomAccess);
    137     assertTrue(multimap.get("bar") instanceof RandomAccess);
    138   }
    139 
    140   public void testUnmodifiableLinkedListMultimapRandomAccess() {
    141     ListMultimap<String, Integer> delegate = LinkedListMultimap.create();
    142     delegate.put("foo", 1);
    143     delegate.put("foo", 3);
    144     ListMultimap<String, Integer> multimap
    145         = Multimaps.unmodifiableListMultimap(delegate);
    146     assertFalse(multimap.get("foo") instanceof RandomAccess);
    147     assertFalse(multimap.get("bar") instanceof RandomAccess);
    148   }
    149 
    150   @GwtIncompatible("slow (~10s)")
    151   public void testUnmodifiableHashMultimap() {
    152     checkUnmodifiableMultimap(HashMultimap.<String, Integer>create(), false);
    153   }
    154 
    155   @GwtIncompatible("SerializableTester")
    156   public void testSerializingUnmodifiableHashMultimap() {
    157     Multimap<String, Integer> unmodifiable =
    158         prepareUnmodifiableTests(HashMultimap.<String, Integer>create(), false, null, null);
    159     SerializableTester.reserializeAndAssert(unmodifiable);
    160   }
    161 
    162   @GwtIncompatible("slow (~10s)")
    163   public void testUnmodifiableTreeMultimap() {
    164     checkUnmodifiableMultimap(
    165         TreeMultimap.<String, Integer>create(), false, "null", 42);
    166   }
    167 
    168   @GwtIncompatible("SerializableTester")
    169   public void testSerializingUnmodifiableTreeMultimap() {
    170     Multimap<String, Integer> unmodifiable =
    171         prepareUnmodifiableTests(TreeMultimap.<String, Integer>create(), false, "null", 42);
    172     SerializableTester.reserializeAndAssert(unmodifiable);
    173   }
    174 
    175   @GwtIncompatible("slow (~10s)")
    176   public void testUnmodifiableSynchronizedArrayListMultimap() {
    177     checkUnmodifiableMultimap(Multimaps.synchronizedListMultimap(
    178         ArrayListMultimap.<String, Integer>create()), true);
    179   }
    180 
    181   @GwtIncompatible("SerializableTester")
    182   public void testSerializingUnmodifiableSynchronizedArrayListMultimap() {
    183     Multimap<String, Integer> unmodifiable =
    184         prepareUnmodifiableTests(Multimaps.synchronizedListMultimap(
    185           ArrayListMultimap.<String, Integer>create()), true, null, null);
    186     SerializableTester.reserializeAndAssert(unmodifiable);
    187   }
    188 
    189   @GwtIncompatible("slow (~10s)")
    190   public void testUnmodifiableSynchronizedHashMultimap() {
    191     checkUnmodifiableMultimap(Multimaps.synchronizedSetMultimap(
    192         HashMultimap.<String, Integer>create()), false);
    193   }
    194 
    195   @GwtIncompatible("SerializableTester")
    196   public void testSerializingUnmodifiableSynchronizedHashMultimap() {
    197     Multimap<String, Integer> unmodifiable =
    198         prepareUnmodifiableTests(Multimaps.synchronizedSetMultimap(
    199         HashMultimap.<String, Integer>create()), false, null, null);
    200     SerializableTester.reserializeAndAssert(unmodifiable);
    201   }
    202 
    203   @GwtIncompatible("slow (~10s)")
    204   public void testUnmodifiableSynchronizedTreeMultimap() {
    205     TreeMultimap<String, Integer> delegate
    206         = TreeMultimap.create(Ordering.<String>natural(), INT_COMPARATOR);
    207     SortedSetMultimap<String, Integer> multimap
    208         = Multimaps.synchronizedSortedSetMultimap(delegate);
    209     checkUnmodifiableMultimap(multimap, false, "null", 42);
    210     assertSame(INT_COMPARATOR, multimap.valueComparator());
    211   }
    212 
    213   @GwtIncompatible("SerializableTester")
    214   public void testSerializingUnmodifiableSynchronizedTreeMultimap() {
    215     TreeMultimap<String, Integer> delegate =
    216         TreeMultimap.create(Ordering.<String>natural(), INT_COMPARATOR);
    217     SortedSetMultimap<String, Integer> multimap =
    218         Multimaps.synchronizedSortedSetMultimap(delegate);
    219     Multimap<String, Integer> unmodifiable =
    220         prepareUnmodifiableTests(multimap, false, "null", 42);
    221     SerializableTester.reserializeAndAssert(unmodifiable);
    222     assertSame(INT_COMPARATOR, multimap.valueComparator());
    223   }
    224 
    225   public void testUnmodifiableMultimapIsView() {
    226     Multimap<String, Integer> mod = HashMultimap.create();
    227     Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod);
    228     assertEquals(mod, unmod);
    229     mod.put("foo", 1);
    230     assertTrue(unmod.containsEntry("foo", 1));
    231     assertEquals(mod, unmod);
    232   }
    233 
    234   @SuppressWarnings("unchecked")
    235   public void testUnmodifiableMultimapEntries() {
    236     Multimap<String, Integer> mod = HashMultimap.create();
    237     Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod);
    238     mod.put("foo", 1);
    239     Entry<String, Integer> entry = unmod.entries().iterator().next();
    240     try {
    241       entry.setValue(2);
    242       fail("UnsupportedOperationException expected");
    243     } catch (UnsupportedOperationException expected) {}
    244     entry = (Entry<String, Integer>) unmod.entries().toArray()[0];
    245     try {
    246       entry.setValue(2);
    247       fail("UnsupportedOperationException expected");
    248     } catch (UnsupportedOperationException expected) {}
    249     Entry<String, Integer>[] array
    250         = (Entry<String, Integer>[]) new Entry<?, ?>[2];
    251     assertSame(array, unmod.entries().toArray(array));
    252     try {
    253       array[0].setValue(2);
    254       fail("UnsupportedOperationException expected");
    255     } catch (UnsupportedOperationException expected) {}
    256     assertFalse(unmod.entries().contains(nefariousMapEntry("pwnd", 2)));
    257     assertFalse(unmod.keys().contains("pwnd"));
    258   }
    259 
    260   /**
    261    * The supplied multimap will be mutated and an unmodifiable instance used
    262    * in its stead. The multimap must support null keys and values.
    263    */
    264   private static void checkUnmodifiableMultimap(
    265       Multimap<String, Integer> multimap, boolean permitsDuplicates) {
    266     checkUnmodifiableMultimap(multimap, permitsDuplicates, null, null);
    267   }
    268 
    269   /**
    270    * The supplied multimap will be mutated and an unmodifiable instance used
    271    * in its stead. If the multimap does not support null keys or values,
    272    * alternatives may be specified for tests involving nulls.
    273    */
    274   private static void checkUnmodifiableMultimap(
    275       Multimap<String, Integer> multimap, boolean permitsDuplicates,
    276       @Nullable String nullKey, @Nullable Integer nullValue) {
    277     Multimap<String, Integer> unmodifiable =
    278         prepareUnmodifiableTests(multimap, permitsDuplicates, nullKey, nullValue);
    279 
    280     UnmodifiableCollectionTests.assertMultimapIsUnmodifiable(
    281         unmodifiable, "test", 123);
    282 
    283     assertUnmodifiableIterableInTandem(
    284         unmodifiable.keys(), multimap.keys());
    285 
    286     assertUnmodifiableIterableInTandem(
    287         unmodifiable.keySet(), multimap.keySet());
    288 
    289     assertUnmodifiableIterableInTandem(
    290         unmodifiable.entries(), multimap.entries());
    291 
    292     assertUnmodifiableIterableInTandem(
    293         unmodifiable.asMap().entrySet(), multimap.asMap().entrySet());
    294 
    295     assertEquals(multimap.toString(), unmodifiable.toString());
    296     assertEquals(multimap.hashCode(), unmodifiable.hashCode());
    297     assertEquals(multimap, unmodifiable);
    298 
    299     ASSERT.that(unmodifiable.asMap().get("bar")).hasContentsAnyOrder(5, -1);
    300     assertNull(unmodifiable.asMap().get("missing"));
    301 
    302     assertFalse(unmodifiable.entries() instanceof Serializable);
    303     assertFalse(unmodifiable.asMap().values() instanceof Serializable);
    304   }
    305 
    306   /**
    307    * Prepares the multimap for unmodifiable tests, returning an unmodifiable view
    308    * of the map.
    309    */
    310   private static Multimap<String, Integer> prepareUnmodifiableTests(
    311       Multimap<String, Integer> multimap, boolean permitsDuplicates,
    312       @Nullable String nullKey, @Nullable Integer nullValue) {
    313     multimap.clear();
    314     multimap.put("foo", 1);
    315     multimap.put("foo", 2);
    316     multimap.put("foo", 3);
    317     multimap.put("bar", 5);
    318     multimap.put("bar", -1);
    319     multimap.put(nullKey, nullValue);
    320     multimap.put("foo", nullValue);
    321     multimap.put(nullKey, 5);
    322     multimap.put("foo", 2);
    323 
    324     if (permitsDuplicates) {
    325       assertEquals(9, multimap.size());
    326     } else {
    327       assertEquals(8, multimap.size());
    328     }
    329 
    330     Multimap<String, Integer> unmodifiable;
    331     if (multimap instanceof SortedSetMultimap) {
    332       unmodifiable = Multimaps.unmodifiableSortedSetMultimap(
    333           (SortedSetMultimap<String, Integer>) multimap);
    334     } else if (multimap instanceof SetMultimap) {
    335       unmodifiable = Multimaps.unmodifiableSetMultimap(
    336           (SetMultimap<String, Integer>) multimap);
    337     } else if (multimap instanceof ListMultimap) {
    338       unmodifiable = Multimaps.unmodifiableListMultimap(
    339           (ListMultimap<String, Integer>) multimap);
    340     } else {
    341       unmodifiable = Multimaps.unmodifiableMultimap(multimap);
    342     }
    343     return unmodifiable;
    344   }
    345 
    346   private static <T> void assertUnmodifiableIterableInTandem(
    347       Iterable<T> unmodifiable, Iterable<T> modifiable) {
    348     UnmodifiableCollectionTests.assertIteratorIsUnmodifiable(
    349         unmodifiable.iterator());
    350     UnmodifiableCollectionTests.assertIteratorsInOrder(
    351         unmodifiable.iterator(), modifiable.iterator());
    352   }
    353 
    354   public void testInvertFrom() {
    355     ImmutableMultimap<Integer, String> empty = ImmutableMultimap.of();
    356 
    357     // typical usage example - sad that ArrayListMultimap.create() won't work
    358     Multimap<String, Integer> multimap = Multimaps.invertFrom(empty,
    359         ArrayListMultimap.<String, Integer>create());
    360     assertTrue(multimap.isEmpty());
    361 
    362     ImmutableMultimap<Integer, String> single
    363         = new ImmutableMultimap.Builder<Integer, String>()
    364             .put(1, "one")
    365             .put(2, "two")
    366             .build();
    367 
    368     // copy into existing multimap
    369     assertSame(multimap, Multimaps.invertFrom(single, multimap));
    370 
    371     ImmutableMultimap<String, Integer> expected
    372         = new ImmutableMultimap.Builder<String, Integer>()
    373         .put("one", 1)
    374         .put("two", 2)
    375         .build();
    376 
    377     assertEquals(expected, multimap);
    378   }
    379 
    380   public void testForMap() {
    381     Map<String, Integer> map = Maps.newHashMap();
    382     map.put("foo", 1);
    383     map.put("bar", 2);
    384     Multimap<String, Integer> multimap = HashMultimap.create();
    385     multimap.put("foo", 1);
    386     multimap.put("bar", 2);
    387     Multimap<String, Integer> multimapView = Multimaps.forMap(map);
    388     assertTrue(multimap.equals(multimapView));
    389     assertTrue(multimapView.equals(multimap));
    390     assertTrue(multimapView.equals(multimapView));
    391     assertFalse(multimapView.equals(map));
    392     Multimap<String, Integer> multimap2 = HashMultimap.create();
    393     multimap2.put("foo", 1);
    394     assertFalse(multimapView.equals(multimap2));
    395     multimap2.put("bar", 1);
    396     assertFalse(multimapView.equals(multimap2));
    397     ListMultimap<String, Integer> listMultimap
    398         = new ImmutableListMultimap.Builder<String, Integer>()
    399             .put("foo", 1).put("bar", 2).build();
    400     assertFalse("SetMultimap equals ListMultimap",
    401         multimapView.equals(listMultimap));
    402     assertEquals(multimap.toString(), multimapView.toString());
    403     assertEquals(multimap.hashCode(), multimapView.hashCode());
    404     assertEquals(multimap.size(), multimapView.size());
    405     assertTrue(multimapView.containsKey("foo"));
    406     assertTrue(multimapView.containsValue(1));
    407     assertTrue(multimapView.containsEntry("bar", 2));
    408     assertEquals(Collections.singleton(1), multimapView.get("foo"));
    409     assertEquals(Collections.singleton(2), multimapView.get("bar"));
    410     try {
    411       multimapView.put("baz", 3);
    412       fail("UnsupportedOperationException expected");
    413     } catch (UnsupportedOperationException expected) {}
    414     try {
    415       multimapView.putAll("baz", Collections.singleton(3));
    416       fail("UnsupportedOperationException expected");
    417     } catch (UnsupportedOperationException expected) {}
    418     try {
    419       multimapView.putAll(multimap);
    420       fail("UnsupportedOperationException expected");
    421     } catch (UnsupportedOperationException expected) {}
    422     try {
    423       multimapView.replaceValues("foo", Collections.<Integer>emptySet());
    424       fail("UnsupportedOperationException expected");
    425     } catch (UnsupportedOperationException expected) {}
    426     multimapView.remove("bar", 2);
    427     assertFalse(multimapView.containsKey("bar"));
    428     assertFalse(map.containsKey("bar"));
    429     assertEquals(map.keySet(), multimapView.keySet());
    430     assertEquals(map.keySet(), multimapView.keys().elementSet());
    431     ASSERT.that(multimapView.keys()).hasContentsAnyOrder("foo");
    432     ASSERT.that(multimapView.values()).hasContentsAnyOrder(1);
    433     ASSERT.that(multimapView.entries()).hasContentsAnyOrder(
    434         Maps.immutableEntry("foo", 1));
    435     ASSERT.that(multimapView.asMap().entrySet()).hasContentsAnyOrder(
    436         Maps.immutableEntry(
    437             "foo", (Collection<Integer>) Collections.singleton(1)));
    438     multimapView.clear();
    439     assertFalse(multimapView.containsKey("foo"));
    440     assertFalse(map.containsKey("foo"));
    441     assertTrue(map.isEmpty());
    442     assertTrue(multimapView.isEmpty());
    443     multimap.clear();
    444     assertEquals(multimap.toString(), multimapView.toString());
    445     assertEquals(multimap.hashCode(), multimapView.hashCode());
    446     assertEquals(multimap.size(), multimapView.size());
    447     assertEquals(multimapView, ArrayListMultimap.create());
    448   }
    449 
    450   @GwtIncompatible("SerializableTester")
    451   public void testForMapSerialization() {
    452     Map<String, Integer> map = Maps.newHashMap();
    453     map.put("foo", 1);
    454     map.put("bar", 2);
    455     Multimap<String, Integer> multimapView = Multimaps.forMap(map);
    456     SerializableTester.reserializeAndAssert(multimapView);
    457   }
    458 
    459   public void testForMapRemoveAll() {
    460     Map<String, Integer> map = Maps.newHashMap();
    461     map.put("foo", 1);
    462     map.put("bar", 2);
    463     map.put("cow", 3);
    464     Multimap<String, Integer> multimap = Multimaps.forMap(map);
    465     assertEquals(3, multimap.size());
    466     assertEquals(Collections.emptySet(), multimap.removeAll("dog"));
    467     assertEquals(3, multimap.size());
    468     assertTrue(multimap.containsKey("bar"));
    469     assertEquals(Collections.singleton(2), multimap.removeAll("bar"));
    470     assertEquals(2, multimap.size());
    471     assertFalse(multimap.containsKey("bar"));
    472   }
    473 
    474   public void testForMapAsMap() {
    475     Map<String, Integer> map = Maps.newHashMap();
    476     map.put("foo", 1);
    477     map.put("bar", 2);
    478     Map<String, Collection<Integer>> asMap = Multimaps.forMap(map).asMap();
    479     assertEquals(Collections.singleton(1), asMap.get("foo"));
    480     assertNull(asMap.get("cow"));
    481     assertTrue(asMap.containsKey("foo"));
    482     assertFalse(asMap.containsKey("cow"));
    483 
    484     Set<Entry<String, Collection<Integer>>> entries = asMap.entrySet();
    485     assertFalse(entries.contains(4.5));
    486     assertFalse(entries.remove(4.5));
    487     assertFalse(entries.contains(Maps.immutableEntry("foo",
    488         Collections.singletonList(1))));
    489     assertFalse(entries.remove(Maps.immutableEntry("foo",
    490         Collections.singletonList(1))));
    491     assertFalse(entries.contains(Maps.immutableEntry("foo",
    492         Sets.newLinkedHashSet(asList(1, 2)))));
    493     assertFalse(entries.remove(Maps.immutableEntry("foo",
    494         Sets.newLinkedHashSet(asList(1, 2)))));
    495     assertFalse(entries.contains(Maps.immutableEntry("foo",
    496         Collections.singleton(2))));
    497     assertFalse(entries.remove(Maps.immutableEntry("foo",
    498         Collections.singleton(2))));
    499     assertTrue(map.containsKey("foo"));
    500     assertTrue(entries.contains(Maps.immutableEntry("foo",
    501         Collections.singleton(1))));
    502     assertTrue(entries.remove(Maps.immutableEntry("foo",
    503         Collections.singleton(1))));
    504     assertFalse(map.containsKey("foo"));
    505   }
    506 
    507   public void testForMapGetIteration() {
    508     IteratorTester<Integer> tester =
    509         new IteratorTester<Integer>(4, MODIFIABLE, newHashSet(1),
    510             IteratorTester.KnownOrder.KNOWN_ORDER) {
    511           private Multimap<String, Integer> multimap;
    512 
    513           @Override protected Iterator<Integer> newTargetIterator() {
    514             Map<String, Integer> map = Maps.newHashMap();
    515             map.put("foo", 1);
    516             map.put("bar", 2);
    517             multimap = Multimaps.forMap(map);
    518             return multimap.get("foo").iterator();
    519           }
    520 
    521           @Override protected void verify(List<Integer> elements) {
    522             assertEquals(newHashSet(elements), multimap.get("foo"));
    523           }
    524         };
    525 
    526     tester.ignoreSunJavaBug6529795();
    527     tester.test();
    528   }
    529 
    530   private enum Color {BLUE, RED, YELLOW, GREEN}
    531 
    532   private static abstract class CountingSupplier<E>
    533       implements Supplier<E>, Serializable {
    534     int count;
    535 
    536     abstract E getImpl();
    537 
    538     @Override
    539     public E get() {
    540       count++;
    541       return getImpl();
    542     }
    543   }
    544 
    545   private static class QueueSupplier extends CountingSupplier<Queue<Integer>> {
    546     @Override public Queue<Integer> getImpl() {
    547       return new LinkedList<Integer>();
    548     }
    549     private static final long serialVersionUID = 0;
    550   }
    551 
    552   public void testNewMultimap() {
    553     // The ubiquitous EnumArrayBlockingQueueMultimap
    554     CountingSupplier<Queue<Integer>> factory = new QueueSupplier();
    555 
    556     Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class);
    557     Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory);
    558     assertEquals(0, factory.count);
    559     multimap.putAll(Color.BLUE, asList(3, 1, 4));
    560     assertEquals(1, factory.count);
    561     multimap.putAll(Color.RED, asList(2, 7, 1, 8));
    562     assertEquals(2, factory.count);
    563     assertEquals("[3, 1, 4]", multimap.get(Color.BLUE).toString());
    564 
    565     Multimap<Color, Integer> ummodifiable =
    566         Multimaps.unmodifiableMultimap(multimap);
    567     assertEquals("[3, 1, 4]", ummodifiable.get(Color.BLUE).toString());
    568 
    569     Collection<Integer> collection = multimap.get(Color.BLUE);
    570     assertEquals(collection, collection);
    571 
    572     assertFalse(multimap.keySet() instanceof SortedSet);
    573     assertFalse(multimap.asMap() instanceof SortedMap);
    574   }
    575 
    576   @GwtIncompatible("SerializableTester")
    577   public void testNewMultimapSerialization() {
    578     CountingSupplier<Queue<Integer>> factory = new QueueSupplier();
    579     Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class);
    580     Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory);
    581     multimap.putAll(Color.BLUE, asList(3, 1, 4));
    582     multimap.putAll(Color.RED, asList(2, 7, 1, 8));
    583     SerializableTester.reserializeAndAssert(multimap);
    584   }
    585 
    586   private static class ListSupplier extends
    587       CountingSupplier<LinkedList<Integer>> {
    588     @Override public LinkedList<Integer> getImpl() {
    589       return new LinkedList<Integer>();
    590     }
    591     private static final long serialVersionUID = 0;
    592   }
    593 
    594   public void testNewListMultimap() {
    595     CountingSupplier<LinkedList<Integer>> factory = new ListSupplier();
    596     Map<Color, Collection<Integer>> map = Maps.newTreeMap();
    597     ListMultimap<Color, Integer> multimap =
    598         Multimaps.newListMultimap(map, factory);
    599     assertEquals(0, factory.count);
    600     multimap.putAll(Color.BLUE, asList(3, 1, 4, 1));
    601     assertEquals(1, factory.count);
    602     multimap.putAll(Color.RED, asList(2, 7, 1, 8));
    603     assertEquals(2, factory.count);
    604     assertEquals("{BLUE=[3, 1, 4, 1], RED=[2, 7, 1, 8]}", multimap.toString());
    605     assertFalse(multimap.get(Color.BLUE) instanceof RandomAccess);
    606 
    607     assertTrue(multimap.keySet() instanceof SortedSet);
    608     assertTrue(multimap.asMap() instanceof SortedMap);
    609   }
    610 
    611   @GwtIncompatible("SerializableTester")
    612   public void testNewListMultimapSerialization() {
    613     CountingSupplier<LinkedList<Integer>> factory = new ListSupplier();
    614     Map<Color, Collection<Integer>> map = Maps.newTreeMap();
    615     ListMultimap<Color, Integer> multimap = Multimaps.newListMultimap(map, factory);
    616     multimap.putAll(Color.BLUE, asList(3, 1, 4, 1));
    617     multimap.putAll(Color.RED, asList(2, 7, 1, 8));
    618     SerializableTester.reserializeAndAssert(multimap);
    619   }
    620 
    621   private static class SetSupplier extends CountingSupplier<HashSet<Integer>> {
    622     @Override public HashSet<Integer> getImpl() {
    623       return new HashSet<Integer>(4);
    624     }
    625     private static final long serialVersionUID = 0;
    626   }
    627 
    628   public void testNewSetMultimap() {
    629     CountingSupplier<HashSet<Integer>> factory = new SetSupplier();
    630     Map<Color, Collection<Integer>> map = Maps.newHashMap();
    631     SetMultimap<Color, Integer> multimap =
    632         Multimaps.newSetMultimap(map, factory);
    633     assertEquals(0, factory.count);
    634     multimap.putAll(Color.BLUE, asList(3, 1, 4));
    635     assertEquals(1, factory.count);
    636     multimap.putAll(Color.RED, asList(2, 7, 1, 8));
    637     assertEquals(2, factory.count);
    638     assertEquals(Sets.newHashSet(4, 3, 1), multimap.get(Color.BLUE));
    639   }
    640 
    641   @GwtIncompatible("SerializableTester")
    642   public void testNewSetMultimapSerialization() {
    643     CountingSupplier<HashSet<Integer>> factory = new SetSupplier();
    644     Map<Color, Collection<Integer>> map = Maps.newHashMap();
    645     SetMultimap<Color, Integer> multimap = Multimaps.newSetMultimap(map, factory);
    646     multimap.putAll(Color.BLUE, asList(3, 1, 4));
    647     multimap.putAll(Color.RED, asList(2, 7, 1, 8));
    648     SerializableTester.reserializeAndAssert(multimap);
    649   }
    650 
    651   private static class SortedSetSupplier extends
    652       CountingSupplier<TreeSet<Integer>> {
    653     @Override public TreeSet<Integer> getImpl() {
    654       return Sets.newTreeSet(INT_COMPARATOR);
    655     }
    656     private static final long serialVersionUID = 0;
    657   }
    658 
    659   public void testNewSortedSetMultimap() {
    660     CountingSupplier<TreeSet<Integer>> factory = new SortedSetSupplier();
    661     Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class);
    662     SortedSetMultimap<Color, Integer> multimap =
    663         Multimaps.newSortedSetMultimap(map, factory);
    664     // newSortedSetMultimap calls the factory once to determine the comparator.
    665     assertEquals(1, factory.count);
    666     multimap.putAll(Color.BLUE, asList(3, 1, 4));
    667     assertEquals(2, factory.count);
    668     multimap.putAll(Color.RED, asList(2, 7, 1, 8));
    669     assertEquals(3, factory.count);
    670     assertEquals("[4, 3, 1]", multimap.get(Color.BLUE).toString());
    671     assertEquals(INT_COMPARATOR, multimap.valueComparator());
    672   }
    673 
    674   @GwtIncompatible("SerializableTester")
    675   public void testNewSortedSetMultimapSerialization() {
    676     CountingSupplier<TreeSet<Integer>> factory = new SortedSetSupplier();
    677     Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class);
    678     SortedSetMultimap<Color, Integer> multimap = Multimaps.newSortedSetMultimap(map, factory);
    679     multimap.putAll(Color.BLUE, asList(3, 1, 4));
    680     multimap.putAll(Color.RED, asList(2, 7, 1, 8));
    681     SerializableTester.reserializeAndAssert(multimap);
    682     assertEquals(INT_COMPARATOR, multimap.valueComparator());
    683   }
    684 
    685   public void testIndex() {
    686     final Multimap<String, Object> stringToObject =
    687         new ImmutableMultimap.Builder<String, Object>()
    688             .put("1", 1)
    689             .put("1", 1L)
    690             .put("1", "1")
    691             .put("2", 2)
    692             .put("2", 2L)
    693             .build();
    694 
    695     ImmutableMultimap<String, Object> outputMap =
    696         Multimaps.index(stringToObject.values(),
    697             Functions.toStringFunction());
    698     assertEquals(stringToObject, outputMap);
    699   }
    700 
    701   public void testIndexIterator() {
    702     final Multimap<String, Object> stringToObject =
    703         new ImmutableMultimap.Builder<String, Object>()
    704             .put("1", 1)
    705             .put("1", 1L)
    706             .put("1", "1")
    707             .put("2", 2)
    708             .put("2", 2L)
    709             .build();
    710 
    711     ImmutableMultimap<String, Object> outputMap =
    712         Multimaps.index(stringToObject.values().iterator(),
    713             Functions.toStringFunction());
    714     assertEquals(stringToObject, outputMap);
    715   }
    716 
    717   // NOTE: evil, never do this
    718   private abstract static class IterableIterator<T>
    719       extends ForwardingIterator<T> implements Iterable<T> {
    720     @Override
    721     public Iterator<T> iterator() {
    722       return this;
    723     }
    724   }
    725 
    726   @SuppressWarnings("deprecation") // that is the purpose of this test
    727   public void testIndexIterableIterator() {
    728     final Multimap<String, Object> stringToObject =
    729         new ImmutableMultimap.Builder<String, Object>()
    730             .put("1", 1)
    731             .put("1", 1L)
    732             .put("1", "1")
    733             .put("2", 2)
    734             .put("2", 2L)
    735             .build();
    736 
    737     IterableIterator<Object> iterIter = new IterableIterator<Object>() {
    738       private final Iterator<Object> iterator = stringToObject.values().iterator();
    739 
    740       public Iterator<Object> delegate() {
    741         return iterator;
    742       }
    743     };
    744 
    745     ImmutableMultimap<String, Object> outputMap =
    746         Multimaps.index(iterIter, Functions.toStringFunction());
    747     assertEquals(stringToObject, outputMap);
    748   }
    749 
    750   public void testIndex_ordering() {
    751     final Multimap<Integer, String> expectedIndex =
    752         new ImmutableListMultimap.Builder<Integer, String>()
    753             .put(4, "Inky")
    754             .put(6, "Blinky")
    755             .put(5, "Pinky")
    756             .put(5, "Pinky")
    757             .put(5, "Clyde")
    758             .build();
    759 
    760     final List<String> badGuys =
    761         Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
    762     final Function<String, Integer> stringLengthFunction =
    763         new Function<String, Integer>() {
    764           @Override
    765           public Integer apply(String input) {
    766             return input.length();
    767           }
    768         };
    769 
    770     Multimap<Integer, String> index =
    771         Multimaps.index(badGuys, stringLengthFunction);
    772 
    773     assertEquals(expectedIndex, index);
    774   }
    775 
    776   public void testIndex_nullValue() {
    777     List<Integer> values = Arrays.asList(1, null);
    778     try {
    779       Multimaps.index(values, Functions.identity());
    780       fail();
    781     } catch (NullPointerException e) {}
    782   }
    783 
    784   public void testIndex_nullKey() {
    785     List<Integer> values = Arrays.asList(1, 2);
    786     try {
    787       Multimaps.index(values, Functions.constant(null));
    788       fail();
    789     } catch (NullPointerException e) {}
    790   }
    791 
    792   @GwtIncompatible(value = "untested")
    793   public void testTransformValues() {
    794     SetMultimap<String, Integer> multimap =
    795         ImmutableSetMultimap.of("a", 2, "b", -3, "b", 3, "a", 4, "c", 6);
    796     Function<Integer, Integer> square = new Function<Integer, Integer>() {
    797       @Override
    798       public Integer apply(Integer in) {
    799         return in * in;
    800       }
    801     };
    802     Multimap<String, Integer> transformed =
    803         Multimaps.transformValues(multimap, square);
    804     ASSERT.that(transformed.entries()).hasContentsInOrder(immutableEntry("a", 4),
    805         immutableEntry("a", 16), immutableEntry("b", 9), immutableEntry("b", 9),
    806         immutableEntry("c", 36));
    807   }
    808 
    809   @GwtIncompatible(value = "untested")
    810   public void testTransformValuesIsView() {
    811     Multimap<String, String> multimap = LinkedListMultimap.create();
    812     multimap.put("a", "a");
    813     Multimap<String, Integer> transformed =
    814         Multimaps.transformValues(multimap, new Function<String, Integer>() {
    815 
    816           @Override public Integer apply(String str) {
    817             return str.length();
    818           }
    819         });
    820     Entry<String, String> entry = multimap.entries().iterator().next();
    821     entry.setValue("bbb");
    822     ASSERT.that(transformed.entries()).hasContentsInOrder(immutableEntry("a", 3));
    823   }
    824 
    825   @GwtIncompatible(value = "untested")
    826   public void testTransformListValues() {
    827     ListMultimap<String, Integer> multimap =
    828         ImmutableListMultimap.of("a", 2, "b", -3, "b", 3, "a", 4, "c", 6);
    829     Function<Integer, Integer> square = new Function<Integer, Integer>() {
    830       @Override
    831       public Integer apply(Integer in) {
    832         return in * in;
    833       }
    834     };
    835     ListMultimap<String, Integer> transformed =
    836         Multimaps.transformValues(multimap, square);
    837     ASSERT.that(transformed.entries()).hasContentsInOrder(immutableEntry("a", 4),
    838         immutableEntry("a", 16), immutableEntry("b", 9), immutableEntry("b", 9),
    839         immutableEntry("c", 36));
    840   }
    841 
    842   @GwtIncompatible(value = "untested")
    843   public void testTransformEntries() {
    844     SetMultimap<String, Integer> multimap =
    845         ImmutableSetMultimap.of("a", 1, "a", 4, "b", -6);
    846     EntryTransformer<String, Integer, String> transformer =
    847         new EntryTransformer<String, Integer, String>() {
    848           @Override
    849           public String transformEntry(String key, Integer value) {
    850             return (value >= 0) ? key : "no" + key;
    851           }
    852         };
    853     Multimap<String, String> transformed =
    854         Multimaps.transformEntries(multimap, transformer);
    855     ASSERT.that(transformed.entries()).hasContentsInOrder(immutableEntry("a", "a"),
    856         immutableEntry("a", "a"), immutableEntry("b", "nob"));
    857   }
    858 
    859   @GwtIncompatible(value = "untested")
    860   public void testTransformListEntries() {
    861     ListMultimap<String, Integer> multimap =
    862         ImmutableListMultimap.of("a", 1, "a", 4, "b", 6, "a", 4);
    863     EntryTransformer<String, Integer, String> transformer =
    864         new EntryTransformer<String, Integer, String>() {
    865           @Override
    866           public String transformEntry(String key, Integer value) {
    867             return key + value;
    868           }
    869         };
    870     ListMultimap<String, String> transformed =
    871         Multimaps.transformEntries(multimap, transformer);
    872     assertEquals(
    873         ImmutableListMultimap.of("a", "a1", "a", "a4", "a", "a4", "b", "b6"),
    874         transformed);
    875     assertEquals("{a=[a1, a4, a4], b=[b6]}", transformed.toString());
    876   }
    877 
    878   @GwtIncompatible("NullPointerTester")
    879   public void testNullPointers() throws Exception {
    880     NullPointerTester tester = new NullPointerTester();
    881     tester.setDefault(Multimap.class, ImmutableMultimap.of());
    882     tester.setDefault(ListMultimap.class, ImmutableListMultimap.of());
    883     tester.setDefault(EntryTransformer.class, ALWAYS_NULL);
    884     tester.ignore(Multimaps.class.getDeclaredMethod("index", Object.class, Function.class));
    885     tester.testAllPublicStaticMethods(Multimaps.class);
    886   }
    887 }
    888