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.truth.Truth.assertThat;
20import static java.util.Arrays.asList;
21
22import com.google.common.annotations.GwtCompatible;
23import com.google.common.testing.EqualsTester;
24
25import junit.framework.TestCase;
26
27import java.util.Arrays;
28import java.util.Collection;
29import java.util.Iterator;
30import java.util.Map;
31
32/**
33 * Unit tests for {@code LinkedHashMultimap}.
34 *
35 * @author Jared Levy
36 */
37@GwtCompatible(emulated = true)
38public class LinkedHashMultimapTest extends TestCase {
39
40  public void testValueSetHashTableExpansion() {
41    LinkedHashMultimap<String, Integer> multimap = LinkedHashMultimap.create();
42    for (int z = 1; z <= 100; z++) {
43      multimap.put("a", z);
44      // The Eclipse compiler (and hence GWT) rejects a parameterized cast.
45      @SuppressWarnings("unchecked")
46      LinkedHashMultimap<String, Integer>.ValueSet valueSet =
47          (LinkedHashMultimap.ValueSet) multimap.backingMap().get("a");
48      assertEquals(z, valueSet.size());
49      assertFalse(Hashing.needsResizing(valueSet.size(), valueSet.hashTable.length,
50          LinkedHashMultimap.VALUE_SET_LOAD_FACTOR));
51    }
52  }
53
54  private Multimap<String, Integer> initializeMultimap5() {
55    Multimap<String, Integer> multimap = LinkedHashMultimap.create();
56    multimap.put("foo", 5);
57    multimap.put("bar", 4);
58    multimap.put("foo", 3);
59    multimap.put("cow", 2);
60    multimap.put("bar", 1);
61    return multimap;
62  }
63
64  public void testToString() {
65    Multimap<String, Integer> multimap = LinkedHashMultimap.create();
66    multimap.put("foo", 3);
67    multimap.put("bar", 1);
68    multimap.putAll("foo", Arrays.asList(-1, 2, 4));
69    multimap.putAll("bar", Arrays.asList(2, 3));
70    multimap.put("foo", 1);
71    assertEquals("{foo=[3, -1, 2, 4, 1], bar=[1, 2, 3]}",
72        multimap.toString());
73  }
74
75  public void testOrderingReadOnly() {
76    Multimap<String, Integer> multimap = initializeMultimap5();
77    assertOrderingReadOnly(multimap);
78  }
79
80  public void testOrderingUnmodifiable() {
81    Multimap<String, Integer> multimap = initializeMultimap5();
82    assertOrderingReadOnly(Multimaps.unmodifiableMultimap(multimap));
83  }
84
85  public void testOrderingSynchronized() {
86    Multimap<String, Integer> multimap = initializeMultimap5();
87    assertOrderingReadOnly(Multimaps.synchronizedMultimap(multimap));
88  }
89
90  private void assertOrderingReadOnly(Multimap<String, Integer> multimap) {
91    assertThat(multimap.get("foo")).has().exactly(5, 3).inOrder();
92    assertThat(multimap.get("bar")).has().exactly(4, 1).inOrder();
93    assertThat(multimap.get("cow")).has().item(2);
94
95    assertThat(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
96    assertThat(multimap.values()).has().exactly(5, 4, 3, 2, 1).inOrder();
97
98    Iterator<Map.Entry<String, Integer>> entryIterator =
99        multimap.entries().iterator();
100    assertEquals(Maps.immutableEntry("foo", 5), entryIterator.next());
101    assertEquals(Maps.immutableEntry("bar", 4), entryIterator.next());
102    assertEquals(Maps.immutableEntry("foo", 3), entryIterator.next());
103    assertEquals(Maps.immutableEntry("cow", 2), entryIterator.next());
104    assertEquals(Maps.immutableEntry("bar", 1), entryIterator.next());
105
106    Iterator<Map.Entry<String, Collection<Integer>>> collectionIterator =
107        multimap.asMap().entrySet().iterator();
108    Map.Entry<String, Collection<Integer>> entry = collectionIterator.next();
109    assertEquals("foo", entry.getKey());
110    assertThat(entry.getValue()).has().exactly(5, 3).inOrder();
111    entry = collectionIterator.next();
112    assertEquals("bar", entry.getKey());
113    assertThat(entry.getValue()).has().exactly(4, 1).inOrder();
114    entry = collectionIterator.next();
115    assertEquals("cow", entry.getKey());
116    assertThat(entry.getValue()).has().item(2);
117  }
118
119  public void testOrderingUpdates() {
120    Multimap<String, Integer> multimap = initializeMultimap5();
121
122    assertThat(multimap.replaceValues("foo", asList(6, 7))).has().exactly(5, 3).inOrder();
123    assertThat(multimap.keySet()).has().exactly("foo", "bar", "cow").inOrder();
124    assertThat(multimap.removeAll("foo")).has().exactly(6, 7).inOrder();
125    assertThat(multimap.keySet()).has().exactly("bar", "cow").inOrder();
126    assertTrue(multimap.remove("bar", 4));
127    assertThat(multimap.keySet()).has().exactly("bar", "cow").inOrder();
128    assertTrue(multimap.remove("bar", 1));
129    assertThat(multimap.keySet()).has().item("cow");
130    multimap.put("bar", 9);
131    assertThat(multimap.keySet()).has().exactly("cow", "bar").inOrder();
132  }
133
134  public void testToStringNullExact() {
135    Multimap<String, Integer> multimap = LinkedHashMultimap.create();
136
137    multimap.put("foo", 3);
138    multimap.put("foo", -1);
139    multimap.put(null, null);
140    multimap.put("bar", 1);
141    multimap.put("foo", 2);
142    multimap.put(null, 0);
143    multimap.put("bar", 2);
144    multimap.put("bar", null);
145    multimap.put("foo", null);
146    multimap.put("foo", 4);
147    multimap.put(null, -1);
148    multimap.put("bar", 3);
149    multimap.put("bar", 1);
150    multimap.put("foo", 1);
151
152    assertEquals(
153        "{foo=[3, -1, 2, null, 4, 1], null=[null, 0, -1], bar=[1, 2, null, 3]}",
154        multimap.toString());
155  }
156
157  public void testPutMultimapOrdered() {
158    Multimap<String, Integer> multimap = LinkedHashMultimap.create();
159    multimap.putAll(initializeMultimap5());
160    assertOrderingReadOnly(multimap);
161  }
162
163  public void testKeysToString_ordering() {
164    Multimap<String, Integer> multimap = initializeMultimap5();
165    assertEquals("[foo x 2, bar x 2, cow]", multimap.keys().toString());
166  }
167
168  public void testCreate() {
169    LinkedHashMultimap<String, Integer> multimap = LinkedHashMultimap.create();
170    multimap.put("foo", 1);
171    multimap.put("bar", 2);
172    multimap.put("foo", 3);
173    assertEquals(ImmutableSet.of(1, 3), multimap.get("foo"));
174  }
175
176  public void testCreateFromMultimap() {
177    Multimap<String, Integer> multimap = LinkedHashMultimap.create();
178    multimap.put("a", 1);
179    multimap.put("b", 2);
180    multimap.put("a", 3);
181    multimap.put("c", 4);
182    LinkedHashMultimap<String, Integer> copy =
183        LinkedHashMultimap.create(multimap);
184    new EqualsTester()
185        .addEqualityGroup(multimap, copy)
186        .testEquals();
187  }
188
189  public void testCreateFromSizes() {
190    LinkedHashMultimap<String, Integer> multimap
191        = LinkedHashMultimap.create(20, 15);
192    multimap.put("foo", 1);
193    multimap.put("bar", 2);
194    multimap.put("foo", 3);
195    assertEquals(ImmutableSet.of(1, 3), multimap.get("foo"));
196  }
197
198  public void testCreateFromIllegalSizes() {
199    try {
200      LinkedHashMultimap.create(-20, 15);
201      fail();
202    } catch (IllegalArgumentException expected) {}
203
204    try {
205      LinkedHashMultimap.create(20, -15);
206      fail();
207    } catch (IllegalArgumentException expected) {}
208  }
209}
210
211