1 /* 2 * Copyright (C) 2008 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 org.junit.contrib.truth.Truth.ASSERT; 20 21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.annotations.GwtIncompatible; 23 import com.google.common.base.Joiner; 24 import com.google.common.collect.ImmutableBiMap.Builder; 25 import com.google.common.collect.testing.MapInterfaceTest; 26 import com.google.common.collect.testing.ReserializingTestSetGenerator; 27 import com.google.common.collect.testing.SetTestSuiteBuilder; 28 import com.google.common.collect.testing.features.CollectionFeature; 29 import com.google.common.collect.testing.features.CollectionSize; 30 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapEntrySetGenerator; 31 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapInverseEntrySetGenerator; 32 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapInverseKeySetGenerator; 33 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapInverseValuesGenerator; 34 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapKeySetGenerator; 35 import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapValuesGenerator; 36 import com.google.common.testing.SerializableTester; 37 38 import junit.framework.Test; 39 import junit.framework.TestCase; 40 import junit.framework.TestSuite; 41 42 import java.util.Collections; 43 import java.util.LinkedHashMap; 44 import java.util.Map; 45 import java.util.Map.Entry; 46 import java.util.Set; 47 48 /** 49 * Tests for {@link ImmutableBiMap}. 50 * 51 * @author Jared Levy 52 */ 53 @GwtCompatible(emulated = true) 54 public class ImmutableBiMapTest extends TestCase { 55 56 // TODO: Reduce duplication of ImmutableMapTest code 57 58 @GwtIncompatible("suite") suite()59 public static Test suite() { 60 TestSuite suite = new TestSuite(); 61 62 suite.addTestSuite(MapTests.class); 63 suite.addTestSuite(InverseMapTests.class); 64 suite.addTestSuite(CreationTests.class); 65 suite.addTestSuite(BiMapSpecificTests.class); 66 67 suite.addTest(SetTestSuiteBuilder.using(new ImmutableBiMapKeySetGenerator()) 68 .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, 69 CollectionFeature.ALLOWS_NULL_QUERIES) 70 .named("ImmutableBiMap.keySet") 71 .createTestSuite()); 72 73 suite.addTest(SetTestSuiteBuilder.using( 74 new ImmutableBiMapEntrySetGenerator()) 75 .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, 76 CollectionFeature.ALLOWS_NULL_QUERIES) 77 .named("ImmutableBiMap.entrySet") 78 .createTestSuite()); 79 80 suite.addTest(SetTestSuiteBuilder.using(new ImmutableBiMapValuesGenerator()) 81 .withFeatures( 82 CollectionSize.ANY, 83 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 84 CollectionFeature.KNOWN_ORDER, 85 CollectionFeature.ALLOWS_NULL_QUERIES) 86 .named("ImmutableBiMap.values") 87 .createTestSuite()); 88 89 suite.addTest(SetTestSuiteBuilder.using( 90 new ImmutableBiMapInverseKeySetGenerator()) 91 .withFeatures( 92 CollectionSize.ANY, 93 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 94 CollectionFeature.KNOWN_ORDER, 95 CollectionFeature.ALLOWS_NULL_QUERIES) 96 .named("ImmutableBiMap.inverse.keys") 97 .createTestSuite()); 98 99 suite.addTest(SetTestSuiteBuilder.using( 100 new ImmutableBiMapInverseEntrySetGenerator()) 101 .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, 102 CollectionFeature.ALLOWS_NULL_QUERIES) 103 .named("ImmutableBiMap.inverse.entrySet") 104 .createTestSuite()); 105 106 suite.addTest(SetTestSuiteBuilder.using( 107 new ImmutableBiMapInverseValuesGenerator()) 108 .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, 109 CollectionFeature.ALLOWS_NULL_QUERIES) 110 .named("ImmutableBiMap.inverse.values") 111 .createTestSuite()); 112 113 suite.addTest(SetTestSuiteBuilder.using( 114 ReserializingTestSetGenerator.newInstance( 115 new ImmutableBiMapKeySetGenerator())) 116 .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, 117 CollectionFeature.ALLOWS_NULL_QUERIES) 118 .named("ImmutableBiMap.keySet, reserialized") 119 .createTestSuite()); 120 121 suite.addTest(SetTestSuiteBuilder.using( 122 ReserializingTestSetGenerator.newInstance( 123 new ImmutableBiMapEntrySetGenerator())) 124 .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, 125 CollectionFeature.ALLOWS_NULL_QUERIES) 126 .named("ImmutableBiMap.entrySet, reserialized") 127 .createTestSuite()); 128 129 suite.addTest(SetTestSuiteBuilder.using( 130 ReserializingTestSetGenerator.newInstance( 131 new ImmutableBiMapValuesGenerator())) 132 .withFeatures( 133 CollectionSize.ANY, 134 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 135 CollectionFeature.KNOWN_ORDER, 136 CollectionFeature.ALLOWS_NULL_QUERIES) 137 .named("ImmutableBiMap.values, reserialized") 138 .createTestSuite()); 139 140 return suite; 141 } 142 143 public static abstract class AbstractMapTests<K, V> 144 extends MapInterfaceTest<K, V> { AbstractMapTests()145 public AbstractMapTests() { 146 super(false, false, false, false, false); 147 } 148 makeEmptyMap()149 @Override protected Map<K, V> makeEmptyMap() { 150 throw new UnsupportedOperationException(); 151 } 152 153 private static final Joiner joiner = Joiner.on(", "); 154 assertMoreInvariants(Map<K, V> map)155 @Override protected void assertMoreInvariants(Map<K, V> map) { 156 157 BiMap<K, V> bimap = (BiMap<K, V>) map; 158 159 for (Entry<K, V> entry : map.entrySet()) { 160 assertEquals(entry.getKey() + "=" + entry.getValue(), 161 entry.toString()); 162 assertEquals(entry.getKey(), bimap.inverse().get(entry.getValue())); 163 } 164 165 assertEquals("{" + joiner.join(map.entrySet()) + "}", 166 map.toString()); 167 assertEquals("[" + joiner.join(map.entrySet()) + "]", 168 map.entrySet().toString()); 169 assertEquals("[" + joiner.join(map.keySet()) + "]", 170 map.keySet().toString()); 171 assertEquals("[" + joiner.join(map.values()) + "]", 172 map.values().toString()); 173 174 assertEquals(Sets.newHashSet(map.entrySet()), map.entrySet()); 175 assertEquals(Sets.newHashSet(map.keySet()), map.keySet()); 176 } 177 } 178 179 public static class MapTests extends AbstractMapTests<String, Integer> { makeEmptyMap()180 @Override protected Map<String, Integer> makeEmptyMap() { 181 return ImmutableBiMap.of(); 182 } 183 makePopulatedMap()184 @Override protected Map<String, Integer> makePopulatedMap() { 185 return ImmutableBiMap.of("one", 1, "two", 2, "three", 3); 186 } 187 getKeyNotInPopulatedMap()188 @Override protected String getKeyNotInPopulatedMap() { 189 return "minus one"; 190 } 191 getValueNotInPopulatedMap()192 @Override protected Integer getValueNotInPopulatedMap() { 193 return -1; 194 } 195 } 196 197 public static class InverseMapTests 198 extends AbstractMapTests<String, Integer> { makeEmptyMap()199 @Override protected Map<String, Integer> makeEmptyMap() { 200 return ImmutableBiMap.of(); 201 } 202 makePopulatedMap()203 @Override protected Map<String, Integer> makePopulatedMap() { 204 return ImmutableBiMap.of(1, "one", 2, "two", 3, "three").inverse(); 205 } 206 getKeyNotInPopulatedMap()207 @Override protected String getKeyNotInPopulatedMap() { 208 return "minus one"; 209 } 210 getValueNotInPopulatedMap()211 @Override protected Integer getValueNotInPopulatedMap() { 212 return -1; 213 } 214 } 215 216 public static class CreationTests extends TestCase { testEmptyBuilder()217 public void testEmptyBuilder() { 218 ImmutableBiMap<String, Integer> map 219 = new Builder<String, Integer>().build(); 220 assertEquals(Collections.<String, Integer>emptyMap(), map); 221 assertEquals(Collections.<Integer, String>emptyMap(), map.inverse()); 222 assertSame(ImmutableBiMap.of(), map); 223 } 224 testSingletonBuilder()225 public void testSingletonBuilder() { 226 ImmutableBiMap<String, Integer> map = new Builder<String, Integer>() 227 .put("one", 1) 228 .build(); 229 assertMapEquals(map, "one", 1); 230 assertMapEquals(map.inverse(), 1, "one"); 231 } 232 testBuilder()233 public void testBuilder() { 234 ImmutableBiMap<String, Integer> map 235 = ImmutableBiMap.<String, Integer>builder() 236 .put("one", 1) 237 .put("two", 2) 238 .put("three", 3) 239 .put("four", 4) 240 .put("five", 5) 241 .build(); 242 assertMapEquals(map, 243 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 244 assertMapEquals(map.inverse(), 245 1, "one", 2, "two", 3, "three", 4, "four", 5, "five"); 246 } 247 testBuilderPutAllWithEmptyMap()248 public void testBuilderPutAllWithEmptyMap() { 249 ImmutableBiMap<String, Integer> map = new Builder<String, Integer>() 250 .putAll(Collections.<String, Integer>emptyMap()) 251 .build(); 252 assertEquals(Collections.<String, Integer>emptyMap(), map); 253 } 254 testBuilderPutAll()255 public void testBuilderPutAll() { 256 Map<String, Integer> toPut = new LinkedHashMap<String, Integer>(); 257 toPut.put("one", 1); 258 toPut.put("two", 2); 259 toPut.put("three", 3); 260 Map<String, Integer> moreToPut = new LinkedHashMap<String, Integer>(); 261 moreToPut.put("four", 4); 262 moreToPut.put("five", 5); 263 264 ImmutableBiMap<String, Integer> map = new Builder<String, Integer>() 265 .putAll(toPut) 266 .putAll(moreToPut) 267 .build(); 268 assertMapEquals(map, 269 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 270 assertMapEquals(map.inverse(), 271 1, "one", 2, "two", 3, "three", 4, "four", 5, "five"); 272 } 273 testBuilderReuse()274 public void testBuilderReuse() { 275 Builder<String, Integer> builder = new Builder<String, Integer>(); 276 ImmutableBiMap<String, Integer> mapOne = builder 277 .put("one", 1) 278 .put("two", 2) 279 .build(); 280 ImmutableBiMap<String, Integer> mapTwo = builder 281 .put("three", 3) 282 .put("four", 4) 283 .build(); 284 285 assertMapEquals(mapOne, "one", 1, "two", 2); 286 assertMapEquals(mapOne.inverse(), 1, "one", 2, "two"); 287 assertMapEquals(mapTwo, "one", 1, "two", 2, "three", 3, "four", 4); 288 assertMapEquals(mapTwo.inverse(), 289 1, "one", 2, "two", 3, "three", 4, "four"); 290 } 291 testBuilderPutNullKey()292 public void testBuilderPutNullKey() { 293 Builder<String, Integer> builder = new Builder<String, Integer>(); 294 try { 295 builder.put(null, 1); 296 fail(); 297 } catch (NullPointerException expected) { 298 } 299 } 300 testBuilderPutNullValue()301 public void testBuilderPutNullValue() { 302 Builder<String, Integer> builder = new Builder<String, Integer>(); 303 try { 304 builder.put("one", null); 305 fail(); 306 } catch (NullPointerException expected) { 307 } 308 } 309 testBuilderPutNullKeyViaPutAll()310 public void testBuilderPutNullKeyViaPutAll() { 311 Builder<String, Integer> builder = new Builder<String, Integer>(); 312 try { 313 builder.putAll(Collections.<String, Integer>singletonMap(null, 1)); 314 fail(); 315 } catch (NullPointerException expected) { 316 } 317 } 318 testBuilderPutNullValueViaPutAll()319 public void testBuilderPutNullValueViaPutAll() { 320 Builder<String, Integer> builder = new Builder<String, Integer>(); 321 try { 322 builder.putAll(Collections.<String, Integer>singletonMap("one", null)); 323 fail(); 324 } catch (NullPointerException expected) { 325 } 326 } 327 testPuttingTheSameKeyTwiceThrowsOnBuild()328 public void testPuttingTheSameKeyTwiceThrowsOnBuild() { 329 Builder<String, Integer> builder = new Builder<String, Integer>() 330 .put("one", 1) 331 .put("one", 1); // throwing on this line would be even better 332 333 try { 334 builder.build(); 335 fail(); 336 } catch (IllegalArgumentException expected) { 337 assertEquals("duplicate key: one", expected.getMessage()); 338 } 339 } 340 testOf()341 public void testOf() { 342 assertMapEquals( 343 ImmutableBiMap.of("one", 1), 344 "one", 1); 345 assertMapEquals( 346 ImmutableBiMap.of("one", 1).inverse(), 347 1, "one"); 348 assertMapEquals( 349 ImmutableBiMap.of("one", 1, "two", 2), 350 "one", 1, "two", 2); 351 assertMapEquals( 352 ImmutableBiMap.of("one", 1, "two", 2).inverse(), 353 1, "one", 2, "two"); 354 assertMapEquals( 355 ImmutableBiMap.of("one", 1, "two", 2, "three", 3), 356 "one", 1, "two", 2, "three", 3); 357 assertMapEquals( 358 ImmutableBiMap.of("one", 1, "two", 2, "three", 3).inverse(), 359 1, "one", 2, "two", 3, "three"); 360 assertMapEquals( 361 ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4), 362 "one", 1, "two", 2, "three", 3, "four", 4); 363 assertMapEquals( 364 ImmutableBiMap.of( 365 "one", 1, "two", 2, "three", 3, "four", 4).inverse(), 366 1, "one", 2, "two", 3, "three", 4, "four"); 367 assertMapEquals( 368 ImmutableBiMap.of( 369 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5), 370 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 371 assertMapEquals( 372 ImmutableBiMap.of( 373 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5).inverse(), 374 1, "one", 2, "two", 3, "three", 4, "four", 5, "five"); 375 } 376 testOfNullKey()377 public void testOfNullKey() { 378 try { 379 ImmutableBiMap.of(null, 1); 380 fail(); 381 } catch (NullPointerException expected) { 382 } 383 384 try { 385 ImmutableBiMap.of("one", 1, null, 2); 386 fail(); 387 } catch (NullPointerException expected) { 388 } 389 } 390 testOfNullValue()391 public void testOfNullValue() { 392 try { 393 ImmutableBiMap.of("one", null); 394 fail(); 395 } catch (NullPointerException expected) { 396 } 397 398 try { 399 ImmutableBiMap.of("one", 1, "two", null); 400 fail(); 401 } catch (NullPointerException expected) { 402 } 403 } 404 testOfWithDuplicateKey()405 public void testOfWithDuplicateKey() { 406 try { 407 ImmutableBiMap.of("one", 1, "one", 1); 408 fail(); 409 } catch (IllegalArgumentException expected) { 410 assertEquals("duplicate key: one", expected.getMessage()); 411 } 412 } 413 testCopyOfEmptyMap()414 public void testCopyOfEmptyMap() { 415 ImmutableBiMap<String, Integer> copy 416 = ImmutableBiMap.copyOf(Collections.<String, Integer>emptyMap()); 417 assertEquals(Collections.<String, Integer>emptyMap(), copy); 418 assertSame(copy, ImmutableBiMap.copyOf(copy)); 419 assertSame(ImmutableBiMap.of(), copy); 420 } 421 testCopyOfSingletonMap()422 public void testCopyOfSingletonMap() { 423 ImmutableBiMap<String, Integer> copy 424 = ImmutableBiMap.copyOf(Collections.singletonMap("one", 1)); 425 assertMapEquals(copy, "one", 1); 426 assertSame(copy, ImmutableBiMap.copyOf(copy)); 427 } 428 testCopyOf()429 public void testCopyOf() { 430 Map<String, Integer> original = new LinkedHashMap<String, Integer>(); 431 original.put("one", 1); 432 original.put("two", 2); 433 original.put("three", 3); 434 435 ImmutableBiMap<String, Integer> copy = ImmutableBiMap.copyOf(original); 436 assertMapEquals(copy, "one", 1, "two", 2, "three", 3); 437 assertSame(copy, ImmutableBiMap.copyOf(copy)); 438 } 439 testEmpty()440 public void testEmpty() { 441 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.of(); 442 assertEquals(Collections.<String, Integer>emptyMap(), bimap); 443 assertEquals(Collections.<String, Integer>emptyMap(), bimap.inverse()); 444 } 445 testFromHashMap()446 public void testFromHashMap() { 447 Map<String, Integer> hashMap = Maps.newLinkedHashMap(); 448 hashMap.put("one", 1); 449 hashMap.put("two", 2); 450 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf( 451 ImmutableMap.of("one", 1, "two", 2)); 452 assertMapEquals(bimap, "one", 1, "two", 2); 453 assertMapEquals(bimap.inverse(), 1, "one", 2, "two"); 454 } 455 testFromImmutableMap()456 public void testFromImmutableMap() { 457 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf( 458 new ImmutableMap.Builder<String, Integer>() 459 .put("one", 1) 460 .put("two", 2) 461 .put("three", 3) 462 .put("four", 4) 463 .put("five", 5) 464 .build()); 465 assertMapEquals(bimap, 466 "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); 467 assertMapEquals(bimap.inverse(), 468 1, "one", 2, "two", 3, "three", 4, "four", 5, "five"); 469 } 470 testDuplicateValues()471 public void testDuplicateValues() { 472 ImmutableMap<String, Integer> map 473 = new ImmutableMap.Builder<String, Integer>() 474 .put("one", 1) 475 .put("two", 2) 476 .put("uno", 1) 477 .put("dos", 2) 478 .build(); 479 480 try { 481 ImmutableBiMap.copyOf(map); 482 fail(); 483 } catch (IllegalArgumentException expected) { 484 assertEquals("duplicate key: 1", expected.getMessage()); 485 } 486 } 487 } 488 489 public static class BiMapSpecificTests extends TestCase { 490 testForcePut()491 public void testForcePut() { 492 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf( 493 ImmutableMap.of("one", 1, "two", 2)); 494 try { 495 bimap.forcePut("three", 3); 496 fail(); 497 } catch (UnsupportedOperationException expected) {} 498 } 499 testKeySet()500 public void testKeySet() { 501 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf( 502 ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4)); 503 Set<String> keys = bimap.keySet(); 504 assertEquals(Sets.newHashSet("one", "two", "three", "four"), keys); 505 ASSERT.that(keys).hasContentsInOrder("one", "two", "three", "four"); 506 } 507 testValues()508 public void testValues() { 509 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf( 510 ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4)); 511 Set<Integer> values = bimap.values(); 512 assertEquals(Sets.newHashSet(1, 2, 3, 4), values); 513 ASSERT.that(values).hasContentsInOrder(1, 2, 3, 4); 514 } 515 testDoubleInverse()516 public void testDoubleInverse() { 517 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf( 518 ImmutableMap.of("one", 1, "two", 2)); 519 assertSame(bimap, bimap.inverse().inverse()); 520 } 521 522 @GwtIncompatible("SerializableTester") testEmptySerialization()523 public void testEmptySerialization() { 524 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.of(); 525 assertSame(bimap, SerializableTester.reserializeAndAssert(bimap)); 526 } 527 528 @GwtIncompatible("SerializableTester") testSerialization()529 public void testSerialization() { 530 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf( 531 ImmutableMap.of("one", 1, "two", 2)); 532 ImmutableBiMap<String, Integer> copy = 533 SerializableTester.reserializeAndAssert(bimap); 534 assertEquals(Integer.valueOf(1), copy.get("one")); 535 assertEquals("one", copy.inverse().get(1)); 536 assertSame(copy, copy.inverse().inverse()); 537 } 538 539 @GwtIncompatible("SerializableTester") testInverseSerialization()540 public void testInverseSerialization() { 541 ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.copyOf( 542 ImmutableMap.of(1, "one", 2, "two")).inverse(); 543 ImmutableBiMap<String, Integer> copy = 544 SerializableTester.reserializeAndAssert(bimap); 545 assertEquals(Integer.valueOf(1), copy.get("one")); 546 assertEquals("one", copy.inverse().get(1)); 547 assertSame(copy, copy.inverse().inverse()); 548 } 549 } 550 assertMapEquals(Map<K, V> map, Object... alternatingKeysAndValues)551 private static <K, V> void assertMapEquals(Map<K, V> map, 552 Object... alternatingKeysAndValues) { 553 int i = 0; 554 for (Entry<K, V> entry : map.entrySet()) { 555 assertEquals(alternatingKeysAndValues[i++], entry.getKey()); 556 assertEquals(alternatingKeysAndValues[i++], entry.getValue()); 557 } 558 } 559 } 560