View Javadoc
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.base.Joiner;
23  import com.google.common.collect.ImmutableBiMap.Builder;
24  import com.google.common.collect.testing.MapInterfaceTest;
25  
26  import junit.framework.TestCase;
27  
28  import java.util.Collections;
29  import java.util.LinkedHashMap;
30  import java.util.Map;
31  import java.util.Map.Entry;
32  import java.util.Set;
33  
34  /**
35   * Tests for {@link ImmutableBiMap}.
36   *
37   * @author Jared Levy
38   */
39  @GwtCompatible(emulated = true)
40  public class ImmutableBiMapTest extends TestCase {
41  
42    // TODO: Reduce duplication of ImmutableMapTest code
43  
44    public static abstract class AbstractMapTests<K, V>
45        extends MapInterfaceTest<K, V> {
46      public AbstractMapTests() {
47        super(false, false, false, false, false);
48      }
49  
50      @Override protected Map<K, V> makeEmptyMap() {
51        throw new UnsupportedOperationException();
52      }
53  
54      private static final Joiner joiner = Joiner.on(", ");
55  
56      @Override protected void assertMoreInvariants(Map<K, V> map) {
57  
58        BiMap<K, V> bimap = (BiMap<K, V>) map;
59  
60        for (Entry<K, V> entry : map.entrySet()) {
61          assertEquals(entry.getKey() + "=" + entry.getValue(),
62              entry.toString());
63          assertEquals(entry.getKey(), bimap.inverse().get(entry.getValue()));
64        }
65  
66        assertEquals("{" + joiner.join(map.entrySet()) + "}",
67            map.toString());
68        assertEquals("[" + joiner.join(map.entrySet()) + "]",
69            map.entrySet().toString());
70        assertEquals("[" + joiner.join(map.keySet()) + "]",
71            map.keySet().toString());
72        assertEquals("[" + joiner.join(map.values()) + "]",
73            map.values().toString());
74  
75        assertEquals(Sets.newHashSet(map.entrySet()), map.entrySet());
76        assertEquals(Sets.newHashSet(map.keySet()), map.keySet());
77      }
78    }
79  
80    public static class MapTests extends AbstractMapTests<String, Integer> {
81      @Override protected Map<String, Integer> makeEmptyMap() {
82        return ImmutableBiMap.of();
83      }
84  
85      @Override protected Map<String, Integer> makePopulatedMap() {
86        return ImmutableBiMap.of("one", 1, "two", 2, "three", 3);
87      }
88  
89      @Override protected String getKeyNotInPopulatedMap() {
90        return "minus one";
91      }
92  
93      @Override protected Integer getValueNotInPopulatedMap() {
94        return -1;
95      }
96    }
97  
98    public static class InverseMapTests
99        extends AbstractMapTests<String, Integer> {
100     @Override protected Map<String, Integer> makeEmptyMap() {
101       return ImmutableBiMap.of();
102     }
103 
104     @Override protected Map<String, Integer> makePopulatedMap() {
105       return ImmutableBiMap.of(1, "one", 2, "two", 3, "three").inverse();
106     }
107 
108     @Override protected String getKeyNotInPopulatedMap() {
109       return "minus one";
110     }
111 
112     @Override protected Integer getValueNotInPopulatedMap() {
113       return -1;
114     }
115   }
116 
117   public static class CreationTests extends TestCase {
118     public void testEmptyBuilder() {
119       ImmutableBiMap<String, Integer> map
120           = new Builder<String, Integer>().build();
121       assertEquals(Collections.<String, Integer>emptyMap(), map);
122       assertEquals(Collections.<Integer, String>emptyMap(), map.inverse());
123       assertSame(ImmutableBiMap.of(), map);
124     }
125 
126     public void testSingletonBuilder() {
127       ImmutableBiMap<String, Integer> map = new Builder<String, Integer>()
128           .put("one", 1)
129           .build();
130       assertMapEquals(map, "one", 1);
131       assertMapEquals(map.inverse(), 1, "one");
132     }
133 
134     public void testBuilder() {
135       ImmutableBiMap<String, Integer> map
136           = ImmutableBiMap.<String, Integer>builder()
137             .put("one", 1)
138             .put("two", 2)
139             .put("three", 3)
140             .put("four", 4)
141             .put("five", 5)
142             .build();
143       assertMapEquals(map,
144           "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
145       assertMapEquals(map.inverse(),
146           1, "one", 2, "two", 3, "three", 4, "four", 5, "five");
147     }
148 
149     public void testBuilderPutAllWithEmptyMap() {
150       ImmutableBiMap<String, Integer> map = new Builder<String, Integer>()
151           .putAll(Collections.<String, Integer>emptyMap())
152           .build();
153       assertEquals(Collections.<String, Integer>emptyMap(), map);
154     }
155 
156     public void testBuilderPutAll() {
157       Map<String, Integer> toPut = new LinkedHashMap<String, Integer>();
158       toPut.put("one", 1);
159       toPut.put("two", 2);
160       toPut.put("three", 3);
161       Map<String, Integer> moreToPut = new LinkedHashMap<String, Integer>();
162       moreToPut.put("four", 4);
163       moreToPut.put("five", 5);
164 
165       ImmutableBiMap<String, Integer> map = new Builder<String, Integer>()
166           .putAll(toPut)
167           .putAll(moreToPut)
168           .build();
169       assertMapEquals(map,
170           "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
171       assertMapEquals(map.inverse(),
172           1, "one", 2, "two", 3, "three", 4, "four", 5, "five");
173     }
174 
175     public void testBuilderReuse() {
176       Builder<String, Integer> builder = new Builder<String, Integer>();
177       ImmutableBiMap<String, Integer> mapOne = builder
178           .put("one", 1)
179           .put("two", 2)
180           .build();
181       ImmutableBiMap<String, Integer> mapTwo = builder
182           .put("three", 3)
183           .put("four", 4)
184           .build();
185 
186       assertMapEquals(mapOne, "one", 1, "two", 2);
187       assertMapEquals(mapOne.inverse(), 1, "one", 2, "two");
188       assertMapEquals(mapTwo, "one", 1, "two", 2, "three", 3, "four", 4);
189       assertMapEquals(mapTwo.inverse(),
190           1, "one", 2, "two", 3, "three", 4, "four");
191     }
192 
193     public void testBuilderPutNullKey() {
194       Builder<String, Integer> builder = new Builder<String, Integer>();
195       try {
196         builder.put(null, 1);
197         fail();
198       } catch (NullPointerException expected) {
199       }
200     }
201 
202     public void testBuilderPutNullValue() {
203       Builder<String, Integer> builder = new Builder<String, Integer>();
204       try {
205         builder.put("one", null);
206         fail();
207       } catch (NullPointerException expected) {
208       }
209     }
210 
211     public void testBuilderPutNullKeyViaPutAll() {
212       Builder<String, Integer> builder = new Builder<String, Integer>();
213       try {
214         builder.putAll(Collections.<String, Integer>singletonMap(null, 1));
215         fail();
216       } catch (NullPointerException expected) {
217       }
218     }
219 
220     public void testBuilderPutNullValueViaPutAll() {
221       Builder<String, Integer> builder = new Builder<String, Integer>();
222       try {
223         builder.putAll(Collections.<String, Integer>singletonMap("one", null));
224         fail();
225       } catch (NullPointerException expected) {
226       }
227     }
228 
229     public void testPuttingTheSameKeyTwiceThrowsOnBuild() {
230       Builder<String, Integer> builder = new Builder<String, Integer>()
231           .put("one", 1)
232           .put("one", 1); // throwing on this line would be even better
233 
234       try {
235         builder.build();
236         fail();
237       } catch (IllegalArgumentException expected) {
238         assertTrue(expected.getMessage().contains("one"));
239       }
240     }
241 
242     public void testOf() {
243       assertMapEquals(
244           ImmutableBiMap.of("one", 1),
245           "one", 1);
246       assertMapEquals(
247           ImmutableBiMap.of("one", 1).inverse(),
248           1, "one");
249       assertMapEquals(
250           ImmutableBiMap.of("one", 1, "two", 2),
251           "one", 1, "two", 2);
252       assertMapEquals(
253           ImmutableBiMap.of("one", 1, "two", 2).inverse(),
254           1, "one", 2, "two");
255       assertMapEquals(
256           ImmutableBiMap.of("one", 1, "two", 2, "three", 3),
257           "one", 1, "two", 2, "three", 3);
258       assertMapEquals(
259           ImmutableBiMap.of("one", 1, "two", 2, "three", 3).inverse(),
260           1, "one", 2, "two", 3, "three");
261       assertMapEquals(
262           ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4),
263           "one", 1, "two", 2, "three", 3, "four", 4);
264       assertMapEquals(
265           ImmutableBiMap.of(
266               "one", 1, "two", 2, "three", 3, "four", 4).inverse(),
267           1, "one", 2, "two", 3, "three", 4, "four");
268       assertMapEquals(
269           ImmutableBiMap.of(
270               "one", 1, "two", 2, "three", 3, "four", 4, "five", 5),
271           "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
272       assertMapEquals(
273           ImmutableBiMap.of(
274               "one", 1, "two", 2, "three", 3, "four", 4, "five", 5).inverse(),
275           1, "one", 2, "two", 3, "three", 4, "four", 5, "five");
276     }
277 
278     public void testOfNullKey() {
279       try {
280         ImmutableBiMap.of(null, 1);
281         fail();
282       } catch (NullPointerException expected) {
283       }
284 
285       try {
286         ImmutableBiMap.of("one", 1, null, 2);
287         fail();
288       } catch (NullPointerException expected) {
289       }
290     }
291 
292     public void testOfNullValue() {
293       try {
294         ImmutableBiMap.of("one", null);
295         fail();
296       } catch (NullPointerException expected) {
297       }
298 
299       try {
300         ImmutableBiMap.of("one", 1, "two", null);
301         fail();
302       } catch (NullPointerException expected) {
303       }
304     }
305 
306     public void testOfWithDuplicateKey() {
307       try {
308         ImmutableBiMap.of("one", 1, "one", 1);
309         fail();
310       } catch (IllegalArgumentException expected) {
311         assertTrue(expected.getMessage().contains("one"));
312       }
313     }
314 
315     public void testCopyOfEmptyMap() {
316       ImmutableBiMap<String, Integer> copy
317           = ImmutableBiMap.copyOf(Collections.<String, Integer>emptyMap());
318       assertEquals(Collections.<String, Integer>emptyMap(), copy);
319       assertSame(copy, ImmutableBiMap.copyOf(copy));
320       assertSame(ImmutableBiMap.of(), copy);
321     }
322 
323     public void testCopyOfSingletonMap() {
324       ImmutableBiMap<String, Integer> copy
325           = ImmutableBiMap.copyOf(Collections.singletonMap("one", 1));
326       assertMapEquals(copy, "one", 1);
327       assertSame(copy, ImmutableBiMap.copyOf(copy));
328     }
329 
330     public void testCopyOf() {
331       Map<String, Integer> original = new LinkedHashMap<String, Integer>();
332       original.put("one", 1);
333       original.put("two", 2);
334       original.put("three", 3);
335 
336       ImmutableBiMap<String, Integer> copy = ImmutableBiMap.copyOf(original);
337       assertMapEquals(copy, "one", 1, "two", 2, "three", 3);
338       assertSame(copy, ImmutableBiMap.copyOf(copy));
339     }
340 
341     public void testEmpty() {
342       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.of();
343       assertEquals(Collections.<String, Integer>emptyMap(), bimap);
344       assertEquals(Collections.<String, Integer>emptyMap(), bimap.inverse());
345     }
346 
347     public void testFromHashMap() {
348       Map<String, Integer> hashMap = Maps.newLinkedHashMap();
349       hashMap.put("one", 1);
350       hashMap.put("two", 2);
351       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf(
352           ImmutableMap.of("one", 1, "two", 2));
353       assertMapEquals(bimap, "one", 1, "two", 2);
354       assertMapEquals(bimap.inverse(), 1, "one", 2, "two");
355     }
356 
357     public void testFromImmutableMap() {
358       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf(
359           new ImmutableMap.Builder<String, Integer>()
360               .put("one", 1)
361               .put("two", 2)
362               .put("three", 3)
363               .put("four", 4)
364               .put("five", 5)
365               .build());
366       assertMapEquals(bimap,
367           "one", 1, "two", 2, "three", 3, "four", 4, "five", 5);
368       assertMapEquals(bimap.inverse(),
369           1, "one", 2, "two", 3, "three", 4, "four", 5, "five");
370     }
371 
372     public void testDuplicateValues() {
373       ImmutableMap<String, Integer> map
374           = new ImmutableMap.Builder<String, Integer>()
375               .put("one", 1)
376               .put("two", 2)
377               .put("uno", 1)
378               .put("dos", 2)
379               .build();
380 
381       try {
382         ImmutableBiMap.copyOf(map);
383         fail();
384       } catch (IllegalArgumentException expected) {
385         assertTrue(expected.getMessage().contains("1"));
386       }
387     }
388   }
389 
390   public static class BiMapSpecificTests extends TestCase {
391 
392     @SuppressWarnings("deprecation")
393     public void testForcePut() {
394       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf(
395           ImmutableMap.of("one", 1, "two", 2));
396       try {
397         bimap.forcePut("three", 3);
398         fail();
399       } catch (UnsupportedOperationException expected) {}
400     }
401 
402     public void testKeySet() {
403       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf(
404           ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4));
405       Set<String> keys = bimap.keySet();
406       assertEquals(Sets.newHashSet("one", "two", "three", "four"), keys);
407       assertThat(keys).has().exactly("one", "two", "three", "four").inOrder();
408     }
409 
410     public void testValues() {
411       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf(
412           ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4));
413       Set<Integer> values = bimap.values();
414       assertEquals(Sets.newHashSet(1, 2, 3, 4), values);
415       assertThat(values).has().exactly(1, 2, 3, 4).inOrder();
416     }
417 
418     public void testDoubleInverse() {
419       ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf(
420           ImmutableMap.of("one", 1, "two", 2));
421       assertSame(bimap, bimap.inverse().inverse());
422     }
423   }
424 
425   private static <K, V> void assertMapEquals(Map<K, V> map,
426       Object... alternatingKeysAndValues) {
427     int i = 0;
428     for (Entry<K, V> entry : map.entrySet()) {
429       assertEquals(alternatingKeysAndValues[i++], entry.getKey());
430       assertEquals(alternatingKeysAndValues[i++], entry.getValue());
431     }
432   }
433 }
434