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