Java程序  |  552行  |  16.36 KB

/*
 * 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());
  }
}