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 17 package com.google.common.collect; 18 19 import static com.google.common.testing.SerializableTester.reserialize; 20 import static com.google.common.truth.Truth.assertThat; 21 import static com.google.common.truth.Truth.assertWithMessage; 22 23 import com.google.common.annotations.GwtCompatible; 24 import com.google.common.annotations.GwtIncompatible; 25 import com.google.common.collect.ImmutableMap.Builder; 26 import com.google.common.collect.testing.CollectionTestSuiteBuilder; 27 import com.google.common.collect.testing.ListTestSuiteBuilder; 28 import com.google.common.collect.testing.MapTestSuiteBuilder; 29 import com.google.common.collect.testing.features.CollectionFeature; 30 import com.google.common.collect.testing.features.CollectionSize; 31 import com.google.common.collect.testing.features.MapFeature; 32 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapCopyOfEntriesGenerator; 33 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapCopyOfEnumMapGenerator; 34 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapCopyOfGenerator; 35 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapEntryListGenerator; 36 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapGenerator; 37 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapKeyListGenerator; 38 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapUnhashableValuesGenerator; 39 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapValueListGenerator; 40 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapValuesAsSingletonSetGenerator; 41 import com.google.common.testing.EqualsTester; 42 import com.google.common.testing.NullPointerTester; 43 import java.io.ByteArrayOutputStream; 44 import java.io.ObjectOutputStream; 45 import java.io.Serializable; 46 import java.util.AbstractMap; 47 import java.util.Arrays; 48 import java.util.Collection; 49 import java.util.Collections; 50 import java.util.LinkedHashMap; 51 import java.util.List; 52 import java.util.Map; 53 import java.util.Map.Entry; 54 import java.util.Set; 55 import java.util.regex.Matcher; 56 import java.util.regex.Pattern; 57 import junit.framework.Test; 58 import junit.framework.TestCase; 59 import junit.framework.TestSuite; 60 import org.checkerframework.checker.nullness.qual.Nullable; 61 62 /** 63 * Tests for {@link ImmutableMap}. 64 * 65 * @author Kevin Bourrillion 66 * @author Jesse Wilson 67 */ 68 @GwtCompatible(emulated = true) 69 @SuppressWarnings("AlwaysThrows") 70 public class ImmutableMapTest extends TestCase { 71 72 @GwtIncompatible // suite suite()73 public static Test suite() { 74 TestSuite suite = new TestSuite(); 75 suite.addTestSuite(ImmutableMapTest.class); 76 77 suite.addTest( 78 MapTestSuiteBuilder.using(new ImmutableMapGenerator()) 79 .withFeatures( 80 CollectionSize.ANY, 81 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 82 CollectionFeature.KNOWN_ORDER, 83 MapFeature.REJECTS_DUPLICATES_AT_CREATION, 84 CollectionFeature.ALLOWS_NULL_QUERIES) 85 .named("ImmutableMap") 86 .createTestSuite()); 87 88 suite.addTest( 89 MapTestSuiteBuilder.using(new ImmutableMapCopyOfGenerator()) 90 .withFeatures( 91 CollectionSize.ANY, 92 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 93 CollectionFeature.KNOWN_ORDER, 94 CollectionFeature.ALLOWS_NULL_QUERIES) 95 .named("ImmutableMap.copyOf[Map]") 96 .createTestSuite()); 97 98 suite.addTest( 99 MapTestSuiteBuilder.using(new ImmutableMapCopyOfEntriesGenerator()) 100 .withFeatures( 101 CollectionSize.ANY, 102 MapFeature.REJECTS_DUPLICATES_AT_CREATION, 103 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 104 CollectionFeature.KNOWN_ORDER, 105 CollectionFeature.ALLOWS_NULL_QUERIES) 106 .named("ImmutableMap.copyOf[Iterable<Entry>]") 107 .createTestSuite()); 108 109 suite.addTest( 110 MapTestSuiteBuilder.using(new ImmutableMapCopyOfEnumMapGenerator()) 111 .withFeatures( 112 CollectionSize.ANY, 113 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 114 CollectionFeature.KNOWN_ORDER, 115 CollectionFeature.ALLOWS_NULL_QUERIES) 116 .named("ImmutableMap.copyOf[EnumMap]") 117 .createTestSuite()); 118 119 suite.addTest( 120 MapTestSuiteBuilder.using(new ImmutableMapValuesAsSingletonSetGenerator()) 121 .withFeatures( 122 CollectionSize.ANY, 123 MapFeature.REJECTS_DUPLICATES_AT_CREATION, 124 CollectionFeature.KNOWN_ORDER, 125 CollectionFeature.ALLOWS_NULL_QUERIES) 126 .named("ImmutableMap.asMultimap.asMap") 127 .createTestSuite()); 128 129 suite.addTest( 130 CollectionTestSuiteBuilder.using(new ImmutableMapUnhashableValuesGenerator()) 131 .withFeatures( 132 CollectionSize.ANY, 133 CollectionFeature.KNOWN_ORDER, 134 CollectionFeature.ALLOWS_NULL_QUERIES) 135 .named("ImmutableMap.values, unhashable") 136 .createTestSuite()); 137 138 suite.addTest( 139 ListTestSuiteBuilder.using(new ImmutableMapKeyListGenerator()) 140 .named("ImmutableMap.keySet.asList") 141 .withFeatures( 142 CollectionSize.ANY, 143 CollectionFeature.SERIALIZABLE, 144 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 145 CollectionFeature.ALLOWS_NULL_QUERIES) 146 .createTestSuite()); 147 148 suite.addTest( 149 ListTestSuiteBuilder.using(new ImmutableMapEntryListGenerator()) 150 .named("ImmutableMap.entrySet.asList") 151 .withFeatures( 152 CollectionSize.ANY, 153 CollectionFeature.SERIALIZABLE, 154 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 155 CollectionFeature.ALLOWS_NULL_QUERIES) 156 .createTestSuite()); 157 158 suite.addTest( 159 ListTestSuiteBuilder.using(new ImmutableMapValueListGenerator()) 160 .named("ImmutableMap.values.asList") 161 .withFeatures( 162 CollectionSize.ANY, 163 CollectionFeature.SERIALIZABLE, 164 CollectionFeature.ALLOWS_NULL_QUERIES) 165 .createTestSuite()); 166 167 return suite; 168 } 169 170 // Creation tests 171 testEmptyBuilder()172 public void testEmptyBuilder() { 173 ImmutableMap<String, Integer> map = new Builder<String, Integer>().buildOrThrow(); 174 assertEquals(Collections.<String, Integer>emptyMap(), map); 175 } 176 testSingletonBuilder()177 public void testSingletonBuilder() { 178 ImmutableMap<String, Integer> map = new Builder<String, Integer>().put("one", 1).buildOrThrow(); 179 assertMapEquals(map, "one", 1); 180 } 181 testBuilder()182 public void testBuilder() { 183 ImmutableMap<String, Integer> map = 184 new Builder<String, Integer>() 185 .put("one", 1) 186 .put("two", 2) 187 .put("three", 3) 188 .put("four", 4) 189 .put("five", 5) 190 .buildOrThrow(); 191 assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 192 } 193 194 @GwtIncompatible testBuilderExactlySizedReusesArray()195 public void testBuilderExactlySizedReusesArray() { 196 ImmutableMap.Builder<Integer, Integer> builder = ImmutableMap.builderWithExpectedSize(10); 197 Object[] builderArray = builder.alternatingKeysAndValues; 198 for (int i = 0; i < 10; i++) { 199 builder.put(i, i); 200 } 201 Object[] builderArrayAfterPuts = builder.alternatingKeysAndValues; 202 RegularImmutableMap<Integer, Integer> map = 203 (RegularImmutableMap<Integer, Integer>) builder.buildOrThrow(); 204 Object[] mapInternalArray = map.alternatingKeysAndValues; 205 assertSame(builderArray, builderArrayAfterPuts); 206 assertSame(builderArray, mapInternalArray); 207 } 208 testBuilder_orderEntriesByValue()209 public void testBuilder_orderEntriesByValue() { 210 ImmutableMap<String, Integer> map = 211 new Builder<String, Integer>() 212 .orderEntriesByValue(Ordering.natural()) 213 .put("three", 3) 214 .put("one", 1) 215 .put("five", 5) 216 .put("four", 4) 217 .put("two", 2) 218 .buildOrThrow(); 219 assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 220 } 221 testBuilder_orderEntriesByValueAfterExactSizeBuild()222 public void testBuilder_orderEntriesByValueAfterExactSizeBuild() { 223 Builder<String, Integer> builder = new Builder<String, Integer>(2).put("four", 4).put("one", 1); 224 ImmutableMap<String, Integer> keyOrdered = builder.buildOrThrow(); 225 ImmutableMap<String, Integer> valueOrdered = 226 builder.orderEntriesByValue(Ordering.natural()).buildOrThrow(); 227 assertMapEquals(keyOrdered, "four", 4, "one", 1); 228 assertMapEquals(valueOrdered, "one", 1, "four", 4); 229 } 230 testBuilder_orderEntriesByValue_usedTwiceFails()231 public void testBuilder_orderEntriesByValue_usedTwiceFails() { 232 ImmutableMap.Builder<String, Integer> builder = 233 new Builder<String, Integer>().orderEntriesByValue(Ordering.natural()); 234 try { 235 builder.orderEntriesByValue(Ordering.natural()); 236 fail("Expected IllegalStateException"); 237 } catch (IllegalStateException expected) { 238 } 239 } 240 241 @GwtIncompatible // we haven't implemented this testBuilder_orderEntriesByValue_keepingLast()242 public void testBuilder_orderEntriesByValue_keepingLast() { 243 ImmutableMap.Builder<String, Integer> builder = 244 new Builder<String, Integer>() 245 .orderEntriesByValue(Ordering.natural()) 246 .put("three", 3) 247 .put("one", 1) 248 .put("five", 5) 249 .put("four", 3) 250 .put("four", 5) 251 .put("four", 4) // this should win because it's last 252 .put("two", 2); 253 assertMapEquals( 254 builder.buildKeepingLast(), "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 255 try { 256 builder.buildOrThrow(); 257 fail("Expected exception from duplicate keys"); 258 } catch (IllegalArgumentException expected) { 259 } 260 } 261 262 @GwtIncompatible // we haven't implemented this testBuilder_orderEntriesByValue_keepingLast_builderSizeFieldPreserved()263 public void testBuilder_orderEntriesByValue_keepingLast_builderSizeFieldPreserved() { 264 ImmutableMap.Builder<String, Integer> builder = 265 new Builder<String, Integer>() 266 .orderEntriesByValue(Ordering.natural()) 267 .put("one", 1) 268 .put("one", 1); 269 assertMapEquals(builder.buildKeepingLast(), "one", 1); 270 try { 271 builder.buildOrThrow(); 272 fail("Expected exception from duplicate keys"); 273 } catch (IllegalArgumentException expected) { 274 } 275 } 276 testBuilder_withImmutableEntry()277 public void testBuilder_withImmutableEntry() { 278 ImmutableMap<String, Integer> map = 279 new Builder<String, Integer>().put(Maps.immutableEntry("one", 1)).buildOrThrow(); 280 assertMapEquals(map, "one", 1); 281 } 282 testBuilder_withImmutableEntryAndNullContents()283 public void testBuilder_withImmutableEntryAndNullContents() { 284 Builder<String, Integer> builder = new Builder<>(); 285 try { 286 builder.put(Maps.immutableEntry("one", (Integer) null)); 287 fail(); 288 } catch (NullPointerException expected) { 289 } 290 try { 291 builder.put(Maps.immutableEntry((String) null, 1)); 292 fail(); 293 } catch (NullPointerException expected) { 294 } 295 } 296 297 private static class StringHolder { 298 String string; 299 } 300 testBuilder_withMutableEntry()301 public void testBuilder_withMutableEntry() { 302 ImmutableMap.Builder<String, Integer> builder = new Builder<>(); 303 final StringHolder holder = new StringHolder(); 304 holder.string = "one"; 305 Entry<String, Integer> entry = 306 new AbstractMapEntry<String, Integer>() { 307 @Override 308 public String getKey() { 309 return holder.string; 310 } 311 312 @Override 313 public Integer getValue() { 314 return 1; 315 } 316 }; 317 318 builder.put(entry); 319 holder.string = "two"; 320 assertMapEquals(builder.buildOrThrow(), "one", 1); 321 } 322 testBuilderPutAllWithEmptyMap()323 public void testBuilderPutAllWithEmptyMap() { 324 ImmutableMap<String, Integer> map = 325 new Builder<String, Integer>() 326 .putAll(Collections.<String, Integer>emptyMap()) 327 .buildOrThrow(); 328 assertEquals(Collections.<String, Integer>emptyMap(), map); 329 } 330 testBuilderPutAll()331 public void testBuilderPutAll() { 332 Map<String, Integer> toPut = new LinkedHashMap<>(); 333 toPut.put("one", 1); 334 toPut.put("two", 2); 335 toPut.put("three", 3); 336 Map<String, Integer> moreToPut = new LinkedHashMap<>(); 337 moreToPut.put("four", 4); 338 moreToPut.put("five", 5); 339 340 ImmutableMap<String, Integer> map = 341 new Builder<String, Integer>().putAll(toPut).putAll(moreToPut).buildOrThrow(); 342 assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 343 } 344 testBuilderReuse()345 public void testBuilderReuse() { 346 Builder<String, Integer> builder = new Builder<>(); 347 ImmutableMap<String, Integer> mapOne = builder.put("one", 1).put("two", 2).buildOrThrow(); 348 ImmutableMap<String, Integer> mapTwo = builder.put("three", 3).put("four", 4).buildOrThrow(); 349 350 assertMapEquals(mapOne, "one", 1, "two", 2); 351 assertMapEquals(mapTwo, "one", 1, "two", 2, "three", 3, "four", 4); 352 } 353 testBuilderPutNullKeyFailsAtomically()354 public void testBuilderPutNullKeyFailsAtomically() { 355 Builder<String, Integer> builder = new Builder<>(); 356 try { 357 builder.put(null, 1); 358 fail(); 359 } catch (NullPointerException expected) { 360 } 361 builder.put("foo", 2); 362 assertMapEquals(builder.buildOrThrow(), "foo", 2); 363 } 364 testBuilderPutImmutableEntryWithNullKeyFailsAtomically()365 public void testBuilderPutImmutableEntryWithNullKeyFailsAtomically() { 366 Builder<String, Integer> builder = new Builder<>(); 367 try { 368 builder.put(Maps.immutableEntry((String) null, 1)); 369 fail(); 370 } catch (NullPointerException expected) { 371 } 372 builder.put("foo", 2); 373 assertMapEquals(builder.buildOrThrow(), "foo", 2); 374 } 375 376 // for GWT compatibility 377 static class SimpleEntry<K, V> extends AbstractMapEntry<K, V> { 378 public K key; 379 public V value; 380 SimpleEntry(K key, V value)381 SimpleEntry(K key, V value) { 382 this.key = key; 383 this.value = value; 384 } 385 386 @Override getKey()387 public K getKey() { 388 return key; 389 } 390 391 @Override getValue()392 public V getValue() { 393 return value; 394 } 395 } 396 testBuilderPutMutableEntryWithNullKeyFailsAtomically()397 public void testBuilderPutMutableEntryWithNullKeyFailsAtomically() { 398 Builder<String, Integer> builder = new Builder<>(); 399 try { 400 builder.put(new SimpleEntry<String, Integer>(null, 1)); 401 fail(); 402 } catch (NullPointerException expected) { 403 } 404 builder.put("foo", 2); 405 assertMapEquals(builder.buildOrThrow(), "foo", 2); 406 } 407 testBuilderPutNullKey()408 public void testBuilderPutNullKey() { 409 Builder<String, Integer> builder = new Builder<>(); 410 try { 411 builder.put(null, 1); 412 fail(); 413 } catch (NullPointerException expected) { 414 } 415 } 416 testBuilderPutNullValue()417 public void testBuilderPutNullValue() { 418 Builder<String, Integer> builder = new Builder<>(); 419 try { 420 builder.put("one", null); 421 fail(); 422 } catch (NullPointerException expected) { 423 } 424 } 425 testBuilderPutNullKeyViaPutAll()426 public void testBuilderPutNullKeyViaPutAll() { 427 Builder<String, Integer> builder = new Builder<>(); 428 try { 429 builder.putAll(Collections.<String, Integer>singletonMap(null, 1)); 430 fail(); 431 } catch (NullPointerException expected) { 432 } 433 } 434 testBuilderPutNullValueViaPutAll()435 public void testBuilderPutNullValueViaPutAll() { 436 Builder<String, Integer> builder = new Builder<>(); 437 try { 438 builder.putAll(Collections.<String, Integer>singletonMap("one", null)); 439 fail(); 440 } catch (NullPointerException expected) { 441 } 442 } 443 testPuttingTheSameKeyTwiceThrowsOnBuild()444 public void testPuttingTheSameKeyTwiceThrowsOnBuild() { 445 Builder<String, Integer> builder = 446 new Builder<String, Integer>() 447 .put("one", 1) 448 .put("one", 1); // throwing on this line might be better but it's too late to change 449 450 try { 451 builder.buildOrThrow(); 452 fail(); 453 } catch (IllegalArgumentException expected) { 454 } 455 } 456 testBuildKeepingLast_allowsOverwrite()457 public void testBuildKeepingLast_allowsOverwrite() { 458 Builder<Integer, String> builder = 459 new Builder<Integer, String>() 460 .put(1, "un") 461 .put(2, "deux") 462 .put(70, "soixante-dix") 463 .put(70, "septante") 464 .put(70, "seventy") 465 .put(1, "one") 466 .put(2, "two"); 467 ImmutableMap<Integer, String> map = builder.buildKeepingLast(); 468 assertMapEquals(map, 1, "one", 2, "two", 70, "seventy"); 469 } 470 testBuildKeepingLast_smallTableSameHash()471 public void testBuildKeepingLast_smallTableSameHash() { 472 String key1 = "QED"; 473 String key2 = "R&D"; 474 assertThat(key1.hashCode()).isEqualTo(key2.hashCode()); 475 ImmutableMap<String, Integer> map = 476 ImmutableMap.<String, Integer>builder() 477 .put(key1, 1) 478 .put(key2, 2) 479 .put(key1, 3) 480 .put(key2, 4) 481 .buildKeepingLast(); 482 assertMapEquals(map, key1, 3, key2, 4); 483 } 484 485 // The java7 branch has different code depending on whether the entry indexes fit in a byte, 486 // short, or int. The small table in testBuildKeepingLast_allowsOverwrite will test the byte 487 // case. This method tests the short case. testBuildKeepingLast_shortTable()488 public void testBuildKeepingLast_shortTable() { 489 Builder<Integer, String> builder = ImmutableMap.builder(); 490 Map<Integer, String> expected = new LinkedHashMap<>(); 491 for (int i = 0; i < 1000; i++) { 492 // Truncate to even key, so we have put(0, "0") then put(0, "1"). Half the entries are 493 // duplicates. 494 Integer key = i & ~1; 495 String value = String.valueOf(i); 496 builder.put(key, value); 497 expected.put(key, value); 498 } 499 ImmutableMap<Integer, String> map = builder.buildKeepingLast(); 500 assertThat(map).hasSize(500); 501 assertThat(map).containsExactlyEntriesIn(expected).inOrder(); 502 } 503 504 // This method tests the int case. testBuildKeepingLast_bigTable()505 public void testBuildKeepingLast_bigTable() { 506 Builder<Integer, String> builder = ImmutableMap.builder(); 507 Map<Integer, String> expected = new LinkedHashMap<>(); 508 for (int i = 0; i < 200_000; i++) { 509 // Truncate to even key, so we have put(0, "0") then put(0, "1"). Half the entries are 510 // duplicates. 511 Integer key = i & ~1; 512 String value = String.valueOf(i); 513 builder.put(key, value); 514 expected.put(key, value); 515 } 516 ImmutableMap<Integer, String> map = builder.buildKeepingLast(); 517 assertThat(map).hasSize(100_000); 518 assertThat(map).containsExactlyEntriesIn(expected).inOrder(); 519 } 520 521 private static class ClassWithTerribleHashCode implements Comparable<ClassWithTerribleHashCode> { 522 private final int value; 523 ClassWithTerribleHashCode(int value)524 ClassWithTerribleHashCode(int value) { 525 this.value = value; 526 } 527 528 @Override compareTo(ClassWithTerribleHashCode that)529 public int compareTo(ClassWithTerribleHashCode that) { 530 return Integer.compare(this.value, that.value); 531 } 532 533 @Override equals(@ullable Object x)534 public boolean equals(@Nullable Object x) { 535 return x instanceof ClassWithTerribleHashCode 536 && ((ClassWithTerribleHashCode) x).value == value; 537 } 538 539 @Override hashCode()540 public int hashCode() { 541 return 23; 542 } 543 544 @Override toString()545 public String toString() { 546 return "ClassWithTerribleHashCode(" + value + ")"; 547 } 548 } 549 550 @GwtIncompatible testBuildKeepingLast_collisions()551 public void testBuildKeepingLast_collisions() { 552 Map<ClassWithTerribleHashCode, Integer> expected = new LinkedHashMap<>(); 553 Builder<ClassWithTerribleHashCode, Integer> builder = new Builder<>(); 554 int size = 18; 555 for (int i = 0; i < size; i++) { 556 ClassWithTerribleHashCode key = new ClassWithTerribleHashCode(i); 557 builder.put(key, i); 558 builder.put(key, -i); 559 expected.put(key, -i); 560 } 561 ImmutableMap<ClassWithTerribleHashCode, Integer> map = builder.buildKeepingLast(); 562 assertThat(map).containsExactlyEntriesIn(expected).inOrder(); 563 } 564 565 @GwtIncompatible // Pattern, Matcher testBuilder_keepingLast_thenOrThrow()566 public void testBuilder_keepingLast_thenOrThrow() { 567 ImmutableMap.Builder<String, Integer> builder = 568 new Builder<String, Integer>() 569 .put("three", 3) 570 .put("one", 1) 571 .put("five", 5) 572 .put("four", 3) 573 .put("four", 5) 574 .put("four", 4) // this should win because it's last 575 .put("two", 2); 576 assertMapEquals( 577 builder.buildKeepingLast(), "three", 3, "one", 1, "five", 5, "four", 4, "two", 2); 578 try { 579 builder.buildOrThrow(); 580 fail("Expected exception from duplicate keys"); 581 } catch (IllegalArgumentException expected) { 582 // We don't really care which values the exception message contains, but they should be 583 // different from each other. If buildKeepingLast() collapsed duplicates, that might end up 584 // not being true. 585 Pattern pattern = Pattern.compile("Multiple entries with same key: four=(.*) and four=(.*)"); 586 assertThat(expected).hasMessageThat().matches(pattern); 587 Matcher matcher = pattern.matcher(expected.getMessage()); 588 assertThat(matcher.matches()).isTrue(); 589 assertThat(matcher.group(1)).isNotEqualTo(matcher.group(2)); 590 } 591 } 592 testOf()593 public void testOf() { 594 assertMapEquals(ImmutableMap.of("one", 1), "one", 1); 595 assertMapEquals(ImmutableMap.of("one", 1, "two", 2), "one", 1, "two", 2); 596 assertMapEquals( 597 ImmutableMap.of("one", 1, "two", 2, "three", 3), "one", 1, "two", 2, "three", 3); 598 assertMapEquals( 599 ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4), 600 "one", 601 1, 602 "two", 603 2, 604 "three", 605 3, 606 "four", 607 4); 608 assertMapEquals( 609 ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4, "five", 5), 610 "one", 611 1, 612 "two", 613 2, 614 "three", 615 3, 616 "four", 617 4, 618 "five", 619 5); 620 assertMapEquals( 621 ImmutableMap.of( 622 "one", 1, 623 "two", 2, 624 "three", 3, 625 "four", 4, 626 "five", 5, 627 "six", 6), 628 "one", 629 1, 630 "two", 631 2, 632 "three", 633 3, 634 "four", 635 4, 636 "five", 637 5, 638 "six", 639 6); 640 assertMapEquals( 641 ImmutableMap.of( 642 "one", 1, 643 "two", 2, 644 "three", 3, 645 "four", 4, 646 "five", 5, 647 "six", 6, 648 "seven", 7), 649 "one", 650 1, 651 "two", 652 2, 653 "three", 654 3, 655 "four", 656 4, 657 "five", 658 5, 659 "six", 660 6, 661 "seven", 662 7); 663 assertMapEquals( 664 ImmutableMap.of( 665 "one", 1, 666 "two", 2, 667 "three", 3, 668 "four", 4, 669 "five", 5, 670 "six", 6, 671 "seven", 7, 672 "eight", 8), 673 "one", 674 1, 675 "two", 676 2, 677 "three", 678 3, 679 "four", 680 4, 681 "five", 682 5, 683 "six", 684 6, 685 "seven", 686 7, 687 "eight", 688 8); 689 assertMapEquals( 690 ImmutableMap.of( 691 "one", 1, 692 "two", 2, 693 "three", 3, 694 "four", 4, 695 "five", 5, 696 "six", 6, 697 "seven", 7, 698 "eight", 8, 699 "nine", 9), 700 "one", 701 1, 702 "two", 703 2, 704 "three", 705 3, 706 "four", 707 4, 708 "five", 709 5, 710 "six", 711 6, 712 "seven", 713 7, 714 "eight", 715 8, 716 "nine", 717 9); 718 assertMapEquals( 719 ImmutableMap.of( 720 "one", 1, 721 "two", 2, 722 "three", 3, 723 "four", 4, 724 "five", 5, 725 "six", 6, 726 "seven", 7, 727 "eight", 8, 728 "nine", 9, 729 "ten", 10), 730 "one", 731 1, 732 "two", 733 2, 734 "three", 735 3, 736 "four", 737 4, 738 "five", 739 5, 740 "six", 741 6, 742 "seven", 743 7, 744 "eight", 745 8, 746 "nine", 747 9, 748 "ten", 749 10); 750 } 751 testOfNullKey()752 public void testOfNullKey() { 753 try { 754 ImmutableMap.of(null, 1); 755 fail(); 756 } catch (NullPointerException expected) { 757 } 758 759 try { 760 ImmutableMap.of("one", 1, null, 2); 761 fail(); 762 } catch (NullPointerException expected) { 763 } 764 } 765 testOfNullValue()766 public void testOfNullValue() { 767 try { 768 ImmutableMap.of("one", null); 769 fail(); 770 } catch (NullPointerException expected) { 771 } 772 773 try { 774 ImmutableMap.of("one", 1, "two", null); 775 fail(); 776 } catch (NullPointerException expected) { 777 } 778 } 779 testOfWithDuplicateKey()780 public void testOfWithDuplicateKey() { 781 try { 782 ImmutableMap.of("one", 1, "one", 1); 783 fail(); 784 } catch (IllegalArgumentException expected) { 785 } 786 } 787 testCopyOfEmptyMap()788 public void testCopyOfEmptyMap() { 789 ImmutableMap<String, Integer> copy = 790 ImmutableMap.copyOf(Collections.<String, Integer>emptyMap()); 791 assertEquals(Collections.<String, Integer>emptyMap(), copy); 792 assertSame(copy, ImmutableMap.copyOf(copy)); 793 } 794 testCopyOfSingletonMap()795 public void testCopyOfSingletonMap() { 796 ImmutableMap<String, Integer> copy = ImmutableMap.copyOf(Collections.singletonMap("one", 1)); 797 assertMapEquals(copy, "one", 1); 798 assertSame(copy, ImmutableMap.copyOf(copy)); 799 } 800 testCopyOf()801 public void testCopyOf() { 802 Map<String, Integer> original = new LinkedHashMap<>(); 803 original.put("one", 1); 804 original.put("two", 2); 805 original.put("three", 3); 806 807 ImmutableMap<String, Integer> copy = ImmutableMap.copyOf(original); 808 assertMapEquals(copy, "one", 1, "two", 2, "three", 3); 809 assertSame(copy, ImmutableMap.copyOf(copy)); 810 } 811 812 // TODO(b/172823566): Use mainline testToImmutableMap once CollectorTester is usable to java7. testToImmutableMap_java7_combine()813 public void testToImmutableMap_java7_combine() { 814 ImmutableMap.Builder<String, Integer> zis = 815 ImmutableMap.<String, Integer>builder().put("one", 1); 816 ImmutableMap.Builder<String, Integer> zat = 817 ImmutableMap.<String, Integer>builder().put("two", 2).put("three", 3); 818 assertMapEquals(zis.combine(zat).build(), "one", 1, "two", 2, "three", 3); 819 } 820 821 // TODO(b/172823566): Use mainline testToImmutableMap once CollectorTester is usable to java7. testToImmutableMap_exceptionOnDuplicateKey_java7_combine()822 public void testToImmutableMap_exceptionOnDuplicateKey_java7_combine() { 823 ImmutableMap.Builder<String, Integer> zis = 824 ImmutableMap.<String, Integer>builder().put("one", 1).put("two", 2); 825 ImmutableMap.Builder<String, Integer> zat = 826 ImmutableMap.<String, Integer>builder().put("two", 22).put("three", 3); 827 try { 828 zis.combine(zat).build(); 829 fail("Expected IllegalArgumentException"); 830 } catch (IllegalArgumentException expected) { 831 // expected 832 } 833 } 834 hashtableTestHelper(ImmutableList<Integer> sizes)835 public static void hashtableTestHelper(ImmutableList<Integer> sizes) { 836 for (int size : sizes) { 837 Builder<Integer, Integer> builder = ImmutableMap.builderWithExpectedSize(size); 838 for (int i = 0; i < size; i++) { 839 Integer integer = i; 840 builder.put(integer, integer); 841 } 842 ImmutableMap<Integer, Integer> map = builder.build(); 843 assertEquals(size, map.size()); 844 int entries = 0; 845 for (Integer key : map.keySet()) { 846 assertEquals(entries, key.intValue()); 847 assertSame(key, map.get(key)); 848 entries++; 849 } 850 assertEquals(size, entries); 851 } 852 } 853 testByteArrayHashtable()854 public void testByteArrayHashtable() { 855 hashtableTestHelper(ImmutableList.of(2, 89)); 856 } 857 testShortArrayHashtable()858 public void testShortArrayHashtable() { 859 hashtableTestHelper(ImmutableList.of(90, 22937)); 860 } 861 testIntArrayHashtable()862 public void testIntArrayHashtable() { 863 hashtableTestHelper(ImmutableList.of(22938)); 864 } 865 866 // Non-creation tests 867 testNullGet()868 public void testNullGet() { 869 ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1); 870 assertNull(map.get(null)); 871 } 872 testAsMultimap()873 public void testAsMultimap() { 874 ImmutableMap<String, Integer> map = 875 ImmutableMap.of("one", 1, "won", 1, "two", 2, "too", 2, "three", 3); 876 ImmutableSetMultimap<String, Integer> expected = 877 ImmutableSetMultimap.of("one", 1, "won", 1, "two", 2, "too", 2, "three", 3); 878 assertEquals(expected, map.asMultimap()); 879 } 880 testAsMultimapWhenEmpty()881 public void testAsMultimapWhenEmpty() { 882 ImmutableMap<String, Integer> map = ImmutableMap.of(); 883 ImmutableSetMultimap<String, Integer> expected = ImmutableSetMultimap.of(); 884 assertEquals(expected, map.asMultimap()); 885 } 886 testAsMultimapCaches()887 public void testAsMultimapCaches() { 888 ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1); 889 ImmutableSetMultimap<String, Integer> multimap1 = map.asMultimap(); 890 ImmutableSetMultimap<String, Integer> multimap2 = map.asMultimap(); 891 assertEquals(1, multimap1.asMap().size()); 892 assertSame(multimap1, multimap2); 893 } 894 895 @GwtIncompatible // NullPointerTester 896 @AndroidIncompatible // see ImmutableTableTest.testNullPointerInstance testNullPointers()897 public void testNullPointers() { 898 NullPointerTester tester = new NullPointerTester(); 899 tester.testAllPublicStaticMethods(ImmutableMap.class); 900 tester.testAllPublicInstanceMethods(new ImmutableMap.Builder<Object, Object>()); 901 tester.testAllPublicInstanceMethods(ImmutableMap.of()); 902 tester.testAllPublicInstanceMethods(ImmutableMap.of("one", 1)); 903 tester.testAllPublicInstanceMethods(ImmutableMap.of("one", 1, "two", 2, "three", 3)); 904 } 905 assertMapEquals(Map<K, V> map, Object... alternatingKeysAndValues)906 private static <K, V> void assertMapEquals(Map<K, V> map, Object... alternatingKeysAndValues) { 907 Map<Object, Object> expected = new LinkedHashMap<>(); 908 for (int i = 0; i < alternatingKeysAndValues.length; i += 2) { 909 expected.put(alternatingKeysAndValues[i], alternatingKeysAndValues[i + 1]); 910 } 911 assertThat(map).containsExactlyEntriesIn(expected).inOrder(); 912 } 913 914 private static class IntHolder implements Serializable { 915 public int value; 916 IntHolder(int value)917 public IntHolder(int value) { 918 this.value = value; 919 } 920 921 @Override equals(@ullable Object o)922 public boolean equals(@Nullable Object o) { 923 return (o instanceof IntHolder) && ((IntHolder) o).value == value; 924 } 925 926 @Override hashCode()927 public int hashCode() { 928 return value; 929 } 930 931 private static final long serialVersionUID = 5; 932 } 933 testMutableValues()934 public void testMutableValues() { 935 IntHolder holderA = new IntHolder(1); 936 IntHolder holderB = new IntHolder(2); 937 Map<String, IntHolder> map = ImmutableMap.of("a", holderA, "b", holderB); 938 holderA.value = 3; 939 assertTrue(map.entrySet().contains(Maps.immutableEntry("a", new IntHolder(3)))); 940 Map<String, Integer> intMap = ImmutableMap.of("a", 3, "b", 2); 941 assertEquals(intMap.hashCode(), map.entrySet().hashCode()); 942 assertEquals(intMap.hashCode(), map.hashCode()); 943 } 944 945 @GwtIncompatible // SerializableTester testViewSerialization()946 public void testViewSerialization() { 947 Map<String, Integer> map = ImmutableMap.of("one", 1, "two", 2, "three", 3); 948 LenientSerializableTester.reserializeAndAssertLenient(map.entrySet()); 949 LenientSerializableTester.reserializeAndAssertLenient(map.keySet()); 950 951 Collection<Integer> reserializedValues = reserialize(map.values()); 952 assertEquals(Lists.newArrayList(map.values()), Lists.newArrayList(reserializedValues)); 953 assertTrue(reserializedValues instanceof ImmutableCollection); 954 } 955 956 @GwtIncompatible // SerializableTester testKeySetIsSerializable_regularImmutableMap()957 public void testKeySetIsSerializable_regularImmutableMap() { 958 class NonSerializableClass {} 959 960 Map<String, NonSerializableClass> map = 961 RegularImmutableMap.create(1, new Object[] {"one", new NonSerializableClass()}); 962 Set<String> set = map.keySet(); 963 964 LenientSerializableTester.reserializeAndAssertLenient(set); 965 } 966 967 @GwtIncompatible // SerializableTester testValuesCollectionIsSerializable_regularImmutableMap()968 public void testValuesCollectionIsSerializable_regularImmutableMap() { 969 class NonSerializableClass {} 970 971 Map<NonSerializableClass, String> map = 972 RegularImmutableMap.create(1, new Object[] {new NonSerializableClass(), "value"}); 973 Collection<String> collection = map.values(); 974 975 LenientSerializableTester.reserializeAndAssertElementsEqual(collection); 976 } 977 978 // TODO: Re-enable this test after moving to new serialization format in ImmutableMap. 979 @GwtIncompatible // SerializableTester 980 @SuppressWarnings("unchecked") ignore_testSerializationNoDuplication_regularImmutableMap()981 public void ignore_testSerializationNoDuplication_regularImmutableMap() throws Exception { 982 // Tests that serializing a map, its keySet, and values only writes the underlying data once. 983 984 Object[] entries = new Object[2000]; 985 for (int i = 0; i < entries.length; i++) { 986 entries[i] = i; 987 } 988 989 ImmutableMap<Integer, Integer> map = RegularImmutableMap.create(entries.length / 2, entries); 990 Set<Integer> keySet = map.keySet(); 991 Collection<Integer> values = map.values(); 992 993 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 994 ObjectOutputStream oos = new ObjectOutputStream(bytes); 995 oos.writeObject(map); 996 oos.flush(); 997 998 int mapSize = bytes.size(); 999 oos.writeObject(keySet); 1000 oos.writeObject(values); 1001 oos.close(); 1002 1003 int finalSize = bytes.size(); 1004 1005 assertThat(finalSize - mapSize).isLessThan(100); 1006 } 1007 testEquals()1008 public void testEquals() { 1009 new EqualsTester() 1010 .addEqualityGroup( 1011 ImmutableMap.of(), 1012 ImmutableMap.builder().buildOrThrow(), 1013 ImmutableMap.ofEntries(), 1014 map()) 1015 .addEqualityGroup( 1016 ImmutableMap.of(1, 1), 1017 ImmutableMap.builder().put(1, 1).buildOrThrow(), 1018 ImmutableMap.ofEntries(entry(1, 1)), 1019 map(1, 1)) 1020 .addEqualityGroup( 1021 ImmutableMap.of(1, 1, 2, 2), 1022 ImmutableMap.builder().put(1, 1).put(2, 2).buildOrThrow(), 1023 ImmutableMap.ofEntries(entry(1, 1), entry(2, 2)), 1024 map(1, 1, 2, 2)) 1025 .addEqualityGroup( 1026 ImmutableMap.of(1, 1, 2, 2, 3, 3), 1027 ImmutableMap.builder().put(1, 1).put(2, 2).put(3, 3).buildOrThrow(), 1028 ImmutableMap.ofEntries(entry(1, 1), entry(2, 2), entry(3, 3)), 1029 map(1, 1, 2, 2, 3, 3)) 1030 .addEqualityGroup( 1031 ImmutableMap.of(1, 4, 2, 2, 3, 3), 1032 ImmutableMap.builder().put(1, 4).put(2, 2).put(3, 3).buildOrThrow(), 1033 ImmutableMap.ofEntries(entry(1, 4), entry(2, 2), entry(3, 3)), 1034 map(1, 4, 2, 2, 3, 3)) 1035 .addEqualityGroup( 1036 ImmutableMap.of(1, 1, 2, 4, 3, 3), 1037 ImmutableMap.builder().put(1, 1).put(2, 4).put(3, 3).buildOrThrow(), 1038 ImmutableMap.ofEntries(entry(1, 1), entry(2, 4), entry(3, 3)), 1039 map(1, 1, 2, 4, 3, 3)) 1040 .addEqualityGroup( 1041 ImmutableMap.of(1, 1, 2, 2, 3, 4), 1042 ImmutableMap.builder().put(1, 1).put(2, 2).put(3, 4).buildOrThrow(), 1043 ImmutableMap.ofEntries(entry(1, 1), entry(2, 2), entry(3, 4)), 1044 map(1, 1, 2, 2, 3, 4)) 1045 .addEqualityGroup( 1046 ImmutableMap.of(1, 2, 2, 3, 3, 1), 1047 ImmutableMap.builder().put(1, 2).put(2, 3).put(3, 1).buildOrThrow(), 1048 ImmutableMap.ofEntries(entry(1, 2), entry(2, 3), entry(3, 1)), 1049 map(1, 2, 2, 3, 3, 1)) 1050 .addEqualityGroup( 1051 ImmutableMap.of(1, 1, 2, 2, 3, 3, 4, 4), 1052 ImmutableMap.builder().put(1, 1).put(2, 2).put(3, 3).put(4, 4).buildOrThrow(), 1053 ImmutableMap.ofEntries(entry(1, 1), entry(2, 2), entry(3, 3), entry(4, 4)), 1054 map(1, 1, 2, 2, 3, 3, 4, 4)) 1055 .addEqualityGroup( 1056 ImmutableMap.of(1, 1, 2, 2, 3, 3, 4, 4, 5, 5), 1057 ImmutableMap.builder().put(1, 1).put(2, 2).put(3, 3).put(4, 4).put(5, 5).buildOrThrow(), 1058 ImmutableMap.ofEntries(entry(1, 1), entry(2, 2), entry(3, 3), entry(4, 4), entry(5, 5)), 1059 map(1, 1, 2, 2, 3, 3, 4, 4, 5, 5)) 1060 .testEquals(); 1061 } 1062 testOfEntriesNull()1063 public void testOfEntriesNull() { 1064 Entry<Integer, Integer> nullKey = entry(null, 23); 1065 try { 1066 ImmutableMap.ofEntries(nullKey); 1067 fail(); 1068 } catch (NullPointerException expected) { 1069 } 1070 Entry<Integer, Integer> nullValue = entry(23, null); 1071 try { 1072 ImmutableMap.ofEntries(nullValue); 1073 fail(); 1074 } catch (NullPointerException expected) { 1075 } 1076 } 1077 map(T... keysAndValues)1078 private static <T> Map<T, T> map(T... keysAndValues) { 1079 assertThat(keysAndValues.length % 2).isEqualTo(0); 1080 LinkedHashMap<T, T> map = new LinkedHashMap<>(); 1081 for (int i = 0; i < keysAndValues.length; i += 2) { 1082 T key = keysAndValues[i]; 1083 T value = keysAndValues[i + 1]; 1084 T old = map.put(key, value); 1085 assertWithMessage("Key %s set to %s and %s", key, value, old).that(old).isNull(); 1086 } 1087 return map; 1088 } 1089 entry(T key, T value)1090 private static <T> Entry<T, T> entry(T key, T value) { 1091 return new AbstractMap.SimpleImmutableEntry<>(key, value); 1092 } 1093 testCopyOfMutableEntryList()1094 public void testCopyOfMutableEntryList() { 1095 List<Entry<String, String>> entryList = 1096 Arrays.asList( 1097 new AbstractMap.SimpleEntry<>("a", "1"), new AbstractMap.SimpleEntry<>("b", "2")); 1098 ImmutableMap<String, String> map = ImmutableMap.copyOf(entryList); 1099 assertThat(map).containsExactly("a", "1", "b", "2").inOrder(); 1100 entryList.get(0).setValue("3"); 1101 assertThat(map).containsExactly("a", "1", "b", "2").inOrder(); 1102 } 1103 testBuilderPutAllEntryList()1104 public void testBuilderPutAllEntryList() { 1105 List<Entry<String, String>> entryList = 1106 Arrays.asList( 1107 new AbstractMap.SimpleEntry<>("a", "1"), new AbstractMap.SimpleEntry<>("b", "2")); 1108 ImmutableMap<String, String> map = 1109 ImmutableMap.<String, String>builder().putAll(entryList).buildOrThrow(); 1110 assertThat(map).containsExactly("a", "1", "b", "2").inOrder(); 1111 entryList.get(0).setValue("3"); 1112 assertThat(map).containsExactly("a", "1", "b", "2").inOrder(); 1113 } 1114 } 1115