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