View Javadoc
1   /*
2    * Copyright (C) 2007 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.collect.testing.Helpers.orderEntriesByKey;
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.collect.testing.Helpers;
25  import com.google.common.collect.testing.SampleElements;
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.BiMapTestSuiteBuilder;
30  import com.google.common.collect.testing.google.TestBiMapGenerator;
31  import com.google.common.testing.EqualsTester;
32  import com.google.common.testing.NullPointerTester;
33  import com.google.common.testing.SerializableTester;
34  
35  import junit.framework.Test;
36  import junit.framework.TestCase;
37  import junit.framework.TestSuite;
38  
39  import java.util.Collections;
40  import java.util.Iterator;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.Map.Entry;
44  import java.util.Set;
45  
46  /**
47   * Tests for {@code EnumBiMap}.
48   *
49   * @author Mike Bostock
50   * @author Jared Levy
51   */
52  @GwtCompatible(emulated = true)
53  public class EnumBiMapTest extends TestCase {
54    private enum Currency { DOLLAR, FRANC, PESO, POUND, YEN }
55    private enum Country { CANADA, CHILE, JAPAN, SWITZERLAND, UK }
56  
57    public static final class EnumBiMapGenerator implements TestBiMapGenerator<Country, Currency> {
58      @SuppressWarnings("unchecked")
59      @Override
60      public BiMap<Country, Currency> create(Object... entries) {
61        BiMap<Country, Currency> result = EnumBiMap.create(Country.class, Currency.class);
62        for (Object object : entries) {
63          Entry<Country, Currency> entry = (Entry<Country, Currency>) object;
64          result.put(entry.getKey(), entry.getValue());
65        }
66        return result;
67      }
68  
69      @Override
70      public SampleElements<Entry<Country, Currency>> samples() {
71        return new SampleElements<Entry<Country, Currency>>(
72            Helpers.mapEntry(Country.CANADA, Currency.DOLLAR),
73            Helpers.mapEntry(Country.CHILE, Currency.PESO),
74            Helpers.mapEntry(Country.UK, Currency.POUND),
75            Helpers.mapEntry(Country.JAPAN, Currency.YEN),
76            Helpers.mapEntry(Country.SWITZERLAND, Currency.FRANC));
77      }
78  
79      @SuppressWarnings("unchecked")
80      @Override
81      public Entry<Country, Currency>[] createArray(int length) {
82        return new Entry[length];
83      }
84  
85      @Override
86      public Iterable<Entry<Country, Currency>> order(List<Entry<Country, Currency>> insertionOrder) {
87        return orderEntriesByKey(insertionOrder);
88      }
89  
90      @Override
91      public Country[] createKeyArray(int length) {
92        return new Country[length];
93      }
94  
95      @Override
96      public Currency[] createValueArray(int length) {
97        return new Currency[length];
98      }
99    }
100 
101   @GwtIncompatible("suite")
102   public static Test suite() {
103     TestSuite suite = new TestSuite();
104     suite.addTest(BiMapTestSuiteBuilder.using(new EnumBiMapGenerator())
105         .named("EnumBiMap")
106         .withFeatures(CollectionSize.ANY,
107             CollectionFeature.SERIALIZABLE,
108             CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
109             MapFeature.GENERAL_PURPOSE,
110             CollectionFeature.KNOWN_ORDER)
111         .createTestSuite());
112     suite.addTestSuite(EnumBiMapTest.class);
113     return suite;
114   }
115 
116   public void testCreate() {
117     EnumBiMap<Currency, Country> bimap =
118         EnumBiMap.create(Currency.class, Country.class);
119     assertTrue(bimap.isEmpty());
120     assertEquals("{}", bimap.toString());
121     assertEquals(HashBiMap.create(), bimap);
122     bimap.put(Currency.DOLLAR, Country.CANADA);
123     assertEquals(Country.CANADA, bimap.get(Currency.DOLLAR));
124     assertEquals(Currency.DOLLAR, bimap.inverse().get(Country.CANADA));
125   }
126 
127   public void testCreateFromMap() {
128     /* Test with non-empty Map. */
129     Map<Currency, Country> map = ImmutableMap.of(
130         Currency.DOLLAR, Country.CANADA,
131         Currency.PESO, Country.CHILE,
132         Currency.FRANC, Country.SWITZERLAND);
133     EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map);
134     assertEquals(Country.CANADA, bimap.get(Currency.DOLLAR));
135     assertEquals(Currency.DOLLAR, bimap.inverse().get(Country.CANADA));
136 
137     /* Map must have at least one entry if not an EnumBiMap. */
138     try {
139       EnumBiMap.create(Collections.<Currency, Country>emptyMap());
140       fail("IllegalArgumentException expected");
141     } catch (IllegalArgumentException expected) {}
142     try {
143       EnumBiMap.create(
144           EnumHashBiMap.<Currency, Country>create(Currency.class));
145       fail("IllegalArgumentException expected");
146     } catch (IllegalArgumentException expected) {}
147 
148     /* Map can be empty if it's an EnumBiMap. */
149     Map<Currency, Country> emptyBimap =
150         EnumBiMap.create(Currency.class, Country.class);
151     bimap = EnumBiMap.create(emptyBimap);
152     assertTrue(bimap.isEmpty());
153   }
154 
155   public void testEnumBiMapConstructor() {
156     /* Test that it copies existing entries. */
157     EnumBiMap<Currency, Country> bimap1 =
158         EnumBiMap.create(Currency.class, Country.class);
159     bimap1.put(Currency.DOLLAR, Country.CANADA);
160     EnumBiMap<Currency, Country> bimap2 =
161         EnumBiMap.create(bimap1);
162     assertEquals(Country.CANADA, bimap2.get(Currency.DOLLAR));
163     assertEquals(bimap1, bimap2);
164     bimap2.inverse().put(Country.SWITZERLAND, Currency.FRANC);
165     assertEquals(Country.SWITZERLAND, bimap2.get(Currency.FRANC));
166     assertNull(bimap1.get(Currency.FRANC));
167     assertFalse(bimap2.equals(bimap1));
168 
169     /* Test that it can be empty. */
170     EnumBiMap<Currency, Country> emptyBimap =
171         EnumBiMap.create(Currency.class, Country.class);
172     EnumBiMap<Currency, Country> bimap3 =
173         EnumBiMap.create(emptyBimap);
174     assertEquals(bimap3, emptyBimap);
175   }
176 
177   public void testKeyType() {
178     EnumBiMap<Currency, Country> bimap =
179         EnumBiMap.create(Currency.class, Country.class);
180     assertEquals(Currency.class, bimap.keyType());
181   }
182 
183   public void testValueType() {
184     EnumBiMap<Currency, Country> bimap =
185         EnumBiMap.create(Currency.class, Country.class);
186     assertEquals(Country.class, bimap.valueType());
187   }
188 
189   public void testIterationOrder() {
190     // The enum orderings are alphabetical, leading to the bimap and its inverse
191     // having inconsistent iteration orderings.
192     Map<Currency, Country> map = ImmutableMap.of(
193         Currency.DOLLAR, Country.CANADA,
194         Currency.PESO, Country.CHILE,
195         Currency.FRANC, Country.SWITZERLAND);
196     EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map);
197 
198     // forward map ordered by currency
199     assertThat(bimap.keySet())
200         .has().exactly(Currency.DOLLAR, Currency.FRANC, Currency.PESO).inOrder();
201     // forward map ordered by currency (even for country values)
202     assertThat(bimap.values())
203         .has().exactly(Country.CANADA, Country.SWITZERLAND, Country.CHILE).inOrder();
204     // backward map ordered by country
205     assertThat(bimap.inverse().keySet())
206         .has().exactly(Country.CANADA, Country.CHILE, Country.SWITZERLAND).inOrder();
207     // backward map ordered by country (even for currency values)
208     assertThat(bimap.inverse().values())
209         .has().exactly(Currency.DOLLAR, Currency.PESO, Currency.FRANC).inOrder();
210   }
211 
212   public void testKeySetIteratorRemove() {
213     // The enum orderings are alphabetical, leading to the bimap and its inverse
214     // having inconsistent iteration orderings.
215     Map<Currency, Country> map = ImmutableMap.of(
216         Currency.DOLLAR, Country.CANADA,
217         Currency.PESO, Country.CHILE,
218         Currency.FRANC, Country.SWITZERLAND);
219     EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map);
220 
221     Iterator<Currency> iter = bimap.keySet().iterator();
222     assertEquals(Currency.DOLLAR, iter.next());
223     iter.remove();
224 
225     // forward map ordered by currency
226     assertThat(bimap.keySet())
227         .has().exactly(Currency.FRANC, Currency.PESO).inOrder();
228     // forward map ordered by currency (even for country values)
229     assertThat(bimap.values())
230         .has().exactly(Country.SWITZERLAND, Country.CHILE).inOrder();
231     // backward map ordered by country
232     assertThat(bimap.inverse().keySet())
233         .has().exactly(Country.CHILE, Country.SWITZERLAND).inOrder();
234     // backward map ordered by country (even for currency values)
235     assertThat(bimap.inverse().values())
236         .has().exactly(Currency.PESO, Currency.FRANC).inOrder();
237   }
238 
239   public void testValuesIteratorRemove() {
240     // The enum orderings are alphabetical, leading to the bimap and its inverse
241     // having inconsistent iteration orderings.
242     Map<Currency, Country> map = ImmutableMap.of(
243         Currency.DOLLAR, Country.CANADA,
244         Currency.PESO, Country.CHILE,
245         Currency.FRANC, Country.SWITZERLAND);
246     EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map);
247 
248     Iterator<Currency> iter = bimap.keySet().iterator();
249     assertEquals(Currency.DOLLAR, iter.next());
250     assertEquals(Currency.FRANC, iter.next());
251     iter.remove();
252 
253     // forward map ordered by currency
254     assertThat(bimap.keySet())
255         .has().exactly(Currency.DOLLAR, Currency.PESO).inOrder();
256     // forward map ordered by currency (even for country values)
257     assertThat(bimap.values())
258         .has().exactly(Country.CANADA, Country.CHILE).inOrder();
259     // backward map ordered by country
260     assertThat(bimap.inverse().keySet())
261         .has().exactly(Country.CANADA, Country.CHILE).inOrder();
262     // backward map ordered by country (even for currency values)
263     assertThat(bimap.inverse().values())
264         .has().exactly(Currency.DOLLAR, Currency.PESO).inOrder();
265   }
266 
267   public void testEntrySet() {
268     // Bug 3168290
269     Map<Currency, Country> map = ImmutableMap.of(
270         Currency.DOLLAR, Country.CANADA,
271         Currency.PESO, Country.CHILE,
272         Currency.FRANC, Country.SWITZERLAND);
273     EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map);
274     Set<Object> uniqueEntries = Sets.newIdentityHashSet();
275     uniqueEntries.addAll(bimap.entrySet());
276     assertEquals(3, uniqueEntries.size());
277   }
278 
279   @GwtIncompatible("serialization")
280   public void testSerializable() {
281     SerializableTester.reserializeAndAssert(
282         EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CANADA)));
283   }
284 
285   @GwtIncompatible("reflection")
286   public void testNulls() {
287     new NullPointerTester().testAllPublicStaticMethods(EnumBiMap.class);
288     new NullPointerTester()
289         .testAllPublicInstanceMethods(
290             EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CHILE)));
291   }
292 
293   public void testEquals() {
294     new EqualsTester()
295         .addEqualityGroup(
296             EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CANADA)),
297             EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CANADA)))
298         .addEqualityGroup(EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CHILE)))
299         .addEqualityGroup(EnumBiMap.create(ImmutableMap.of(Currency.FRANC, Country.CANADA)))
300         .testEquals();
301   }
302 
303   /* Remaining behavior tested by AbstractBiMapTest. */
304 }