View Javadoc
1   /*
2    * Copyright (C) 2008 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.truth.Truth.assertThat;
20  
21  import com.google.common.annotations.GwtCompatible;
22  import com.google.common.annotations.GwtIncompatible;
23  import com.google.common.collect.ImmutableListMultimap.Builder;
24  import com.google.common.collect.testing.features.CollectionFeature;
25  import com.google.common.collect.testing.features.CollectionSize;
26  import com.google.common.collect.testing.features.MapFeature;
27  import com.google.common.collect.testing.google.ListMultimapTestSuiteBuilder;
28  import com.google.common.collect.testing.google.TestStringListMultimapGenerator;
29  import com.google.common.collect.testing.google.UnmodifiableCollectionTests;
30  import com.google.common.testing.EqualsTester;
31  import com.google.common.testing.SerializableTester;
32  
33  import junit.framework.Test;
34  import junit.framework.TestCase;
35  import junit.framework.TestSuite;
36  
37  import java.util.Arrays;
38  import java.util.Collection;
39  import java.util.Collections;
40  import java.util.Map.Entry;
41  
42  /**
43   * Tests for {@link ImmutableListMultimap}.
44   *
45   * @author Jared Levy
46   */
47  @GwtCompatible(emulated = true)
48  public class ImmutableListMultimapTest extends TestCase {
49    public static class ImmutableListMultimapGenerator extends TestStringListMultimapGenerator {
50      @Override
51      protected ListMultimap<String, String> create(Entry<String, String>[] entries) {
52        ImmutableListMultimap.Builder<String, String> builder = ImmutableListMultimap.builder();
53        for (Entry<String, String> entry : entries) {
54          builder.put(entry.getKey(), entry.getValue());
55        }
56        return builder.build();
57      }
58    }
59  
60    @GwtIncompatible("suite")
61    public static Test suite() {
62      TestSuite suite = new TestSuite();
63      suite.addTest(ListMultimapTestSuiteBuilder.using(new ImmutableListMultimapGenerator())
64        .named("ImmutableListMultimap")
65        .withFeatures(
66            MapFeature.ALLOWS_ANY_NULL_QUERIES,
67            CollectionFeature.SERIALIZABLE,
68            CollectionFeature.KNOWN_ORDER,
69            CollectionSize.ANY)
70        .createTestSuite());
71      suite.addTestSuite(ImmutableListMultimapTest.class);
72      return suite;
73    }
74  
75    public void testBuilder_withImmutableEntry() {
76      ImmutableListMultimap<String, Integer> multimap = new Builder<String, Integer>()
77          .put(Maps.immutableEntry("one", 1))
78          .build();
79      assertEquals(Arrays.asList(1), multimap.get("one"));
80    }
81  
82    public void testBuilder_withImmutableEntryAndNullContents() {
83      Builder<String, Integer> builder = new Builder<String, Integer>();
84      try {
85        builder.put(Maps.immutableEntry("one", (Integer) null));
86        fail();
87      } catch (NullPointerException expected) {
88      }
89      try {
90        builder.put(Maps.immutableEntry((String) null, 1));
91        fail();
92      } catch (NullPointerException expected) {
93      }
94    }
95  
96    private static class StringHolder {
97      String string;
98    }
99  
100   public void testBuilder_withMutableEntry() {
101     ImmutableListMultimap.Builder<String, Integer> builder =
102         new Builder<String, Integer>();
103     final StringHolder holder = new StringHolder();
104     holder.string = "one";
105     Entry<String, Integer> entry = new AbstractMapEntry<String, Integer>() {
106       @Override public String getKey() {
107         return holder.string;
108       }
109       @Override public Integer getValue() {
110         return 1;
111       }
112     };
113 
114     builder.put(entry);
115     holder.string = "two";
116     assertEquals(Arrays.asList(1), builder.build().get("one"));
117   }
118 
119   public void testBuilderPutAllIterable() {
120     ImmutableListMultimap.Builder<String, Integer> builder
121         = ImmutableListMultimap.builder();
122     builder.putAll("foo", Arrays.asList(1, 2, 3));
123     builder.putAll("bar", Arrays.asList(4, 5));
124     builder.putAll("foo", Arrays.asList(6, 7));
125     Multimap<String, Integer> multimap = builder.build();
126     assertEquals(Arrays.asList(1, 2, 3, 6, 7), multimap.get("foo"));
127     assertEquals(Arrays.asList(4, 5), multimap.get("bar"));
128     assertEquals(7, multimap.size());
129   }
130 
131   public void testBuilderPutAllVarargs() {
132     ImmutableListMultimap.Builder<String, Integer> builder
133         = ImmutableListMultimap.builder();
134     builder.putAll("foo", 1, 2, 3);
135     builder.putAll("bar", 4, 5);
136     builder.putAll("foo", 6, 7);
137     Multimap<String, Integer> multimap = builder.build();
138     assertEquals(Arrays.asList(1, 2, 3, 6, 7), multimap.get("foo"));
139     assertEquals(Arrays.asList(4, 5), multimap.get("bar"));
140     assertEquals(7, multimap.size());
141   }
142 
143   public void testBuilderPutAllMultimap() {
144     Multimap<String, Integer> toPut = LinkedListMultimap.create();
145     toPut.put("foo", 1);
146     toPut.put("bar", 4);
147     toPut.put("foo", 2);
148     toPut.put("foo", 3);
149     Multimap<String, Integer> moreToPut = LinkedListMultimap.create();
150     moreToPut.put("foo", 6);
151     moreToPut.put("bar", 5);
152     moreToPut.put("foo", 7);
153     ImmutableListMultimap.Builder<String, Integer> builder
154         = ImmutableListMultimap.builder();
155     builder.putAll(toPut);
156     builder.putAll(moreToPut);
157     Multimap<String, Integer> multimap = builder.build();
158     assertEquals(Arrays.asList(1, 2, 3, 6, 7), multimap.get("foo"));
159     assertEquals(Arrays.asList(4, 5), multimap.get("bar"));
160     assertEquals(7, multimap.size());
161   }
162 
163   public void testBuilderPutAllWithDuplicates() {
164     ImmutableListMultimap.Builder<String, Integer> builder
165         = ImmutableListMultimap.builder();
166     builder.putAll("foo", 1, 2, 3);
167     builder.putAll("bar", 4, 5);
168     builder.putAll("foo", 1, 6, 7);
169     ImmutableListMultimap<String, Integer> multimap = builder.build();
170     assertEquals(Arrays.asList(1, 2, 3, 1, 6, 7), multimap.get("foo"));
171     assertEquals(Arrays.asList(4, 5), multimap.get("bar"));
172     assertEquals(8, multimap.size());
173   }
174 
175   public void testBuilderPutWithDuplicates() {
176     ImmutableListMultimap.Builder<String, Integer> builder
177         = ImmutableListMultimap.builder();
178     builder.putAll("foo", 1, 2, 3);
179     builder.putAll("bar", 4, 5);
180     builder.put("foo", 1);
181     ImmutableListMultimap<String, Integer> multimap = builder.build();
182     assertEquals(Arrays.asList(1, 2, 3, 1), multimap.get("foo"));
183     assertEquals(Arrays.asList(4, 5), multimap.get("bar"));
184     assertEquals(6, multimap.size());
185   }
186 
187   public void testBuilderPutAllMultimapWithDuplicates() {
188     Multimap<String, Integer> toPut = LinkedListMultimap.create();
189     toPut.put("foo", 1);
190     toPut.put("bar", 4);
191     toPut.put("foo", 2);
192     toPut.put("foo", 1);
193     toPut.put("bar", 5);
194     Multimap<String, Integer> moreToPut = LinkedListMultimap.create();
195     moreToPut.put("foo", 6);
196     moreToPut.put("bar", 4);
197     moreToPut.put("foo", 7);
198     moreToPut.put("foo", 2);
199     ImmutableListMultimap.Builder<String, Integer> builder
200         = ImmutableListMultimap.builder();
201     builder.putAll(toPut);
202     builder.putAll(moreToPut);
203     Multimap<String, Integer> multimap = builder.build();
204     assertEquals(Arrays.asList(1, 2, 1, 6, 7, 2), multimap.get("foo"));
205     assertEquals(Arrays.asList(4, 5, 4), multimap.get("bar"));
206     assertEquals(9, multimap.size());
207   }
208 
209   public void testBuilderPutNullKey() {
210     Multimap<String, Integer> toPut = LinkedListMultimap.create();
211     toPut.put("foo", null);
212     ImmutableListMultimap.Builder<String, Integer> builder
213         = ImmutableListMultimap.builder();
214     try {
215       builder.put(null, 1);
216       fail();
217     } catch (NullPointerException expected) {}
218     try {
219       builder.putAll(null, Arrays.asList(1, 2, 3));
220       fail();
221     } catch (NullPointerException expected) {}
222     try {
223       builder.putAll(null, 1, 2, 3);
224       fail();
225     } catch (NullPointerException expected) {}
226     try {
227       builder.putAll(toPut);
228       fail();
229     } catch (NullPointerException expected) {}
230   }
231 
232   public void testBuilderPutNullValue() {
233     Multimap<String, Integer> toPut = LinkedListMultimap.create();
234     toPut.put(null, 1);
235     ImmutableListMultimap.Builder<String, Integer> builder
236         = ImmutableListMultimap.builder();
237     try {
238       builder.put("foo", null);
239       fail();
240     } catch (NullPointerException expected) {}
241     try {
242       builder.putAll("foo", Arrays.asList(1, null, 3));
243       fail();
244     } catch (NullPointerException expected) {}
245     try {
246       builder.putAll("foo", 1, null, 3);
247       fail();
248     } catch (NullPointerException expected) {}
249     try {
250       builder.putAll(toPut);
251       fail();
252     } catch (NullPointerException expected) {}
253   }
254 
255   public void testBuilderOrderKeysBy() {
256     ImmutableListMultimap.Builder<String, Integer> builder
257         = ImmutableListMultimap.builder();
258     builder.put("b", 3);
259     builder.put("d", 2);
260     builder.put("a", 5);
261     builder.orderKeysBy(Collections.reverseOrder());
262     builder.put("c", 4);
263     builder.put("a", 2);
264     builder.put("b", 6);
265     ImmutableListMultimap<String, Integer> multimap = builder.build();
266     assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
267     assertThat(multimap.values()).has().exactly(2, 4, 3, 6, 5, 2).inOrder();
268     assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
269     assertThat(multimap.get("b")).has().exactly(3, 6).inOrder();
270   }
271 
272   public void testBuilderOrderKeysByDuplicates() {
273     ImmutableListMultimap.Builder<String, Integer> builder
274         = ImmutableListMultimap.builder();
275     builder.put("bb", 3);
276     builder.put("d", 2);
277     builder.put("a", 5);
278     builder.orderKeysBy(new Ordering<String>() {
279       @Override
280       public int compare(String left, String right) {
281         return left.length() - right.length();
282       }
283     });
284     builder.put("cc", 4);
285     builder.put("a", 2);
286     builder.put("bb", 6);
287     ImmutableListMultimap<String, Integer> multimap = builder.build();
288     assertThat(multimap.keySet()).has().exactly("d", "a", "bb", "cc").inOrder();
289     assertThat(multimap.values()).has().exactly(2, 5, 2, 3, 6, 4).inOrder();
290     assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
291     assertThat(multimap.get("bb")).has().exactly(3, 6).inOrder();
292   }
293 
294   public void testBuilderOrderValuesBy() {
295     ImmutableListMultimap.Builder<String, Integer> builder
296         = ImmutableListMultimap.builder();
297     builder.put("b", 3);
298     builder.put("d", 2);
299     builder.put("a", 5);
300     builder.orderValuesBy(Collections.reverseOrder());
301     builder.put("c", 4);
302     builder.put("a", 2);
303     builder.put("b", 6);
304     ImmutableListMultimap<String, Integer> multimap = builder.build();
305     assertThat(multimap.keySet()).has().exactly("b", "d", "a", "c").inOrder();
306     assertThat(multimap.values()).has().exactly(6, 3, 2, 5, 2, 4).inOrder();
307     assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
308     assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
309   }
310 
311   public void testBuilderOrderKeysAndValuesBy() {
312     ImmutableListMultimap.Builder<String, Integer> builder
313         = ImmutableListMultimap.builder();
314     builder.put("b", 3);
315     builder.put("d", 2);
316     builder.put("a", 5);
317     builder.orderKeysBy(Collections.reverseOrder());
318     builder.orderValuesBy(Collections.reverseOrder());
319     builder.put("c", 4);
320     builder.put("a", 2);
321     builder.put("b", 6);
322     ImmutableListMultimap<String, Integer> multimap = builder.build();
323     assertThat(multimap.keySet()).has().exactly("d", "c", "b", "a").inOrder();
324     assertThat(multimap.values()).has().exactly(2, 4, 6, 3, 5, 2).inOrder();
325     assertThat(multimap.get("a")).has().exactly(5, 2).inOrder();
326     assertThat(multimap.get("b")).has().exactly(6, 3).inOrder();
327   }
328 
329   public void testCopyOf() {
330     ArrayListMultimap<String, Integer> input = ArrayListMultimap.create();
331     input.put("foo", 1);
332     input.put("bar", 2);
333     input.put("foo", 3);
334     Multimap<String, Integer> multimap = ImmutableListMultimap.copyOf(input);
335     assertEquals(multimap, input);
336     assertEquals(input, multimap);
337   }
338 
339   public void testCopyOfWithDuplicates() {
340     ArrayListMultimap<String, Integer> input = ArrayListMultimap.create();
341     input.put("foo", 1);
342     input.put("bar", 2);
343     input.put("foo", 3);
344     input.put("foo", 1);
345     Multimap<String, Integer> multimap = ImmutableListMultimap.copyOf(input);
346     assertEquals(multimap, input);
347     assertEquals(input, multimap);
348   }
349 
350   public void testCopyOfEmpty() {
351     ArrayListMultimap<String, Integer> input = ArrayListMultimap.create();
352     Multimap<String, Integer> multimap = ImmutableListMultimap.copyOf(input);
353     assertEquals(multimap, input);
354     assertEquals(input, multimap);
355   }
356 
357   public void testCopyOfImmutableListMultimap() {
358     Multimap<String, Integer> multimap = createMultimap();
359     assertSame(multimap, ImmutableListMultimap.copyOf(multimap));
360   }
361 
362   public void testCopyOfNullKey() {
363     ArrayListMultimap<String, Integer> input = ArrayListMultimap.create();
364     input.put(null, 1);
365     try {
366       ImmutableListMultimap.copyOf(input);
367       fail();
368     } catch (NullPointerException expected) {}
369   }
370 
371   public void testCopyOfNullValue() {
372     ArrayListMultimap<String, Integer> input = ArrayListMultimap.create();
373     input.putAll("foo", Arrays.asList(1, null, 3));
374     try {
375       ImmutableListMultimap.copyOf(input);
376       fail();
377     } catch (NullPointerException expected) {}
378   }
379 
380   public void testEmptyMultimapReads() {
381     Multimap<String, Integer> multimap = ImmutableListMultimap.of();
382     assertFalse(multimap.containsKey("foo"));
383     assertFalse(multimap.containsValue(1));
384     assertFalse(multimap.containsEntry("foo", 1));
385     assertTrue(multimap.entries().isEmpty());
386     assertTrue(multimap.equals(ArrayListMultimap.create()));
387     assertEquals(Collections.emptyList(), multimap.get("foo"));
388     assertEquals(0, multimap.hashCode());
389     assertTrue(multimap.isEmpty());
390     assertEquals(HashMultiset.create(), multimap.keys());
391     assertEquals(Collections.emptySet(), multimap.keySet());
392     assertEquals(0, multimap.size());
393     assertTrue(multimap.values().isEmpty());
394     assertEquals("{}", multimap.toString());
395   }
396 
397   public void testEmptyMultimapWrites() {
398     Multimap<String, Integer> multimap = ImmutableListMultimap.of();
399     UnmodifiableCollectionTests.assertMultimapIsUnmodifiable(
400         multimap, "foo", 1);
401   }
402 
403   private Multimap<String, Integer> createMultimap() {
404     return ImmutableListMultimap.<String, Integer>builder()
405         .put("foo", 1).put("bar", 2).put("foo", 3).build();
406   }
407 
408   public void testMultimapReads() {
409     Multimap<String, Integer> multimap = createMultimap();
410     assertTrue(multimap.containsKey("foo"));
411     assertFalse(multimap.containsKey("cat"));
412     assertTrue(multimap.containsValue(1));
413     assertFalse(multimap.containsValue(5));
414     assertTrue(multimap.containsEntry("foo", 1));
415     assertFalse(multimap.containsEntry("cat", 1));
416     assertFalse(multimap.containsEntry("foo", 5));
417     assertFalse(multimap.entries().isEmpty());
418     assertEquals(3, multimap.size());
419     assertFalse(multimap.isEmpty());
420     assertEquals("{foo=[1, 3], bar=[2]}", multimap.toString());
421   }
422 
423   public void testMultimapWrites() {
424     Multimap<String, Integer> multimap = createMultimap();
425     UnmodifiableCollectionTests.assertMultimapIsUnmodifiable(
426         multimap, "bar", 2);
427   }
428 
429   public void testMultimapEquals() {
430     Multimap<String, Integer> multimap = createMultimap();
431     Multimap<String, Integer> arrayListMultimap
432         = ArrayListMultimap.create();
433     arrayListMultimap.putAll("foo", Arrays.asList(1, 3));
434     arrayListMultimap.put("bar", 2);
435 
436     new EqualsTester()
437         .addEqualityGroup(multimap, createMultimap(), arrayListMultimap,
438             ImmutableListMultimap.<String, Integer>builder()
439                 .put("bar", 2).put("foo", 1).put("foo", 3).build())
440         .addEqualityGroup(ImmutableListMultimap.<String, Integer>builder()
441             .put("bar", 2).put("foo", 3).put("foo", 1).build())
442         .addEqualityGroup(ImmutableListMultimap.<String, Integer>builder()
443             .put("foo", 2).put("foo", 3).put("foo", 1).build())
444         .addEqualityGroup(ImmutableListMultimap.<String, Integer>builder()
445             .put("bar", 2).put("foo", 3).build())
446         .testEquals();
447   }
448 
449   public void testOf() {
450     assertMultimapEquals(
451         ImmutableListMultimap.of("one", 1),
452         "one", 1);
453     assertMultimapEquals(
454         ImmutableListMultimap.of("one", 1, "two", 2),
455         "one", 1, "two", 2);
456     assertMultimapEquals(
457         ImmutableListMultimap.of("one", 1, "two", 2, "three", 3),
458         "one", 1, "two", 2, "three", 3);
459     assertMultimapEquals(
460         ImmutableListMultimap.of("one", 1, "two", 2, "three", 3, "four", 4),
461         "one", 1, "two", 2, "three", 3, "four", 4);
462     assertMultimapEquals(
463         ImmutableListMultimap.of(
464             "one", 1, "two", 2, "three", 3, "four", 4, "five", 5),
465         "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
466   }
467 
468   public void testInverse() {
469     assertEquals(
470         ImmutableListMultimap.<Integer, String>of(),
471         ImmutableListMultimap.<String, Integer>of().inverse());
472     assertEquals(
473         ImmutableListMultimap.of(1, "one"),
474         ImmutableListMultimap.of("one", 1).inverse());
475     assertEquals(
476         ImmutableListMultimap.of(1, "one", 2, "two"),
477         ImmutableListMultimap.of("one", 1, "two", 2).inverse());
478     assertEquals(
479         ImmutableListMultimap.of("of", 'o', "of", 'f', "to", 't', "to", 'o').inverse(),
480         ImmutableListMultimap.of('o', "of", 'f', "of", 't', "to", 'o', "to"));
481     assertEquals(
482         ImmutableListMultimap.of('f', "foo", 'o', "foo", 'o', "foo"),
483         ImmutableListMultimap.of("foo", 'f', "foo", 'o', "foo", 'o').inverse());
484   }
485 
486   public void testInverseMinimizesWork() {
487     ImmutableListMultimap<String, Character> multimap =
488         ImmutableListMultimap.<String, Character>builder()
489             .put("foo", 'f')
490             .put("foo", 'o')
491             .put("foo", 'o')
492             .put("poo", 'p')
493             .put("poo", 'o')
494             .put("poo", 'o')
495             .build();
496     assertSame(multimap.inverse(), multimap.inverse());
497     assertSame(multimap, multimap.inverse().inverse());
498   }
499 
500   private static <K, V> void assertMultimapEquals(Multimap<K, V> multimap,
501       Object... alternatingKeysAndValues) {
502     assertEquals(multimap.size(), alternatingKeysAndValues.length / 2);
503     int i = 0;
504     for (Entry<K, V> entry : multimap.entries()) {
505       assertEquals(alternatingKeysAndValues[i++], entry.getKey());
506       assertEquals(alternatingKeysAndValues[i++], entry.getValue());
507     }
508   }
509 
510   @GwtIncompatible("SerializableTester")
511   public void testSerialization() {
512     Multimap<String, Integer> multimap = createMultimap();
513     SerializableTester.reserializeAndAssert(multimap);
514     assertEquals(multimap.size(),
515         SerializableTester.reserialize(multimap).size());
516     SerializableTester.reserializeAndAssert(multimap.get("foo"));
517     LenientSerializableTester.reserializeAndAssertLenient(multimap.keySet());
518     LenientSerializableTester.reserializeAndAssertLenient(multimap.keys());
519     SerializableTester.reserializeAndAssert(multimap.asMap());
520     Collection<Integer> valuesCopy
521         = SerializableTester.reserialize(multimap.values());
522     assertEquals(HashMultiset.create(multimap.values()),
523         HashMultiset.create(valuesCopy));
524   }
525 
526   @GwtIncompatible("SerializableTester")
527   public void testEmptySerialization() {
528     Multimap<String, Integer> multimap = ImmutableListMultimap.of();
529     assertSame(multimap, SerializableTester.reserialize(multimap));
530   }
531 }