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 testKeyType()186 public void testKeyType() { 187 EnumBiMap<Currency, Country> bimap = EnumBiMap.create(Currency.class, Country.class); 188 assertEquals(Currency.class, bimap.keyType()); 189 } 190 testValueType()191 public void testValueType() { 192 EnumBiMap<Currency, Country> bimap = EnumBiMap.create(Currency.class, Country.class); 193 assertEquals(Country.class, bimap.valueType()); 194 } 195 testIterationOrder()196 public void testIterationOrder() { 197 // The enum orderings are alphabetical, leading to the bimap and its inverse 198 // having inconsistent iteration orderings. 199 Map<Currency, Country> map = 200 ImmutableMap.of( 201 Currency.DOLLAR, Country.CANADA, 202 Currency.PESO, Country.CHILE, 203 Currency.FRANC, Country.SWITZERLAND); 204 EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map); 205 206 // forward map ordered by currency 207 assertThat(bimap.keySet()) 208 .containsExactly(Currency.DOLLAR, Currency.FRANC, Currency.PESO) 209 .inOrder(); 210 // forward map ordered by currency (even for country values) 211 assertThat(bimap.values()) 212 .containsExactly(Country.CANADA, Country.SWITZERLAND, Country.CHILE) 213 .inOrder(); 214 // backward map ordered by country 215 assertThat(bimap.inverse().keySet()) 216 .containsExactly(Country.CANADA, Country.CHILE, Country.SWITZERLAND) 217 .inOrder(); 218 // backward map ordered by country (even for currency values) 219 assertThat(bimap.inverse().values()) 220 .containsExactly(Currency.DOLLAR, Currency.PESO, Currency.FRANC) 221 .inOrder(); 222 } 223 testKeySetIteratorRemove()224 public void testKeySetIteratorRemove() { 225 // The enum orderings are alphabetical, leading to the bimap and its inverse 226 // having inconsistent iteration orderings. 227 Map<Currency, Country> map = 228 ImmutableMap.of( 229 Currency.DOLLAR, Country.CANADA, 230 Currency.PESO, Country.CHILE, 231 Currency.FRANC, Country.SWITZERLAND); 232 EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map); 233 234 Iterator<Currency> iter = bimap.keySet().iterator(); 235 assertEquals(Currency.DOLLAR, iter.next()); 236 iter.remove(); 237 238 // forward map ordered by currency 239 assertThat(bimap.keySet()).containsExactly(Currency.FRANC, Currency.PESO).inOrder(); 240 // forward map ordered by currency (even for country values) 241 assertThat(bimap.values()).containsExactly(Country.SWITZERLAND, Country.CHILE).inOrder(); 242 // backward map ordered by country 243 assertThat(bimap.inverse().keySet()) 244 .containsExactly(Country.CHILE, Country.SWITZERLAND) 245 .inOrder(); 246 // backward map ordered by country (even for currency values) 247 assertThat(bimap.inverse().values()).containsExactly(Currency.PESO, Currency.FRANC).inOrder(); 248 } 249 testValuesIteratorRemove()250 public void testValuesIteratorRemove() { 251 // The enum orderings are alphabetical, leading to the bimap and its inverse 252 // having inconsistent iteration orderings. 253 Map<Currency, Country> map = 254 ImmutableMap.of( 255 Currency.DOLLAR, Country.CANADA, 256 Currency.PESO, Country.CHILE, 257 Currency.FRANC, Country.SWITZERLAND); 258 EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map); 259 260 Iterator<Currency> iter = bimap.keySet().iterator(); 261 assertEquals(Currency.DOLLAR, iter.next()); 262 assertEquals(Currency.FRANC, iter.next()); 263 iter.remove(); 264 265 // forward map ordered by currency 266 assertThat(bimap.keySet()).containsExactly(Currency.DOLLAR, Currency.PESO).inOrder(); 267 // forward map ordered by currency (even for country values) 268 assertThat(bimap.values()).containsExactly(Country.CANADA, Country.CHILE).inOrder(); 269 // backward map ordered by country 270 assertThat(bimap.inverse().keySet()).containsExactly(Country.CANADA, Country.CHILE).inOrder(); 271 // backward map ordered by country (even for currency values) 272 assertThat(bimap.inverse().values()).containsExactly(Currency.DOLLAR, Currency.PESO).inOrder(); 273 } 274 testEntrySet()275 public void testEntrySet() { 276 // Bug 3168290 277 Map<Currency, Country> map = 278 ImmutableMap.of( 279 Currency.DOLLAR, Country.CANADA, 280 Currency.PESO, Country.CHILE, 281 Currency.FRANC, Country.SWITZERLAND); 282 EnumBiMap<Currency, Country> bimap = EnumBiMap.create(map); 283 Set<Object> uniqueEntries = Sets.newIdentityHashSet(); 284 uniqueEntries.addAll(bimap.entrySet()); 285 assertEquals(3, uniqueEntries.size()); 286 } 287 288 @GwtIncompatible // serialization testSerializable()289 public void testSerializable() { 290 SerializableTester.reserializeAndAssert( 291 EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CANADA))); 292 } 293 294 @GwtIncompatible // reflection testNulls()295 public void testNulls() { 296 new NullPointerTester().testAllPublicStaticMethods(EnumBiMap.class); 297 new NullPointerTester() 298 .testAllPublicInstanceMethods( 299 EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CHILE))); 300 } 301 testEquals()302 public void testEquals() { 303 new EqualsTester() 304 .addEqualityGroup( 305 EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CANADA)), 306 EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CANADA))) 307 .addEqualityGroup(EnumBiMap.create(ImmutableMap.of(Currency.DOLLAR, Country.CHILE))) 308 .addEqualityGroup(EnumBiMap.create(ImmutableMap.of(Currency.FRANC, Country.CANADA))) 309 .testEquals(); 310 } 311 312 /* Remaining behavior tested by AbstractBiMapTest. */ 313 } 314