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 22 import com.google.common.annotations.GwtCompatible; 23 import com.google.common.annotations.GwtIncompatible; 24 import com.google.common.base.Joiner; 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.MapInterfaceTest; 29 import com.google.common.collect.testing.MapTestSuiteBuilder; 30 import com.google.common.collect.testing.MinimalSet; 31 import com.google.common.collect.testing.SampleElements.Colliders; 32 import com.google.common.collect.testing.SampleElements.Unhashables; 33 import com.google.common.collect.testing.UnhashableObject; 34 import com.google.common.collect.testing.features.CollectionFeature; 35 import com.google.common.collect.testing.features.CollectionSize; 36 import com.google.common.collect.testing.features.MapFeature; 37 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapCopyOfEntriesGenerator; 38 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapCopyOfEnumMapGenerator; 39 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapCopyOfGenerator; 40 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapEntryListGenerator; 41 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapGenerator; 42 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapKeyListGenerator; 43 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapUnhashableValuesGenerator; 44 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapValueListGenerator; 45 import com.google.common.collect.testing.google.MapGenerators.ImmutableMapValuesAsSingletonSetGenerator; 46 import com.google.common.testing.EqualsTester; 47 import com.google.common.testing.NullPointerTester; 48 import com.google.common.testing.SerializableTester; 49 import java.io.ByteArrayOutputStream; 50 import java.io.ObjectOutputStream; 51 import java.io.Serializable; 52 import java.util.Collection; 53 import java.util.Collections; 54 import java.util.LinkedHashMap; 55 import java.util.Map; 56 import java.util.Map.Entry; 57 import java.util.Set; 58 import junit.framework.Test; 59 import junit.framework.TestCase; 60 import junit.framework.TestSuite; 61 62 /** 63 * Tests for {@link ImmutableMap}. 64 * 65 * @author Kevin Bourrillion 66 * @author Jesse Wilson 67 */ 68 @GwtCompatible(emulated = true) 69 public class ImmutableMapTest extends TestCase { 70 71 @GwtIncompatible // suite suite()72 public static Test suite() { 73 TestSuite suite = new TestSuite(); 74 suite.addTestSuite(ImmutableMapTest.class); 75 76 suite.addTest( 77 MapTestSuiteBuilder.using(new ImmutableMapGenerator()) 78 .withFeatures( 79 CollectionSize.ANY, 80 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 81 CollectionFeature.KNOWN_ORDER, 82 MapFeature.REJECTS_DUPLICATES_AT_CREATION, 83 CollectionFeature.ALLOWS_NULL_QUERIES) 84 .named("ImmutableMap") 85 .createTestSuite()); 86 87 suite.addTest( 88 MapTestSuiteBuilder.using(new ImmutableMapCopyOfGenerator()) 89 .withFeatures( 90 CollectionSize.ANY, 91 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 92 CollectionFeature.KNOWN_ORDER, 93 CollectionFeature.ALLOWS_NULL_QUERIES) 94 .named("ImmutableMap.copyOf[Map]") 95 .createTestSuite()); 96 97 suite.addTest( 98 MapTestSuiteBuilder.using(new ImmutableMapCopyOfEntriesGenerator()) 99 .withFeatures( 100 CollectionSize.ANY, 101 MapFeature.REJECTS_DUPLICATES_AT_CREATION, 102 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 103 CollectionFeature.KNOWN_ORDER, 104 CollectionFeature.ALLOWS_NULL_QUERIES) 105 .named("ImmutableMap.copyOf[Iterable<Entry>]") 106 .createTestSuite()); 107 108 suite.addTest( 109 MapTestSuiteBuilder.using(new ImmutableMapCopyOfEnumMapGenerator()) 110 .withFeatures( 111 CollectionSize.ANY, 112 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 113 CollectionFeature.KNOWN_ORDER, 114 CollectionFeature.ALLOWS_NULL_QUERIES) 115 .named("ImmutableMap.copyOf[EnumMap]") 116 .createTestSuite()); 117 118 suite.addTest( 119 MapTestSuiteBuilder.using(new ImmutableMapValuesAsSingletonSetGenerator()) 120 .withFeatures( 121 CollectionSize.ANY, 122 MapFeature.REJECTS_DUPLICATES_AT_CREATION, 123 CollectionFeature.KNOWN_ORDER, 124 CollectionFeature.ALLOWS_NULL_QUERIES) 125 .named("ImmutableMap.asMultimap.asMap") 126 .createTestSuite()); 127 128 suite.addTest( 129 CollectionTestSuiteBuilder.using(new ImmutableMapUnhashableValuesGenerator()) 130 .withFeatures( 131 CollectionSize.ANY, 132 CollectionFeature.KNOWN_ORDER, 133 CollectionFeature.ALLOWS_NULL_QUERIES) 134 .named("ImmutableMap.values, unhashable") 135 .createTestSuite()); 136 137 suite.addTest( 138 ListTestSuiteBuilder.using(new ImmutableMapKeyListGenerator()) 139 .named("ImmutableMap.keySet.asList") 140 .withFeatures( 141 CollectionSize.ANY, 142 CollectionFeature.SERIALIZABLE, 143 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 144 CollectionFeature.ALLOWS_NULL_QUERIES) 145 .createTestSuite()); 146 147 suite.addTest( 148 ListTestSuiteBuilder.using(new ImmutableMapEntryListGenerator()) 149 .named("ImmutableMap.entrySet.asList") 150 .withFeatures( 151 CollectionSize.ANY, 152 CollectionFeature.SERIALIZABLE, 153 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 154 CollectionFeature.ALLOWS_NULL_QUERIES) 155 .createTestSuite()); 156 157 suite.addTest( 158 ListTestSuiteBuilder.using(new ImmutableMapValueListGenerator()) 159 .named("ImmutableMap.values.asList") 160 .withFeatures( 161 CollectionSize.ANY, 162 CollectionFeature.SERIALIZABLE, 163 CollectionFeature.ALLOWS_NULL_QUERIES) 164 .createTestSuite()); 165 166 return suite; 167 } 168 169 public abstract static class AbstractMapTests<K, V> extends MapInterfaceTest<K, V> { AbstractMapTests()170 public AbstractMapTests() { 171 super(false, false, false, false, false); 172 } 173 174 @Override makeEmptyMap()175 protected Map<K, V> makeEmptyMap() { 176 throw new UnsupportedOperationException(); 177 } 178 179 private static final Joiner joiner = Joiner.on(", "); 180 181 @Override assertMoreInvariants(Map<K, V> map)182 protected void assertMoreInvariants(Map<K, V> map) { 183 // TODO: can these be moved to MapInterfaceTest? 184 for (Entry<K, V> entry : map.entrySet()) { 185 assertEquals(entry.getKey() + "=" + entry.getValue(), entry.toString()); 186 } 187 188 assertEquals("{" + joiner.join(map.entrySet()) + "}", map.toString()); 189 assertEquals("[" + joiner.join(map.entrySet()) + "]", map.entrySet().toString()); 190 assertEquals("[" + joiner.join(map.keySet()) + "]", map.keySet().toString()); 191 assertEquals("[" + joiner.join(map.values()) + "]", map.values().toString()); 192 193 assertEquals(MinimalSet.from(map.entrySet()), map.entrySet()); 194 assertEquals(Sets.newHashSet(map.keySet()), map.keySet()); 195 } 196 } 197 198 public static class MapTests extends AbstractMapTests<String, Integer> { 199 @Override makeEmptyMap()200 protected Map<String, Integer> makeEmptyMap() { 201 return ImmutableMap.of(); 202 } 203 204 @Override makePopulatedMap()205 protected Map<String, Integer> makePopulatedMap() { 206 return ImmutableMap.of("one", 1, "two", 2, "three", 3); 207 } 208 209 @Override getKeyNotInPopulatedMap()210 protected String getKeyNotInPopulatedMap() { 211 return "minus one"; 212 } 213 214 @Override getValueNotInPopulatedMap()215 protected Integer getValueNotInPopulatedMap() { 216 return -1; 217 } 218 } 219 220 public static class SingletonMapTests extends AbstractMapTests<String, Integer> { 221 @Override makePopulatedMap()222 protected Map<String, Integer> makePopulatedMap() { 223 return ImmutableMap.of("one", 1); 224 } 225 226 @Override getKeyNotInPopulatedMap()227 protected String getKeyNotInPopulatedMap() { 228 return "minus one"; 229 } 230 231 @Override getValueNotInPopulatedMap()232 protected Integer getValueNotInPopulatedMap() { 233 return -1; 234 } 235 } 236 237 @GwtIncompatible // SerializableTester 238 public static class ReserializedMapTests extends AbstractMapTests<String, Integer> { 239 @Override makePopulatedMap()240 protected Map<String, Integer> makePopulatedMap() { 241 return SerializableTester.reserialize(ImmutableMap.of("one", 1, "two", 2, "three", 3)); 242 } 243 244 @Override getKeyNotInPopulatedMap()245 protected String getKeyNotInPopulatedMap() { 246 return "minus one"; 247 } 248 249 @Override getValueNotInPopulatedMap()250 protected Integer getValueNotInPopulatedMap() { 251 return -1; 252 } 253 } 254 255 public static class MapTestsWithBadHashes extends AbstractMapTests<Object, Integer> { 256 257 @Override makeEmptyMap()258 protected Map<Object, Integer> makeEmptyMap() { 259 throw new UnsupportedOperationException(); 260 } 261 262 @Override makePopulatedMap()263 protected Map<Object, Integer> makePopulatedMap() { 264 Colliders colliders = new Colliders(); 265 return ImmutableMap.of( 266 colliders.e0(), 0, 267 colliders.e1(), 1, 268 colliders.e2(), 2, 269 colliders.e3(), 3); 270 } 271 272 @Override getKeyNotInPopulatedMap()273 protected Object getKeyNotInPopulatedMap() { 274 return new Colliders().e4(); 275 } 276 277 @Override getValueNotInPopulatedMap()278 protected Integer getValueNotInPopulatedMap() { 279 return 4; 280 } 281 } 282 283 @GwtIncompatible // GWT's ImmutableMap emulation is backed by java.util.HashMap. 284 public static class MapTestsWithUnhashableValues 285 extends AbstractMapTests<Integer, UnhashableObject> { 286 @Override makeEmptyMap()287 protected Map<Integer, UnhashableObject> makeEmptyMap() { 288 return ImmutableMap.of(); 289 } 290 291 @Override makePopulatedMap()292 protected Map<Integer, UnhashableObject> makePopulatedMap() { 293 Unhashables unhashables = new Unhashables(); 294 return ImmutableMap.of(0, unhashables.e0(), 1, unhashables.e1(), 2, unhashables.e2()); 295 } 296 297 @Override getKeyNotInPopulatedMap()298 protected Integer getKeyNotInPopulatedMap() { 299 return 3; 300 } 301 302 @Override getValueNotInPopulatedMap()303 protected UnhashableObject getValueNotInPopulatedMap() { 304 return new Unhashables().e3(); 305 } 306 } 307 308 @GwtIncompatible // GWT's ImmutableMap emulation is backed by java.util.HashMap. 309 public static class MapTestsWithSingletonUnhashableValue extends MapTestsWithUnhashableValues { 310 @Override makePopulatedMap()311 protected Map<Integer, UnhashableObject> makePopulatedMap() { 312 Unhashables unhashables = new Unhashables(); 313 return ImmutableMap.of(0, unhashables.e0()); 314 } 315 } 316 317 public static class CreationTests extends TestCase { testEmptyBuilder()318 public void testEmptyBuilder() { 319 ImmutableMap<String, Integer> map = new Builder<String, Integer>().build(); 320 assertEquals(Collections.<String, Integer>emptyMap(), map); 321 } 322 testSingletonBuilder()323 public void testSingletonBuilder() { 324 ImmutableMap<String, Integer> map = new Builder<String, Integer>().put("one", 1).build(); 325 assertMapEquals(map, "one", 1); 326 } 327 testBuilder()328 public void testBuilder() { 329 ImmutableMap<String, Integer> map = 330 new Builder<String, Integer>() 331 .put("one", 1) 332 .put("two", 2) 333 .put("three", 3) 334 .put("four", 4) 335 .put("five", 5) 336 .build(); 337 assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 338 } 339 340 @GwtIncompatible testBuilderExactlySizedReusesArray()341 public void testBuilderExactlySizedReusesArray() { 342 ImmutableMap.Builder<Integer, Integer> builder = ImmutableMap.builderWithExpectedSize(10); 343 Object[] builderArray = builder.alternatingKeysAndValues; 344 for (int i = 0; i < 10; i++) { 345 builder.put(i, i); 346 } 347 Object[] builderArrayAfterPuts = builder.alternatingKeysAndValues; 348 RegularImmutableMap<Integer, Integer> map = 349 (RegularImmutableMap<Integer, Integer>) builder.build(); 350 Object[] mapInternalArray = map.alternatingKeysAndValues; 351 assertSame(builderArray, builderArrayAfterPuts); 352 assertSame(builderArray, mapInternalArray); 353 } 354 testBuilder_orderEntriesByValue()355 public void testBuilder_orderEntriesByValue() { 356 ImmutableMap<String, Integer> map = 357 new Builder<String, Integer>() 358 .orderEntriesByValue(Ordering.natural()) 359 .put("three", 3) 360 .put("one", 1) 361 .put("five", 5) 362 .put("four", 4) 363 .put("two", 2) 364 .build(); 365 assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 366 } 367 testBuilder_orderEntriesByValueAfterExactSizeBuild()368 public void testBuilder_orderEntriesByValueAfterExactSizeBuild() { 369 Builder<String, Integer> builder = 370 new Builder<String, Integer>(2).put("four", 4).put("one", 1); 371 ImmutableMap<String, Integer> keyOrdered = builder.build(); 372 ImmutableMap<String, Integer> valueOrdered = 373 builder.orderEntriesByValue(Ordering.natural()).build(); 374 assertMapEquals(keyOrdered, "four", 4, "one", 1); 375 assertMapEquals(valueOrdered, "one", 1, "four", 4); 376 } 377 testBuilder_orderEntriesByValue_usedTwiceFails()378 public void testBuilder_orderEntriesByValue_usedTwiceFails() { 379 ImmutableMap.Builder<String, Integer> builder = 380 new Builder<String, Integer>().orderEntriesByValue(Ordering.natural()); 381 try { 382 builder.orderEntriesByValue(Ordering.natural()); 383 fail("Expected IllegalStateException"); 384 } catch (IllegalStateException expected) { 385 } 386 } 387 testBuilder_withImmutableEntry()388 public void testBuilder_withImmutableEntry() { 389 ImmutableMap<String, Integer> map = 390 new Builder<String, Integer>().put(Maps.immutableEntry("one", 1)).build(); 391 assertMapEquals(map, "one", 1); 392 } 393 testBuilder_withImmutableEntryAndNullContents()394 public void testBuilder_withImmutableEntryAndNullContents() { 395 Builder<String, Integer> builder = new Builder<>(); 396 try { 397 builder.put(Maps.immutableEntry("one", (Integer) null)); 398 fail(); 399 } catch (NullPointerException expected) { 400 } 401 try { 402 builder.put(Maps.immutableEntry((String) null, 1)); 403 fail(); 404 } catch (NullPointerException expected) { 405 } 406 } 407 408 private static class StringHolder { 409 String string; 410 } 411 testBuilder_withMutableEntry()412 public void testBuilder_withMutableEntry() { 413 ImmutableMap.Builder<String, Integer> builder = new Builder<>(); 414 final StringHolder holder = new StringHolder(); 415 holder.string = "one"; 416 Entry<String, Integer> entry = 417 new AbstractMapEntry<String, Integer>() { 418 @Override 419 public String getKey() { 420 return holder.string; 421 } 422 423 @Override 424 public Integer getValue() { 425 return 1; 426 } 427 }; 428 429 builder.put(entry); 430 holder.string = "two"; 431 assertMapEquals(builder.build(), "one", 1); 432 } 433 testBuilderPutAllWithEmptyMap()434 public void testBuilderPutAllWithEmptyMap() { 435 ImmutableMap<String, Integer> map = 436 new Builder<String, Integer>().putAll(Collections.<String, Integer>emptyMap()).build(); 437 assertEquals(Collections.<String, Integer>emptyMap(), map); 438 } 439 testBuilderPutAll()440 public void testBuilderPutAll() { 441 Map<String, Integer> toPut = new LinkedHashMap<>(); 442 toPut.put("one", 1); 443 toPut.put("two", 2); 444 toPut.put("three", 3); 445 Map<String, Integer> moreToPut = new LinkedHashMap<>(); 446 moreToPut.put("four", 4); 447 moreToPut.put("five", 5); 448 449 ImmutableMap<String, Integer> map = 450 new Builder<String, Integer>().putAll(toPut).putAll(moreToPut).build(); 451 assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 452 } 453 testBuilderReuse()454 public void testBuilderReuse() { 455 Builder<String, Integer> builder = new Builder<>(); 456 ImmutableMap<String, Integer> mapOne = builder.put("one", 1).put("two", 2).build(); 457 ImmutableMap<String, Integer> mapTwo = builder.put("three", 3).put("four", 4).build(); 458 459 assertMapEquals(mapOne, "one", 1, "two", 2); 460 assertMapEquals(mapTwo, "one", 1, "two", 2, "three", 3, "four", 4); 461 } 462 testBuilderPutNullKeyFailsAtomically()463 public void testBuilderPutNullKeyFailsAtomically() { 464 Builder<String, Integer> builder = new Builder<>(); 465 try { 466 builder.put(null, 1); 467 fail(); 468 } catch (NullPointerException expected) { 469 } 470 builder.put("foo", 2); 471 assertMapEquals(builder.build(), "foo", 2); 472 } 473 testBuilderPutImmutableEntryWithNullKeyFailsAtomically()474 public void testBuilderPutImmutableEntryWithNullKeyFailsAtomically() { 475 Builder<String, Integer> builder = new Builder<>(); 476 try { 477 builder.put(Maps.immutableEntry((String) null, 1)); 478 fail(); 479 } catch (NullPointerException expected) { 480 } 481 builder.put("foo", 2); 482 assertMapEquals(builder.build(), "foo", 2); 483 } 484 485 // for GWT compatibility 486 static class SimpleEntry<K, V> extends AbstractMapEntry<K, V> { 487 public K key; 488 public V value; 489 SimpleEntry(K key, V value)490 SimpleEntry(K key, V value) { 491 this.key = key; 492 this.value = value; 493 } 494 495 @Override getKey()496 public K getKey() { 497 return key; 498 } 499 500 @Override getValue()501 public V getValue() { 502 return value; 503 } 504 } 505 testBuilderPutMutableEntryWithNullKeyFailsAtomically()506 public void testBuilderPutMutableEntryWithNullKeyFailsAtomically() { 507 Builder<String, Integer> builder = new Builder<>(); 508 try { 509 builder.put(new SimpleEntry<String, Integer>(null, 1)); 510 fail(); 511 } catch (NullPointerException expected) { 512 } 513 builder.put("foo", 2); 514 assertMapEquals(builder.build(), "foo", 2); 515 } 516 testBuilderPutNullKey()517 public void testBuilderPutNullKey() { 518 Builder<String, Integer> builder = new Builder<>(); 519 try { 520 builder.put(null, 1); 521 fail(); 522 } catch (NullPointerException expected) { 523 } 524 } 525 testBuilderPutNullValue()526 public void testBuilderPutNullValue() { 527 Builder<String, Integer> builder = new Builder<>(); 528 try { 529 builder.put("one", null); 530 fail(); 531 } catch (NullPointerException expected) { 532 } 533 } 534 testBuilderPutNullKeyViaPutAll()535 public void testBuilderPutNullKeyViaPutAll() { 536 Builder<String, Integer> builder = new Builder<>(); 537 try { 538 builder.putAll(Collections.<String, Integer>singletonMap(null, 1)); 539 fail(); 540 } catch (NullPointerException expected) { 541 } 542 } 543 testBuilderPutNullValueViaPutAll()544 public void testBuilderPutNullValueViaPutAll() { 545 Builder<String, Integer> builder = new Builder<>(); 546 try { 547 builder.putAll(Collections.<String, Integer>singletonMap("one", null)); 548 fail(); 549 } catch (NullPointerException expected) { 550 } 551 } 552 testPuttingTheSameKeyTwiceThrowsOnBuild()553 public void testPuttingTheSameKeyTwiceThrowsOnBuild() { 554 Builder<String, Integer> builder = 555 new Builder<String, Integer>() 556 .put("one", 1) 557 .put("one", 1); // throwing on this line would be even better 558 559 try { 560 builder.build(); 561 fail(); 562 } catch (IllegalArgumentException expected) { 563 } 564 } 565 testOf()566 public void testOf() { 567 assertMapEquals(ImmutableMap.of("one", 1), "one", 1); 568 assertMapEquals(ImmutableMap.of("one", 1, "two", 2), "one", 1, "two", 2); 569 assertMapEquals( 570 ImmutableMap.of("one", 1, "two", 2, "three", 3), "one", 1, "two", 2, "three", 3); 571 assertMapEquals( 572 ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4), 573 "one", 574 1, 575 "two", 576 2, 577 "three", 578 3, 579 "four", 580 4); 581 assertMapEquals( 582 ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4, "five", 5), 583 "one", 584 1, 585 "two", 586 2, 587 "three", 588 3, 589 "four", 590 4, 591 "five", 592 5); 593 } 594 testOfNullKey()595 public void testOfNullKey() { 596 try { 597 ImmutableMap.of(null, 1); 598 fail(); 599 } catch (NullPointerException expected) { 600 } 601 602 try { 603 ImmutableMap.of("one", 1, null, 2); 604 fail(); 605 } catch (NullPointerException expected) { 606 } 607 } 608 testOfNullValue()609 public void testOfNullValue() { 610 try { 611 ImmutableMap.of("one", null); 612 fail(); 613 } catch (NullPointerException expected) { 614 } 615 616 try { 617 ImmutableMap.of("one", 1, "two", null); 618 fail(); 619 } catch (NullPointerException expected) { 620 } 621 } 622 testOfWithDuplicateKey()623 public void testOfWithDuplicateKey() { 624 try { 625 ImmutableMap.of("one", 1, "one", 1); 626 fail(); 627 } catch (IllegalArgumentException expected) { 628 } 629 } 630 testCopyOfEmptyMap()631 public void testCopyOfEmptyMap() { 632 ImmutableMap<String, Integer> copy = 633 ImmutableMap.copyOf(Collections.<String, Integer>emptyMap()); 634 assertEquals(Collections.<String, Integer>emptyMap(), copy); 635 assertSame(copy, ImmutableMap.copyOf(copy)); 636 } 637 testCopyOfSingletonMap()638 public void testCopyOfSingletonMap() { 639 ImmutableMap<String, Integer> copy = ImmutableMap.copyOf(Collections.singletonMap("one", 1)); 640 assertMapEquals(copy, "one", 1); 641 assertSame(copy, ImmutableMap.copyOf(copy)); 642 } 643 testCopyOf()644 public void testCopyOf() { 645 Map<String, Integer> original = new LinkedHashMap<>(); 646 original.put("one", 1); 647 original.put("two", 2); 648 original.put("three", 3); 649 650 ImmutableMap<String, Integer> copy = ImmutableMap.copyOf(original); 651 assertMapEquals(copy, "one", 1, "two", 2, "three", 3); 652 assertSame(copy, ImmutableMap.copyOf(copy)); 653 } 654 hashtableTestHelper(ImmutableList<Integer> sizes)655 public static void hashtableTestHelper(ImmutableList<Integer> sizes) { 656 for (int size : sizes) { 657 Builder<Integer, Integer> builder = ImmutableMap.builderWithExpectedSize(size); 658 for (int i = 0; i < size; i++) { 659 Integer integer = i; 660 builder.put(integer, integer); 661 } 662 ImmutableMap<Integer, Integer> map = builder.build(); 663 assertEquals(size, map.size()); 664 int entries = 0; 665 for (Integer key : map.keySet()) { 666 assertEquals(entries, key.intValue()); 667 assertSame(key, map.get(key)); 668 entries++; 669 } 670 assertEquals(size, entries); 671 } 672 } 673 testByteArrayHashtable()674 public void testByteArrayHashtable() { 675 hashtableTestHelper(ImmutableList.of(2, 89)); 676 } 677 testShortArrayHashtable()678 public void testShortArrayHashtable() { 679 hashtableTestHelper(ImmutableList.of(90, 22937)); 680 } 681 testIntArrayHashtable()682 public void testIntArrayHashtable() { 683 hashtableTestHelper(ImmutableList.of(22938)); 684 } 685 } 686 testNullGet()687 public void testNullGet() { 688 ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1); 689 assertNull(map.get(null)); 690 } 691 testAsMultimap()692 public void testAsMultimap() { 693 ImmutableMap<String, Integer> map = 694 ImmutableMap.of("one", 1, "won", 1, "two", 2, "too", 2, "three", 3); 695 ImmutableSetMultimap<String, Integer> expected = 696 ImmutableSetMultimap.of("one", 1, "won", 1, "two", 2, "too", 2, "three", 3); 697 assertEquals(expected, map.asMultimap()); 698 } 699 testAsMultimapWhenEmpty()700 public void testAsMultimapWhenEmpty() { 701 ImmutableMap<String, Integer> map = ImmutableMap.of(); 702 ImmutableSetMultimap<String, Integer> expected = ImmutableSetMultimap.of(); 703 assertEquals(expected, map.asMultimap()); 704 } 705 testAsMultimapCaches()706 public void testAsMultimapCaches() { 707 ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1); 708 ImmutableSetMultimap<String, Integer> multimap1 = map.asMultimap(); 709 ImmutableSetMultimap<String, Integer> multimap2 = map.asMultimap(); 710 assertEquals(1, multimap1.asMap().size()); 711 assertSame(multimap1, multimap2); 712 } 713 714 @GwtIncompatible // NullPointerTester testNullPointers()715 public void testNullPointers() { 716 NullPointerTester tester = new NullPointerTester(); 717 tester.testAllPublicStaticMethods(ImmutableMap.class); 718 tester.testAllPublicInstanceMethods(new ImmutableMap.Builder<Object, Object>()); 719 tester.testAllPublicInstanceMethods(ImmutableMap.of()); 720 tester.testAllPublicInstanceMethods(ImmutableMap.of("one", 1)); 721 tester.testAllPublicInstanceMethods(ImmutableMap.of("one", 1, "two", 2, "three", 3)); 722 } 723 assertMapEquals(Map<K, V> map, Object... alternatingKeysAndValues)724 private static <K, V> void assertMapEquals(Map<K, V> map, Object... alternatingKeysAndValues) { 725 assertEquals(map.size(), alternatingKeysAndValues.length / 2); 726 int i = 0; 727 for (Entry<K, V> entry : map.entrySet()) { 728 assertEquals(alternatingKeysAndValues[i++], entry.getKey()); 729 assertEquals(alternatingKeysAndValues[i++], entry.getValue()); 730 } 731 } 732 733 private static class IntHolder implements Serializable { 734 public int value; 735 IntHolder(int value)736 public IntHolder(int value) { 737 this.value = value; 738 } 739 740 @Override equals(Object o)741 public boolean equals(Object o) { 742 return (o instanceof IntHolder) && ((IntHolder) o).value == value; 743 } 744 745 @Override hashCode()746 public int hashCode() { 747 return value; 748 } 749 750 private static final long serialVersionUID = 5; 751 } 752 testMutableValues()753 public void testMutableValues() { 754 IntHolder holderA = new IntHolder(1); 755 IntHolder holderB = new IntHolder(2); 756 Map<String, IntHolder> map = ImmutableMap.of("a", holderA, "b", holderB); 757 holderA.value = 3; 758 assertTrue(map.entrySet().contains(Maps.immutableEntry("a", new IntHolder(3)))); 759 Map<String, Integer> intMap = ImmutableMap.of("a", 3, "b", 2); 760 assertEquals(intMap.hashCode(), map.entrySet().hashCode()); 761 assertEquals(intMap.hashCode(), map.hashCode()); 762 } 763 764 @GwtIncompatible // SerializableTester testViewSerialization()765 public void testViewSerialization() { 766 Map<String, Integer> map = ImmutableMap.of("one", 1, "two", 2, "three", 3); 767 LenientSerializableTester.reserializeAndAssertLenient(map.entrySet()); 768 LenientSerializableTester.reserializeAndAssertLenient(map.keySet()); 769 770 Collection<Integer> reserializedValues = reserialize(map.values()); 771 assertEquals(Lists.newArrayList(map.values()), Lists.newArrayList(reserializedValues)); 772 assertTrue(reserializedValues instanceof ImmutableCollection); 773 } 774 775 @GwtIncompatible // SerializableTester testKeySetIsSerializable_regularImmutableMap()776 public void testKeySetIsSerializable_regularImmutableMap() { 777 class NonSerializableClass {} 778 779 Map<String, NonSerializableClass> map = 780 RegularImmutableMap.create(1, new Object[] {"one", new NonSerializableClass()}); 781 Set<String> set = map.keySet(); 782 783 LenientSerializableTester.reserializeAndAssertLenient(set); 784 } 785 786 @GwtIncompatible // SerializableTester testValuesCollectionIsSerializable_regularImmutableMap()787 public void testValuesCollectionIsSerializable_regularImmutableMap() { 788 class NonSerializableClass {} 789 790 Map<NonSerializableClass, String> map = 791 RegularImmutableMap.create(1, new Object[] {new NonSerializableClass(), "value"}); 792 Collection<String> collection = map.values(); 793 794 LenientSerializableTester.reserializeAndAssertElementsEqual(collection); 795 } 796 797 // TODO: Re-enable this test after moving to new serialization format in ImmutableMap. 798 @GwtIncompatible // SerializableTester 799 @SuppressWarnings("unchecked") ignore_testSerializationNoDuplication_regularImmutableMap()800 public void ignore_testSerializationNoDuplication_regularImmutableMap() throws Exception { 801 // Tests that searializing a map, its keySet, and values only writes the underlying data once. 802 803 Object[] entries = new Object[2000]; 804 for (int i = 0; i < entries.length; i++) { 805 entries[i] = i; 806 } 807 808 ImmutableMap<Integer, Integer> map = RegularImmutableMap.create(entries.length / 2, entries); 809 Set<Integer> keySet = map.keySet(); 810 Collection<Integer> values = map.values(); 811 812 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 813 ObjectOutputStream oos = new ObjectOutputStream(bytes); 814 oos.writeObject(map); 815 oos.flush(); 816 817 int mapSize = bytes.size(); 818 oos.writeObject(keySet); 819 oos.writeObject(values); 820 oos.close(); 821 822 int finalSize = bytes.size(); 823 824 assertThat(finalSize - mapSize).isLessThan(100); 825 } 826 testEquals()827 public void testEquals() { 828 new EqualsTester() 829 .addEqualityGroup(ImmutableMap.of(), ImmutableMap.builder().build()) 830 .addEqualityGroup(ImmutableMap.of(1, 1), ImmutableMap.builder().put(1, 1).build()) 831 .addEqualityGroup(ImmutableMap.of(1, 1, 2, 2)) 832 .addEqualityGroup(ImmutableMap.of(1, 1, 2, 2, 3, 3)) 833 .addEqualityGroup(ImmutableMap.of(1, 4, 2, 2, 3, 3)) 834 .addEqualityGroup(ImmutableMap.of(1, 1, 2, 4, 3, 3)) 835 .addEqualityGroup(ImmutableMap.of(1, 1, 2, 2, 3, 4)) 836 .addEqualityGroup(ImmutableMap.of(1, 2, 2, 3, 3, 1)) 837 .addEqualityGroup(ImmutableMap.of(1, 1, 2, 2, 3, 3, 4, 4)) 838 .testEquals(); 839 } 840 } 841