1/*
2 * Copyright (C) 2007 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 com.google.common.collect.Lists.newArrayList;
20import static com.google.common.collect.Sets.newHashSet;
21import static com.google.common.collect.Sets.newLinkedHashSet;
22import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
23import static java.util.Arrays.asList;
24import static org.junit.contrib.truth.Truth.ASSERT;
25
26import com.google.common.annotations.GwtCompatible;
27import com.google.common.annotations.GwtIncompatible;
28import com.google.common.collect.testing.IteratorTester;
29import com.google.common.testing.SerializableTester;
30
31import java.util.Collection;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Map;
35import java.util.Map.Entry;
36import java.util.Set;
37
38/**
39 * Unit tests for {@code LinkedHashMultimap}.
40 *
41 * @author Jared Levy
42 */
43@GwtCompatible(emulated = true)
44public class LinkedHashMultimapTest extends AbstractSetMultimapTest {
45
46  @Override protected Multimap<String, Integer> create() {
47    return LinkedHashMultimap.create();
48  }
49
50  private Multimap<String, Integer> initializeMultimap5() {
51    Multimap<String, Integer> multimap = getMultimap();
52    multimap.put("foo", 5);
53    multimap.put("bar", 4);
54    multimap.put("foo", 3);
55    multimap.put("cow", 2);
56    multimap.put("bar", 1);
57    return multimap;
58  }
59
60  public void testToString() {
61    assertEquals("{foo=[3, -1, 2, 4, 1], bar=[1, 2, 3]}",
62        createSample().toString());
63  }
64
65  public void testOrderingReadOnly() {
66    Multimap<String, Integer> multimap = initializeMultimap5();
67    assertOrderingReadOnly(multimap);
68  }
69
70  public void testOrderingUnmodifiable() {
71    Multimap<String, Integer> multimap = initializeMultimap5();
72    assertOrderingReadOnly(Multimaps.unmodifiableMultimap(multimap));
73  }
74
75  public void testOrderingSynchronized() {
76    Multimap<String, Integer> multimap = initializeMultimap5();
77    assertOrderingReadOnly(Multimaps.synchronizedMultimap(multimap));
78  }
79
80  @GwtIncompatible("SeriazableTester")
81  public void testSerializationOrdering() {
82    Multimap<String, Integer> multimap = initializeMultimap5();
83    Multimap<String, Integer> copy
84        = SerializableTester.reserializeAndAssert(multimap);
85    assertOrderingReadOnly(copy);
86  }
87
88  private void assertOrderingReadOnly(Multimap<String, Integer> multimap) {
89    ASSERT.that(multimap.get("foo")).hasContentsInOrder(5, 3);
90    ASSERT.that(multimap.get("bar")).hasContentsInOrder(4, 1);
91    ASSERT.that(multimap.get("cow")).hasContentsInOrder(2);
92
93    ASSERT.that(multimap.keySet()).hasContentsInOrder("foo", "bar", "cow");
94    ASSERT.that(multimap.values()).hasContentsInOrder(5, 4, 3, 2, 1);
95
96    Iterator<Map.Entry<String, Integer>> entryIterator =
97        multimap.entries().iterator();
98    assertEquals(Maps.immutableEntry("foo", 5), entryIterator.next());
99    assertEquals(Maps.immutableEntry("bar", 4), entryIterator.next());
100    assertEquals(Maps.immutableEntry("foo", 3), entryIterator.next());
101    assertEquals(Maps.immutableEntry("cow", 2), entryIterator.next());
102    assertEquals(Maps.immutableEntry("bar", 1), entryIterator.next());
103
104    Iterator<Map.Entry<String, Collection<Integer>>> collectionIterator =
105        multimap.asMap().entrySet().iterator();
106    Map.Entry<String, Collection<Integer>> entry = collectionIterator.next();
107    assertEquals("foo", entry.getKey());
108    ASSERT.that(entry.getValue()).hasContentsInOrder(5, 3);
109    entry = collectionIterator.next();
110    assertEquals("bar", entry.getKey());
111    ASSERT.that(entry.getValue()).hasContentsInOrder(4, 1);
112    entry = collectionIterator.next();
113    assertEquals("cow", entry.getKey());
114    ASSERT.that(entry.getValue()).hasContentsInOrder(2);
115  }
116
117  public void testOrderingUpdates() {
118    Multimap<String, Integer> multimap = initializeMultimap5();
119
120    ASSERT.that(multimap.replaceValues("foo", asList(6, 7))).hasContentsInOrder(5, 3);
121    ASSERT.that(multimap.keySet()).hasContentsInOrder("foo", "bar", "cow");
122    ASSERT.that(multimap.removeAll("foo")).hasContentsInOrder(6, 7);
123    ASSERT.that(multimap.keySet()).hasContentsInOrder("bar", "cow");
124    assertTrue(multimap.remove("bar", 4));
125    ASSERT.that(multimap.keySet()).hasContentsInOrder("bar", "cow");
126    assertTrue(multimap.remove("bar", 1));
127    ASSERT.that(multimap.keySet()).hasContentsInOrder("cow");
128    multimap.put("bar", 9);
129    ASSERT.that(multimap.keySet()).hasContentsInOrder("cow", "bar");
130  }
131
132  public void testToStringNullExact() {
133    Multimap<String, Integer> multimap = getMultimap();
134
135    multimap.put("foo", 3);
136    multimap.put("foo", -1);
137    multimap.put(null, null);
138    multimap.put("bar", 1);
139    multimap.put("foo", 2);
140    multimap.put(null, 0);
141    multimap.put("bar", 2);
142    multimap.put("bar", null);
143    multimap.put("foo", null);
144    multimap.put("foo", 4);
145    multimap.put(null, -1);
146    multimap.put("bar", 3);
147    multimap.put("bar", 1);
148    multimap.put("foo", 1);
149
150    assertEquals(
151        "{foo=[3, -1, 2, null, 4, 1], null=[null, 0, -1], bar=[1, 2, null, 3]}",
152        multimap.toString());
153  }
154
155  public void testPutMultimapOrdered() {
156    Multimap<String, Integer> multimap = LinkedHashMultimap.create();
157    multimap.putAll(initializeMultimap5());
158    assertOrderingReadOnly(multimap);
159  }
160
161  public void testKeysToString_ordering() {
162    Multimap<String, Integer> multimap = initializeMultimap5();
163    assertEquals("[foo x 2, bar x 2, cow]", multimap.keys().toString());
164  }
165
166  public void testCreate() {
167    LinkedHashMultimap<String, Integer> multimap = LinkedHashMultimap.create();
168    multimap.put("foo", 1);
169    multimap.put("bar", 2);
170    multimap.put("foo", 3);
171    assertEquals(ImmutableSet.of(1, 3), multimap.get("foo"));
172    assertEquals(8, multimap.expectedValuesPerKey);
173  }
174
175  public void testCreateFromMultimap() {
176    Multimap<String, Integer> multimap = createSample();
177    LinkedHashMultimap<String, Integer> copy =
178        LinkedHashMultimap.create(multimap);
179    assertEquals(multimap, copy);
180    assertEquals(8, copy.expectedValuesPerKey);
181  }
182
183  public void testCreateFromSizes() {
184    LinkedHashMultimap<String, Integer> multimap
185        = LinkedHashMultimap.create(20, 15);
186    multimap.put("foo", 1);
187    multimap.put("bar", 2);
188    multimap.put("foo", 3);
189    assertEquals(ImmutableSet.of(1, 3), multimap.get("foo"));
190    assertEquals(15, multimap.expectedValuesPerKey);
191  }
192
193  public void testCreateFromIllegalSizes() {
194    try {
195      LinkedHashMultimap.create(-20, 15);
196      fail();
197    } catch (IllegalArgumentException expected) {}
198
199    try {
200      LinkedHashMultimap.create(20, -15);
201      fail();
202    } catch (IllegalArgumentException expected) {}
203  }
204
205  @GwtIncompatible("unreasonable slow")
206  public void testGetIteration() {
207    new IteratorTester<Integer>(6, MODIFIABLE,
208        newLinkedHashSet(asList(2, 3, 4, 7, 8)),
209        IteratorTester.KnownOrder.KNOWN_ORDER) {
210      private Multimap<String, Integer> multimap;
211
212      @Override protected Iterator<Integer> newTargetIterator() {
213        multimap = create();
214        multimap.putAll("foo", asList(2, 3, 4));
215        multimap.putAll("bar", asList(5, 6));
216        multimap.putAll("foo", asList(7, 8));
217        return multimap.get("foo").iterator();
218      }
219
220      @Override protected void verify(List<Integer> elements) {
221        assertEquals(newHashSet(elements), multimap.get("foo"));
222      }
223    }.test();
224  }
225
226  @GwtIncompatible("unreasonable slow")
227  public void testEntriesIteration() {
228    @SuppressWarnings("unchecked")
229    Set<Entry<String, Integer>> set = Sets.newLinkedHashSet(asList(
230        Maps.immutableEntry("foo", 2),
231        Maps.immutableEntry("foo", 3),
232        Maps.immutableEntry("bar", 4),
233        Maps.immutableEntry("bar", 5),
234        Maps.immutableEntry("foo", 6)));
235
236    new IteratorTester<Entry<String, Integer>>(6, MODIFIABLE, set,
237        IteratorTester.KnownOrder.KNOWN_ORDER) {
238      private Multimap<String, Integer> multimap;
239
240      @Override protected Iterator<Entry<String, Integer>> newTargetIterator() {
241        multimap = create();
242        multimap.putAll("foo", asList(2, 3));
243        multimap.putAll("bar", asList(4, 5));
244        multimap.putAll("foo", asList(6));
245        return multimap.entries().iterator();
246      }
247
248      @Override protected void verify(List<Entry<String, Integer>> elements) {
249        assertEquals(newHashSet(elements), multimap.entries());
250      }
251    }.test();
252  }
253
254  @GwtIncompatible("unreasonable slow")
255  public void testKeysIteration() {
256    new IteratorTester<String>(6, MODIFIABLE, newArrayList("foo", "foo", "bar",
257        "bar", "foo"), IteratorTester.KnownOrder.KNOWN_ORDER) {
258      private Multimap<String, Integer> multimap;
259
260      @Override protected Iterator<String> newTargetIterator() {
261        multimap = create();
262        multimap.putAll("foo", asList(2, 3));
263        multimap.putAll("bar", asList(4, 5));
264        multimap.putAll("foo", asList(6));
265        return multimap.keys().iterator();
266      }
267
268      @Override protected void verify(List<String> elements) {
269        assertEquals(elements, Lists.newArrayList(multimap.keys()));
270      }
271    }.test();
272  }
273
274  @GwtIncompatible("unreasonable slow")
275  public void testValuesIteration() {
276    new IteratorTester<Integer>(6, MODIFIABLE, newArrayList(2, 3, 4, 5, 6),
277        IteratorTester.KnownOrder.KNOWN_ORDER) {
278      private Multimap<String, Integer> multimap;
279
280      @Override protected Iterator<Integer> newTargetIterator() {
281        multimap = create();
282        multimap.putAll("foo", asList(2, 3));
283        multimap.putAll("bar", asList(4, 5));
284        multimap.putAll("foo", asList(6));
285        return multimap.values().iterator();
286      }
287
288      @Override protected void verify(List<Integer> elements) {
289        assertEquals(elements, Lists.newArrayList(multimap.values()));
290      }
291    }.test();
292  }
293
294  @GwtIncompatible("unreasonable slow")
295  public void testKeySetIteration() {
296    new IteratorTester<String>(6, MODIFIABLE, newLinkedHashSet(asList(
297        "foo", "bar", "baz", "dog", "cat")),
298        IteratorTester.KnownOrder.KNOWN_ORDER) {
299      private Multimap<String, Integer> multimap;
300
301      @Override protected Iterator<String> newTargetIterator() {
302        multimap = create();
303        multimap.putAll("foo", asList(2, 3));
304        multimap.putAll("bar", asList(4, 5));
305        multimap.putAll("foo", asList(6));
306        multimap.putAll("baz", asList(7, 8));
307        multimap.putAll("dog", asList(9));
308        multimap.putAll("bar", asList(10, 11));
309        multimap.putAll("cat", asList(12, 13, 14));
310        return multimap.keySet().iterator();
311      }
312
313      @Override protected void verify(List<String> elements) {
314        assertEquals(newHashSet(elements), multimap.keySet());
315      }
316    }.test();
317  }
318
319  @GwtIncompatible("unreasonable slow")
320  public void testAsSetIteration() {
321    @SuppressWarnings("unchecked")
322    Set<Entry<String, Collection<Integer>>> set = newLinkedHashSet(asList(
323        Maps.immutableEntry("foo",
324            (Collection<Integer>) Sets.newHashSet(2, 3, 6)),
325        Maps.immutableEntry("bar",
326            (Collection<Integer>) Sets.newHashSet(4, 5, 10, 11)),
327        Maps.immutableEntry("baz",
328            (Collection<Integer>) Sets.newHashSet(7, 8)),
329        Maps.immutableEntry("dog",
330            (Collection<Integer>) Sets.newHashSet(9)),
331        Maps.immutableEntry("cat",
332            (Collection<Integer>) Sets.newHashSet(12, 13, 14))
333    ));
334    new IteratorTester<Entry<String, Collection<Integer>>>(6, MODIFIABLE, set,
335        IteratorTester.KnownOrder.KNOWN_ORDER) {
336      private Multimap<String, Integer> multimap;
337
338      @Override protected Iterator<Entry<String, Collection<Integer>>>
339          newTargetIterator() {
340        multimap = create();
341        multimap.putAll("foo", asList(2, 3));
342        multimap.putAll("bar", asList(4, 5));
343        multimap.putAll("foo", asList(6));
344        multimap.putAll("baz", asList(7, 8));
345        multimap.putAll("dog", asList(9));
346        multimap.putAll("bar", asList(10, 11));
347        multimap.putAll("cat", asList(12, 13, 14));
348        return multimap.asMap().entrySet().iterator();
349      }
350
351      @Override protected void verify(
352          List<Entry<String, Collection<Integer>>> elements) {
353        assertEquals(newHashSet(elements), multimap.asMap().entrySet());
354      }
355    }.test();
356  }
357
358}
359