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