• 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.truth.Truth.assertThat;
20 
21 import com.google.common.annotations.GwtCompatible;
22 import com.google.common.annotations.GwtIncompatible;
23 import com.google.common.base.Joiner;
24 import com.google.common.collect.ImmutableBiMap.Builder;
25 import com.google.common.collect.testing.MapInterfaceTest;
26 import com.google.common.collect.testing.features.CollectionFeature;
27 import com.google.common.collect.testing.features.CollectionSize;
28 import com.google.common.collect.testing.features.MapFeature;
29 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapCopyOfEntriesGenerator;
30 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapCopyOfGenerator;
31 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapGenerator;
32 import com.google.common.collect.testing.google.BiMapInverseTester;
33 import com.google.common.collect.testing.google.BiMapTestSuiteBuilder;
34 import com.google.common.testing.SerializableTester;
35 import java.util.Collections;
36 import java.util.LinkedHashMap;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.Set;
40 import junit.framework.Test;
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43 
44 /**
45  * Tests for {@link ImmutableBiMap}.
46  *
47  * @author Jared Levy
48  */
49 @GwtCompatible(emulated = true)
50 public class ImmutableBiMapTest extends TestCase {
51 
52   // TODO: Reduce duplication of ImmutableMapTest code
53 
54   @GwtIncompatible // suite
suite()55   public static Test suite() {
56     TestSuite suite = new TestSuite();
57 
58     suite.addTestSuite(MapTests.class);
59     suite.addTestSuite(InverseMapTests.class);
60     suite.addTestSuite(CreationTests.class);
61     suite.addTestSuite(BiMapSpecificTests.class);
62 
63     suite.addTest(
64         BiMapTestSuiteBuilder.using(new ImmutableBiMapGenerator())
65             .named("ImmutableBiMap")
66             .withFeatures(
67                 CollectionSize.ANY,
68                 CollectionFeature.SERIALIZABLE,
69                 CollectionFeature.KNOWN_ORDER,
70                 MapFeature.REJECTS_DUPLICATES_AT_CREATION,
71                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
72             .suppressing(BiMapInverseTester.getInverseSameAfterSerializingMethods())
73             .createTestSuite());
74     suite.addTest(
75         BiMapTestSuiteBuilder.using(new ImmutableBiMapCopyOfGenerator())
76             .named("ImmutableBiMap.copyOf[Map]")
77             .withFeatures(
78                 CollectionSize.ANY,
79                 CollectionFeature.SERIALIZABLE,
80                 CollectionFeature.KNOWN_ORDER,
81                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
82             .suppressing(BiMapInverseTester.getInverseSameAfterSerializingMethods())
83             .createTestSuite());
84     suite.addTest(
85         BiMapTestSuiteBuilder.using(new ImmutableBiMapCopyOfEntriesGenerator())
86             .named("ImmutableBiMap.copyOf[Iterable<Entry>]")
87             .withFeatures(
88                 CollectionSize.ANY,
89                 CollectionFeature.SERIALIZABLE,
90                 CollectionFeature.KNOWN_ORDER,
91                 MapFeature.REJECTS_DUPLICATES_AT_CREATION,
92                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
93             .suppressing(BiMapInverseTester.getInverseSameAfterSerializingMethods())
94             .createTestSuite());
95 
96     return suite;
97   }
98 
99   public abstract static class AbstractMapTests<K, V> extends MapInterfaceTest<K, V> {
AbstractMapTests()100     public AbstractMapTests() {
101       super(false, false, false, false, false);
102     }
103 
104     @Override
makeEmptyMap()105     protected Map<K, V> makeEmptyMap() {
106       throw new UnsupportedOperationException();
107     }
108 
109     private static final Joiner joiner = Joiner.on(", ");
110 
111     @Override
assertMoreInvariants(Map<K, V> map)112     protected void assertMoreInvariants(Map<K, V> map) {
113 
114       BiMap<K, V> bimap = (BiMap<K, V>) map;
115 
116       for (Entry<K, V> entry : map.entrySet()) {
117         assertEquals(entry.getKey() + "=" + entry.getValue(), entry.toString());
118         assertEquals(entry.getKey(), bimap.inverse().get(entry.getValue()));
119       }
120 
121       assertEquals("{" + joiner.join(map.entrySet()) + "}", map.toString());
122       assertEquals("[" + joiner.join(map.entrySet()) + "]", map.entrySet().toString());
123       assertEquals("[" + joiner.join(map.keySet()) + "]", map.keySet().toString());
124       assertEquals("[" + joiner.join(map.values()) + "]", map.values().toString());
125 
126       assertEquals(Sets.newHashSet(map.entrySet()), map.entrySet());
127       assertEquals(Sets.newHashSet(map.keySet()), map.keySet());
128     }
129   }
130 
131   public static class MapTests extends AbstractMapTests<String, Integer> {
132     @Override
makeEmptyMap()133     protected Map<String, Integer> makeEmptyMap() {
134       return ImmutableBiMap.of();
135     }
136 
137     @Override
makePopulatedMap()138     protected Map<String, Integer> makePopulatedMap() {
139       return ImmutableBiMap.of("one", 1, "two", 2, "three", 3);
140     }
141 
142     @Override
getKeyNotInPopulatedMap()143     protected String getKeyNotInPopulatedMap() {
144       return "minus one";
145     }
146 
147     @Override
getValueNotInPopulatedMap()148     protected Integer getValueNotInPopulatedMap() {
149       return -1;
150     }
151   }
152 
153   public static class InverseMapTests extends AbstractMapTests<String, Integer> {
154     @Override
makeEmptyMap()155     protected Map<String, Integer> makeEmptyMap() {
156       return ImmutableBiMap.of();
157     }
158 
159     @Override
makePopulatedMap()160     protected Map<String, Integer> makePopulatedMap() {
161       return ImmutableBiMap.of(1, "one", 2, "two", 3, "three").inverse();
162     }
163 
164     @Override
getKeyNotInPopulatedMap()165     protected String getKeyNotInPopulatedMap() {
166       return "minus one";
167     }
168 
169     @Override
getValueNotInPopulatedMap()170     protected Integer getValueNotInPopulatedMap() {
171       return -1;
172     }
173   }
174 
175   public static class CreationTests extends TestCase {
testEmptyBuilder()176     public void testEmptyBuilder() {
177       ImmutableBiMap<String, Integer> map = new Builder<String, Integer>().build();
178       assertEquals(Collections.<String, Integer>emptyMap(), map);
179       assertEquals(Collections.<Integer, String>emptyMap(), map.inverse());
180       assertSame(ImmutableBiMap.of(), map);
181     }
182 
testSingletonBuilder()183     public void testSingletonBuilder() {
184       ImmutableBiMap<String, Integer> map = new Builder<String, Integer>().put("one", 1).build();
185       assertMapEquals(map, "one", 1);
186       assertMapEquals(map.inverse(), 1, "one");
187     }
188 
testBuilder_withImmutableEntry()189     public void testBuilder_withImmutableEntry() {
190       ImmutableBiMap<String, Integer> map =
191           new Builder<String, Integer>().put(Maps.immutableEntry("one", 1)).build();
192       assertMapEquals(map, "one", 1);
193     }
194 
testBuilder()195     public void testBuilder() {
196       ImmutableBiMap<String, Integer> map =
197           ImmutableBiMap.<String, Integer>builder()
198               .put("one", 1)
199               .put("two", 2)
200               .put("three", 3)
201               .put("four", 4)
202               .put("five", 5)
203               .build();
204       assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
205       assertMapEquals(map.inverse(), 1, "one", 2, "two", 3, "three", 4, "four", 5, "five");
206     }
207 
208     @GwtIncompatible
testBuilderExactlySizedReusesArray()209     public void testBuilderExactlySizedReusesArray() {
210       ImmutableBiMap.Builder<Integer, Integer> builder = ImmutableBiMap.builderWithExpectedSize(10);
211       Object[] builderArray = builder.alternatingKeysAndValues;
212       for (int i = 0; i < 10; i++) {
213         builder.put(i, i);
214       }
215       Object[] builderArrayAfterPuts = builder.alternatingKeysAndValues;
216       RegularImmutableBiMap<Integer, Integer> map =
217           (RegularImmutableBiMap<Integer, Integer>) builder.build();
218       Object[] mapInternalArray = map.alternatingKeysAndValues;
219       assertSame(builderArray, builderArrayAfterPuts);
220       assertSame(builderArray, mapInternalArray);
221     }
222 
testBuilder_orderEntriesByValue()223     public void testBuilder_orderEntriesByValue() {
224       ImmutableBiMap<String, Integer> map =
225           ImmutableBiMap.<String, Integer>builder()
226               .orderEntriesByValue(Ordering.natural())
227               .put("three", 3)
228               .put("one", 1)
229               .put("five", 5)
230               .put("four", 4)
231               .put("two", 2)
232               .build();
233       assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
234       assertMapEquals(map.inverse(), 1, "one", 2, "two", 3, "three", 4, "four", 5, "five");
235     }
236 
testBuilder_orderEntriesByValueAfterExactSizeBuild()237     public void testBuilder_orderEntriesByValueAfterExactSizeBuild() {
238       ImmutableBiMap.Builder<String, Integer> builder =
239           new ImmutableBiMap.Builder<String, Integer>(2).put("four", 4).put("one", 1);
240       ImmutableMap<String, Integer> keyOrdered = builder.build();
241       ImmutableMap<String, Integer> valueOrdered =
242           builder.orderEntriesByValue(Ordering.natural()).build();
243       assertMapEquals(keyOrdered, "four", 4, "one", 1);
244       assertMapEquals(valueOrdered, "one", 1, "four", 4);
245     }
246 
testBuilder_orderEntriesByValue_usedTwiceFails()247     public void testBuilder_orderEntriesByValue_usedTwiceFails() {
248       ImmutableBiMap.Builder<String, Integer> builder =
249           new Builder<String, Integer>().orderEntriesByValue(Ordering.natural());
250       try {
251         builder.orderEntriesByValue(Ordering.natural());
252         fail("Expected IllegalStateException");
253       } catch (IllegalStateException expected) {
254       }
255     }
256 
testBuilderPutAllWithEmptyMap()257     public void testBuilderPutAllWithEmptyMap() {
258       ImmutableBiMap<String, Integer> map =
259           new Builder<String, Integer>().putAll(Collections.<String, Integer>emptyMap()).build();
260       assertEquals(Collections.<String, Integer>emptyMap(), map);
261     }
262 
testBuilderPutAll()263     public void testBuilderPutAll() {
264       Map<String, Integer> toPut = new LinkedHashMap<>();
265       toPut.put("one", 1);
266       toPut.put("two", 2);
267       toPut.put("three", 3);
268       Map<String, Integer> moreToPut = new LinkedHashMap<>();
269       moreToPut.put("four", 4);
270       moreToPut.put("five", 5);
271 
272       ImmutableBiMap<String, Integer> map =
273           new Builder<String, Integer>().putAll(toPut).putAll(moreToPut).build();
274       assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
275       assertMapEquals(map.inverse(), 1, "one", 2, "two", 3, "three", 4, "four", 5, "five");
276     }
277 
testBuilderReuse()278     public void testBuilderReuse() {
279       Builder<String, Integer> builder = new Builder<>();
280       ImmutableBiMap<String, Integer> mapOne = builder.put("one", 1).put("two", 2).build();
281       ImmutableBiMap<String, Integer> mapTwo = builder.put("three", 3).put("four", 4).build();
282 
283       assertMapEquals(mapOne, "one", 1, "two", 2);
284       assertMapEquals(mapOne.inverse(), 1, "one", 2, "two");
285       assertMapEquals(mapTwo, "one", 1, "two", 2, "three", 3, "four", 4);
286       assertMapEquals(mapTwo.inverse(), 1, "one", 2, "two", 3, "three", 4, "four");
287     }
288 
testBuilderPutNullKey()289     public void testBuilderPutNullKey() {
290       Builder<String, Integer> builder = new Builder<>();
291       try {
292         builder.put(null, 1);
293         fail();
294       } catch (NullPointerException expected) {
295       }
296     }
297 
testBuilderPutNullValue()298     public void testBuilderPutNullValue() {
299       Builder<String, Integer> builder = new Builder<>();
300       try {
301         builder.put("one", null);
302         fail();
303       } catch (NullPointerException expected) {
304       }
305     }
306 
testBuilderPutNullKeyViaPutAll()307     public void testBuilderPutNullKeyViaPutAll() {
308       Builder<String, Integer> builder = new Builder<>();
309       try {
310         builder.putAll(Collections.<String, Integer>singletonMap(null, 1));
311         fail();
312       } catch (NullPointerException expected) {
313       }
314     }
315 
testBuilderPutNullValueViaPutAll()316     public void testBuilderPutNullValueViaPutAll() {
317       Builder<String, Integer> builder = new Builder<>();
318       try {
319         builder.putAll(Collections.<String, Integer>singletonMap("one", null));
320         fail();
321       } catch (NullPointerException expected) {
322       }
323     }
324 
testPuttingTheSameKeyTwiceThrowsOnBuild()325     public void testPuttingTheSameKeyTwiceThrowsOnBuild() {
326       Builder<String, Integer> builder =
327           new Builder<String, Integer>()
328               .put("one", 1)
329               .put("one", 1); // throwing on this line would be even better
330 
331       try {
332         builder.build();
333         fail();
334       } catch (IllegalArgumentException expected) {
335         assertThat(expected.getMessage()).contains("one");
336       }
337     }
338 
testOf()339     public void testOf() {
340       assertMapEquals(ImmutableBiMap.of("one", 1), "one", 1);
341       assertMapEquals(ImmutableBiMap.of("one", 1).inverse(), 1, "one");
342       assertMapEquals(ImmutableBiMap.of("one", 1, "two", 2), "one", 1, "two", 2);
343       assertMapEquals(ImmutableBiMap.of("one", 1, "two", 2).inverse(), 1, "one", 2, "two");
344       assertMapEquals(
345           ImmutableBiMap.of("one", 1, "two", 2, "three", 3), "one", 1, "two", 2, "three", 3);
346       assertMapEquals(
347           ImmutableBiMap.of("one", 1, "two", 2, "three", 3).inverse(),
348           1,
349           "one",
350           2,
351           "two",
352           3,
353           "three");
354       assertMapEquals(
355           ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4),
356           "one",
357           1,
358           "two",
359           2,
360           "three",
361           3,
362           "four",
363           4);
364       assertMapEquals(
365           ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4).inverse(),
366           1,
367           "one",
368           2,
369           "two",
370           3,
371           "three",
372           4,
373           "four");
374       assertMapEquals(
375           ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4, "five", 5),
376           "one",
377           1,
378           "two",
379           2,
380           "three",
381           3,
382           "four",
383           4,
384           "five",
385           5);
386       assertMapEquals(
387           ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4, "five", 5).inverse(),
388           1,
389           "one",
390           2,
391           "two",
392           3,
393           "three",
394           4,
395           "four",
396           5,
397           "five");
398     }
399 
testOfNullKey()400     public void testOfNullKey() {
401       try {
402         ImmutableBiMap.of(null, 1);
403         fail();
404       } catch (NullPointerException expected) {
405       }
406 
407       try {
408         ImmutableBiMap.of("one", 1, null, 2);
409         fail();
410       } catch (NullPointerException expected) {
411       }
412     }
413 
testOfNullValue()414     public void testOfNullValue() {
415       try {
416         ImmutableBiMap.of("one", null);
417         fail();
418       } catch (NullPointerException expected) {
419       }
420 
421       try {
422         ImmutableBiMap.of("one", 1, "two", null);
423         fail();
424       } catch (NullPointerException expected) {
425       }
426     }
427 
testOfWithDuplicateKey()428     public void testOfWithDuplicateKey() {
429       try {
430         ImmutableBiMap.of("one", 1, "one", 1);
431         fail();
432       } catch (IllegalArgumentException expected) {
433         assertThat(expected.getMessage()).contains("one");
434       }
435     }
436 
testCopyOfEmptyMap()437     public void testCopyOfEmptyMap() {
438       ImmutableBiMap<String, Integer> copy =
439           ImmutableBiMap.copyOf(Collections.<String, Integer>emptyMap());
440       assertEquals(Collections.<String, Integer>emptyMap(), copy);
441       assertSame(copy, ImmutableBiMap.copyOf(copy));
442       assertSame(ImmutableBiMap.of(), copy);
443     }
444 
testCopyOfSingletonMap()445     public void testCopyOfSingletonMap() {
446       ImmutableBiMap<String, Integer> copy =
447           ImmutableBiMap.copyOf(Collections.singletonMap("one", 1));
448       assertMapEquals(copy, "one", 1);
449       assertSame(copy, ImmutableBiMap.copyOf(copy));
450     }
451 
testCopyOf()452     public void testCopyOf() {
453       Map<String, Integer> original = new LinkedHashMap<>();
454       original.put("one", 1);
455       original.put("two", 2);
456       original.put("three", 3);
457 
458       ImmutableBiMap<String, Integer> copy = ImmutableBiMap.copyOf(original);
459       assertMapEquals(copy, "one", 1, "two", 2, "three", 3);
460       assertSame(copy, ImmutableBiMap.copyOf(copy));
461     }
462 
testEmpty()463     public void testEmpty() {
464       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.of();
465       assertEquals(Collections.<String, Integer>emptyMap(), bimap);
466       assertEquals(Collections.<String, Integer>emptyMap(), bimap.inverse());
467     }
468 
testFromHashMap()469     public void testFromHashMap() {
470       Map<String, Integer> hashMap = Maps.newLinkedHashMap();
471       hashMap.put("one", 1);
472       hashMap.put("two", 2);
473       ImmutableBiMap<String, Integer> bimap =
474           ImmutableBiMap.copyOf(ImmutableMap.of("one", 1, "two", 2));
475       assertMapEquals(bimap, "one", 1, "two", 2);
476       assertMapEquals(bimap.inverse(), 1, "one", 2, "two");
477     }
478 
testFromImmutableMap()479     public void testFromImmutableMap() {
480       ImmutableBiMap<String, Integer> bimap =
481           ImmutableBiMap.copyOf(
482               new ImmutableMap.Builder<String, Integer>()
483                   .put("one", 1)
484                   .put("two", 2)
485                   .put("three", 3)
486                   .put("four", 4)
487                   .put("five", 5)
488                   .build());
489       assertMapEquals(bimap, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
490       assertMapEquals(bimap.inverse(), 1, "one", 2, "two", 3, "three", 4, "four", 5, "five");
491     }
492 
testDuplicateValues()493     public void testDuplicateValues() {
494       ImmutableMap<String, Integer> map =
495           new ImmutableMap.Builder<String, Integer>()
496               .put("one", 1)
497               .put("two", 2)
498               .put("uno", 1)
499               .put("dos", 2)
500               .build();
501 
502       try {
503         ImmutableBiMap.copyOf(map);
504         fail();
505       } catch (IllegalArgumentException expected) {
506         assertThat(expected.getMessage()).contains("1");
507       }
508     }
509   }
510 
511   public static class BiMapSpecificTests extends TestCase {
512 
testForcePut()513     public void testForcePut() {
514       BiMap<String, Integer> bimap = ImmutableBiMap.copyOf(ImmutableMap.of("one", 1, "two", 2));
515       try {
516         bimap.forcePut("three", 3);
517         fail();
518       } catch (UnsupportedOperationException expected) {
519       }
520     }
521 
testKeySet()522     public void testKeySet() {
523       ImmutableBiMap<String, Integer> bimap =
524           ImmutableBiMap.copyOf(ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4));
525       Set<String> keys = bimap.keySet();
526       assertEquals(Sets.newHashSet("one", "two", "three", "four"), keys);
527       assertThat(keys).containsExactly("one", "two", "three", "four").inOrder();
528     }
529 
testValues()530     public void testValues() {
531       ImmutableBiMap<String, Integer> bimap =
532           ImmutableBiMap.copyOf(ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4));
533       Set<Integer> values = bimap.values();
534       assertEquals(Sets.newHashSet(1, 2, 3, 4), values);
535       assertThat(values).containsExactly(1, 2, 3, 4).inOrder();
536     }
537 
testDoubleInverse()538     public void testDoubleInverse() {
539       ImmutableBiMap<String, Integer> bimap =
540           ImmutableBiMap.copyOf(ImmutableMap.of("one", 1, "two", 2));
541       assertSame(bimap, bimap.inverse().inverse());
542     }
543 
544     @GwtIncompatible // SerializableTester
testEmptySerialization()545     public void testEmptySerialization() {
546       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.of();
547       assertSame(bimap, SerializableTester.reserializeAndAssert(bimap));
548     }
549 
550     @GwtIncompatible // SerializableTester
testSerialization()551     public void testSerialization() {
552       ImmutableBiMap<String, Integer> bimap =
553           ImmutableBiMap.copyOf(ImmutableMap.of("one", 1, "two", 2));
554       ImmutableBiMap<String, Integer> copy = SerializableTester.reserializeAndAssert(bimap);
555       assertEquals(Integer.valueOf(1), copy.get("one"));
556       assertEquals("one", copy.inverse().get(1));
557       assertSame(copy, copy.inverse().inverse());
558     }
559 
560     @GwtIncompatible // SerializableTester
testInverseSerialization()561     public void testInverseSerialization() {
562       ImmutableBiMap<String, Integer> bimap =
563           ImmutableBiMap.copyOf(ImmutableMap.of(1, "one", 2, "two")).inverse();
564       ImmutableBiMap<String, Integer> copy = SerializableTester.reserializeAndAssert(bimap);
565       assertEquals(Integer.valueOf(1), copy.get("one"));
566       assertEquals("one", copy.inverse().get(1));
567       assertSame(copy, copy.inverse().inverse());
568     }
569   }
570 
assertMapEquals(Map<K, V> map, Object... alternatingKeysAndValues)571   private static <K, V> void assertMapEquals(Map<K, V> map, Object... alternatingKeysAndValues) {
572     int i = 0;
573     for (Entry<K, V> entry : map.entrySet()) {
574       assertEquals(alternatingKeysAndValues[i++], entry.getKey());
575       assertEquals(alternatingKeysAndValues[i++], entry.getValue());
576     }
577   }
578 }
579