/*
* Copyright (C) 2007 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 java.util.Arrays.asList;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.testing.SerializableTester;
import junit.framework.TestCase;
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Common tests for any {@code BiMap}.
*
* @author Kevin Bourrillion
*/
@GwtCompatible(emulated = true)
public abstract class AbstractBiMapTest extends TestCase {
protected abstract BiMap<Integer, String> create();
protected BiMap<Integer, String> bimap;
protected Set<Entry<Integer, String>> entrySet;
// public for GWT
@Override public void setUp() throws Exception {
super.setUp();
bimap = create();
entrySet = bimap.entrySet();
}
public void testClear() {
bimap.clear();
assertTrue(bimap.isEmpty());
putOneTwoThree();
bimap.clear();
assertTrue(bimap.isEmpty());
}
public void testContainsKey() {
assertFalse(bimap.containsKey(null));
assertFalse(bimap.containsKey(1));
assertFalse(bimap.containsKey("one"));
bimap.put(1, "one");
assertTrue(bimap.containsKey(1));
bimap.put(null, null);
assertTrue(bimap.containsKey(null));
}
public void testContainsValue() {
assertFalse(bimap.containsValue(null));
assertFalse(bimap.containsValue(1));
assertFalse(bimap.containsValue("one"));
bimap.put(1, "one");
assertTrue(bimap.containsValue("one"));
bimap.put(null, null);
assertTrue(bimap.containsValue(null));
}
public void testEquals() {
BiMap<Integer, String> biMap = create();
assertEquals(biMap, biMap);
assertEquals(create(), biMap);
biMap.put(1, null);
assertFalse(create().equals(biMap));
}
public void testGet() {
assertNull(bimap.get(1));
assertNull(bimap.get(null));
assertNull(bimap.get("bad"));
bimap.put(1, "one");
bimap.put(0, null);
bimap.put(null, "nothing");
assertEquals("one", bimap.get(1));
assertNull(bimap.get(0));
assertEquals("nothing", bimap.get(null));
assertNull(bimap.get("bad"));
bimap.forcePut(null, null);
assertNull(bimap.get(null));
bimap.remove(null);
assertNull(bimap.get(null));
}
public void testInverseSimple() {
BiMap<String, Integer> inverse = bimap.inverse();
bimap.put(1, "one");
bimap.put(2, "two");
assertEquals(ImmutableMap.of("one", 1, "two", 2), inverse);
// see InverseBiMapTest
assertSame(bimap, inverse.inverse());
}
public void testInversePut() {
BiMap<String, Integer> inverse = bimap.inverse();
bimap.put(1, "one");
bimap.inverse().put("two", 2);
assertEquals(ImmutableMap.of("one", 1, "two", 2), inverse);
assertEquals(ImmutableMap.of(1, "one", 2, "two"), bimap);
}
public void testIsEmpty() {
assertTrue(bimap.isEmpty());
bimap.put(1, "one");
assertFalse(bimap.isEmpty());
bimap.remove(1);
assertTrue(bimap.isEmpty());
}
public void testPut() {
bimap.put(1, "one");
assertEquals(ImmutableMap.of(1, "one"), bimap);
bimap.put(2, "two");
assertEquals(ImmutableMap.of(1, "one", 2, "two"), bimap);
bimap.put(2, "two");
assertEquals(ImmutableMap.of(1, "one", 2, "two"), bimap);
bimap.put(1, "ONE");
assertEquals(ImmutableMap.of(1, "ONE", 2, "two"), bimap);
try {
bimap.put(3, "two");
fail();
} catch (IllegalArgumentException e) {
}
assertEquals(ImmutableMap.of(1, "ONE", 2, "two"), bimap);
bimap.put(-1, null);
bimap.put(null, "null");
Map<Integer, String> expected = Maps.newHashMap();
expected.put(1, "ONE");
expected.put(2, "two");
expected.put(-1, null);
expected.put(null, "null");
assertEquals(expected, bimap);
bimap.remove(-1);
bimap.put(null, null);
expected.remove(-1);
expected.put(null, null);
assertEquals(expected, bimap);
}
public void testPutNull() {
bimap.put(-1, null);
assertTrue(bimap.containsValue(null));
bimap.put(1, "one");
assertTrue(bimap.containsValue(null));
}
public void testPutAll() {
bimap.put(1, "one");
Map<Integer, String> newEntries = ImmutableMap.of(2, "two", 3, "three");
bimap.putAll(newEntries);
assertEquals(ImmutableMap.of(1, "one", 2, "two", 3, "three"), bimap);
}
public void testForcePut() {
assertNull(bimap.forcePut(1, "one"));
assertEquals(ImmutableMap.of(1, "one"), bimap);
assertEquals("one", bimap.forcePut(1, "one"));
assertEquals(ImmutableMap.of(1, "one"), bimap);
assertEquals("one", bimap.forcePut(1, "ONE"));
assertEquals(ImmutableMap.of(1, "ONE"), bimap);
assertNull(bimap.forcePut(-1, "ONE")); // key 1 disappears without a trace
assertEquals(ImmutableMap.of(-1, "ONE"), bimap);
assertNull(bimap.forcePut(2, "two"));
assertEquals(ImmutableMap.of(-1, "ONE", 2, "two"), bimap);
assertEquals("two", bimap.forcePut(2, "ONE"));
assertEquals(ImmutableMap.of(2, "ONE"), bimap);
}
public void testRemove() {
Map<Integer, String> map = Maps.newHashMap();
map.put(0, null);
map.put(1, "one");
map.put(null, "null");
bimap.putAll(map);
assertNull(bimap.remove(0));
map.remove(0);
assertEquals(map, bimap);
assertEquals("null", bimap.remove(null));
assertEquals(Collections.singletonMap(1, "one"), bimap);
assertNull(bimap.remove(15));
assertEquals("one", bimap.remove(1));
assertTrue(bimap.isEmpty());
}
public void testSize() {
assertEquals(0, bimap.size());
bimap.put(1, "one");
assertEquals(1, bimap.size());
bimap.put(1, "ONE");
assertEquals(1, bimap.size());
bimap.put(2, "two");
assertEquals(2, bimap.size());
bimap.forcePut(1, "two");
assertEquals(1, bimap.size());
}
public void testToString() {
bimap.put(1, "one");
bimap.put(2, "two");
String string = bimap.toString();
String expected = string.startsWith("{1")
? "{1=one, 2=two}"
: "{2=two, 1=one}";
assertEquals(expected, bimap.toString());
}
// Entry Set
public void testEntrySetAdd() {
try {
entrySet.add(Maps.immutableEntry(1, "one"));
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void testEntrySetAddAll() {
try {
entrySet.addAll(Collections.singleton(Maps.immutableEntry(1, "one")));
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void testEntrySetClear() {
entrySet.clear();
assertTrue(entrySet.isEmpty());
assertTrue(bimap.isEmpty());
putOneTwoThree();
entrySet.clear();
assertTrue(entrySet.isEmpty());
assertTrue(bimap.isEmpty());
}
public void testEntrySetContains() {
assertFalse(entrySet.contains(Maps.immutableEntry(1, "one")));
bimap.put(1, "one");
assertTrue(entrySet.contains(Maps.immutableEntry(1, "one")));
assertFalse(entrySet.contains(Maps.immutableEntry(1, "")));
assertFalse(entrySet.contains(Maps.immutableEntry(0, "one")));
assertFalse(entrySet.contains(Maps.immutableEntry(1, null)));
assertFalse(entrySet.contains(Maps.immutableEntry(null, "one")));
assertFalse(entrySet.contains(Maps.immutableEntry(null, null)));
bimap.put(null, null);
assertTrue(entrySet.contains(Maps.immutableEntry(1, "one")));
assertTrue(entrySet.contains(Maps.immutableEntry(null, null)));
assertFalse(entrySet.contains(Maps.immutableEntry(1, "")));
assertFalse(entrySet.contains(Maps.immutableEntry(0, "one")));
assertFalse(entrySet.contains(Maps.immutableEntry(1, null)));
assertFalse(entrySet.contains(Maps.immutableEntry(null, "one")));
bimap.put(null, "null");
bimap.put(0, null);
assertTrue(entrySet.contains(Maps.immutableEntry(1, "one")));
assertTrue(entrySet.contains(Maps.immutableEntry(null, "null")));
assertTrue(entrySet.contains(Maps.immutableEntry(0, null)));
assertFalse(entrySet.contains(Maps.immutableEntry(1, "")));
assertFalse(entrySet.contains(Maps.immutableEntry(0, "one")));
assertFalse(entrySet.contains(Maps.immutableEntry(1, null)));
assertFalse(entrySet.contains(Maps.immutableEntry(null, "one")));
assertFalse(entrySet.contains(Maps.immutableEntry(null, null)));
}
public void testEntrySetIsEmpty() {
assertTrue(entrySet.isEmpty());
bimap.put(1, "one");
assertFalse(entrySet.isEmpty());
bimap.remove(1);
assertTrue(entrySet.isEmpty());
}
public void testEntrySetRemove() {
putOneTwoThree();
assertTrue(bimap.containsKey(1));
assertTrue(bimap.containsValue("one"));
assertTrue(entrySet.remove(Maps.immutableEntry(1, "one")));
assertFalse(bimap.containsKey(1));
assertFalse(bimap.containsValue("one"));
assertEquals(2, bimap.size());
assertEquals(2, bimap.inverse().size());
assertFalse(entrySet.remove(Maps.immutableEntry(2, "three")));
assertFalse(entrySet.remove(3));
assertEquals(2, bimap.size());
assertEquals(2, bimap.inverse().size());
}
public void testEntrySetRemoveAll() {
putOneTwoThree();
assertTrue(bimap.containsKey(1));
assertTrue(bimap.containsValue("one"));
assertTrue(entrySet.removeAll(
Collections.singleton(Maps.immutableEntry(1, "one"))));
assertFalse(bimap.containsKey(1));
assertFalse(bimap.containsValue("one"));
assertEquals(2, bimap.size());
assertEquals(2, bimap.inverse().size());
}
public void testEntrySetValue() {
bimap.put(1, "one");
Entry<Integer, String> entry = bimap.entrySet().iterator().next();
bimap.put(2, "two");
assertEquals("one", entry.getValue());
bimap.put(1, "one");
assertEquals("one", entry.getValue());
assertEquals("one", bimap.get(1));
assertEquals(Integer.valueOf(1), bimap.inverse().get("one"));
bimap.put(1, "uno");
assertEquals("uno", entry.getValue());
assertEquals("uno", bimap.get(1));
assertEquals(Integer.valueOf(1), bimap.inverse().get("uno"));
assertEquals(2, bimap.size());
assertEquals(2, bimap.inverse().size());
try {
entry.setValue("two");
fail();
} catch (IllegalArgumentException expected) {}
assertEquals("uno", entry.getValue());
assertEquals("uno", bimap.get(1));
assertEquals(Integer.valueOf(1), bimap.inverse().get("uno"));
assertEquals(2, bimap.size());
assertEquals(2, bimap.inverse().size());
}
public void testEntrySetValueRemovedEntry() {
bimap.put(1, "a");
Entry<Integer, String> entry = bimap.entrySet().iterator().next();
bimap.clear();
try {
entry.setValue("b");
fail();
} catch (IllegalStateException expected) {}
assertEquals(0, bimap.size());
assertEquals(0, bimap.inverse().size());
}
public void testEntrySetValueRemovedEntryNullOldValue() {
bimap.put(1, null);
Entry<Integer, String> entry = bimap.entrySet().iterator().next();
bimap.clear();
try {
entry.setValue("b");
fail();
} catch (IllegalStateException expected) {}
assertEquals(0, bimap.size());
assertEquals(0, bimap.inverse().size());
}
public void testEntrySetValueRemovedEntryAddedEqualEntry() {
bimap.put(1, "a");
Entry<Integer, String> entry = bimap.entrySet().iterator().next();
bimap.clear();
bimap.put(1, "a");
try {
entry.setValue("b");
fail();
} catch (IllegalStateException expected) {}
assertEquals(1, bimap.size());
assertEquals("a", bimap.get(1));
assertEquals(1, bimap.inverse().size());
assertEquals((Integer) 1, bimap.inverse().get("a"));
}
public void testKeySetIteratorRemove() {
putOneTwoThree();
Iterator<Integer> iterator = bimap.keySet().iterator();
iterator.next();
iterator.remove();
assertEquals(2, bimap.size());
assertEquals(2, bimap.inverse().size());
}
public void testKeySetRemoveAll() {
putOneTwoThree();
Set<Integer> keySet = bimap.keySet();
assertTrue(keySet.removeAll(asList(1, 3)));
assertEquals(1, bimap.size());
assertTrue(keySet.contains(2));
}
public void testKeySetRetainAll() {
putOneTwoThree();
Set<Integer> keySet = bimap.keySet();
assertTrue(keySet.retainAll(Collections.singleton(2)));
assertEquals(1, bimap.size());
assertTrue(keySet.contains(2));
}
public void testEntriesIteratorRemove() {
putOneTwoThree();
Iterator<Entry<Integer, String>> iterator = bimap.entrySet().iterator();
iterator.next();
iterator.remove();
assertEquals(2, bimap.size());
assertEquals(2, bimap.inverse().size());
}
public void testEntriesRetainAll() {
putOneTwoThree();
Set<Map.Entry<Integer, String>> entries = bimap.entrySet();
Map.Entry<Integer, String> entry = Maps.immutableEntry(2, "two");
assertTrue(entries.retainAll(Collections.singleton(entry)));
assertEquals(1, bimap.size());
assertTrue(bimap.containsKey(2));
}
public void testValuesIteratorRemove() {
putOneTwoThree();
Iterator<String> iterator = bimap.values().iterator();
iterator.next();
iterator.remove();
assertEquals(2, bimap.size());
assertEquals(2, bimap.inverse().size());
}
public void testValuesToArray() {
bimap.put(1, "one");
String[] array = new String[3];
array[1] = "garbage";
assertSame(array, bimap.values().toArray(array));
assertEquals("one", array[0]);
assertNull(array[1]);
}
public void testValuesToString() {
bimap.put(1, "one");
assertEquals("[one]", bimap.values().toString());
}
@GwtIncompatible("SerializableTester")
public void testSerialization() {
bimap.put(1, "one");
bimap.put(2, "two");
bimap.put(3, "three");
bimap.put(null, null);
BiMap<Integer, String> copy =
SerializableTester.reserializeAndAssert(bimap);
assertEquals(bimap.inverse(), copy.inverse());
}
void putOneTwoThree() {
bimap.put(1, "one");
bimap.put(2, "two");
bimap.put(3, "three");
}
@GwtIncompatible("used only by @GwtIncompatible code")
private static class BiMapPair implements Serializable {
final BiMap<Integer, String> forward;
final BiMap<String, Integer> backward;
BiMapPair(BiMap<Integer, String> original) {
this.forward = original;
this.backward = original.inverse();
}
private static final long serialVersionUID = 0;
}
@GwtIncompatible("SerializableTester")
public void testSerializationWithInverseEqual() {
bimap.put(1, "one");
bimap.put(2, "two");
bimap.put(3, "three");
bimap.put(null, null);
BiMapPair pair = new BiMapPair(bimap);
BiMapPair copy = SerializableTester.reserialize(pair);
assertEquals(pair.forward, copy.forward);
assertEquals(pair.backward, copy.backward);
copy.forward.put(4, "four");
copy.backward.put("five", 5);
assertEquals(copy.backward, copy.forward.inverse());
assertEquals(copy.forward, copy.backward.inverse());
assertTrue(copy.forward.containsKey(4));
assertTrue(copy.forward.containsKey(5));
assertTrue(copy.backward.containsValue(4));
assertTrue(copy.backward.containsValue(5));
assertTrue(copy.forward.containsValue("four"));
assertTrue(copy.forward.containsValue("five"));
assertTrue(copy.backward.containsKey("four"));
assertTrue(copy.backward.containsKey("five"));
}
/**
* The sameness checks ensure that a bimap and its inverse remain consistent,
* even after the deserialized instances are updated. Also, the relationship
* {@code a == b.inverse()} should continue to hold after both bimaps are
* serialized and deserialized together.
*/
@GwtIncompatible("SerializableTester")
public void testSerializationWithInverseSame() {
bimap.put(1, "one");
bimap.put(2, "two");
bimap.put(3, "three");
bimap.put(null, null);
BiMapPair pair = new BiMapPair(bimap);
BiMapPair copy = SerializableTester.reserialize(pair);
assertSame(copy.backward, copy.forward.inverse());
assertSame(copy.forward, copy.backward.inverse());
}
}