• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
create()75   @Override protected Multimap<String, Integer> create() {
76     return Multimaps.synchronizedSetMultimap(
77         HashMultimap.<String, Integer>create());
78   }
79 
80   @SuppressWarnings("deprecation")
testUnmodifiableListMultimapShortCircuit()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")
testUnmodifiableSetMultimapShortCircuit()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")
testUnmodifiableMultimapShortCircuit()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)")
testUnmodifiableArrayListMultimap()118   public void testUnmodifiableArrayListMultimap() {
119     checkUnmodifiableMultimap(
120         ArrayListMultimap.<String, Integer>create(), true);
121   }
122 
123   @GwtIncompatible("SerializableTester")
testSerializingUnmodifiableArrayListMultimap()124   public void testSerializingUnmodifiableArrayListMultimap() {
125     Multimap<String, Integer> unmodifiable =
126         prepareUnmodifiableTests(ArrayListMultimap.<String, Integer>create(), true, null, null);
127     SerializableTester.reserializeAndAssert(unmodifiable);
128   }
129 
testUnmodifiableArrayListMultimapRandomAccess()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 
testUnmodifiableLinkedListMultimapRandomAccess()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)")
testUnmodifiableHashMultimap()151   public void testUnmodifiableHashMultimap() {
152     checkUnmodifiableMultimap(HashMultimap.<String, Integer>create(), false);
153   }
154 
155   @GwtIncompatible("SerializableTester")
testSerializingUnmodifiableHashMultimap()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)")
testUnmodifiableTreeMultimap()163   public void testUnmodifiableTreeMultimap() {
164     checkUnmodifiableMultimap(
165         TreeMultimap.<String, Integer>create(), false, "null", 42);
166   }
167 
168   @GwtIncompatible("SerializableTester")
testSerializingUnmodifiableTreeMultimap()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)")
testUnmodifiableSynchronizedArrayListMultimap()176   public void testUnmodifiableSynchronizedArrayListMultimap() {
177     checkUnmodifiableMultimap(Multimaps.synchronizedListMultimap(
178         ArrayListMultimap.<String, Integer>create()), true);
179   }
180 
181   @GwtIncompatible("SerializableTester")
testSerializingUnmodifiableSynchronizedArrayListMultimap()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)")
testUnmodifiableSynchronizedHashMultimap()190   public void testUnmodifiableSynchronizedHashMultimap() {
191     checkUnmodifiableMultimap(Multimaps.synchronizedSetMultimap(
192         HashMultimap.<String, Integer>create()), false);
193   }
194 
195   @GwtIncompatible("SerializableTester")
testSerializingUnmodifiableSynchronizedHashMultimap()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)")
testUnmodifiableSynchronizedTreeMultimap()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")
testSerializingUnmodifiableSynchronizedTreeMultimap()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 
testUnmodifiableMultimapIsView()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")
testUnmodifiableMultimapEntries()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    */
checkUnmodifiableMultimap( Multimap<String, Integer> multimap, boolean permitsDuplicates)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    */
checkUnmodifiableMultimap( Multimap<String, Integer> multimap, boolean permitsDuplicates, @Nullable String nullKey, @Nullable Integer nullValue)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    */
prepareUnmodifiableTests( Multimap<String, Integer> multimap, boolean permitsDuplicates, @Nullable String nullKey, @Nullable Integer nullValue)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 
assertUnmodifiableIterableInTandem( Iterable<T> unmodifiable, Iterable<T> modifiable)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 
testInvertFrom()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 
testForMap()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")
testForMapSerialization()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 
testForMapRemoveAll()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 
testForMapAsMap()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 
testForMapGetIteration()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 
getImpl()536     abstract E getImpl();
537 
538     @Override
get()539     public E get() {
540       count++;
541       return getImpl();
542     }
543   }
544 
545   private static class QueueSupplier extends CountingSupplier<Queue<Integer>> {
getImpl()546     @Override public Queue<Integer> getImpl() {
547       return new LinkedList<Integer>();
548     }
549     private static final long serialVersionUID = 0;
550   }
551 
testNewMultimap()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")
testNewMultimapSerialization()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>> {
getImpl()588     @Override public LinkedList<Integer> getImpl() {
589       return new LinkedList<Integer>();
590     }
591     private static final long serialVersionUID = 0;
592   }
593 
testNewListMultimap()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")
testNewListMultimapSerialization()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>> {
getImpl()622     @Override public HashSet<Integer> getImpl() {
623       return new HashSet<Integer>(4);
624     }
625     private static final long serialVersionUID = 0;
626   }
627 
testNewSetMultimap()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")
testNewSetMultimapSerialization()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>> {
getImpl()653     @Override public TreeSet<Integer> getImpl() {
654       return Sets.newTreeSet(INT_COMPARATOR);
655     }
656     private static final long serialVersionUID = 0;
657   }
658 
testNewSortedSetMultimap()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")
testNewSortedSetMultimapSerialization()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 
testIndex()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 
testIndexIterator()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
iterator()721     public Iterator<T> iterator() {
722       return this;
723     }
724   }
725 
726   @SuppressWarnings("deprecation") // that is the purpose of this test
testIndexIterableIterator()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 
testIndex_ordering()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 
testIndex_nullValue()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 
testIndex_nullKey()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")
testTransformValues()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")
testTransformValuesIsView()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")
testTransformListValues()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")
testTransformEntries()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")
testTransformListEntries()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")
testNullPointers()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