• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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