1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.base.Joiner;
21 import com.google.common.collect.ImmutableMap.Builder;
22 import com.google.common.collect.testing.AnEnum;
23 import com.google.common.collect.testing.MapInterfaceTest;
24 import com.google.common.collect.testing.MinimalSet;
25 import com.google.common.collect.testing.SampleElements.Colliders;
26 import com.google.common.testing.EqualsTester;
27
28 import junit.framework.TestCase;
29
30 import java.io.Serializable;
31 import java.util.Collections;
32 import java.util.EnumMap;
33 import java.util.LinkedHashMap;
34 import java.util.Map;
35 import java.util.Map.Entry;
36
37
38
39
40
41
42
43 @GwtCompatible(emulated = true)
44 public class ImmutableMapTest extends TestCase {
45
46 public abstract static class AbstractMapTests<K, V>
47 extends MapInterfaceTest<K, V> {
48 public AbstractMapTests() {
49 super(false, false, false, false, false);
50 }
51
52 @Override protected Map<K, V> makeEmptyMap() {
53 throw new UnsupportedOperationException();
54 }
55
56 private static final Joiner joiner = Joiner.on(", ");
57
58 @Override protected void assertMoreInvariants(Map<K, V> map) {
59
60 for (Entry<K, V> entry : map.entrySet()) {
61 assertEquals(entry.getKey() + "=" + entry.getValue(),
62 entry.toString());
63 }
64
65 assertEquals("{" + joiner.join(map.entrySet()) + "}",
66 map.toString());
67 assertEquals("[" + joiner.join(map.entrySet()) + "]",
68 map.entrySet().toString());
69 assertEquals("[" + joiner.join(map.keySet()) + "]",
70 map.keySet().toString());
71 assertEquals("[" + joiner.join(map.values()) + "]",
72 map.values().toString());
73
74 assertEquals(MinimalSet.from(map.entrySet()), map.entrySet());
75 assertEquals(Sets.newHashSet(map.keySet()), map.keySet());
76 }
77 }
78
79 public static class MapTests extends AbstractMapTests<String, Integer> {
80 @Override protected Map<String, Integer> makeEmptyMap() {
81 return ImmutableMap.of();
82 }
83
84 @Override protected Map<String, Integer> makePopulatedMap() {
85 return ImmutableMap.of("one", 1, "two", 2, "three", 3);
86 }
87
88 @Override protected String getKeyNotInPopulatedMap() {
89 return "minus one";
90 }
91
92 @Override protected Integer getValueNotInPopulatedMap() {
93 return -1;
94 }
95 }
96
97 public static class SingletonMapTests
98 extends AbstractMapTests<String, Integer> {
99 @Override protected Map<String, Integer> makePopulatedMap() {
100 return ImmutableMap.of("one", 1);
101 }
102
103 @Override protected String getKeyNotInPopulatedMap() {
104 return "minus one";
105 }
106
107 @Override protected Integer getValueNotInPopulatedMap() {
108 return -1;
109 }
110 }
111
112 public static class MapTestsWithBadHashes
113 extends AbstractMapTests<Object, Integer> {
114
115 @Override protected Map<Object, Integer> makeEmptyMap() {
116 throw new UnsupportedOperationException();
117 }
118
119 @Override protected Map<Object, Integer> makePopulatedMap() {
120 Colliders colliders = new Colliders();
121 return ImmutableMap.of(
122 colliders.e0, 0,
123 colliders.e1, 1,
124 colliders.e2, 2,
125 colliders.e3, 3);
126 }
127
128 @Override protected Object getKeyNotInPopulatedMap() {
129 return new Colliders().e4;
130 }
131
132 @Override protected Integer getValueNotInPopulatedMap() {
133 return 4;
134 }
135 }
136
137 public static class CreationTests extends TestCase {
138 public void testEmptyBuilder() {
139 ImmutableMap<String, Integer> map
140 = new Builder<String, Integer>().build();
141 assertEquals(Collections.<String, Integer>emptyMap(), map);
142 }
143
144 public void testSingletonBuilder() {
145 ImmutableMap<String, Integer> map = new Builder<String, Integer>()
146 .put("one", 1)
147 .build();
148 assertMapEquals(map, "one", 1);
149 }
150
151 public void testBuilder() {
152 ImmutableMap<String, Integer> map = new Builder<String, Integer>()
153 .put("one", 1)
154 .put("two", 2)
155 .put("three", 3)
156 .put("four", 4)
157 .put("five", 5)
158 .build();
159 assertMapEquals(map,
160 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
161 }
162
163 public void testBuilder_withImmutableEntry() {
164 ImmutableMap<String, Integer> map = new Builder<String, Integer>()
165 .put(Maps.immutableEntry("one", 1))
166 .build();
167 assertMapEquals(map, "one", 1);
168 }
169
170 public void testBuilder_withImmutableEntryAndNullContents() {
171 Builder<String, Integer> builder = new Builder<String, Integer>();
172 try {
173 builder.put(Maps.immutableEntry("one", (Integer) null));
174 fail();
175 } catch (NullPointerException expected) {
176 }
177 try {
178 builder.put(Maps.immutableEntry((String) null, 1));
179 fail();
180 } catch (NullPointerException expected) {
181 }
182 }
183
184 private static class StringHolder {
185 String string;
186 }
187
188 public void testBuilder_withMutableEntry() {
189 ImmutableMap.Builder<String, Integer> builder =
190 new Builder<String, Integer>();
191 final StringHolder holder = new StringHolder();
192 holder.string = "one";
193 Entry<String, Integer> entry = new AbstractMapEntry<String, Integer>() {
194 @Override public String getKey() {
195 return holder.string;
196 }
197 @Override public Integer getValue() {
198 return 1;
199 }
200 };
201
202 builder.put(entry);
203 holder.string = "two";
204 assertMapEquals(builder.build(), "one", 1);
205 }
206
207 public void testBuilderPutAllWithEmptyMap() {
208 ImmutableMap<String, Integer> map = new Builder<String, Integer>()
209 .putAll(Collections.<String, Integer>emptyMap())
210 .build();
211 assertEquals(Collections.<String, Integer>emptyMap(), map);
212 }
213
214 public void testBuilderPutAll() {
215 Map<String, Integer> toPut = new LinkedHashMap<String, Integer>();
216 toPut.put("one", 1);
217 toPut.put("two", 2);
218 toPut.put("three", 3);
219 Map<String, Integer> moreToPut = new LinkedHashMap<String, Integer>();
220 moreToPut.put("four", 4);
221 moreToPut.put("five", 5);
222
223 ImmutableMap<String, Integer> map = new Builder<String, Integer>()
224 .putAll(toPut)
225 .putAll(moreToPut)
226 .build();
227 assertMapEquals(map,
228 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
229 }
230
231 public void testBuilderReuse() {
232 Builder<String, Integer> builder = new Builder<String, Integer>();
233 ImmutableMap<String, Integer> mapOne = builder
234 .put("one", 1)
235 .put("two", 2)
236 .build();
237 ImmutableMap<String, Integer> mapTwo = builder
238 .put("three", 3)
239 .put("four", 4)
240 .build();
241
242 assertMapEquals(mapOne, "one", 1, "two", 2);
243 assertMapEquals(mapTwo, "one", 1, "two", 2, "three", 3, "four", 4);
244 }
245
246 public void testBuilderPutNullKeyFailsAtomically() {
247 Builder<String, Integer> builder = new Builder<String, Integer>();
248 try {
249 builder.put(null, 1);
250 fail();
251 } catch (NullPointerException expected) {}
252 builder.put("foo", 2);
253 assertMapEquals(builder.build(), "foo", 2);
254 }
255
256 public void testBuilderPutImmutableEntryWithNullKeyFailsAtomically() {
257 Builder<String, Integer> builder = new Builder<String, Integer>();
258 try {
259 builder.put(Maps.immutableEntry((String) null, 1));
260 fail();
261 } catch (NullPointerException expected) {}
262 builder.put("foo", 2);
263 assertMapEquals(builder.build(), "foo", 2);
264 }
265
266
267 static class SimpleEntry<K, V> extends AbstractMapEntry<K, V> {
268 public K key;
269 public V value;
270
271 SimpleEntry(K key, V value) {
272 this.key = key;
273 this.value = value;
274 }
275
276 @Override
277 public K getKey() {
278 return key;
279 }
280
281 @Override
282 public V getValue() {
283 return value;
284 }
285 }
286
287 public void testBuilderPutMutableEntryWithNullKeyFailsAtomically() {
288 Builder<String, Integer> builder = new Builder<String, Integer>();
289 try {
290 builder.put(new SimpleEntry<String, Integer>(null, 1));
291 fail();
292 } catch (NullPointerException expected) {}
293 builder.put("foo", 2);
294 assertMapEquals(builder.build(), "foo", 2);
295 }
296
297 public void testBuilderPutNullKey() {
298 Builder<String, Integer> builder = new Builder<String, Integer>();
299 try {
300 builder.put(null, 1);
301 fail();
302 } catch (NullPointerException expected) {
303 }
304 }
305
306 public void testBuilderPutNullValue() {
307 Builder<String, Integer> builder = new Builder<String, Integer>();
308 try {
309 builder.put("one", null);
310 fail();
311 } catch (NullPointerException expected) {
312 }
313 }
314
315 public void testBuilderPutNullKeyViaPutAll() {
316 Builder<String, Integer> builder = new Builder<String, Integer>();
317 try {
318 builder.putAll(Collections.<String, Integer>singletonMap(null, 1));
319 fail();
320 } catch (NullPointerException expected) {
321 }
322 }
323
324 public void testBuilderPutNullValueViaPutAll() {
325 Builder<String, Integer> builder = new Builder<String, Integer>();
326 try {
327 builder.putAll(Collections.<String, Integer>singletonMap("one", null));
328 fail();
329 } catch (NullPointerException expected) {
330 }
331 }
332
333 public void testPuttingTheSameKeyTwiceThrowsOnBuild() {
334 Builder<String, Integer> builder = new Builder<String, Integer>()
335 .put("one", 1)
336 .put("one", 1);
337
338 try {
339 builder.build();
340 fail();
341 } catch (IllegalArgumentException expected) {
342 }
343 }
344
345 public void testOf() {
346 assertMapEquals(
347 ImmutableMap.of("one", 1),
348 "one", 1);
349 assertMapEquals(
350 ImmutableMap.of("one", 1, "two", 2),
351 "one", 1, "two", 2);
352 assertMapEquals(
353 ImmutableMap.of("one", 1, "two", 2, "three", 3),
354 "one", 1, "two", 2, "three", 3);
355 assertMapEquals(
356 ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4),
357 "one", 1, "two", 2, "three", 3, "four", 4);
358 assertMapEquals(
359 ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4, "five", 5),
360 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
361 }
362
363 public void testOfNullKey() {
364 try {
365 ImmutableMap.of(null, 1);
366 fail();
367 } catch (NullPointerException expected) {
368 }
369
370 try {
371 ImmutableMap.of("one", 1, null, 2);
372 fail();
373 } catch (NullPointerException expected) {
374 }
375 }
376
377 public void testOfNullValue() {
378 try {
379 ImmutableMap.of("one", null);
380 fail();
381 } catch (NullPointerException expected) {
382 }
383
384 try {
385 ImmutableMap.of("one", 1, "two", null);
386 fail();
387 } catch (NullPointerException expected) {
388 }
389 }
390
391 public void testOfWithDuplicateKey() {
392 try {
393 ImmutableMap.of("one", 1, "one", 1);
394 fail();
395 } catch (IllegalArgumentException expected) {
396 }
397 }
398
399 public void testCopyOfEmptyMap() {
400 ImmutableMap<String, Integer> copy
401 = ImmutableMap.copyOf(Collections.<String, Integer>emptyMap());
402 assertEquals(Collections.<String, Integer>emptyMap(), copy);
403 assertSame(copy, ImmutableMap.copyOf(copy));
404 }
405
406 public void testCopyOfSingletonMap() {
407 ImmutableMap<String, Integer> copy
408 = ImmutableMap.copyOf(Collections.singletonMap("one", 1));
409 assertMapEquals(copy, "one", 1);
410 assertSame(copy, ImmutableMap.copyOf(copy));
411 }
412
413 public void testCopyOf() {
414 Map<String, Integer> original = new LinkedHashMap<String, Integer>();
415 original.put("one", 1);
416 original.put("two", 2);
417 original.put("three", 3);
418
419 ImmutableMap<String, Integer> copy = ImmutableMap.copyOf(original);
420 assertMapEquals(copy, "one", 1, "two", 2, "three", 3);
421 assertSame(copy, ImmutableMap.copyOf(copy));
422 }
423 }
424
425 public void testNullGet() {
426 ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1);
427 assertNull(map.get(null));
428 }
429
430 public void testAsMultimap() {
431 ImmutableMap<String, Integer> map = ImmutableMap.of(
432 "one", 1, "won", 1, "two", 2, "too", 2, "three", 3);
433 ImmutableSetMultimap<String, Integer> expected = ImmutableSetMultimap.of(
434 "one", 1, "won", 1, "two", 2, "too", 2, "three", 3);
435 assertEquals(expected, map.asMultimap());
436 }
437
438 public void testAsMultimapWhenEmpty() {
439 ImmutableMap<String, Integer> map = ImmutableMap.of();
440 ImmutableSetMultimap<String, Integer> expected = ImmutableSetMultimap.of();
441 assertEquals(expected, map.asMultimap());
442 }
443
444 public void testAsMultimapCaches() {
445 ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1);
446 ImmutableSetMultimap<String, Integer> multimap1 = map.asMultimap();
447 ImmutableSetMultimap<String, Integer> multimap2 = map.asMultimap();
448 assertEquals(1, multimap1.asMap().size());
449 assertSame(multimap1, multimap2);
450 }
451
452 private static <K, V> void assertMapEquals(Map<K, V> map,
453 Object... alternatingKeysAndValues) {
454 assertEquals(map.size(), alternatingKeysAndValues.length / 2);
455 int i = 0;
456 for (Entry<K, V> entry : map.entrySet()) {
457 assertEquals(alternatingKeysAndValues[i++], entry.getKey());
458 assertEquals(alternatingKeysAndValues[i++], entry.getValue());
459 }
460 }
461
462 private static class IntHolder implements Serializable {
463 public int value;
464
465 public IntHolder(int value) {
466 this.value = value;
467 }
468
469 @Override public boolean equals(Object o) {
470 return (o instanceof IntHolder) && ((IntHolder) o).value == value;
471 }
472
473 @Override public int hashCode() {
474 return value;
475 }
476
477 private static final long serialVersionUID = 5;
478 }
479
480 public void testMutableValues() {
481 IntHolder holderA = new IntHolder(1);
482 IntHolder holderB = new IntHolder(2);
483 Map<String, IntHolder> map = ImmutableMap.of("a", holderA, "b", holderB);
484 holderA.value = 3;
485 assertTrue(map.entrySet().contains(
486 Maps.immutableEntry("a", new IntHolder(3))));
487 Map<String, Integer> intMap = ImmutableMap.of("a", 3, "b", 2);
488 assertEquals(intMap.hashCode(), map.entrySet().hashCode());
489 assertEquals(intMap.hashCode(), map.hashCode());
490 }
491
492 public void testCopyOfEnumMap() {
493 EnumMap<AnEnum, String> map = new EnumMap<AnEnum, String>(AnEnum.class);
494 map.put(AnEnum.B, "foo");
495 map.put(AnEnum.C, "bar");
496 assertTrue(ImmutableMap.copyOf(map) instanceof ImmutableEnumMap);
497 }
498
499 public void testEquals() {
500 new EqualsTester()
501 .addEqualityGroup(ImmutableList.of(), ImmutableList.of())
502 .addEqualityGroup(ImmutableList.of(1), ImmutableList.of(1))
503 .addEqualityGroup(ImmutableList.of(1, 2), ImmutableList.of(1, 2))
504 .addEqualityGroup(ImmutableList.of(1, 2, 3))
505 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4))
506 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5))
507 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6))
508 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7))
509 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8))
510 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8, 9))
511 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
512 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11))
513 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))
514 .addEqualityGroup(ImmutableList.of(100, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))
515 .addEqualityGroup(ImmutableList.of(1, 200, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))
516 .addEqualityGroup(ImmutableList.of(1, 2, 300, 4, 5, 6, 7, 8, 9, 10, 11, 12))
517 .addEqualityGroup(ImmutableList.of(1, 2, 3, 400, 5, 6, 7, 8, 9, 10, 11, 12))
518 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 500, 6, 7, 8, 9, 10, 11, 12))
519 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 600, 7, 8, 9, 10, 11, 12))
520 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 700, 8, 9, 10, 11, 12))
521 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 800, 9, 10, 11, 12))
522 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8, 900, 10, 11, 12))
523 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 1000, 11, 12))
524 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1100, 12))
525 .addEqualityGroup(ImmutableList.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1200))
526 .testEquals();
527
528 }
529 }
530