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