/* * Copyright (C) 2008 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.common.collect; import static org.junit.contrib.truth.Truth.ASSERT; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableBiMap.Builder; import com.google.common.collect.testing.MapInterfaceTest; import com.google.common.collect.testing.ReserializingTestSetGenerator; import com.google.common.collect.testing.SetTestSuiteBuilder; import com.google.common.collect.testing.features.CollectionFeature; import com.google.common.collect.testing.features.CollectionSize; import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapEntrySetGenerator; import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapInverseEntrySetGenerator; import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapInverseKeySetGenerator; import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapInverseValuesGenerator; import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapKeySetGenerator; import com.google.common.collect.testing.google.BiMapGenerators.ImmutableBiMapValuesGenerator; import com.google.common.testing.SerializableTester; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * Tests for {@link ImmutableBiMap}. * * @author Jared Levy */ @GwtCompatible(emulated = true) public class ImmutableBiMapTest extends TestCase { // TODO: Reduce duplication of ImmutableMapTest code @GwtIncompatible("suite") public static Test suite() { TestSuite suite = new TestSuite(); suite.addTestSuite(MapTests.class); suite.addTestSuite(InverseMapTests.class); suite.addTestSuite(CreationTests.class); suite.addTestSuite(BiMapSpecificTests.class); suite.addTest(SetTestSuiteBuilder.using(new ImmutableBiMapKeySetGenerator()) .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.keySet") .createTestSuite()); suite.addTest(SetTestSuiteBuilder.using( new ImmutableBiMapEntrySetGenerator()) .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.entrySet") .createTestSuite()); suite.addTest(SetTestSuiteBuilder.using(new ImmutableBiMapValuesGenerator()) .withFeatures( CollectionSize.ANY, CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.values") .createTestSuite()); suite.addTest(SetTestSuiteBuilder.using( new ImmutableBiMapInverseKeySetGenerator()) .withFeatures( CollectionSize.ANY, CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.inverse.keys") .createTestSuite()); suite.addTest(SetTestSuiteBuilder.using( new ImmutableBiMapInverseEntrySetGenerator()) .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.inverse.entrySet") .createTestSuite()); suite.addTest(SetTestSuiteBuilder.using( new ImmutableBiMapInverseValuesGenerator()) .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.inverse.values") .createTestSuite()); suite.addTest(SetTestSuiteBuilder.using( ReserializingTestSetGenerator.newInstance( new ImmutableBiMapKeySetGenerator())) .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.keySet, reserialized") .createTestSuite()); suite.addTest(SetTestSuiteBuilder.using( ReserializingTestSetGenerator.newInstance( new ImmutableBiMapEntrySetGenerator())) .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.entrySet, reserialized") .createTestSuite()); suite.addTest(SetTestSuiteBuilder.using( ReserializingTestSetGenerator.newInstance( new ImmutableBiMapValuesGenerator())) .withFeatures( CollectionSize.ANY, CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES) .named("ImmutableBiMap.values, reserialized") .createTestSuite()); return suite; } public static abstract class AbstractMapTests extends MapInterfaceTest { public AbstractMapTests() { super(false, false, false, false, false); } @Override protected Map makeEmptyMap() { throw new UnsupportedOperationException(); } private static final Joiner joiner = Joiner.on(", "); @Override protected void assertMoreInvariants(Map map) { BiMap bimap = (BiMap) map; for (Entry entry : map.entrySet()) { assertEquals(entry.getKey() + "=" + entry.getValue(), entry.toString()); assertEquals(entry.getKey(), bimap.inverse().get(entry.getValue())); } assertEquals("{" + joiner.join(map.entrySet()) + "}", map.toString()); assertEquals("[" + joiner.join(map.entrySet()) + "]", map.entrySet().toString()); assertEquals("[" + joiner.join(map.keySet()) + "]", map.keySet().toString()); assertEquals("[" + joiner.join(map.values()) + "]", map.values().toString()); assertEquals(Sets.newHashSet(map.entrySet()), map.entrySet()); assertEquals(Sets.newHashSet(map.keySet()), map.keySet()); } } public static class MapTests extends AbstractMapTests { @Override protected Map makeEmptyMap() { return ImmutableBiMap.of(); } @Override protected Map makePopulatedMap() { return ImmutableBiMap.of("one", 1, "two", 2, "three", 3); } @Override protected String getKeyNotInPopulatedMap() { return "minus one"; } @Override protected Integer getValueNotInPopulatedMap() { return -1; } } public static class InverseMapTests extends AbstractMapTests { @Override protected Map makeEmptyMap() { return ImmutableBiMap.of(); } @Override protected Map makePopulatedMap() { return ImmutableBiMap.of(1, "one", 2, "two", 3, "three").inverse(); } @Override protected String getKeyNotInPopulatedMap() { return "minus one"; } @Override protected Integer getValueNotInPopulatedMap() { return -1; } } public static class CreationTests extends TestCase { public void testEmptyBuilder() { ImmutableBiMap map = new Builder().build(); assertEquals(Collections.emptyMap(), map); assertEquals(Collections.emptyMap(), map.inverse()); assertSame(ImmutableBiMap.of(), map); } public void testSingletonBuilder() { ImmutableBiMap map = new Builder() .put("one", 1) .build(); assertMapEquals(map, "one", 1); assertMapEquals(map.inverse(), 1, "one"); } public void testBuilder() { ImmutableBiMap map = ImmutableBiMap.builder() .put("one", 1) .put("two", 2) .put("three", 3) .put("four", 4) .put("five", 5) .build(); assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); assertMapEquals(map.inverse(), 1, "one", 2, "two", 3, "three", 4, "four", 5, "five"); } public void testBuilderPutAllWithEmptyMap() { ImmutableBiMap map = new Builder() .putAll(Collections.emptyMap()) .build(); assertEquals(Collections.emptyMap(), map); } public void testBuilderPutAll() { Map toPut = new LinkedHashMap(); toPut.put("one", 1); toPut.put("two", 2); toPut.put("three", 3); Map moreToPut = new LinkedHashMap(); moreToPut.put("four", 4); moreToPut.put("five", 5); ImmutableBiMap map = new Builder() .putAll(toPut) .putAll(moreToPut) .build(); assertMapEquals(map, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); assertMapEquals(map.inverse(), 1, "one", 2, "two", 3, "three", 4, "four", 5, "five"); } public void testBuilderReuse() { Builder builder = new Builder(); ImmutableBiMap mapOne = builder .put("one", 1) .put("two", 2) .build(); ImmutableBiMap mapTwo = builder .put("three", 3) .put("four", 4) .build(); assertMapEquals(mapOne, "one", 1, "two", 2); assertMapEquals(mapOne.inverse(), 1, "one", 2, "two"); assertMapEquals(mapTwo, "one", 1, "two", 2, "three", 3, "four", 4); assertMapEquals(mapTwo.inverse(), 1, "one", 2, "two", 3, "three", 4, "four"); } public void testBuilderPutNullKey() { Builder builder = new Builder(); try { builder.put(null, 1); fail(); } catch (NullPointerException expected) { } } public void testBuilderPutNullValue() { Builder builder = new Builder(); try { builder.put("one", null); fail(); } catch (NullPointerException expected) { } } public void testBuilderPutNullKeyViaPutAll() { Builder builder = new Builder(); try { builder.putAll(Collections.singletonMap(null, 1)); fail(); } catch (NullPointerException expected) { } } public void testBuilderPutNullValueViaPutAll() { Builder builder = new Builder(); try { builder.putAll(Collections.singletonMap("one", null)); fail(); } catch (NullPointerException expected) { } } public void testPuttingTheSameKeyTwiceThrowsOnBuild() { Builder builder = new Builder() .put("one", 1) .put("one", 1); // throwing on this line would be even better try { builder.build(); fail(); } catch (IllegalArgumentException expected) { assertEquals("duplicate key: one", expected.getMessage()); } } public void testOf() { assertMapEquals( ImmutableBiMap.of("one", 1), "one", 1); assertMapEquals( ImmutableBiMap.of("one", 1).inverse(), 1, "one"); assertMapEquals( ImmutableBiMap.of("one", 1, "two", 2), "one", 1, "two", 2); assertMapEquals( ImmutableBiMap.of("one", 1, "two", 2).inverse(), 1, "one", 2, "two"); assertMapEquals( ImmutableBiMap.of("one", 1, "two", 2, "three", 3), "one", 1, "two", 2, "three", 3); assertMapEquals( ImmutableBiMap.of("one", 1, "two", 2, "three", 3).inverse(), 1, "one", 2, "two", 3, "three"); assertMapEquals( ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4), "one", 1, "two", 2, "three", 3, "four", 4); assertMapEquals( ImmutableBiMap.of( "one", 1, "two", 2, "three", 3, "four", 4).inverse(), 1, "one", 2, "two", 3, "three", 4, "four"); assertMapEquals( ImmutableBiMap.of( "one", 1, "two", 2, "three", 3, "four", 4, "five", 5), "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); assertMapEquals( ImmutableBiMap.of( "one", 1, "two", 2, "three", 3, "four", 4, "five", 5).inverse(), 1, "one", 2, "two", 3, "three", 4, "four", 5, "five"); } public void testOfNullKey() { try { ImmutableBiMap.of(null, 1); fail(); } catch (NullPointerException expected) { } try { ImmutableBiMap.of("one", 1, null, 2); fail(); } catch (NullPointerException expected) { } } public void testOfNullValue() { try { ImmutableBiMap.of("one", null); fail(); } catch (NullPointerException expected) { } try { ImmutableBiMap.of("one", 1, "two", null); fail(); } catch (NullPointerException expected) { } } public void testOfWithDuplicateKey() { try { ImmutableBiMap.of("one", 1, "one", 1); fail(); } catch (IllegalArgumentException expected) { assertEquals("duplicate key: one", expected.getMessage()); } } public void testCopyOfEmptyMap() { ImmutableBiMap copy = ImmutableBiMap.copyOf(Collections.emptyMap()); assertEquals(Collections.emptyMap(), copy); assertSame(copy, ImmutableBiMap.copyOf(copy)); assertSame(ImmutableBiMap.of(), copy); } public void testCopyOfSingletonMap() { ImmutableBiMap copy = ImmutableBiMap.copyOf(Collections.singletonMap("one", 1)); assertMapEquals(copy, "one", 1); assertSame(copy, ImmutableBiMap.copyOf(copy)); } public void testCopyOf() { Map original = new LinkedHashMap(); original.put("one", 1); original.put("two", 2); original.put("three", 3); ImmutableBiMap copy = ImmutableBiMap.copyOf(original); assertMapEquals(copy, "one", 1, "two", 2, "three", 3); assertSame(copy, ImmutableBiMap.copyOf(copy)); } public void testEmpty() { ImmutableBiMap bimap = ImmutableBiMap.of(); assertEquals(Collections.emptyMap(), bimap); assertEquals(Collections.emptyMap(), bimap.inverse()); } public void testFromHashMap() { Map hashMap = Maps.newLinkedHashMap(); hashMap.put("one", 1); hashMap.put("two", 2); ImmutableBiMap bimap = ImmutableBiMap.copyOf( ImmutableMap.of("one", 1, "two", 2)); assertMapEquals(bimap, "one", 1, "two", 2); assertMapEquals(bimap.inverse(), 1, "one", 2, "two"); } public void testFromImmutableMap() { ImmutableBiMap bimap = ImmutableBiMap.copyOf( new ImmutableMap.Builder() .put("one", 1) .put("two", 2) .put("three", 3) .put("four", 4) .put("five", 5) .build()); assertMapEquals(bimap, "one", 1, "two", 2, "three", 3, "four", 4, "five", 5); assertMapEquals(bimap.inverse(), 1, "one", 2, "two", 3, "three", 4, "four", 5, "five"); } public void testDuplicateValues() { ImmutableMap map = new ImmutableMap.Builder() .put("one", 1) .put("two", 2) .put("uno", 1) .put("dos", 2) .build(); try { ImmutableBiMap.copyOf(map); fail(); } catch (IllegalArgumentException expected) { assertEquals("duplicate key: 1", expected.getMessage()); } } } public static class BiMapSpecificTests extends TestCase { public void testForcePut() { ImmutableBiMap bimap = ImmutableBiMap.copyOf( ImmutableMap.of("one", 1, "two", 2)); try { bimap.forcePut("three", 3); fail(); } catch (UnsupportedOperationException expected) {} } public void testKeySet() { ImmutableBiMap bimap = ImmutableBiMap.copyOf( ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4)); Set keys = bimap.keySet(); assertEquals(Sets.newHashSet("one", "two", "three", "four"), keys); ASSERT.that(keys).hasContentsInOrder("one", "two", "three", "four"); } public void testValues() { ImmutableBiMap bimap = ImmutableBiMap.copyOf( ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4)); Set values = bimap.values(); assertEquals(Sets.newHashSet(1, 2, 3, 4), values); ASSERT.that(values).hasContentsInOrder(1, 2, 3, 4); } public void testDoubleInverse() { ImmutableBiMap bimap = ImmutableBiMap.copyOf( ImmutableMap.of("one", 1, "two", 2)); assertSame(bimap, bimap.inverse().inverse()); } @GwtIncompatible("SerializableTester") public void testEmptySerialization() { ImmutableBiMap bimap = ImmutableBiMap.of(); assertSame(bimap, SerializableTester.reserializeAndAssert(bimap)); } @GwtIncompatible("SerializableTester") public void testSerialization() { ImmutableBiMap bimap = ImmutableBiMap.copyOf( ImmutableMap.of("one", 1, "two", 2)); ImmutableBiMap copy = SerializableTester.reserializeAndAssert(bimap); assertEquals(Integer.valueOf(1), copy.get("one")); assertEquals("one", copy.inverse().get(1)); assertSame(copy, copy.inverse().inverse()); } @GwtIncompatible("SerializableTester") public void testInverseSerialization() { ImmutableBiMap bimap = ImmutableBiMap.copyOf( ImmutableMap.of(1, "one", 2, "two")).inverse(); ImmutableBiMap copy = SerializableTester.reserializeAndAssert(bimap); assertEquals(Integer.valueOf(1), copy.get("one")); assertEquals("one", copy.inverse().get(1)); assertSame(copy, copy.inverse().inverse()); } } private static void assertMapEquals(Map map, Object... alternatingKeysAndValues) { int i = 0; for (Entry entry : map.entrySet()) { assertEquals(alternatingKeysAndValues[i++], entry.getKey()); assertEquals(alternatingKeysAndValues[i++], entry.getValue()); } } }