Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2007 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.collect.Maps.transformEntries;
     20 import static com.google.common.collect.Maps.transformValues;
     21 import static com.google.common.collect.testing.Helpers.mapEntry;
     22 import static com.google.common.truth.Truth.assertThat;
     23 
     24 import com.google.common.annotations.GwtCompatible;
     25 import com.google.common.base.Converter;
     26 import com.google.common.base.Equivalence;
     27 import com.google.common.base.Function;
     28 import com.google.common.base.Functions;
     29 import com.google.common.base.Predicate;
     30 import com.google.common.base.Predicates;
     31 import com.google.common.collect.Maps.EntryTransformer;
     32 import com.google.common.collect.Maps.ValueDifferenceImpl;
     33 import com.google.common.collect.SetsTest.Derived;
     34 import com.google.common.testing.EqualsTester;
     35 import com.google.common.testing.SerializableTester;
     36 
     37 import junit.framework.TestCase;
     38 
     39 import java.util.Arrays;
     40 import java.util.Collections;
     41 import java.util.Comparator;
     42 import java.util.EnumMap;
     43 import java.util.HashMap;
     44 import java.util.IdentityHashMap;
     45 import java.util.Iterator;
     46 import java.util.LinkedHashMap;
     47 import java.util.List;
     48 import java.util.Map;
     49 import java.util.Map.Entry;
     50 import java.util.Set;
     51 import java.util.SortedMap;
     52 import java.util.SortedSet;
     53 import java.util.TreeMap;
     54 import java.util.concurrent.ConcurrentMap;
     55 
     56 /**
     57  * Unit test for {@code Maps}.
     58  *
     59  * @author Kevin Bourrillion
     60  * @author Mike Bostock
     61  * @author Jared Levy
     62  */
     63 @GwtCompatible(emulated = true)
     64 public class MapsTest extends TestCase {
     65 
     66   private static final Comparator<Integer> SOME_COMPARATOR =
     67       Collections.reverseOrder();
     68 
     69   public void testHashMap() {
     70     HashMap<Integer, Integer> map = Maps.newHashMap();
     71     assertEquals(Collections.emptyMap(), map);
     72   }
     73 
     74   public void testHashMapWithInitialMap() {
     75     Map<String, Integer> original = new TreeMap<String, Integer>();
     76     original.put("a", 1);
     77     original.put("b", 2);
     78     original.put("c", 3);
     79     HashMap<String, Integer> map = Maps.newHashMap(original);
     80     assertEquals(original, map);
     81   }
     82 
     83   public void testHashMapGeneralizesTypes() {
     84     Map<String, Integer> original = new TreeMap<String, Integer>();
     85     original.put("a", 1);
     86     original.put("b", 2);
     87     original.put("c", 3);
     88     HashMap<Object, Object> map =
     89         Maps.newHashMap((Map<? extends Object, ? extends Object>) original);
     90     assertEquals(original, map);
     91   }
     92 
     93   public void testCapacityForNegativeSizeFails() {
     94     try {
     95       Maps.capacity(-1);
     96       fail("Negative expected size must result in IllegalArgumentException");
     97     } catch (IllegalArgumentException ex) {
     98     }
     99   }
    100 
    101   public void testCapacityForLargeSizes() {
    102     int[] largeExpectedSizes = new int[] {
    103       Integer.MAX_VALUE / 2 - 1,
    104       Integer.MAX_VALUE / 2,
    105       Integer.MAX_VALUE / 2 + 1,
    106       Integer.MAX_VALUE - 1,
    107       Integer.MAX_VALUE};
    108     for (int expectedSize : largeExpectedSizes) {
    109       int capacity = Maps.capacity(expectedSize);
    110       assertTrue(
    111           "capacity (" + capacity + ") must be >= expectedSize (" + expectedSize + ")",
    112           capacity >= expectedSize);
    113     }
    114   }
    115 
    116   public void testLinkedHashMap() {
    117     LinkedHashMap<Integer, Integer> map = Maps.newLinkedHashMap();
    118     assertEquals(Collections.emptyMap(), map);
    119   }
    120 
    121   @SuppressWarnings("serial")
    122   public void testLinkedHashMapWithInitialMap() {
    123     Map<String, String> map = new LinkedHashMap<String, String>() {{
    124       put("Hello", "World");
    125       put("first", "second");
    126       put("polygene", "lubricants");
    127       put("alpha", "betical");
    128     }};
    129 
    130     LinkedHashMap<String, String> copy = Maps.newLinkedHashMap(map);
    131 
    132     Iterator<Entry<String, String>> iter = copy.entrySet().iterator();
    133     assertTrue(iter.hasNext());
    134     Entry<String, String> entry = iter.next();
    135     assertEquals("Hello", entry.getKey());
    136     assertEquals("World", entry.getValue());
    137     assertTrue(iter.hasNext());
    138 
    139     entry = iter.next();
    140     assertEquals("first", entry.getKey());
    141     assertEquals("second", entry.getValue());
    142     assertTrue(iter.hasNext());
    143 
    144     entry = iter.next();
    145     assertEquals("polygene", entry.getKey());
    146     assertEquals("lubricants", entry.getValue());
    147     assertTrue(iter.hasNext());
    148 
    149     entry = iter.next();
    150     assertEquals("alpha", entry.getKey());
    151     assertEquals("betical", entry.getValue());
    152     assertFalse(iter.hasNext());
    153   }
    154 
    155   public void testLinkedHashMapGeneralizesTypes() {
    156     Map<String, Integer> original = new LinkedHashMap<String, Integer>();
    157     original.put("a", 1);
    158     original.put("b", 2);
    159     original.put("c", 3);
    160     HashMap<Object, Object> map
    161         = Maps.<Object, Object>newLinkedHashMap(original);
    162     assertEquals(original, map);
    163   }
    164 
    165   public void testIdentityHashMap() {
    166     IdentityHashMap<Integer, Integer> map = Maps.newIdentityHashMap();
    167     assertEquals(Collections.emptyMap(), map);
    168   }
    169 
    170   public void testConcurrentMap() {
    171     ConcurrentMap<Integer, Integer> map = Maps.newConcurrentMap();
    172     assertEquals(Collections.emptyMap(), map);
    173   }
    174 
    175   public void testTreeMap() {
    176     TreeMap<Integer, Integer> map = Maps.newTreeMap();
    177     assertEquals(Collections.emptyMap(), map);
    178     assertNull(map.comparator());
    179   }
    180 
    181   public void testTreeMapDerived() {
    182     TreeMap<Derived, Integer> map = Maps.newTreeMap();
    183     assertEquals(Collections.emptyMap(), map);
    184     map.put(new Derived("foo"), 1);
    185     map.put(new Derived("bar"), 2);
    186     assertThat(map.keySet()).has().exactly(
    187         new Derived("bar"), new Derived("foo")).inOrder();
    188     assertThat(map.values()).has().exactly(2, 1).inOrder();
    189     assertNull(map.comparator());
    190   }
    191 
    192   public void testTreeMapNonGeneric() {
    193     TreeMap<LegacyComparable, Integer> map = Maps.newTreeMap();
    194     assertEquals(Collections.emptyMap(), map);
    195     map.put(new LegacyComparable("foo"), 1);
    196     map.put(new LegacyComparable("bar"), 2);
    197     assertThat(map.keySet()).has().exactly(
    198         new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder();
    199     assertThat(map.values()).has().exactly(2, 1).inOrder();
    200     assertNull(map.comparator());
    201   }
    202 
    203   public void testTreeMapWithComparator() {
    204     TreeMap<Integer, Integer> map = Maps.newTreeMap(SOME_COMPARATOR);
    205     assertEquals(Collections.emptyMap(), map);
    206     assertSame(SOME_COMPARATOR, map.comparator());
    207   }
    208 
    209   public void testTreeMapWithInitialMap() {
    210     SortedMap<Integer, Integer> map = Maps.newTreeMap();
    211     map.put(5, 10);
    212     map.put(3, 20);
    213     map.put(1, 30);
    214     TreeMap<Integer, Integer> copy = Maps.newTreeMap(map);
    215     assertEquals(copy, map);
    216     assertSame(copy.comparator(), map.comparator());
    217   }
    218 
    219   public enum SomeEnum { SOME_INSTANCE }
    220 
    221   public void testEnumMap() {
    222     EnumMap<SomeEnum, Integer> map = Maps.newEnumMap(SomeEnum.class);
    223     assertEquals(Collections.emptyMap(), map);
    224     map.put(SomeEnum.SOME_INSTANCE, 0);
    225     assertEquals(Collections.singletonMap(SomeEnum.SOME_INSTANCE, 0), map);
    226   }
    227 
    228   public void testEnumMapNullClass() {
    229     try {
    230       Maps.<SomeEnum, Long>newEnumMap((Class<MapsTest.SomeEnum>) null);
    231       fail("no exception thrown");
    232     } catch (NullPointerException expected) {
    233     }
    234   }
    235 
    236   public void testEnumMapWithInitialEnumMap() {
    237     EnumMap<SomeEnum, Integer> original = Maps.newEnumMap(SomeEnum.class);
    238     original.put(SomeEnum.SOME_INSTANCE, 0);
    239     EnumMap<SomeEnum, Integer> copy = Maps.newEnumMap(original);
    240     assertEquals(original, copy);
    241   }
    242 
    243   public void testEnumMapWithInitialEmptyEnumMap() {
    244     EnumMap<SomeEnum, Integer> original = Maps.newEnumMap(SomeEnum.class);
    245     EnumMap<SomeEnum, Integer> copy = Maps.newEnumMap(original);
    246     assertEquals(original, copy);
    247     assertNotSame(original, copy);
    248   }
    249 
    250   public void testEnumMapWithInitialMap() {
    251     HashMap<SomeEnum, Integer> original = Maps.newHashMap();
    252     original.put(SomeEnum.SOME_INSTANCE, 0);
    253     EnumMap<SomeEnum, Integer> copy = Maps.newEnumMap(original);
    254     assertEquals(original, copy);
    255   }
    256 
    257   public void testEnumMapWithInitialEmptyMap() {
    258     Map<SomeEnum, Integer> original = Maps.newHashMap();
    259     try {
    260       Maps.newEnumMap(original);
    261       fail("Empty map must result in an IllegalArgumentException");
    262     } catch (IllegalArgumentException expected) {}
    263   }
    264 
    265   public void testToStringImplWithNullKeys() throws Exception {
    266     Map<String, String> hashmap = Maps.newHashMap();
    267     hashmap.put("foo", "bar");
    268     hashmap.put(null, "baz");
    269 
    270     assertEquals(hashmap.toString(), Maps.toStringImpl(hashmap));
    271   }
    272 
    273   public void testToStringImplWithNullValues() throws Exception {
    274     Map<String, String> hashmap = Maps.newHashMap();
    275     hashmap.put("foo", "bar");
    276     hashmap.put("baz", null);
    277 
    278     assertEquals(hashmap.toString(), Maps.toStringImpl(hashmap));
    279   }
    280 
    281   private static final Map<Integer, Integer> EMPTY
    282       = Collections.emptyMap();
    283   private static final Map<Integer, Integer> SINGLETON
    284       = Collections.singletonMap(1, 2);
    285 
    286   public void testMapDifferenceEmptyEmpty() {
    287     MapDifference<Integer, Integer> diff = Maps.difference(EMPTY, EMPTY);
    288     assertTrue(diff.areEqual());
    289     assertEquals(EMPTY, diff.entriesOnlyOnLeft());
    290     assertEquals(EMPTY, diff.entriesOnlyOnRight());
    291     assertEquals(EMPTY, diff.entriesInCommon());
    292     assertEquals(EMPTY, diff.entriesDiffering());
    293     assertEquals("equal", diff.toString());
    294   }
    295 
    296   public void testMapDifferenceEmptySingleton() {
    297     MapDifference<Integer, Integer> diff = Maps.difference(EMPTY, SINGLETON);
    298     assertFalse(diff.areEqual());
    299     assertEquals(EMPTY, diff.entriesOnlyOnLeft());
    300     assertEquals(SINGLETON, diff.entriesOnlyOnRight());
    301     assertEquals(EMPTY, diff.entriesInCommon());
    302     assertEquals(EMPTY, diff.entriesDiffering());
    303     assertEquals("not equal: only on right={1=2}", diff.toString());
    304   }
    305 
    306   public void testMapDifferenceSingletonEmpty() {
    307     MapDifference<Integer, Integer> diff = Maps.difference(SINGLETON, EMPTY);
    308     assertFalse(diff.areEqual());
    309     assertEquals(SINGLETON, diff.entriesOnlyOnLeft());
    310     assertEquals(EMPTY, diff.entriesOnlyOnRight());
    311     assertEquals(EMPTY, diff.entriesInCommon());
    312     assertEquals(EMPTY, diff.entriesDiffering());
    313     assertEquals("not equal: only on left={1=2}", diff.toString());
    314   }
    315 
    316   public void testMapDifferenceTypical() {
    317     Map<Integer, String> left = ImmutableMap.of(
    318         1, "a", 2, "b", 3, "c", 4, "d", 5, "e");
    319     Map<Integer, String> right = ImmutableMap.of(
    320         1, "a", 3, "f", 5, "g", 6, "z");
    321 
    322     MapDifference<Integer, String> diff1 = Maps.difference(left, right);
    323     assertFalse(diff1.areEqual());
    324     assertEquals(ImmutableMap.of(2, "b", 4, "d"), diff1.entriesOnlyOnLeft());
    325     assertEquals(ImmutableMap.of(6, "z"), diff1.entriesOnlyOnRight());
    326     assertEquals(ImmutableMap.of(1, "a"), diff1.entriesInCommon());
    327     assertEquals(ImmutableMap.of(3,
    328         ValueDifferenceImpl.create("c", "f"), 5,
    329         ValueDifferenceImpl.create("e", "g")),
    330         diff1.entriesDiffering());
    331     assertEquals("not equal: only on left={2=b, 4=d}: only on right={6=z}: "
    332         + "value differences={3=(c, f), 5=(e, g)}", diff1.toString());
    333 
    334     MapDifference<Integer, String> diff2 = Maps.difference(right, left);
    335     assertFalse(diff2.areEqual());
    336     assertEquals(ImmutableMap.of(6, "z"), diff2.entriesOnlyOnLeft());
    337     assertEquals(ImmutableMap.of(2, "b", 4, "d"), diff2.entriesOnlyOnRight());
    338     assertEquals(ImmutableMap.of(1, "a"), diff2.entriesInCommon());
    339     assertEquals(ImmutableMap.of(3,
    340         ValueDifferenceImpl.create("f", "c"), 5,
    341         ValueDifferenceImpl.create("g", "e")),
    342         diff2.entriesDiffering());
    343     assertEquals("not equal: only on left={6=z}: only on right={2=b, 4=d}: "
    344         + "value differences={3=(f, c), 5=(g, e)}", diff2.toString());
    345   }
    346 
    347   public void testMapDifferenceEquals() {
    348     Map<Integer, String> left = ImmutableMap.of(
    349         1, "a", 2, "b", 3, "c", 4, "d", 5, "e");
    350     Map<Integer, String> right = ImmutableMap.of(
    351         1, "a", 3, "f", 5, "g", 6, "z");
    352     Map<Integer, String> right2 = ImmutableMap.of(
    353         1, "a", 3, "h", 5, "g", 6, "z");
    354     MapDifference<Integer, String> original = Maps.difference(left, right);
    355     MapDifference<Integer, String> same = Maps.difference(left, right);
    356     MapDifference<Integer, String> reverse = Maps.difference(right, left);
    357     MapDifference<Integer, String> diff2 = Maps.difference(left, right2);
    358 
    359     new EqualsTester()
    360         .addEqualityGroup(original, same)
    361         .addEqualityGroup(reverse)
    362         .addEqualityGroup(diff2)
    363         .testEquals();
    364   }
    365 
    366   public void testMapDifferencePredicateTypical() {
    367     Map<Integer, String> left = ImmutableMap.of(
    368         1, "a", 2, "b", 3, "c", 4, "d", 5, "e");
    369     Map<Integer, String> right = ImmutableMap.of(
    370         1, "A", 3, "F", 5, "G", 6, "Z");
    371 
    372     // TODO(kevinb): replace with Ascii.caseInsensitiveEquivalence() when it
    373     // exists
    374     Equivalence<String> caseInsensitiveEquivalence = Equivalence.equals().onResultOf(
    375         new Function<String, String>() {
    376           @Override public String apply(String input) {
    377             return input.toLowerCase();
    378           }
    379         });
    380 
    381     MapDifference<Integer, String> diff1 = Maps.difference(left, right,
    382         caseInsensitiveEquivalence);
    383     assertFalse(diff1.areEqual());
    384     assertEquals(ImmutableMap.of(2, "b", 4, "d"), diff1.entriesOnlyOnLeft());
    385     assertEquals(ImmutableMap.of(6, "Z"), diff1.entriesOnlyOnRight());
    386     assertEquals(ImmutableMap.of(1, "a"), diff1.entriesInCommon());
    387     assertEquals(ImmutableMap.of(3,
    388         ValueDifferenceImpl.create("c", "F"), 5,
    389         ValueDifferenceImpl.create("e", "G")),
    390         diff1.entriesDiffering());
    391     assertEquals("not equal: only on left={2=b, 4=d}: only on right={6=Z}: "
    392         + "value differences={3=(c, F), 5=(e, G)}", diff1.toString());
    393 
    394     MapDifference<Integer, String> diff2 = Maps.difference(right, left,
    395         caseInsensitiveEquivalence);
    396     assertFalse(diff2.areEqual());
    397     assertEquals(ImmutableMap.of(6, "Z"), diff2.entriesOnlyOnLeft());
    398     assertEquals(ImmutableMap.of(2, "b", 4, "d"), diff2.entriesOnlyOnRight());
    399     assertEquals(ImmutableMap.of(1, "A"), diff2.entriesInCommon());
    400     assertEquals(ImmutableMap.of(3,
    401         ValueDifferenceImpl.create("F", "c"), 5,
    402         ValueDifferenceImpl.create("G", "e")),
    403         diff2.entriesDiffering());
    404     assertEquals("not equal: only on left={6=Z}: only on right={2=b, 4=d}: "
    405         + "value differences={3=(F, c), 5=(G, e)}", diff2.toString());
    406   }
    407 
    408   private static final SortedMap<Integer, Integer> SORTED_EMPTY = Maps.newTreeMap();
    409   private static final SortedMap<Integer, Integer> SORTED_SINGLETON =
    410       ImmutableSortedMap.of(1, 2);
    411 
    412   public void testMapDifferenceOfSortedMapIsSorted() {
    413     Map<Integer, Integer> map = SORTED_SINGLETON;
    414     MapDifference<Integer, Integer> difference = Maps.difference(map, EMPTY);
    415     assertTrue(difference instanceof SortedMapDifference);
    416   }
    417 
    418   public void testSortedMapDifferenceEmptyEmpty() {
    419     SortedMapDifference<Integer, Integer> diff =
    420         Maps.difference(SORTED_EMPTY, SORTED_EMPTY);
    421     assertTrue(diff.areEqual());
    422     assertEquals(SORTED_EMPTY, diff.entriesOnlyOnLeft());
    423     assertEquals(SORTED_EMPTY, diff.entriesOnlyOnRight());
    424     assertEquals(SORTED_EMPTY, diff.entriesInCommon());
    425     assertEquals(SORTED_EMPTY, diff.entriesDiffering());
    426     assertEquals("equal", diff.toString());
    427   }
    428 
    429   public void testSortedMapDifferenceEmptySingleton() {
    430     SortedMapDifference<Integer, Integer> diff =
    431         Maps.difference(SORTED_EMPTY, SORTED_SINGLETON);
    432     assertFalse(diff.areEqual());
    433     assertEquals(SORTED_EMPTY, diff.entriesOnlyOnLeft());
    434     assertEquals(SORTED_SINGLETON, diff.entriesOnlyOnRight());
    435     assertEquals(SORTED_EMPTY, diff.entriesInCommon());
    436     assertEquals(SORTED_EMPTY, diff.entriesDiffering());
    437     assertEquals("not equal: only on right={1=2}", diff.toString());
    438   }
    439 
    440   public void testSortedMapDifferenceSingletonEmpty() {
    441     SortedMapDifference<Integer, Integer> diff =
    442         Maps.difference(SORTED_SINGLETON, SORTED_EMPTY);
    443     assertFalse(diff.areEqual());
    444     assertEquals(SORTED_SINGLETON, diff.entriesOnlyOnLeft());
    445     assertEquals(SORTED_EMPTY, diff.entriesOnlyOnRight());
    446     assertEquals(SORTED_EMPTY, diff.entriesInCommon());
    447     assertEquals(SORTED_EMPTY, diff.entriesDiffering());
    448     assertEquals("not equal: only on left={1=2}", diff.toString());
    449   }
    450 
    451   public void testSortedMapDifferenceTypical() {
    452     SortedMap<Integer, String> left =
    453         ImmutableSortedMap.<Integer, String>reverseOrder()
    454         .put(1, "a").put(2, "b").put(3, "c").put(4, "d").put(5, "e")
    455         .build();
    456 
    457     SortedMap<Integer, String> right =
    458         ImmutableSortedMap.of(1, "a", 3, "f", 5, "g", 6, "z");
    459 
    460     SortedMapDifference<Integer, String> diff1 =
    461         Maps.difference(left, right);
    462     assertFalse(diff1.areEqual());
    463     assertThat(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
    464         Maps.immutableEntry(4, "d"), Maps.immutableEntry(2, "b")).inOrder();
    465     assertThat(diff1.entriesOnlyOnRight().entrySet()).has().item(
    466         Maps.immutableEntry(6, "z"));
    467     assertThat(diff1.entriesInCommon().entrySet()).has().item(
    468         Maps.immutableEntry(1, "a"));
    469     assertThat(diff1.entriesDiffering().entrySet()).has().exactly(
    470         Maps.immutableEntry(5, ValueDifferenceImpl.create("e", "g")),
    471         Maps.immutableEntry(3, ValueDifferenceImpl.create("c", "f"))).inOrder();
    472     assertEquals("not equal: only on left={4=d, 2=b}: only on right={6=z}: "
    473         + "value differences={5=(e, g), 3=(c, f)}", diff1.toString());
    474 
    475     SortedMapDifference<Integer, String> diff2 =
    476         Maps.difference(right, left);
    477     assertFalse(diff2.areEqual());
    478     assertThat(diff2.entriesOnlyOnLeft().entrySet()).has().item(
    479         Maps.immutableEntry(6, "z"));
    480     assertThat(diff2.entriesOnlyOnRight().entrySet()).has().exactly(
    481         Maps.immutableEntry(2, "b"), Maps.immutableEntry(4, "d")).inOrder();
    482     assertThat(diff1.entriesInCommon().entrySet()).has().item(
    483         Maps.immutableEntry(1, "a"));
    484     assertEquals(ImmutableMap.of(
    485             3, ValueDifferenceImpl.create("f", "c"),
    486             5, ValueDifferenceImpl.create("g", "e")),
    487         diff2.entriesDiffering());
    488     assertEquals("not equal: only on left={6=z}: only on right={2=b, 4=d}: "
    489         + "value differences={3=(f, c), 5=(g, e)}", diff2.toString());
    490   }
    491 
    492   public void testSortedMapDifferenceImmutable() {
    493     SortedMap<Integer, String> left = Maps.newTreeMap(
    494         ImmutableSortedMap.of(1, "a", 2, "b", 3, "c", 4, "d", 5, "e"));
    495     SortedMap<Integer, String> right =
    496         Maps.newTreeMap(ImmutableSortedMap.of(1, "a", 3, "f", 5, "g", 6, "z"));
    497 
    498     SortedMapDifference<Integer, String> diff1 =
    499         Maps.difference(left, right);
    500     left.put(6, "z");
    501     assertFalse(diff1.areEqual());
    502     assertThat(diff1.entriesOnlyOnLeft().entrySet()).has().exactly(
    503         Maps.immutableEntry(2, "b"), Maps.immutableEntry(4, "d")).inOrder();
    504     assertThat(diff1.entriesOnlyOnRight().entrySet()).has().item(
    505         Maps.immutableEntry(6, "z"));
    506     assertThat(diff1.entriesInCommon().entrySet()).has().item(
    507         Maps.immutableEntry(1, "a"));
    508     assertThat(diff1.entriesDiffering().entrySet()).has().exactly(
    509         Maps.immutableEntry(3, ValueDifferenceImpl.create("c", "f")),
    510         Maps.immutableEntry(5, ValueDifferenceImpl.create("e", "g"))).inOrder();
    511     try {
    512       diff1.entriesInCommon().put(7, "x");
    513       fail();
    514     } catch (UnsupportedOperationException expected) {
    515     }
    516     try {
    517       diff1.entriesOnlyOnLeft().put(7, "x");
    518       fail();
    519     } catch (UnsupportedOperationException expected) {
    520     }
    521     try {
    522       diff1.entriesOnlyOnRight().put(7, "x");
    523       fail();
    524     } catch (UnsupportedOperationException expected) {
    525     }
    526   }
    527 
    528   public void testSortedMapDifferenceEquals() {
    529     SortedMap<Integer, String> left =
    530         ImmutableSortedMap.of(1, "a", 2, "b", 3, "c", 4, "d", 5, "e");
    531     SortedMap<Integer, String> right =
    532         ImmutableSortedMap.of(1, "a", 3, "f", 5, "g", 6, "z");
    533     SortedMap<Integer, String> right2 =
    534         ImmutableSortedMap.of(1, "a", 3, "h", 5, "g", 6, "z");
    535     SortedMapDifference<Integer, String> original =
    536         Maps.difference(left, right);
    537     SortedMapDifference<Integer, String> same =
    538         Maps.difference(left, right);
    539     SortedMapDifference<Integer, String> reverse =
    540         Maps.difference(right, left);
    541     SortedMapDifference<Integer, String> diff2 =
    542         Maps.difference(left, right2);
    543 
    544     new EqualsTester()
    545         .addEqualityGroup(original, same)
    546         .addEqualityGroup(reverse)
    547         .addEqualityGroup(diff2)
    548         .testEquals();
    549   }
    550 
    551   private static final Function<String, Integer> LENGTH_FUNCTION =
    552       new Function<String, Integer>() {
    553         @Override
    554         public Integer apply(String input) {
    555           return input.length();
    556         }
    557       };
    558 
    559   public void testAsMap() {
    560     Set<String> strings = ImmutableSet.of("one", "two", "three");
    561     Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
    562     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
    563     assertEquals(Integer.valueOf(5), map.get("three"));
    564     assertNull(map.get("five"));
    565     assertThat(map.entrySet()).has().exactly(
    566         mapEntry("one", 3),
    567         mapEntry("two", 3),
    568         mapEntry("three", 5)).inOrder();
    569   }
    570 
    571   public void testAsMapReadsThrough() {
    572     Set<String> strings = Sets.newLinkedHashSet();
    573     Collections.addAll(strings, "one", "two", "three");
    574     Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
    575     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
    576     assertNull(map.get("four"));
    577     strings.add("four");
    578     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5, "four", 4), map);
    579     assertEquals(Integer.valueOf(4), map.get("four"));
    580   }
    581 
    582   public void testAsMapWritesThrough() {
    583     Set<String> strings = Sets.newLinkedHashSet();
    584     Collections.addAll(strings, "one", "two", "three");
    585     Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
    586     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
    587     assertEquals(Integer.valueOf(3), map.remove("two"));
    588     assertThat(strings).has().exactly("one", "three").inOrder();
    589   }
    590 
    591   public void testAsMapEmpty() {
    592     Set<String> strings = ImmutableSet.of();
    593     Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
    594     assertThat(map.entrySet()).isEmpty();
    595     assertTrue(map.isEmpty());
    596     assertNull(map.get("five"));
    597   }
    598 
    599   private static class NonNavigableSortedSet
    600       extends ForwardingSortedSet<String> {
    601     private final SortedSet<String> delegate = Sets.newTreeSet();
    602 
    603     @Override
    604     protected SortedSet<String> delegate() {
    605       return delegate;
    606     }
    607   }
    608 
    609   public void testAsMapReturnsSortedMapForSortedSetInput() {
    610     Set<String> set = new NonNavigableSortedSet();
    611     assertTrue(Maps.asMap(set, Functions.identity()) instanceof SortedMap);
    612   }
    613 
    614   public void testAsMapSorted() {
    615     SortedSet<String> strings = new NonNavigableSortedSet();
    616     Collections.addAll(strings, "one", "two", "three");
    617     SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
    618     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
    619     assertEquals(Integer.valueOf(5), map.get("three"));
    620     assertNull(map.get("five"));
    621     assertThat(map.entrySet()).has().exactly(
    622         mapEntry("one", 3),
    623         mapEntry("three", 5),
    624         mapEntry("two", 3)).inOrder();
    625     assertThat(map.tailMap("onea").entrySet()).has().exactly(
    626         mapEntry("three", 5),
    627         mapEntry("two", 3)).inOrder();
    628     assertThat(map.subMap("one", "two").entrySet()).has().exactly(
    629         mapEntry("one", 3),
    630         mapEntry("three", 5)).inOrder();
    631   }
    632 
    633   public void testAsMapSortedReadsThrough() {
    634     SortedSet<String> strings = new NonNavigableSortedSet();
    635     Collections.addAll(strings, "one", "two", "three");
    636     SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
    637     assertNull(map.comparator());
    638     assertEquals(ImmutableSortedMap.of("one", 3, "two", 3, "three", 5), map);
    639     assertNull(map.get("four"));
    640     strings.add("four");
    641     assertEquals(
    642         ImmutableSortedMap.of("one", 3, "two", 3, "three", 5, "four", 4),
    643         map);
    644     assertEquals(Integer.valueOf(4), map.get("four"));
    645     SortedMap<String, Integer> headMap = map.headMap("two");
    646     assertEquals(
    647         ImmutableSortedMap.of("four", 4, "one", 3, "three", 5),
    648         headMap);
    649     strings.add("five");
    650     strings.remove("one");
    651     assertEquals(
    652         ImmutableSortedMap.of("five", 4, "four", 4, "three", 5),
    653         headMap);
    654     assertThat(map.entrySet()).has().exactly(
    655         mapEntry("five", 4),
    656         mapEntry("four", 4),
    657         mapEntry("three", 5),
    658         mapEntry("two", 3)).inOrder();
    659   }
    660 
    661   public void testAsMapSortedWritesThrough() {
    662     SortedSet<String> strings = new NonNavigableSortedSet();
    663     Collections.addAll(strings, "one", "two", "three");
    664     SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
    665     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
    666     assertEquals(Integer.valueOf(3), map.remove("two"));
    667     assertThat(strings).has().exactly("one", "three").inOrder();
    668   }
    669 
    670   public void testAsMapSortedSubViewKeySetsDoNotSupportAdd() {
    671     SortedMap<String, Integer> map = Maps.asMap(
    672         new NonNavigableSortedSet(), LENGTH_FUNCTION);
    673     try {
    674       map.subMap("a", "z").keySet().add("a");
    675       fail();
    676     } catch (UnsupportedOperationException expected) {
    677     }
    678     try {
    679       map.tailMap("a").keySet().add("a");
    680       fail();
    681     } catch (UnsupportedOperationException expected) {
    682     }
    683     try {
    684       map.headMap("r").keySet().add("a");
    685       fail();
    686     } catch (UnsupportedOperationException expected) {
    687     }
    688     try {
    689       map.headMap("r").tailMap("m").keySet().add("a");
    690       fail();
    691     } catch (UnsupportedOperationException expected) {
    692     }
    693   }
    694 
    695   public void testAsMapSortedEmpty() {
    696     SortedSet<String> strings = new NonNavigableSortedSet();
    697     SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION);
    698     assertThat(map.entrySet()).isEmpty();
    699     assertTrue(map.isEmpty());
    700     assertNull(map.get("five"));
    701   }
    702 
    703   public void testToMap() {
    704     Iterable<String> strings = ImmutableList.of("one", "two", "three");
    705     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
    706     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
    707     assertThat(map.entrySet()).has().exactly(
    708         mapEntry("one", 3),
    709         mapEntry("two", 3),
    710         mapEntry("three", 5)).inOrder();
    711   }
    712 
    713   public void testToMapIterator() {
    714     Iterator<String> strings = ImmutableList.of("one", "two", "three").iterator();
    715     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
    716     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
    717     assertThat(map.entrySet()).has().exactly(
    718         mapEntry("one", 3),
    719         mapEntry("two", 3),
    720         mapEntry("three", 5)).inOrder();
    721   }
    722 
    723   public void testToMapWithDuplicateKeys() {
    724     Iterable<String> strings = ImmutableList.of("one", "two", "three", "two", "one");
    725     ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION);
    726     assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map);
    727     assertThat(map.entrySet()).has().exactly(
    728         mapEntry("one", 3),
    729         mapEntry("two", 3),
    730         mapEntry("three", 5)).inOrder();
    731   }
    732 
    733   public void testToMapWithNullKeys() {
    734     Iterable<String> strings = Arrays.asList("one", null, "three");
    735     try {
    736       Maps.toMap(strings, Functions.constant("foo"));
    737       fail();
    738     } catch (NullPointerException expected) {
    739     }
    740   }
    741 
    742   public void testToMapWithNullValues() {
    743     Iterable<String> strings = ImmutableList.of("one", "two", "three");
    744     try {
    745       Maps.toMap(strings, Functions.constant(null));
    746       fail();
    747     } catch (NullPointerException expected) {
    748     }
    749   }
    750 
    751   private static final BiMap<Integer, String> INT_TO_STRING_MAP =
    752       new ImmutableBiMap.Builder<Integer, String>()
    753           .put(1, "one")
    754           .put(2, "two")
    755           .put(3, "three")
    756           .build();
    757 
    758   public void testUniqueIndexCollection() {
    759     ImmutableMap<Integer, String> outputMap =
    760         Maps.uniqueIndex(INT_TO_STRING_MAP.values(),
    761             Functions.forMap(INT_TO_STRING_MAP.inverse()));
    762     assertEquals(INT_TO_STRING_MAP, outputMap);
    763   }
    764 
    765   public void testUniqueIndexIterable() {
    766     ImmutableMap<Integer, String> outputMap =
    767         Maps.uniqueIndex(new Iterable<String>() {
    768           @Override
    769           public Iterator<String> iterator() {
    770             return INT_TO_STRING_MAP.values().iterator();
    771           }
    772         },
    773         Functions.forMap(INT_TO_STRING_MAP.inverse()));
    774     assertEquals(INT_TO_STRING_MAP, outputMap);
    775   }
    776 
    777   public void testUniqueIndexIterator() {
    778     ImmutableMap<Integer, String> outputMap =
    779         Maps.uniqueIndex(INT_TO_STRING_MAP.values().iterator(),
    780             Functions.forMap(INT_TO_STRING_MAP.inverse()));
    781     assertEquals(INT_TO_STRING_MAP, outputMap);
    782   }
    783 
    784   /** Can't create the map if more than one value maps to the same key. */
    785   public void testUniqueIndexDuplicates() {
    786     try {
    787       Maps.uniqueIndex(ImmutableSet.of("one", "uno"), Functions.constant(1));
    788       fail();
    789     } catch (IllegalArgumentException expected) {
    790     }
    791   }
    792 
    793   /** Null values are not allowed. */
    794   public void testUniqueIndexNullValue() {
    795     List<String> listWithNull = Lists.newArrayList((String) null);
    796     try {
    797       Maps.uniqueIndex(listWithNull, Functions.constant(1));
    798       fail();
    799     } catch (NullPointerException expected) {
    800     }
    801   }
    802 
    803   /** Null keys aren't allowed either. */
    804   public void testUniqueIndexNullKey() {
    805     List<String> oneStringList = Lists.newArrayList("foo");
    806     try {
    807       Maps.uniqueIndex(oneStringList, Functions.constant(null));
    808       fail();
    809     } catch (NullPointerException expected) {
    810     }
    811   }
    812 
    813   public void testAsConverter_nominal() throws Exception {
    814     ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of(
    815         "one", 1,
    816         "two", 2);
    817     Converter<String, Integer> converter = Maps.asConverter(biMap);
    818     for (Entry<String, Integer> entry : biMap.entrySet()) {
    819       assertSame(entry.getValue(), converter.convert(entry.getKey()));
    820     }
    821   }
    822 
    823   public void testAsConverter_inverse() throws Exception {
    824     ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of(
    825         "one", 1,
    826         "two", 2);
    827     Converter<String, Integer> converter = Maps.asConverter(biMap);
    828     for (Entry<String, Integer> entry : biMap.entrySet()) {
    829       assertSame(entry.getKey(), converter.reverse().convert(entry.getValue()));
    830     }
    831   }
    832 
    833   public void testAsConverter_noMapping() throws Exception {
    834     ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of(
    835         "one", 1,
    836         "two", 2);
    837     Converter<String, Integer> converter = Maps.asConverter(biMap);
    838     try {
    839       converter.convert("three");
    840       fail();
    841     } catch (IllegalArgumentException expected) {
    842     }
    843   }
    844 
    845   public void testAsConverter_nullConversions() throws Exception {
    846     ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of(
    847         "one", 1,
    848         "two", 2);
    849     Converter<String, Integer> converter = Maps.asConverter(biMap);
    850     assertNull(converter.convert(null));
    851     assertNull(converter.reverse().convert(null));
    852   }
    853 
    854   public void testAsConverter_isAView() throws Exception {
    855     BiMap<String, Integer> biMap = HashBiMap.create();
    856     biMap.put("one", 1);
    857     biMap.put("two", 2);
    858     Converter<String, Integer> converter = Maps.asConverter(biMap);
    859 
    860     assertSame(1, converter.convert("one"));
    861     assertSame(2, converter.convert("two"));
    862     try {
    863       converter.convert("three");
    864       fail();
    865     } catch (IllegalArgumentException expected) {
    866     }
    867 
    868     biMap.put("three", 3);
    869 
    870     assertSame(1, converter.convert("one"));
    871     assertSame(2, converter.convert("two"));
    872     assertSame(3, converter.convert("three"));
    873   }
    874 
    875   public void testAsConverter_withNullMapping() throws Exception {
    876     BiMap<String, Integer> biMap = HashBiMap.create();
    877     biMap.put("one", 1);
    878     biMap.put("two", 2);
    879     biMap.put("three", null);
    880     try {
    881       Maps.asConverter(biMap).convert("three");
    882       fail();
    883     } catch (IllegalArgumentException expected) {
    884     }
    885   }
    886 
    887   public void testAsConverter_toString() {
    888     ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of(
    889         "one", 1,
    890         "two", 2);
    891     Converter<String, Integer> converter = Maps.asConverter(biMap);
    892     assertEquals("Maps.asConverter({one=1, two=2})", converter.toString());
    893   }
    894 
    895   public void testAsConverter_serialization() {
    896     ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of(
    897         "one", 1,
    898         "two", 2);
    899     Converter<String, Integer> converter = Maps.asConverter(biMap);
    900     SerializableTester.reserializeAndAssert(converter);
    901   }
    902 
    903   public void testUnmodifiableBiMap() {
    904     BiMap<Integer, String> mod = HashBiMap.create();
    905     mod.put(1, "one");
    906     mod.put(2, "two");
    907     mod.put(3, "three");
    908 
    909     BiMap<Number, String> unmod = Maps.<Number, String>unmodifiableBiMap(mod);
    910 
    911     /* No aliasing on inverse operations. */
    912     assertSame(unmod.inverse(), unmod.inverse());
    913     assertSame(unmod, unmod.inverse().inverse());
    914 
    915     /* Unmodifiable is a view. */
    916     mod.put(4, "four");
    917     assertEquals(true, unmod.get(4).equals("four"));
    918     assertEquals(true, unmod.inverse().get("four").equals(4));
    919 
    920     /* UnsupportedOperationException on direct modifications. */
    921     try {
    922       unmod.put(4, "four");
    923       fail("UnsupportedOperationException expected");
    924     } catch (UnsupportedOperationException expected) {}
    925     try {
    926       unmod.forcePut(4, "four");
    927       fail("UnsupportedOperationException expected");
    928     } catch (UnsupportedOperationException expected) {}
    929     try {
    930       unmod.putAll(Collections.singletonMap(4, "four"));
    931       fail("UnsupportedOperationException expected");
    932     } catch (UnsupportedOperationException expected) {}
    933 
    934     /* UnsupportedOperationException on indirect modifications. */
    935     BiMap<String, Number> inverse = unmod.inverse();
    936     try {
    937       inverse.put("four", 4);
    938       fail("UnsupportedOperationException expected");
    939     } catch (UnsupportedOperationException expected) {}
    940     try {
    941       inverse.forcePut("four", 4);
    942       fail("UnsupportedOperationException expected");
    943     } catch (UnsupportedOperationException expected) {}
    944     try {
    945       inverse.putAll(Collections.singletonMap("four", 4));
    946       fail("UnsupportedOperationException expected");
    947     } catch (UnsupportedOperationException expected) {}
    948     Set<String> values = unmod.values();
    949     try {
    950       values.remove("four");
    951       fail("UnsupportedOperationException expected");
    952     } catch (UnsupportedOperationException expected) {}
    953     Set<Map.Entry<Number, String>> entries = unmod.entrySet();
    954     Map.Entry<Number, String> entry = entries.iterator().next();
    955     try {
    956       entry.setValue("four");
    957       fail("UnsupportedOperationException expected");
    958     } catch (UnsupportedOperationException expected) {}
    959     @SuppressWarnings("unchecked")
    960     Map.Entry<Integer, String> entry2
    961         = (Map.Entry<Integer, String>) entries.toArray()[0];
    962     try {
    963       entry2.setValue("four");
    964       fail("UnsupportedOperationException expected");
    965     } catch (UnsupportedOperationException expected) {}
    966   }
    967 
    968   public void testImmutableEntry() {
    969     Map.Entry<String, Integer> e = Maps.immutableEntry("foo", 1);
    970     assertEquals("foo", e.getKey());
    971     assertEquals(1, (int) e.getValue());
    972     try {
    973       e.setValue(2);
    974       fail("UnsupportedOperationException expected");
    975     } catch (UnsupportedOperationException expected) {}
    976     assertEquals("foo=1", e.toString());
    977     assertEquals(101575, e.hashCode());
    978   }
    979 
    980   public void testImmutableEntryNull() {
    981     Map.Entry<String, Integer> e
    982         = Maps.immutableEntry((String) null, (Integer) null);
    983     assertNull(e.getKey());
    984     assertNull(e.getValue());
    985     try {
    986       e.setValue(null);
    987       fail("UnsupportedOperationException expected");
    988     } catch (UnsupportedOperationException expected) {}
    989     assertEquals("null=null", e.toString());
    990     assertEquals(0, e.hashCode());
    991   }
    992 
    993   /** See {@link SynchronizedBiMapTest} for more tests. */
    994   public void testSynchronizedBiMap() {
    995     BiMap<String, Integer> bimap = HashBiMap.create();
    996     bimap.put("one", 1);
    997     BiMap<String, Integer> sync = Maps.synchronizedBiMap(bimap);
    998     bimap.put("two", 2);
    999     sync.put("three", 3);
   1000     assertEquals(ImmutableSet.of(1, 2, 3), bimap.inverse().keySet());
   1001     assertEquals(ImmutableSet.of(1, 2, 3), sync.inverse().keySet());
   1002   }
   1003 
   1004   private static final Predicate<String> NOT_LENGTH_3
   1005       = new Predicate<String>() {
   1006         @Override
   1007         public boolean apply(String input) {
   1008           return input == null || input.length() != 3;
   1009         }
   1010       };
   1011 
   1012   private static final Predicate<Integer> EVEN
   1013       = new Predicate<Integer>() {
   1014         @Override
   1015         public boolean apply(Integer input) {
   1016           return input == null || input % 2 == 0;
   1017         }
   1018       };
   1019 
   1020   private static final Predicate<Entry<String, Integer>> CORRECT_LENGTH
   1021       = new Predicate<Entry<String, Integer>>() {
   1022         @Override
   1023         public boolean apply(Entry<String, Integer> input) {
   1024           return input.getKey().length() == input.getValue();
   1025         }
   1026       };
   1027 
   1028   private static final Function<Integer, Double> SQRT_FUNCTION = new Function<Integer, Double>() {
   1029       @Override
   1030       public Double apply(Integer in) {
   1031         return Math.sqrt(in);
   1032       }
   1033     };
   1034 
   1035   public static class FilteredMapTest extends TestCase {
   1036     Map<String, Integer> createUnfiltered() {
   1037       return Maps.newHashMap();
   1038     }
   1039 
   1040     public void testFilteredKeysIllegalPut() {
   1041       Map<String, Integer> unfiltered = createUnfiltered();
   1042       Map<String, Integer> filtered = Maps.filterKeys(unfiltered, NOT_LENGTH_3);
   1043       filtered.put("a", 1);
   1044       filtered.put("b", 2);
   1045       assertEquals(ImmutableMap.of("a", 1, "b", 2), filtered);
   1046 
   1047       try {
   1048         filtered.put("yyy", 3);
   1049         fail();
   1050       } catch (IllegalArgumentException expected) {}
   1051     }
   1052 
   1053     public void testFilteredKeysIllegalPutAll() {
   1054       Map<String, Integer> unfiltered = createUnfiltered();
   1055       Map<String, Integer> filtered = Maps.filterKeys(unfiltered, NOT_LENGTH_3);
   1056       filtered.put("a", 1);
   1057       filtered.put("b", 2);
   1058       assertEquals(ImmutableMap.of("a", 1, "b", 2), filtered);
   1059 
   1060       try {
   1061         filtered.putAll(ImmutableMap.of("c", 3, "zzz", 4, "b", 5));
   1062         fail();
   1063       } catch (IllegalArgumentException expected) {}
   1064 
   1065       assertEquals(ImmutableMap.of("a", 1, "b", 2), filtered);
   1066     }
   1067 
   1068     public void testFilteredKeysFilteredReflectsBackingChanges() {
   1069       Map<String, Integer> unfiltered = createUnfiltered();
   1070       Map<String, Integer> filtered = Maps.filterKeys(unfiltered, NOT_LENGTH_3);
   1071       unfiltered.put("two", 2);
   1072       unfiltered.put("three", 3);
   1073       unfiltered.put("four", 4);
   1074       assertEquals(ImmutableMap.of("two", 2, "three", 3, "four", 4), unfiltered);
   1075       assertEquals(ImmutableMap.of("three", 3, "four", 4), filtered);
   1076 
   1077       unfiltered.remove("three");
   1078       assertEquals(ImmutableMap.of("two", 2, "four", 4), unfiltered);
   1079       assertEquals(ImmutableMap.of("four", 4), filtered);
   1080 
   1081       unfiltered.clear();
   1082       assertEquals(ImmutableMap.of(), unfiltered);
   1083       assertEquals(ImmutableMap.of(), filtered);
   1084     }
   1085 
   1086     public void testFilteredValuesIllegalPut() {
   1087       Map<String, Integer> unfiltered = createUnfiltered();
   1088       Map<String, Integer> filtered = Maps.filterValues(unfiltered, EVEN);
   1089       filtered.put("a", 2);
   1090       unfiltered.put("b", 4);
   1091       unfiltered.put("c", 5);
   1092       assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered);
   1093 
   1094       try {
   1095         filtered.put("yyy", 3);
   1096         fail();
   1097       } catch (IllegalArgumentException expected) {}
   1098       assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered);
   1099     }
   1100 
   1101     public void testFilteredValuesIllegalPutAll() {
   1102       Map<String, Integer> unfiltered = createUnfiltered();
   1103       Map<String, Integer> filtered = Maps.filterValues(unfiltered, EVEN);
   1104       filtered.put("a", 2);
   1105       unfiltered.put("b", 4);
   1106       unfiltered.put("c", 5);
   1107       assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered);
   1108 
   1109       try {
   1110         filtered.putAll(ImmutableMap.of("c", 4, "zzz", 5, "b", 6));
   1111         fail();
   1112       } catch (IllegalArgumentException expected) {}
   1113       assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered);
   1114     }
   1115 
   1116     public void testFilteredValuesIllegalSetValue() {
   1117       Map<String, Integer> unfiltered = createUnfiltered();
   1118       Map<String, Integer> filtered = Maps.filterValues(unfiltered, EVEN);
   1119       filtered.put("a", 2);
   1120       filtered.put("b", 4);
   1121       assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered);
   1122 
   1123       Entry<String, Integer> entry = filtered.entrySet().iterator().next();
   1124       try {
   1125         entry.setValue(5);
   1126         fail();
   1127       } catch (IllegalArgumentException expected) {}
   1128 
   1129       assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered);
   1130     }
   1131 
   1132     public void testFilteredValuesClear() {
   1133       Map<String, Integer> unfiltered = createUnfiltered();
   1134       unfiltered.put("one", 1);
   1135       unfiltered.put("two", 2);
   1136       unfiltered.put("three", 3);
   1137       unfiltered.put("four", 4);
   1138       Map<String, Integer> filtered = Maps.filterValues(unfiltered, EVEN);
   1139       assertEquals(ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4),
   1140           unfiltered);
   1141       assertEquals(ImmutableMap.of("two", 2, "four", 4), filtered);
   1142 
   1143       filtered.clear();
   1144       assertEquals(ImmutableMap.of("one", 1, "three", 3), unfiltered);
   1145       assertTrue(filtered.isEmpty());
   1146     }
   1147 
   1148     public void testFilteredEntriesIllegalPut() {
   1149       Map<String, Integer> unfiltered = createUnfiltered();
   1150       unfiltered.put("cat", 3);
   1151       unfiltered.put("dog", 2);
   1152       unfiltered.put("horse", 5);
   1153       Map<String, Integer> filtered
   1154           = Maps.filterEntries(unfiltered, CORRECT_LENGTH);
   1155       assertEquals(ImmutableMap.of("cat", 3, "horse", 5), filtered);
   1156 
   1157       filtered.put("chicken", 7);
   1158       assertEquals(ImmutableMap.of("cat", 3, "horse", 5, "chicken", 7), filtered);
   1159 
   1160       try {
   1161         filtered.put("cow", 7);
   1162         fail();
   1163       } catch (IllegalArgumentException expected) {}
   1164       assertEquals(ImmutableMap.of("cat", 3, "horse", 5, "chicken", 7), filtered);
   1165     }
   1166 
   1167     public void testFilteredEntriesIllegalPutAll() {
   1168       Map<String, Integer> unfiltered = createUnfiltered();
   1169       unfiltered.put("cat", 3);
   1170       unfiltered.put("dog", 2);
   1171       unfiltered.put("horse", 5);
   1172       Map<String, Integer> filtered
   1173           = Maps.filterEntries(unfiltered, CORRECT_LENGTH);
   1174       assertEquals(ImmutableMap.of("cat", 3, "horse", 5), filtered);
   1175 
   1176       filtered.put("chicken", 7);
   1177       assertEquals(ImmutableMap.of("cat", 3, "horse", 5, "chicken", 7), filtered);
   1178 
   1179       try {
   1180         filtered.putAll(ImmutableMap.of("sheep", 5, "cow", 7));
   1181         fail();
   1182       } catch (IllegalArgumentException expected) {}
   1183       assertEquals(ImmutableMap.of("cat", 3, "horse", 5, "chicken", 7), filtered);
   1184     }
   1185 
   1186     public void testFilteredEntriesObjectPredicate() {
   1187       Map<String, Integer> unfiltered = createUnfiltered();
   1188       unfiltered.put("cat", 3);
   1189       unfiltered.put("dog", 2);
   1190       unfiltered.put("horse", 5);
   1191       Predicate<Object> predicate = Predicates.alwaysFalse();
   1192       Map<String, Integer> filtered
   1193           = Maps.filterEntries(unfiltered, predicate);
   1194       assertTrue(filtered.isEmpty());
   1195     }
   1196 
   1197     public void testFilteredEntriesWildCardEntryPredicate() {
   1198       Map<String, Integer> unfiltered = createUnfiltered();
   1199       unfiltered.put("cat", 3);
   1200       unfiltered.put("dog", 2);
   1201       unfiltered.put("horse", 5);
   1202       Predicate<Entry<?, ?>> predicate = new Predicate<Entry<?, ?>>() {
   1203         @Override
   1204         public boolean apply(Entry<?, ?> input) {
   1205           return "cat".equals(input.getKey())
   1206               || Integer.valueOf(2) == input.getValue();
   1207         }
   1208       };
   1209       Map<String, Integer> filtered
   1210           = Maps.filterEntries(unfiltered, predicate);
   1211       assertEquals(ImmutableMap.of("cat", 3, "dog", 2), filtered);
   1212     }
   1213   }
   1214 
   1215   public static class FilteredSortedMapTest extends FilteredMapTest {
   1216     @Override
   1217     SortedMap<String, Integer> createUnfiltered() {
   1218       return Maps.newTreeMap();
   1219     }
   1220 
   1221     public void testFilterKeysIdentifiesSortedMap() {
   1222       SortedMap<String, Integer> map = createUnfiltered();
   1223       assertTrue(Maps.filterKeys((Map<String, Integer>) map, NOT_LENGTH_3)
   1224           instanceof SortedMap);
   1225     }
   1226 
   1227     public void testFilterValuesIdentifiesSortedMap() {
   1228       SortedMap<String, Integer> map = createUnfiltered();
   1229       assertTrue(Maps.filterValues((Map<String, Integer>) map, EVEN)
   1230           instanceof SortedMap);
   1231     }
   1232 
   1233     public void testFilterEntriesIdentifiesSortedMap() {
   1234       SortedMap<String, Integer> map = createUnfiltered();
   1235       assertTrue(Maps.filterEntries((Map<String, Integer>) map, CORRECT_LENGTH)
   1236           instanceof SortedMap);
   1237     }
   1238 
   1239     public void testFirstAndLastKeyFilteredMap() {
   1240       SortedMap<String, Integer> unfiltered = createUnfiltered();
   1241       unfiltered.put("apple", 2);
   1242       unfiltered.put("banana", 6);
   1243       unfiltered.put("cat", 3);
   1244       unfiltered.put("dog", 5);
   1245 
   1246       SortedMap<String, Integer> filtered = Maps.filterEntries(unfiltered, CORRECT_LENGTH);
   1247       assertEquals("banana", filtered.firstKey());
   1248       assertEquals("cat", filtered.lastKey());
   1249     }
   1250 
   1251     public void testHeadSubTailMap_FilteredMap() {
   1252       SortedMap<String, Integer> unfiltered = createUnfiltered();
   1253       unfiltered.put("apple", 2);
   1254       unfiltered.put("banana", 6);
   1255       unfiltered.put("cat", 4);
   1256       unfiltered.put("dog", 3);
   1257       SortedMap<String, Integer> filtered = Maps.filterEntries(unfiltered, CORRECT_LENGTH);
   1258 
   1259       assertEquals(ImmutableMap.of("banana", 6), filtered.headMap("dog"));
   1260       assertEquals(ImmutableMap.of(), filtered.headMap("banana"));
   1261       assertEquals(ImmutableMap.of("banana", 6, "dog", 3), filtered.headMap("emu"));
   1262 
   1263       assertEquals(ImmutableMap.of("banana", 6), filtered.subMap("banana", "dog"));
   1264       assertEquals(ImmutableMap.of("dog", 3), filtered.subMap("cat", "emu"));
   1265 
   1266       assertEquals(ImmutableMap.of("dog", 3), filtered.tailMap("cat"));
   1267       assertEquals(ImmutableMap.of("banana", 6, "dog", 3), filtered.tailMap("banana"));
   1268     }
   1269   }
   1270 
   1271   public static class FilteredBiMapTest extends FilteredMapTest {
   1272     @Override
   1273     BiMap<String, Integer> createUnfiltered() {
   1274       return HashBiMap.create();
   1275     }
   1276 
   1277     public void testFilterKeysIdentifiesBiMap() {
   1278       BiMap<String, Integer> map = createUnfiltered();
   1279       assertTrue(Maps.filterKeys((Map<String, Integer>) map, NOT_LENGTH_3)
   1280           instanceof BiMap);
   1281     }
   1282 
   1283     public void testFilterValuesIdentifiesBiMap() {
   1284       BiMap<String, Integer> map = createUnfiltered();
   1285       assertTrue(Maps.filterValues((Map<String, Integer>) map, EVEN)
   1286           instanceof BiMap);
   1287     }
   1288 
   1289     public void testFilterEntriesIdentifiesBiMap() {
   1290       BiMap<String, Integer> map = createUnfiltered();
   1291       assertTrue(Maps.filterEntries((Map<String, Integer>) map, CORRECT_LENGTH)
   1292           instanceof BiMap);
   1293     }
   1294   }
   1295 
   1296   public void testTransformValues() {
   1297     Map<String, Integer> map = ImmutableMap.of("a", 4, "b", 9);
   1298     Map<String, Double> transformed = transformValues(map, SQRT_FUNCTION);
   1299 
   1300     assertEquals(ImmutableMap.of("a", 2.0, "b", 3.0), transformed);
   1301   }
   1302 
   1303   public void testTransformValuesSecretlySorted() {
   1304     Map<String, Integer> map =
   1305         sortedNotNavigable(ImmutableSortedMap.of("a", 4, "b", 9));
   1306     Map<String, Double> transformed = transformValues(map, SQRT_FUNCTION);
   1307 
   1308     assertEquals(ImmutableMap.of("a", 2.0, "b", 3.0), transformed);
   1309     assertTrue(transformed instanceof SortedMap);
   1310   }
   1311 
   1312   public void testTransformEntries() {
   1313     Map<String, String> map = ImmutableMap.of("a", "4", "b", "9");
   1314     EntryTransformer<String, String, String> concat =
   1315         new EntryTransformer<String, String, String>() {
   1316           @Override
   1317           public String transformEntry(String key, String value) {
   1318             return key + value;
   1319           }
   1320         };
   1321     Map<String, String> transformed = transformEntries(map, concat);
   1322 
   1323     assertEquals(ImmutableMap.of("a", "a4", "b", "b9"), transformed);
   1324   }
   1325 
   1326   public void testTransformEntriesSecretlySorted() {
   1327     Map<String, String> map = ImmutableSortedMap.of("a", "4", "b", "9");
   1328     EntryTransformer<String, String, String> concat =
   1329         new EntryTransformer<String, String, String>() {
   1330           @Override
   1331           public String transformEntry(String key, String value) {
   1332             return key + value;
   1333           }
   1334         };
   1335     Map<String, String> transformed = transformEntries(map, concat);
   1336 
   1337     assertEquals(ImmutableMap.of("a", "a4", "b", "b9"), transformed);
   1338     assertTrue(transformed instanceof SortedMap);
   1339   }
   1340 
   1341   @SuppressWarnings("unused")
   1342   public void testTransformEntriesGenerics() {
   1343     Map<Object, Object> map1 = ImmutableMap.<Object, Object>of(1, 2);
   1344     Map<Object, Number> map2 = ImmutableMap.<Object, Number>of(1, 2);
   1345     Map<Object, Integer> map3 = ImmutableMap.<Object, Integer>of(1, 2);
   1346     Map<Number, Object> map4 = ImmutableMap.<Number, Object>of(1, 2);
   1347     Map<Number, Number> map5 = ImmutableMap.<Number, Number>of(1, 2);
   1348     Map<Number, Integer> map6 = ImmutableMap.<Number, Integer>of(1, 2);
   1349     Map<Integer, Object> map7 = ImmutableMap.<Integer, Object>of(1, 2);
   1350     Map<Integer, Number> map8 = ImmutableMap.<Integer, Number>of(1, 2);
   1351     Map<Integer, Integer> map9 = ImmutableMap.<Integer, Integer>of(1, 2);
   1352     Map<? extends Number, ? extends Number> map0 = ImmutableMap.of(1, 2);
   1353 
   1354     EntryTransformer<Number, Number, Double> transformer =
   1355         new EntryTransformer<Number, Number, Double>() {
   1356           @Override
   1357           public Double transformEntry(Number key, Number value) {
   1358             return key.doubleValue() + value.doubleValue();
   1359           }
   1360         };
   1361 
   1362     Map<Object, Double> objectKeyed;
   1363     Map<Number, Double> numberKeyed;
   1364     Map<Integer, Double> integerKeyed;
   1365 
   1366     numberKeyed = transformEntries(map5, transformer);
   1367     numberKeyed = transformEntries(map6, transformer);
   1368     integerKeyed = transformEntries(map8, transformer);
   1369     integerKeyed = transformEntries(map9, transformer);
   1370 
   1371     Map<? extends Number, Double> wildcarded = transformEntries(map0, transformer);
   1372 
   1373     // Can't loosen the key type:
   1374     // objectKeyed = transformEntries(map5, transformer);
   1375     // objectKeyed = transformEntries(map6, transformer);
   1376     // objectKeyed = transformEntries(map8, transformer);
   1377     // objectKeyed = transformEntries(map9, transformer);
   1378     // numberKeyed = transformEntries(map8, transformer);
   1379     // numberKeyed = transformEntries(map9, transformer);
   1380 
   1381     // Can't loosen the value type:
   1382     // Map<Number, Number> looseValued1 = transformEntries(map5, transformer);
   1383     // Map<Number, Number> looseValued2 = transformEntries(map6, transformer);
   1384     // Map<Integer, Number> looseValued3 = transformEntries(map8, transformer);
   1385     // Map<Integer, Number> looseValued4 = transformEntries(map9, transformer);
   1386 
   1387     // Can't call with too loose a key:
   1388     // transformEntries(map1, transformer);
   1389     // transformEntries(map2, transformer);
   1390     // transformEntries(map3, transformer);
   1391 
   1392     // Can't call with too loose a value:
   1393     // transformEntries(map1, transformer);
   1394     // transformEntries(map4, transformer);
   1395     // transformEntries(map7, transformer);
   1396   }
   1397 
   1398   public void testTransformEntriesExample() {
   1399     Map<String, Boolean> options =
   1400         ImmutableMap.of("verbose", true, "sort", false);
   1401     EntryTransformer<String, Boolean, String> flagPrefixer =
   1402         new EntryTransformer<String, Boolean, String>() {
   1403           @Override
   1404           public String transformEntry(String key, Boolean value) {
   1405             return value ? key : "no" + key;
   1406           }
   1407         };
   1408     Map<String, String> transformed = transformEntries(options, flagPrefixer);
   1409     assertEquals("{verbose=verbose, sort=nosort}", transformed.toString());
   1410   }
   1411 
   1412   // Logically this would accept a NavigableMap, but that won't work under GWT.
   1413   private static <K, V> SortedMap<K, V> sortedNotNavigable(
   1414       final SortedMap<K, V> map) {
   1415     return new ForwardingSortedMap<K, V>() {
   1416       @Override protected SortedMap<K, V> delegate() {
   1417         return map;
   1418       }
   1419     };
   1420   }
   1421 
   1422   public void testSortedMapTransformValues() {
   1423     SortedMap<String, Integer> map =
   1424         sortedNotNavigable(ImmutableSortedMap.of("a", 4, "b", 9));
   1425     SortedMap<String, Double> transformed =
   1426         transformValues(map, SQRT_FUNCTION);
   1427 
   1428     /*
   1429      * We'd like to sanity check that we didn't get a NavigableMap out, but we
   1430      * can't easily do so while maintaining GWT compatibility.
   1431      */
   1432     assertEquals(ImmutableSortedMap.of("a", 2.0, "b", 3.0), transformed);
   1433   }
   1434 
   1435   public void testSortedMapTransformEntries() {
   1436     SortedMap<String, String> map =
   1437         sortedNotNavigable(ImmutableSortedMap.of("a", "4", "b", "9"));
   1438     EntryTransformer<String, String, String> concat =
   1439         new EntryTransformer<String, String, String>() {
   1440           @Override
   1441           public String transformEntry(String key, String value) {
   1442             return key + value;
   1443           }
   1444         };
   1445     SortedMap<String, String> transformed = transformEntries(map, concat);
   1446 
   1447     /*
   1448      * We'd like to sanity check that we didn't get a NavigableMap out, but we
   1449      * can't easily do so while maintaining GWT compatibility.
   1450      */
   1451     assertEquals(ImmutableSortedMap.of("a", "a4", "b", "b9"), transformed);
   1452   }
   1453 }
   1454 
   1455