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