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 org.truth0.Truth.ASSERT; 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 create(Object... entries)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 samples()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 createArray(int length)81 public Entry<Country, Currency>[] createArray(int length) { 82 return new Entry[length]; 83 } 84 85 @Override order(List<Entry<Country, Currency>> insertionOrder)86 public Iterable<Entry<Country, Currency>> order(List<Entry<Country, Currency>> insertionOrder) { 87 return orderEntriesByKey(insertionOrder); 88 } 89 90 @Override createKeyArray(int length)91 public Country[] createKeyArray(int length) { 92 return new Country[length]; 93 } 94 95 @Override createValueArray(int length)96 public Currency[] createValueArray(int length) { 97 return new Currency[length]; 98 } 99 } 100 101 @GwtIncompatible("suite") 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 testCreate()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 testCreateFromMap()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 testEnumBiMapConstructor()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 testKeyType()177 public void testKeyType() { 178 EnumBiMap<Currency, Country> bimap = 179 EnumBiMap.create(Currency.class, Country.class); 180 assertEquals(Currency.class, bimap.keyType()); 181 } 182 testValueType()183 public void testValueType() { 184 EnumBiMap<Currency, Country> bimap = 185 EnumBiMap.create(Currency.class, Country.class); 186 assertEquals(Country.class, bimap.valueType()); 187 } 188 testIterationOrder()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 ASSERT.that(bimap.keySet()) 200 .has().exactly(Currency.DOLLAR, Currency.FRANC, Currency.PESO).inOrder(); 201 // forward map ordered by currency (even for country values) 202 ASSERT.that(bimap.values()) 203 .has().exactly(Country.CANADA, Country.SWITZERLAND, Country.CHILE).inOrder(); 204 // backward map ordered by country 205 ASSERT.that(bimap.inverse().keySet()) 206 .has().exactly(Country.CANADA, Country.CHILE, Country.SWITZERLAND).inOrder(); 207 // backward map ordered by country (even for currency values) 208 ASSERT.that(bimap.inverse().values()) 209 .has().exactly(Currency.DOLLAR, Currency.PESO, Currency.FRANC).inOrder(); 210 } 211 testKeySetIteratorRemove()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 ASSERT.that(bimap.keySet()) 227 .has().exactly(Currency.FRANC, Currency.PESO).inOrder(); 228 // forward map ordered by currency (even for country values) 229 ASSERT.that(bimap.values()) 230 .has().exactly(Country.SWITZERLAND, Country.CHILE).inOrder(); 231 // backward map ordered by country 232 ASSERT.that(bimap.inverse().keySet()) 233 .has().exactly(Country.CHILE, Country.SWITZERLAND).inOrder(); 234 // backward map ordered by country (even for currency values) 235 ASSERT.that(bimap.inverse().values()) 236 .has().exactly(Currency.PESO, Currency.FRANC).inOrder(); 237 } 238 testValuesIteratorRemove()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 ASSERT.that(bimap.keySet()) 255 .has().exactly(Currency.DOLLAR, Currency.PESO).inOrder(); 256 // forward map ordered by currency (even for country values) 257 ASSERT.that(bimap.values()) 258 .has().exactly(Country.CANADA, Country.CHILE).inOrder(); 259 // backward map ordered by country 260 ASSERT.that(bimap.inverse().keySet()) 261 .has().exactly(Country.CANADA, Country.CHILE).inOrder(); 262 // backward map ordered by country (even for currency values) 263 ASSERT.that(bimap.inverse().values()) 264 .has().exactly(Currency.DOLLAR, Currency.PESO).inOrder(); 265 } 266 testEntrySet()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") testSerializable()280 public void testSerializable() { 281 SerializableTester.reserializeAndAssert( 282 EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CANADA))); 283 } 284 285 @GwtIncompatible("reflection") testNulls()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 testEquals()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 } 305