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