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 17 package com.google.common.collect; 18 19 import static com.google.common.collect.Lists.newArrayList; 20 import static com.google.common.collect.Sets.newHashSet; 21 import static com.google.common.collect.Sets.newLinkedHashSet; 22 import static com.google.common.collect.testing.Helpers.mapEntry; 23 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE; 24 import static com.google.common.truth.Truth.assertThat; 25 import static java.util.Arrays.asList; 26 27 import com.google.common.annotations.GwtCompatible; 28 import com.google.common.annotations.GwtIncompatible; 29 import com.google.common.collect.testing.IteratorTester; 30 import com.google.common.collect.testing.features.CollectionFeature; 31 import com.google.common.collect.testing.features.CollectionSize; 32 import com.google.common.collect.testing.features.MapFeature; 33 import com.google.common.collect.testing.google.SetMultimapTestSuiteBuilder; 34 import com.google.common.collect.testing.google.TestStringSetMultimapGenerator; 35 import com.google.common.testing.EqualsTester; 36 import com.google.common.testing.SerializableTester; 37 import java.util.Arrays; 38 import java.util.Collection; 39 import java.util.Iterator; 40 import java.util.List; 41 import java.util.Map.Entry; 42 import java.util.Set; 43 import junit.framework.Test; 44 import junit.framework.TestCase; 45 import junit.framework.TestSuite; 46 47 /** 48 * Unit tests for {@code LinkedHashMultimap}. 49 * 50 * @author Jared Levy 51 */ 52 @GwtCompatible(emulated = true) 53 public class LinkedHashMultimapTest extends TestCase { 54 55 @GwtIncompatible // suite suite()56 public static Test suite() { 57 TestSuite suite = new TestSuite(); 58 suite.addTest( 59 SetMultimapTestSuiteBuilder.using( 60 new TestStringSetMultimapGenerator() { 61 @Override 62 protected SetMultimap<String, String> create(Entry<String, String>[] entries) { 63 SetMultimap<String, String> multimap = LinkedHashMultimap.create(); 64 for (Entry<String, String> entry : entries) { 65 multimap.put(entry.getKey(), entry.getValue()); 66 } 67 return multimap; 68 } 69 }) 70 .named("LinkedHashMultimap") 71 .withFeatures( 72 MapFeature.ALLOWS_NULL_KEYS, 73 MapFeature.ALLOWS_NULL_VALUES, 74 MapFeature.ALLOWS_ANY_NULL_QUERIES, 75 MapFeature.GENERAL_PURPOSE, 76 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 77 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 78 CollectionFeature.KNOWN_ORDER, 79 CollectionFeature.SERIALIZABLE, 80 CollectionSize.ANY) 81 .createTestSuite()); 82 suite.addTestSuite(LinkedHashMultimapTest.class); 83 return suite; 84 } 85 testValueSetHashTableExpansion()86 public void testValueSetHashTableExpansion() { 87 LinkedHashMultimap<String, Integer> multimap = LinkedHashMultimap.create(); 88 for (int z = 1; z <= 100; z++) { 89 multimap.put("a", z); 90 // The Eclipse compiler (and hence GWT) rejects a parameterized cast. 91 @SuppressWarnings("unchecked") 92 LinkedHashMultimap<String, Integer>.ValueSet valueSet = 93 (LinkedHashMultimap.ValueSet) multimap.backingMap().get("a"); 94 assertEquals(z, valueSet.size()); 95 assertFalse( 96 Hashing.needsResizing( 97 valueSet.size(), 98 valueSet.hashTable.length, 99 LinkedHashMultimap.VALUE_SET_LOAD_FACTOR)); 100 } 101 } 102 initializeMultimap5()103 private Multimap<String, Integer> initializeMultimap5() { 104 Multimap<String, Integer> multimap = LinkedHashMultimap.create(); 105 multimap.put("foo", 5); 106 multimap.put("bar", 4); 107 multimap.put("foo", 3); 108 multimap.put("cow", 2); 109 multimap.put("bar", 1); 110 return multimap; 111 } 112 testToString()113 public void testToString() { 114 Multimap<String, Integer> multimap = LinkedHashMultimap.create(); 115 multimap.put("foo", 3); 116 multimap.put("bar", 1); 117 multimap.putAll("foo", Arrays.asList(-1, 2, 4)); 118 multimap.putAll("bar", Arrays.asList(2, 3)); 119 multimap.put("foo", 1); 120 assertEquals("{foo=[3, -1, 2, 4, 1], bar=[1, 2, 3]}", multimap.toString()); 121 } 122 testOrderingReadOnly()123 public void testOrderingReadOnly() { 124 Multimap<String, Integer> multimap = initializeMultimap5(); 125 assertOrderingReadOnly(multimap); 126 } 127 testOrderingUnmodifiable()128 public void testOrderingUnmodifiable() { 129 Multimap<String, Integer> multimap = initializeMultimap5(); 130 assertOrderingReadOnly(Multimaps.unmodifiableMultimap(multimap)); 131 } 132 testOrderingSynchronized()133 public void testOrderingSynchronized() { 134 Multimap<String, Integer> multimap = initializeMultimap5(); 135 assertOrderingReadOnly(Multimaps.synchronizedMultimap(multimap)); 136 } 137 138 @GwtIncompatible // SeriazableTester testSerializationOrdering()139 public void testSerializationOrdering() { 140 Multimap<String, Integer> multimap = initializeMultimap5(); 141 Multimap<String, Integer> copy = SerializableTester.reserializeAndAssert(multimap); 142 assertOrderingReadOnly(copy); 143 } 144 145 @GwtIncompatible // SeriazableTester testSerializationOrderingKeysAndEntries()146 public void testSerializationOrderingKeysAndEntries() { 147 Multimap<String, Integer> multimap = LinkedHashMultimap.create(); 148 multimap.put("a", 1); 149 multimap.put("b", 2); 150 multimap.put("a", 3); 151 multimap.put("c", 4); 152 multimap.remove("a", 1); 153 multimap = SerializableTester.reserializeAndAssert(multimap); 154 assertThat(multimap.keySet()).containsExactly("a", "b", "c").inOrder(); 155 assertThat(multimap.entries()) 156 .containsExactly(mapEntry("b", 2), mapEntry("a", 3), mapEntry("c", 4)) 157 .inOrder(); 158 // note that the keys and entries are in different orders 159 } 160 assertOrderingReadOnly(Multimap<String, Integer> multimap)161 private void assertOrderingReadOnly(Multimap<String, Integer> multimap) { 162 assertThat(multimap.get("foo")).containsExactly(5, 3).inOrder(); 163 assertThat(multimap.get("bar")).containsExactly(4, 1).inOrder(); 164 assertThat(multimap.get("cow")).contains(2); 165 166 assertThat(multimap.keySet()).containsExactly("foo", "bar", "cow").inOrder(); 167 assertThat(multimap.values()).containsExactly(5, 4, 3, 2, 1).inOrder(); 168 169 Iterator<Entry<String, Integer>> entryIterator = multimap.entries().iterator(); 170 assertEquals(Maps.immutableEntry("foo", 5), entryIterator.next()); 171 assertEquals(Maps.immutableEntry("bar", 4), entryIterator.next()); 172 assertEquals(Maps.immutableEntry("foo", 3), entryIterator.next()); 173 assertEquals(Maps.immutableEntry("cow", 2), entryIterator.next()); 174 assertEquals(Maps.immutableEntry("bar", 1), entryIterator.next()); 175 176 Iterator<Entry<String, Collection<Integer>>> collectionIterator = 177 multimap.asMap().entrySet().iterator(); 178 Entry<String, Collection<Integer>> entry = collectionIterator.next(); 179 assertEquals("foo", entry.getKey()); 180 assertThat(entry.getValue()).containsExactly(5, 3).inOrder(); 181 entry = collectionIterator.next(); 182 assertEquals("bar", entry.getKey()); 183 assertThat(entry.getValue()).containsExactly(4, 1).inOrder(); 184 entry = collectionIterator.next(); 185 assertEquals("cow", entry.getKey()); 186 assertThat(entry.getValue()).contains(2); 187 } 188 testOrderingUpdates()189 public void testOrderingUpdates() { 190 Multimap<String, Integer> multimap = initializeMultimap5(); 191 192 assertThat(multimap.replaceValues("foo", asList(6, 7))).containsExactly(5, 3).inOrder(); 193 assertThat(multimap.keySet()).containsExactly("foo", "bar", "cow").inOrder(); 194 assertThat(multimap.removeAll("foo")).containsExactly(6, 7).inOrder(); 195 assertThat(multimap.keySet()).containsExactly("bar", "cow").inOrder(); 196 assertTrue(multimap.remove("bar", 4)); 197 assertThat(multimap.keySet()).containsExactly("bar", "cow").inOrder(); 198 assertTrue(multimap.remove("bar", 1)); 199 assertThat(multimap.keySet()).contains("cow"); 200 multimap.put("bar", 9); 201 assertThat(multimap.keySet()).containsExactly("cow", "bar").inOrder(); 202 } 203 testToStringNullExact()204 public void testToStringNullExact() { 205 Multimap<String, Integer> multimap = LinkedHashMultimap.create(); 206 207 multimap.put("foo", 3); 208 multimap.put("foo", -1); 209 multimap.put(null, null); 210 multimap.put("bar", 1); 211 multimap.put("foo", 2); 212 multimap.put(null, 0); 213 multimap.put("bar", 2); 214 multimap.put("bar", null); 215 multimap.put("foo", null); 216 multimap.put("foo", 4); 217 multimap.put(null, -1); 218 multimap.put("bar", 3); 219 multimap.put("bar", 1); 220 multimap.put("foo", 1); 221 222 assertEquals( 223 "{foo=[3, -1, 2, null, 4, 1], null=[null, 0, -1], bar=[1, 2, null, 3]}", 224 multimap.toString()); 225 } 226 testPutMultimapOrdered()227 public void testPutMultimapOrdered() { 228 Multimap<String, Integer> multimap = LinkedHashMultimap.create(); 229 multimap.putAll(initializeMultimap5()); 230 assertOrderingReadOnly(multimap); 231 } 232 testKeysToString_ordering()233 public void testKeysToString_ordering() { 234 Multimap<String, Integer> multimap = initializeMultimap5(); 235 assertEquals("[foo x 2, bar x 2, cow]", multimap.keys().toString()); 236 } 237 testCreate()238 public void testCreate() { 239 LinkedHashMultimap<String, Integer> multimap = LinkedHashMultimap.create(); 240 multimap.put("foo", 1); 241 multimap.put("bar", 2); 242 multimap.put("foo", 3); 243 assertEquals(ImmutableSet.of(1, 3), multimap.get("foo")); 244 } 245 testCreateFromMultimap()246 public void testCreateFromMultimap() { 247 Multimap<String, Integer> multimap = LinkedHashMultimap.create(); 248 multimap.put("a", 1); 249 multimap.put("b", 2); 250 multimap.put("a", 3); 251 multimap.put("c", 4); 252 LinkedHashMultimap<String, Integer> copy = LinkedHashMultimap.create(multimap); 253 new EqualsTester().addEqualityGroup(multimap, copy).testEquals(); 254 } 255 testCreateFromSizes()256 public void testCreateFromSizes() { 257 LinkedHashMultimap<String, Integer> multimap = LinkedHashMultimap.create(20, 15); 258 multimap.put("foo", 1); 259 multimap.put("bar", 2); 260 multimap.put("foo", 3); 261 assertEquals(ImmutableSet.of(1, 3), multimap.get("foo")); 262 } 263 testCreateFromIllegalSizes()264 public void testCreateFromIllegalSizes() { 265 try { 266 LinkedHashMultimap.create(-20, 15); 267 fail(); 268 } catch (IllegalArgumentException expected) { 269 } 270 271 try { 272 LinkedHashMultimap.create(20, -15); 273 fail(); 274 } catch (IllegalArgumentException expected) { 275 } 276 } 277 278 @GwtIncompatible // unreasonably slow testGetIteration()279 public void testGetIteration() { 280 new IteratorTester<Integer>( 281 6, 282 MODIFIABLE, 283 newLinkedHashSet(asList(2, 3, 4, 7, 8)), 284 IteratorTester.KnownOrder.KNOWN_ORDER) { 285 private Multimap<String, Integer> multimap; 286 287 @Override 288 protected Iterator<Integer> newTargetIterator() { 289 multimap = LinkedHashMultimap.create(); 290 multimap.putAll("foo", asList(2, 3, 4)); 291 multimap.putAll("bar", asList(5, 6)); 292 multimap.putAll("foo", asList(7, 8)); 293 return multimap.get("foo").iterator(); 294 } 295 296 @Override 297 protected void verify(List<Integer> elements) { 298 assertEquals(newHashSet(elements), multimap.get("foo")); 299 } 300 }.test(); 301 } 302 303 @GwtIncompatible // unreasonably slow testEntriesIteration()304 public void testEntriesIteration() { 305 @SuppressWarnings("unchecked") 306 Set<Entry<String, Integer>> set = 307 Sets.newLinkedHashSet( 308 asList( 309 Maps.immutableEntry("foo", 2), 310 Maps.immutableEntry("foo", 3), 311 Maps.immutableEntry("bar", 4), 312 Maps.immutableEntry("bar", 5), 313 Maps.immutableEntry("foo", 6))); 314 315 new IteratorTester<Entry<String, Integer>>( 316 6, MODIFIABLE, set, IteratorTester.KnownOrder.KNOWN_ORDER) { 317 private Multimap<String, Integer> multimap; 318 319 @Override 320 protected Iterator<Entry<String, Integer>> newTargetIterator() { 321 multimap = LinkedHashMultimap.create(); 322 multimap.putAll("foo", asList(2, 3)); 323 multimap.putAll("bar", asList(4, 5)); 324 multimap.putAll("foo", asList(6)); 325 return multimap.entries().iterator(); 326 } 327 328 @Override 329 protected void verify(List<Entry<String, Integer>> elements) { 330 assertEquals(newHashSet(elements), multimap.entries()); 331 } 332 }.test(); 333 } 334 335 @GwtIncompatible // unreasonably slow testKeysIteration()336 public void testKeysIteration() { 337 new IteratorTester<String>( 338 6, 339 MODIFIABLE, 340 newArrayList("foo", "foo", "bar", "bar", "foo"), 341 IteratorTester.KnownOrder.KNOWN_ORDER) { 342 private Multimap<String, Integer> multimap; 343 344 @Override 345 protected Iterator<String> newTargetIterator() { 346 multimap = LinkedHashMultimap.create(); 347 multimap.putAll("foo", asList(2, 3)); 348 multimap.putAll("bar", asList(4, 5)); 349 multimap.putAll("foo", asList(6)); 350 return multimap.keys().iterator(); 351 } 352 353 @Override 354 protected void verify(List<String> elements) { 355 assertEquals(elements, Lists.newArrayList(multimap.keys())); 356 } 357 }.test(); 358 } 359 360 @GwtIncompatible // unreasonably slow testValuesIteration()361 public void testValuesIteration() { 362 new IteratorTester<Integer>( 363 6, MODIFIABLE, newArrayList(2, 3, 4, 5, 6), IteratorTester.KnownOrder.KNOWN_ORDER) { 364 private Multimap<String, Integer> multimap; 365 366 @Override 367 protected Iterator<Integer> newTargetIterator() { 368 multimap = LinkedHashMultimap.create(); 369 multimap.putAll("foo", asList(2, 3)); 370 multimap.putAll("bar", asList(4, 5)); 371 multimap.putAll("foo", asList(6)); 372 return multimap.values().iterator(); 373 } 374 375 @Override 376 protected void verify(List<Integer> elements) { 377 assertEquals(elements, Lists.newArrayList(multimap.values())); 378 } 379 }.test(); 380 } 381 382 @GwtIncompatible // unreasonably slow testKeySetIteration()383 public void testKeySetIteration() { 384 new IteratorTester<String>( 385 6, 386 MODIFIABLE, 387 newLinkedHashSet(asList("foo", "bar", "baz", "dog", "cat")), 388 IteratorTester.KnownOrder.KNOWN_ORDER) { 389 private Multimap<String, Integer> multimap; 390 391 @Override 392 protected Iterator<String> newTargetIterator() { 393 multimap = LinkedHashMultimap.create(); 394 multimap.putAll("foo", asList(2, 3)); 395 multimap.putAll("bar", asList(4, 5)); 396 multimap.putAll("foo", asList(6)); 397 multimap.putAll("baz", asList(7, 8)); 398 multimap.putAll("dog", asList(9)); 399 multimap.putAll("bar", asList(10, 11)); 400 multimap.putAll("cat", asList(12, 13, 14)); 401 return multimap.keySet().iterator(); 402 } 403 404 @Override 405 protected void verify(List<String> elements) { 406 assertEquals(newHashSet(elements), multimap.keySet()); 407 } 408 }.test(); 409 } 410 411 @GwtIncompatible // unreasonably slow testAsSetIteration()412 public void testAsSetIteration() { 413 @SuppressWarnings("unchecked") 414 Set<Entry<String, Collection<Integer>>> set = 415 newLinkedHashSet( 416 asList( 417 Maps.immutableEntry("foo", (Collection<Integer>) Sets.newHashSet(2, 3, 6)), 418 Maps.immutableEntry("bar", (Collection<Integer>) Sets.newHashSet(4, 5, 10, 11)), 419 Maps.immutableEntry("baz", (Collection<Integer>) Sets.newHashSet(7, 8)), 420 Maps.immutableEntry("dog", (Collection<Integer>) Sets.newHashSet(9)), 421 Maps.immutableEntry("cat", (Collection<Integer>) Sets.newHashSet(12, 13, 14)))); 422 new IteratorTester<Entry<String, Collection<Integer>>>( 423 6, MODIFIABLE, set, IteratorTester.KnownOrder.KNOWN_ORDER) { 424 private Multimap<String, Integer> multimap; 425 426 @Override 427 protected Iterator<Entry<String, Collection<Integer>>> newTargetIterator() { 428 multimap = LinkedHashMultimap.create(); 429 multimap.putAll("foo", asList(2, 3)); 430 multimap.putAll("bar", asList(4, 5)); 431 multimap.putAll("foo", asList(6)); 432 multimap.putAll("baz", asList(7, 8)); 433 multimap.putAll("dog", asList(9)); 434 multimap.putAll("bar", asList(10, 11)); 435 multimap.putAll("cat", asList(12, 13, 14)); 436 return multimap.asMap().entrySet().iterator(); 437 } 438 439 @Override 440 protected void verify(List<Entry<String, Collection<Integer>>> elements) { 441 assertEquals(newHashSet(elements), multimap.asMap().entrySet()); 442 } 443 }.test(); 444 } 445 } 446