Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2009 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 org.junit.contrib.truth.Truth.ASSERT;
     20 
     21 import com.google.common.annotations.GwtCompatible;
     22 import com.google.common.annotations.GwtIncompatible;
     23 import com.google.common.base.Joiner;
     24 import com.google.common.collect.ImmutableSortedMap.Builder;
     25 import com.google.common.collect.testing.CollectionTestSuiteBuilder;
     26 import com.google.common.collect.testing.ReserializingTestCollectionGenerator;
     27 import com.google.common.collect.testing.ReserializingTestSetGenerator;
     28 import com.google.common.collect.testing.SetTestSuiteBuilder;
     29 import com.google.common.collect.testing.SortedMapInterfaceTest;
     30 import com.google.common.collect.testing.features.CollectionFeature;
     31 import com.google.common.collect.testing.features.CollectionSize;
     32 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapEntrySetGenerator;
     33 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapHeadMapKeySetGenerator;
     34 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapKeySetGenerator;
     35 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapSubMapEntryGenerator;
     36 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapTailMapValuesGenerator;
     37 import com.google.common.collect.testing.google.SortedMapGenerators.ImmutableSortedMapValuesGenerator;
     38 import com.google.common.testing.NullPointerTester;
     39 import com.google.common.testing.SerializableTester;
     40 
     41 import junit.framework.Test;
     42 import junit.framework.TestCase;
     43 import junit.framework.TestSuite;
     44 
     45 import java.io.Serializable;
     46 import java.util.Collections;
     47 import java.util.Comparator;
     48 import java.util.LinkedHashMap;
     49 import java.util.Map;
     50 import java.util.Map.Entry;
     51 import java.util.SortedMap;
     52 
     53 /**
     54  * Tests for {@link ImmutableSortedMap}.
     55  *
     56  * @author Kevin Bourrillion
     57  * @author Jesse Wilson
     58  * @author Jared Levy
     59  */
     60 @GwtCompatible(emulated = true)
     61 public class ImmutableSortedMapTest extends TestCase {
     62   // TODO: Avoid duplicating code in ImmutableMapTest
     63 
     64   @GwtIncompatible("suite")
     65   public static Test suite() {
     66     TestSuite suite = new TestSuite();
     67     suite.addTestSuite(ImmutableSortedMapTest.class);
     68 
     69     suite.addTest(SetTestSuiteBuilder.using(
     70         new ImmutableSortedMapKeySetGenerator())
     71         .withFeatures(
     72             CollectionSize.ANY,
     73             CollectionFeature.KNOWN_ORDER,
     74             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
     75             CollectionFeature.ALLOWS_NULL_QUERIES)
     76         .named("ImmutableSortedMap.keySet")
     77         .createTestSuite());
     78 
     79     suite.addTest(SetTestSuiteBuilder.using(
     80         new ImmutableSortedMapEntrySetGenerator())
     81         .withFeatures(
     82             CollectionSize.ANY,
     83             CollectionFeature.KNOWN_ORDER,
     84             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
     85             CollectionFeature.ALLOWS_NULL_QUERIES)
     86         .named("ImmutableSortedMap.entrySet")
     87         .createTestSuite());
     88 
     89     suite.addTest(CollectionTestSuiteBuilder.using(
     90         new ImmutableSortedMapValuesGenerator())
     91         .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
     92             CollectionFeature.ALLOWS_NULL_QUERIES)
     93         .named("ImmutableSortedMap.values")
     94         .createTestSuite());
     95 
     96     suite.addTest(SetTestSuiteBuilder.using(
     97         ReserializingTestSetGenerator.newInstance(
     98             new ImmutableSortedMapKeySetGenerator()))
     99         .withFeatures(
    100             CollectionSize.ANY,
    101             CollectionFeature.KNOWN_ORDER,
    102             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
    103             CollectionFeature.ALLOWS_NULL_QUERIES)
    104         .named("ImmutableSortedMap.keySet, reserialized")
    105         .createTestSuite());
    106 
    107     suite.addTest(SetTestSuiteBuilder.using(
    108         ReserializingTestSetGenerator.newInstance(
    109             new ImmutableSortedMapEntrySetGenerator()))
    110         .withFeatures(
    111             CollectionSize.ANY,
    112             CollectionFeature.KNOWN_ORDER,
    113             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
    114             CollectionFeature.ALLOWS_NULL_QUERIES)
    115         .named("ImmutableSortedMap.entrySet, reserialized")
    116         .createTestSuite());
    117 
    118     suite.addTest(CollectionTestSuiteBuilder.using(
    119         ReserializingTestCollectionGenerator.newInstance(
    120             new ImmutableSortedMapValuesGenerator()))
    121         .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
    122             CollectionFeature.ALLOWS_NULL_QUERIES)
    123         .named("ImmutableSortedMap.values, reserialized")
    124         .createTestSuite());
    125 
    126     suite.addTest(SetTestSuiteBuilder.using(
    127         new ImmutableSortedMapHeadMapKeySetGenerator())
    128         .withFeatures(
    129             CollectionSize.ANY,
    130             CollectionFeature.KNOWN_ORDER,
    131             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
    132             CollectionFeature.ALLOWS_NULL_QUERIES)
    133         .named("ImmutableSortedMap.headMap.keySet")
    134         .createTestSuite());
    135 
    136     suite.addTest(SetTestSuiteBuilder.using(
    137         new ImmutableSortedMapSubMapEntryGenerator())
    138         .withFeatures(
    139             CollectionSize.ANY,
    140             CollectionFeature.KNOWN_ORDER,
    141             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
    142             CollectionFeature.ALLOWS_NULL_QUERIES)
    143         .named("ImmutableSortedMap.subMap.entrySet")
    144         .createTestSuite());
    145 
    146     suite.addTest(CollectionTestSuiteBuilder.using(
    147         new ImmutableSortedMapTailMapValuesGenerator())
    148         .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
    149             CollectionFeature.ALLOWS_NULL_QUERIES)
    150         .named("ImmutableSortedMap.tailMap.values")
    151         .createTestSuite());
    152 
    153     return suite;
    154   }
    155 
    156   public abstract static class AbstractMapTests<K, V>
    157       extends SortedMapInterfaceTest<K, V> {
    158     public AbstractMapTests() {
    159       super(false, false, false, false, false);
    160     }
    161 
    162     @Override protected SortedMap<K, V> makeEmptyMap() {
    163       throw new UnsupportedOperationException();
    164     }
    165 
    166     private static final Joiner joiner = Joiner.on(", ");
    167 
    168     @Override protected void assertMoreInvariants(Map<K, V> map) {
    169       // TODO: can these be moved to MapInterfaceTest?
    170       for (Entry<K, V> entry : map.entrySet()) {
    171         assertEquals(entry.getKey() + "=" + entry.getValue(),
    172             entry.toString());
    173       }
    174 
    175       assertEquals("{" + joiner.join(map.entrySet()) + "}",
    176           map.toString());
    177       assertEquals("[" + joiner.join(map.entrySet()) + "]",
    178           map.entrySet().toString());
    179       assertEquals("[" + joiner.join(map.keySet()) + "]",
    180           map.keySet().toString());
    181       assertEquals("[" + joiner.join(map.values()) + "]",
    182           map.values().toString());
    183 
    184       assertEquals(Sets.newHashSet(map.entrySet()), map.entrySet());
    185       assertEquals(Sets.newHashSet(map.keySet()), map.keySet());
    186     }
    187   }
    188 
    189   public static class MapTests extends AbstractMapTests<String, Integer> {
    190     @Override protected SortedMap<String, Integer> makeEmptyMap() {
    191       return ImmutableSortedMap.of();
    192     }
    193 
    194     @Override protected SortedMap<String, Integer> makePopulatedMap() {
    195       return ImmutableSortedMap.of("one", 1, "two", 2, "three", 3);
    196     }
    197 
    198     @Override protected String getKeyNotInPopulatedMap() {
    199       return "minus one";
    200     }
    201 
    202     @Override protected Integer getValueNotInPopulatedMap() {
    203       return -1;
    204     }
    205   }
    206 
    207   public static class SingletonMapTests
    208       extends AbstractMapTests<String, Integer> {
    209     @Override protected SortedMap<String, Integer> makePopulatedMap() {
    210       return ImmutableSortedMap.of("one", 1);
    211     }
    212 
    213     @Override protected String getKeyNotInPopulatedMap() {
    214       return "minus one";
    215     }
    216 
    217     @Override protected Integer getValueNotInPopulatedMap() {
    218       return -1;
    219     }
    220   }
    221 
    222   @GwtIncompatible("SerializableTester")
    223   public static class ReserializedMapTests
    224       extends AbstractMapTests<String, Integer> {
    225     @Override protected SortedMap<String, Integer> makePopulatedMap() {
    226       return SerializableTester.reserialize(
    227           ImmutableSortedMap.of("one", 1, "two", 2, "three", 3));
    228     }
    229 
    230     @Override protected String getKeyNotInPopulatedMap() {
    231       return "minus one";
    232     }
    233 
    234     @Override protected Integer getValueNotInPopulatedMap() {
    235       return -1;
    236     }
    237   }
    238 
    239   public static class HeadMapTests extends AbstractMapTests<String, Integer> {
    240     @Override protected SortedMap<String, Integer> makePopulatedMap() {
    241       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
    242           .headMap("d");
    243     }
    244 
    245     @Override protected String getKeyNotInPopulatedMap() {
    246       return "d";
    247     }
    248 
    249     @Override protected Integer getValueNotInPopulatedMap() {
    250       return 4;
    251     }
    252   }
    253 
    254   public static class HeadMapInclusiveTests extends AbstractMapTests<String, Integer> {
    255     @Override protected SortedMap<String, Integer> makePopulatedMap() {
    256       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
    257           .headMap("c", true);
    258     }
    259 
    260     @Override protected String getKeyNotInPopulatedMap() {
    261       return "d";
    262     }
    263 
    264     @Override protected Integer getValueNotInPopulatedMap() {
    265       return 4;
    266     }
    267   }
    268 
    269   public static class TailMapTests extends AbstractMapTests<String, Integer> {
    270     @Override protected SortedMap<String, Integer> makePopulatedMap() {
    271       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
    272           .tailMap("b");
    273     }
    274 
    275     @Override protected String getKeyNotInPopulatedMap() {
    276       return "a";
    277     }
    278 
    279     @Override protected Integer getValueNotInPopulatedMap() {
    280       return 1;
    281     }
    282   }
    283 
    284   public static class TailExclusiveMapTests extends AbstractMapTests<String, Integer> {
    285     @Override protected SortedMap<String, Integer> makePopulatedMap() {
    286       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
    287           .tailMap("a", false);
    288     }
    289 
    290     @Override protected String getKeyNotInPopulatedMap() {
    291       return "a";
    292     }
    293 
    294     @Override protected Integer getValueNotInPopulatedMap() {
    295       return 1;
    296     }
    297   }
    298 
    299   public static class SubMapTests extends AbstractMapTests<String, Integer> {
    300     @Override protected SortedMap<String, Integer> makePopulatedMap() {
    301       return ImmutableSortedMap.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5)
    302           .subMap("b", "d");
    303     }
    304 
    305     @Override protected String getKeyNotInPopulatedMap() {
    306       return "a";
    307     }
    308 
    309     @Override protected Integer getValueNotInPopulatedMap() {
    310       return 4;
    311     }
    312   }
    313 
    314   public static class CreationTests extends TestCase {
    315     public void testEmptyBuilder() {
    316       ImmutableSortedMap<String, Integer> map
    317           = ImmutableSortedMap.<String, Integer>naturalOrder().build();
    318       assertEquals(Collections.<String, Integer>emptyMap(), map);
    319     }
    320 
    321     public void testSingletonBuilder() {
    322       ImmutableSortedMap<String, Integer> map
    323           = ImmutableSortedMap.<String, Integer>naturalOrder()
    324               .put("one", 1)
    325               .build();
    326       assertMapEquals(map, "one", 1);
    327     }
    328 
    329     public void testBuilder() {
    330       ImmutableSortedMap<String, Integer> map
    331           = ImmutableSortedMap.<String, Integer>naturalOrder()
    332               .put("one", 1)
    333               .put("two", 2)
    334               .put("three", 3)
    335               .put("four", 4)
    336               .put("five", 5)
    337               .build();
    338       assertMapEquals(map,
    339           "five", 5, "four", 4, "one", 1, "three", 3, "two", 2);
    340     }
    341 
    342     public void testBuilder_withImmutableEntry() {
    343       ImmutableSortedMap<String, Integer> map =
    344           ImmutableSortedMap.<String, Integer>naturalOrder()
    345               .put(Maps.immutableEntry("one", 1))
    346               .build();
    347       assertMapEquals(map, "one", 1);
    348     }
    349 
    350     public void testBuilder_withImmutableEntryAndNullContents() {
    351       Builder<String, Integer> builder =
    352           ImmutableSortedMap.naturalOrder();
    353       try {
    354         builder.put(Maps.immutableEntry("one", (Integer) null));
    355         fail();
    356       } catch (NullPointerException expected) {
    357       }
    358       try {
    359         builder.put(Maps.immutableEntry((String) null, 1));
    360         fail();
    361       } catch (NullPointerException expected) {
    362       }
    363     }
    364 
    365     private static class StringHolder {
    366       String string;
    367     }
    368 
    369     public void testBuilder_withMutableEntry() {
    370       ImmutableSortedMap.Builder<String, Integer> builder =
    371           ImmutableSortedMap.naturalOrder();
    372       final StringHolder holder = new StringHolder();
    373       holder.string = "one";
    374       Entry<String, Integer> entry = new AbstractMapEntry<String, Integer>() {
    375         @Override public String getKey() {
    376           return holder.string;
    377         }
    378         @Override public Integer getValue() {
    379           return 1;
    380         }
    381       };
    382 
    383       builder.put(entry);
    384       holder.string = "two";
    385       assertMapEquals(builder.build(), "one", 1);
    386     }
    387 
    388     public void testBuilderPutAllWithEmptyMap() {
    389       ImmutableSortedMap<String, Integer> map
    390           = ImmutableSortedMap.<String, Integer>naturalOrder()
    391               .putAll(Collections.<String, Integer>emptyMap())
    392               .build();
    393       assertEquals(Collections.<String, Integer>emptyMap(), map);
    394     }
    395 
    396     public void testBuilderPutAll() {
    397       Map<String, Integer> toPut = new LinkedHashMap<String, Integer>();
    398       toPut.put("one", 1);
    399       toPut.put("two", 2);
    400       toPut.put("three", 3);
    401       Map<String, Integer> moreToPut = new LinkedHashMap<String, Integer>();
    402       moreToPut.put("four", 4);
    403       moreToPut.put("five", 5);
    404 
    405       ImmutableSortedMap<String, Integer> map
    406           = ImmutableSortedMap.<String, Integer>naturalOrder()
    407               .putAll(toPut)
    408               .putAll(moreToPut)
    409               .build();
    410       assertMapEquals(map,
    411           "five", 5, "four", 4, "one", 1, "three", 3, "two", 2);
    412     }
    413 
    414     public void testBuilderReuse() {
    415       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
    416       ImmutableSortedMap<String, Integer> mapOne = builder
    417           .put("one", 1)
    418           .put("two", 2)
    419           .build();
    420       ImmutableSortedMap<String, Integer> mapTwo = builder
    421           .put("three", 3)
    422           .put("four", 4)
    423           .build();
    424 
    425       assertMapEquals(mapOne, "one", 1, "two", 2);
    426       assertMapEquals(mapTwo, "four", 4, "one", 1, "three", 3, "two", 2);
    427     }
    428 
    429     public void testBuilderPutNullKey() {
    430       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
    431       try {
    432         builder.put(null, 1);
    433         fail();
    434       } catch (NullPointerException expected) {
    435       }
    436     }
    437 
    438     public void testBuilderPutNullValue() {
    439       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
    440       try {
    441         builder.put("one", null);
    442         fail();
    443       } catch (NullPointerException expected) {
    444       }
    445     }
    446 
    447     public void testBuilderPutNullKeyViaPutAll() {
    448       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
    449       try {
    450         builder.putAll(Collections.<String, Integer>singletonMap(null, 1));
    451         fail();
    452       } catch (NullPointerException expected) {
    453       }
    454     }
    455 
    456     public void testBuilderPutNullValueViaPutAll() {
    457       Builder<String, Integer> builder = ImmutableSortedMap.naturalOrder();
    458       try {
    459         builder.putAll(Collections.<String, Integer>singletonMap("one", null));
    460         fail();
    461       } catch (NullPointerException expected) {
    462       }
    463     }
    464 
    465     public void testPuttingTheSameKeyTwiceThrowsOnBuild() {
    466       Builder<String, Integer> builder
    467           = ImmutableSortedMap.<String, Integer>naturalOrder()
    468               .put("one", 1)
    469               .put("one", 2); // throwing on this line would be even better
    470 
    471       try {
    472         builder.build();
    473         fail();
    474       } catch (IllegalArgumentException expected) {
    475         assertEquals("Duplicate keys in mappings one=1 and one=2",
    476             expected.getMessage());
    477       }
    478     }
    479 
    480     public void testOf() {
    481       assertMapEquals(
    482           ImmutableSortedMap.of("one", 1),
    483           "one", 1);
    484       assertMapEquals(
    485           ImmutableSortedMap.of("one", 1, "two", 2),
    486           "one", 1, "two", 2);
    487       assertMapEquals(
    488           ImmutableSortedMap.of("one", 1, "two", 2, "three", 3),
    489           "one", 1, "three", 3, "two", 2);
    490       assertMapEquals(
    491           ImmutableSortedMap.of("one", 1, "two", 2, "three", 3, "four", 4),
    492           "four", 4, "one", 1, "three", 3, "two", 2);
    493       assertMapEquals(
    494           ImmutableSortedMap.of(
    495               "one", 1, "two", 2, "three", 3, "four", 4, "five", 5),
    496           "five", 5, "four", 4, "one", 1, "three", 3, "two", 2);
    497     }
    498 
    499     public void testOfNullKey() {
    500       Integer n = null;
    501       try {
    502         ImmutableSortedMap.of(n, 1);
    503         fail();
    504       } catch (NullPointerException expected) {
    505       }
    506 
    507       try {
    508         ImmutableSortedMap.of("one", 1, null, 2);
    509         fail();
    510       } catch (NullPointerException expected) {
    511       }
    512     }
    513 
    514     public void testOfNullValue() {
    515       try {
    516         ImmutableSortedMap.of("one", null);
    517         fail();
    518       } catch (NullPointerException expected) {
    519       }
    520 
    521       try {
    522         ImmutableSortedMap.of("one", 1, "two", null);
    523         fail();
    524       } catch (NullPointerException expected) {
    525       }
    526     }
    527 
    528     public void testOfWithDuplicateKey() {
    529       try {
    530         ImmutableSortedMap.of("one", 1, "one", 1);
    531         fail();
    532       } catch (IllegalArgumentException expected) {
    533         assertEquals("Duplicate keys in mappings one=1 and one=1",
    534             expected.getMessage());
    535       }
    536     }
    537 
    538     public void testCopyOfEmptyMap() {
    539       ImmutableSortedMap<String, Integer> copy
    540           = ImmutableSortedMap.copyOf(Collections.<String, Integer>emptyMap());
    541       assertEquals(Collections.<String, Integer>emptyMap(), copy);
    542       assertSame(copy, ImmutableSortedMap.copyOf(copy));
    543       assertSame(Ordering.natural(), copy.comparator());
    544     }
    545 
    546     public void testCopyOfSingletonMap() {
    547       ImmutableSortedMap<String, Integer> copy
    548           = ImmutableSortedMap.copyOf(Collections.singletonMap("one", 1));
    549       assertMapEquals(copy, "one", 1);
    550       assertSame(copy, ImmutableSortedMap.copyOf(copy));
    551       assertSame(Ordering.natural(), copy.comparator());
    552     }
    553 
    554     public void testCopyOf() {
    555       Map<String, Integer> original = new LinkedHashMap<String, Integer>();
    556       original.put("one", 1);
    557       original.put("two", 2);
    558       original.put("three", 3);
    559 
    560       ImmutableSortedMap<String, Integer> copy
    561           = ImmutableSortedMap.copyOf(original);
    562       assertMapEquals(copy, "one", 1, "three", 3, "two", 2);
    563       assertSame(copy, ImmutableSortedMap.copyOf(copy));
    564       assertSame(Ordering.natural(), copy.comparator());
    565     }
    566 
    567     public void testCopyOfExplicitComparator() {
    568       Comparator<String> comparator = Ordering.natural().reverse();
    569       Map<String, Integer> original = new LinkedHashMap<String, Integer>();
    570       original.put("one", 1);
    571       original.put("two", 2);
    572       original.put("three", 3);
    573 
    574       ImmutableSortedMap<String, Integer> copy
    575           = ImmutableSortedMap.copyOf(original, comparator);
    576       assertMapEquals(copy, "two", 2, "three", 3, "one", 1);
    577       assertSame(copy, ImmutableSortedMap.copyOf(copy, comparator));
    578       assertSame(comparator, copy.comparator());
    579     }
    580 
    581     public void testCopyOfImmutableSortedSetDifferentComparator() {
    582       Comparator<String> comparator = Ordering.natural().reverse();
    583       Map<String, Integer> original
    584           = ImmutableSortedMap.of("one", 1, "two", 2, "three", 3);
    585       ImmutableSortedMap<String, Integer> copy
    586           = ImmutableSortedMap.copyOf(original, comparator);
    587       assertMapEquals(copy, "two", 2, "three", 3, "one", 1);
    588       assertSame(copy, ImmutableSortedMap.copyOf(copy, comparator));
    589       assertSame(comparator, copy.comparator());
    590     }
    591 
    592     public void testCopyOfSortedNatural() {
    593       SortedMap<String, Integer> original = Maps.newTreeMap();
    594       original.put("one", 1);
    595       original.put("two", 2);
    596       original.put("three", 3);
    597 
    598       ImmutableSortedMap<String, Integer> copy
    599           = ImmutableSortedMap.copyOfSorted(original);
    600       assertMapEquals(copy, "one", 1, "three", 3, "two", 2);
    601       assertSame(copy, ImmutableSortedMap.copyOfSorted(copy));
    602       assertSame(Ordering.natural(), copy.comparator());
    603     }
    604 
    605     public void testCopyOfSortedExplicit() {
    606       Comparator<String> comparator = Ordering.natural().reverse();
    607       SortedMap<String, Integer> original = Maps.newTreeMap(comparator);
    608       original.put("one", 1);
    609       original.put("two", 2);
    610       original.put("three", 3);
    611 
    612       ImmutableSortedMap<String, Integer> copy
    613           = ImmutableSortedMap.copyOfSorted(original);
    614       assertMapEquals(copy, "two", 2, "three", 3, "one", 1);
    615       assertSame(copy, ImmutableSortedMap.copyOfSorted(copy));
    616       assertSame(comparator, copy.comparator());
    617     }
    618 
    619     private static class IntegerDiv10 implements Comparable<IntegerDiv10> {
    620       final int value;
    621 
    622       IntegerDiv10(int value) {
    623         this.value = value;
    624       }
    625 
    626       @Override
    627       public int compareTo(IntegerDiv10 o) {
    628         return value / 10 - o.value / 10;
    629       }
    630 
    631       @Override public String toString() {
    632         return Integer.toString(value);
    633       }
    634     }
    635 
    636     public void testCopyOfDuplicateKey() {
    637       Map<IntegerDiv10, String> original = ImmutableMap.of(
    638           new IntegerDiv10(3), "three",
    639           new IntegerDiv10(20), "twenty",
    640           new IntegerDiv10(11), "eleven",
    641           new IntegerDiv10(35), "thirty five",
    642           new IntegerDiv10(12), "twelve"
    643       );
    644 
    645       try {
    646         ImmutableSortedMap.copyOf(original);
    647         fail("Expected IllegalArgumentException");
    648       } catch (IllegalArgumentException expected) {
    649         assertEquals("Duplicate keys in mappings 11=eleven and 12=twelve",
    650             expected.getMessage());
    651       }
    652     }
    653 
    654     public void testImmutableMapCopyOfImmutableSortedMap() {
    655       IntegerDiv10 three = new IntegerDiv10(3);
    656       IntegerDiv10 eleven = new IntegerDiv10(11);
    657       IntegerDiv10 twelve = new IntegerDiv10(12);
    658       IntegerDiv10 twenty = new IntegerDiv10(20);
    659       Map<IntegerDiv10, String> original = ImmutableSortedMap.of(
    660           three, "three", eleven, "eleven", twenty, "twenty");
    661       Map<IntegerDiv10, String> copy = ImmutableMap.copyOf(original);
    662       assertTrue(original.containsKey(twelve));
    663       assertFalse(copy.containsKey(twelve));
    664     }
    665 
    666     public void testBuilderReverseOrder() {
    667       ImmutableSortedMap<String, Integer> map
    668           = ImmutableSortedMap.<String, Integer>reverseOrder()
    669               .put("one", 1)
    670               .put("two", 2)
    671               .put("three", 3)
    672               .put("four", 4)
    673               .put("five", 5)
    674               .build();
    675       assertMapEquals(map,
    676           "two", 2, "three", 3, "one", 1, "four", 4, "five", 5);
    677       assertEquals(Ordering.natural().reverse(), map.comparator());
    678     }
    679 
    680     public void testBuilderComparator() {
    681       Comparator<String> comparator = Ordering.natural().reverse();
    682       ImmutableSortedMap<String, Integer> map
    683           = new ImmutableSortedMap.Builder<String, Integer>(comparator)
    684               .put("one", 1)
    685               .put("two", 2)
    686               .put("three", 3)
    687               .put("four", 4)
    688               .put("five", 5)
    689               .build();
    690       assertMapEquals(map,
    691           "two", 2, "three", 3, "one", 1, "four", 4, "five", 5);
    692       assertSame(comparator, map.comparator());
    693     }
    694   }
    695 
    696   public void testNullGet() {
    697     ImmutableSortedMap<String, Integer> map = ImmutableSortedMap.of("one", 1);
    698     assertNull(map.get(null));
    699   }
    700 
    701   @GwtIncompatible("NullPointerTester")
    702   public void testNullPointers() throws Exception {
    703     NullPointerTester tester = new NullPointerTester();
    704     tester.testAllPublicStaticMethods(ImmutableSortedMap.class);
    705     tester.testAllPublicInstanceMethods(
    706         ImmutableSortedMap.<String, Integer>naturalOrder());
    707     tester.testAllPublicInstanceMethods(ImmutableSortedMap.of());
    708     tester.testAllPublicInstanceMethods(ImmutableSortedMap.of("one", 1));
    709     tester.testAllPublicInstanceMethods(
    710         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3));
    711   }
    712 
    713   private static <K, V> void assertMapEquals(Map<K, V> map,
    714       Object... alternatingKeysAndValues) {
    715     assertEquals(map.size(), alternatingKeysAndValues.length / 2);
    716     int i = 0;
    717     for (Entry<K, V> entry : map.entrySet()) {
    718       assertEquals(alternatingKeysAndValues[i++], entry.getKey());
    719       assertEquals(alternatingKeysAndValues[i++], entry.getValue());
    720     }
    721   }
    722 
    723   private static class IntHolder implements Serializable {
    724     public int value;
    725 
    726     public IntHolder(int value) {
    727       this.value = value;
    728     }
    729 
    730     @Override public boolean equals(Object o) {
    731       return (o instanceof IntHolder) && ((IntHolder) o).value == value;
    732     }
    733 
    734     @Override public int hashCode() {
    735       return value;
    736     }
    737 
    738     private static final long serialVersionUID = 5;
    739   }
    740 
    741   public void testMutableValues() {
    742     IntHolder holderA = new IntHolder(1);
    743     IntHolder holderB = new IntHolder(2);
    744     Map<String, IntHolder> map
    745         = ImmutableSortedMap.of("a", holderA, "b", holderB);
    746     holderA.value = 3;
    747     assertTrue(map.entrySet().contains(
    748         Maps.immutableEntry("a", new IntHolder(3))));
    749     Map<String, Integer> intMap
    750         = ImmutableSortedMap.of("a", 3, "b", 2);
    751     assertEquals(intMap.hashCode(), map.entrySet().hashCode());
    752     assertEquals(intMap.hashCode(), map.hashCode());
    753   }
    754 
    755   @GwtIncompatible("SerializableTester")
    756   public void testViewSerialization() {
    757     Map<String, Integer> map
    758         = ImmutableSortedMap.of("one", 1, "two", 2, "three", 3);
    759     SerializableTester.reserializeAndAssert(map.entrySet());
    760     SerializableTester.reserializeAndAssert(map.keySet());
    761     assertEquals(Lists.newArrayList(map.values()),
    762         Lists.newArrayList(SerializableTester.reserialize(map.values())));
    763   }
    764 
    765   @SuppressWarnings("unchecked") // varargs
    766   public void testHeadMapInclusive() {
    767     Map<String, Integer> map =
    768         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).headMap("three", true);
    769     ASSERT.that(map.entrySet()).hasContentsInOrder(Maps.immutableEntry("one", 1),
    770         Maps.immutableEntry("three", 3));
    771   }
    772 
    773   @SuppressWarnings("unchecked") // varargs
    774   public void testHeadMapExclusive() {
    775     Map<String, Integer> map =
    776         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).headMap("three", false);
    777     ASSERT.that(map.entrySet()).hasContentsInOrder(Maps.immutableEntry("one", 1));
    778   }
    779 
    780   @SuppressWarnings("unchecked") // varargs
    781   public void testTailMapInclusive() {
    782     Map<String, Integer> map =
    783         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).tailMap("three", true);
    784     ASSERT.that(map.entrySet()).hasContentsInOrder(Maps.immutableEntry("three", 3),
    785         Maps.immutableEntry("two", 2));
    786   }
    787 
    788   @SuppressWarnings("unchecked") // varargs
    789   public void testTailMapExclusive() {
    790     Map<String, Integer> map =
    791         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).tailMap("three", false);
    792     ASSERT.that(map.entrySet()).hasContentsInOrder(Maps.immutableEntry("two", 2));
    793   }
    794 
    795   @SuppressWarnings("unchecked") // varargs
    796   public void testSubMapExclusiveExclusive() {
    797     Map<String, Integer> map =
    798         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", false, "two", false);
    799     ASSERT.that(map.entrySet()).hasContentsInOrder(Maps.immutableEntry("three", 3));
    800   }
    801 
    802   @SuppressWarnings("unchecked") // varargs
    803   public void testSubMapInclusiveExclusive() {
    804     Map<String, Integer> map =
    805         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", true, "two", false);
    806     ASSERT.that(map.entrySet()).hasContentsInOrder(Maps.immutableEntry("one", 1),
    807         Maps.immutableEntry("three", 3));
    808   }
    809 
    810   @SuppressWarnings("unchecked") // varargs
    811   public void testSubMapExclusiveInclusive() {
    812     Map<String, Integer> map =
    813         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", false, "two", true);
    814     ASSERT.that(map.entrySet()).hasContentsInOrder(Maps.immutableEntry("three", 3),
    815         Maps.immutableEntry("two", 2));
    816   }
    817 
    818   @SuppressWarnings("unchecked") // varargs
    819   public void testSubMapInclusiveInclusive() {
    820     Map<String, Integer> map =
    821         ImmutableSortedMap.of("one", 1, "two", 2, "three", 3).subMap("one", true, "two", true);
    822     ASSERT.that(map.entrySet()).hasContentsInOrder(Maps.immutableEntry("one", 1),
    823         Maps.immutableEntry("three", 3), Maps.immutableEntry("two", 2));
    824   }
    825 }
    826