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