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