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