Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2011 The Guava Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package com.google.common.collect;
     16 
     17 import static com.google.common.base.Preconditions.checkArgument;
     18 import static com.google.common.truth.Truth.assertThat;
     19 import static java.util.Arrays.asList;
     20 
     21 import com.google.common.base.Function;
     22 import com.google.common.collect.Multiset.Entry;
     23 import com.google.common.collect.testing.ListTestSuiteBuilder;
     24 import com.google.common.collect.testing.MinimalCollection;
     25 import com.google.common.collect.testing.TestStringListGenerator;
     26 import com.google.common.collect.testing.features.CollectionFeature;
     27 import com.google.common.collect.testing.features.CollectionSize;
     28 import com.google.common.collect.testing.google.SortedMultisetTestSuiteBuilder;
     29 import com.google.common.collect.testing.google.TestStringMultisetGenerator;
     30 import com.google.common.collect.testing.google.UnmodifiableCollectionTests;
     31 import com.google.common.testing.NullPointerTester;
     32 import com.google.common.testing.SerializableTester;
     33 
     34 import junit.framework.Test;
     35 import junit.framework.TestCase;
     36 import junit.framework.TestSuite;
     37 
     38 import org.easymock.EasyMock;
     39 
     40 import java.util.ArrayList;
     41 import java.util.Arrays;
     42 import java.util.Collection;
     43 import java.util.Comparator;
     44 import java.util.HashSet;
     45 import java.util.Iterator;
     46 import java.util.List;
     47 import java.util.Set;
     48 
     49 /**
     50  * Tests for {@link ImmutableSortedMultiset}.
     51  *
     52  * @author Louis Wasserman
     53  */
     54 public class ImmutableSortedMultisetTest extends TestCase {
     55   public static Test suite() {
     56     TestSuite suite = new TestSuite();
     57     suite.addTestSuite(ImmutableSortedMultisetTest.class);
     58 
     59     suite.addTest(SortedMultisetTestSuiteBuilder.using(new TestStringMultisetGenerator() {
     60         @Override
     61         protected Multiset<String> create(String[] elements) {
     62           return ImmutableSortedMultiset.copyOf(elements);
     63         }
     64 
     65         @Override
     66         public List<String> order(List<String> insertionOrder) {
     67           return Ordering.natural().sortedCopy(insertionOrder);
     68         }
     69       })
     70       .named("ImmutableSortedMultiset")
     71       .withFeatures(CollectionSize.ANY,
     72           CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS,
     73           CollectionFeature.ALLOWS_NULL_QUERIES)
     74         .createTestSuite());
     75 
     76     suite.addTest(ListTestSuiteBuilder.using(new TestStringListGenerator() {
     77         @Override
     78         protected List<String> create(String[] elements) {
     79           return ImmutableSortedMultiset.copyOf(elements).asList();
     80         }
     81 
     82         @Override
     83         public List<String> order(List<String> insertionOrder) {
     84           return Ordering.natural().sortedCopy(insertionOrder);
     85         }
     86       })
     87       .named("ImmutableSortedMultiset.asList")
     88       .withFeatures(CollectionSize.ANY,
     89           CollectionFeature.SERIALIZABLE,
     90           CollectionFeature.ALLOWS_NULL_QUERIES)
     91         .createTestSuite());
     92 
     93     suite.addTest(ListTestSuiteBuilder.using(new TestStringListGenerator() {
     94         @Override
     95         protected List<String> create(String[] elements) {
     96           Set<String> set = Sets.newHashSet();
     97           ImmutableSortedMultiset.Builder<String> builder = ImmutableSortedMultiset.naturalOrder();
     98           for (String s : elements) {
     99             checkArgument(set.add(s));
    100             builder.addCopies(s, 2);
    101           }
    102           return builder.build().elementSet().asList();
    103         }
    104 
    105         @Override
    106         public List<String> order(List<String> insertionOrder) {
    107           return Ordering.natural().sortedCopy(insertionOrder);
    108         }
    109       })
    110       .named("ImmutableSortedMultiset.elementSet.asList")
    111       .withFeatures(CollectionSize.ANY,
    112           CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
    113           CollectionFeature.SERIALIZABLE,
    114           CollectionFeature.ALLOWS_NULL_QUERIES)
    115         .createTestSuite());
    116 
    117     return suite;
    118   }
    119 
    120   public void testCreation_noArgs() {
    121     Multiset<String> multiset = ImmutableSortedMultiset.of();
    122     assertTrue(multiset.isEmpty());
    123   }
    124 
    125   public void testCreation_oneElement() {
    126     Multiset<String> multiset = ImmutableSortedMultiset.of("a");
    127     assertEquals(HashMultiset.create(asList("a")), multiset);
    128   }
    129 
    130   public void testCreation_twoElements() {
    131     Multiset<String> multiset = ImmutableSortedMultiset.of("a", "b");
    132     assertEquals(HashMultiset.create(asList("a", "b")), multiset);
    133   }
    134 
    135   public void testCreation_threeElements() {
    136     Multiset<String> multiset = ImmutableSortedMultiset.of("a", "b", "c");
    137     assertEquals(HashMultiset.create(asList("a", "b", "c")), multiset);
    138   }
    139 
    140   public void testCreation_fourElements() {
    141     Multiset<String> multiset = ImmutableSortedMultiset.of("a", "b", "c", "d");
    142     assertEquals(HashMultiset.create(asList("a", "b", "c", "d")), multiset);
    143   }
    144 
    145   public void testCreation_fiveElements() {
    146     Multiset<String> multiset = ImmutableSortedMultiset.of("a", "b", "c", "d", "e");
    147     assertEquals(HashMultiset.create(asList("a", "b", "c", "d", "e")), multiset);
    148   }
    149 
    150   public void testCreation_sixElements() {
    151     Multiset<String> multiset = ImmutableSortedMultiset.of("a", "b", "c", "d", "e", "f");
    152     assertEquals(HashMultiset.create(asList("a", "b", "c", "d", "e", "f")), multiset);
    153   }
    154 
    155   public void testCreation_sevenElements() {
    156     Multiset<String> multiset = ImmutableSortedMultiset.of("a", "b", "c", "d", "e", "f", "g");
    157     assertEquals(HashMultiset.create(asList("a", "b", "c", "d", "e", "f", "g")), multiset);
    158   }
    159 
    160   public void testCreation_emptyArray() {
    161     String[] array = new String[0];
    162     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(array);
    163     assertTrue(multiset.isEmpty());
    164   }
    165 
    166   public void testCreation_arrayOfOneElement() {
    167     String[] array = new String[] {"a"};
    168     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(array);
    169     assertEquals(HashMultiset.create(asList("a")), multiset);
    170   }
    171 
    172   public void testCreation_arrayOfArray() {
    173     Comparator<String[]> comparator =
    174         Ordering.natural().lexicographical()
    175             .onResultOf(new Function<String[], Iterable<Comparable>>() {
    176               @Override
    177               public Iterable<Comparable> apply(String[] input) {
    178                 return Arrays.<Comparable>asList(input);
    179               }
    180             });
    181     String[] array = new String[] {"a"};
    182     Multiset<String[]> multiset = ImmutableSortedMultiset.orderedBy(comparator).add(array).build();
    183     Multiset<String[]> expected = HashMultiset.create();
    184     expected.add(array);
    185     assertEquals(expected, multiset);
    186   }
    187 
    188   public void testCreation_arrayContainingOnlyNull() {
    189     String[] array = new String[] {null};
    190     try {
    191       ImmutableSortedMultiset.copyOf(array);
    192       fail();
    193     } catch (NullPointerException expected) {}
    194   }
    195 
    196   public void testCopyOf_collection_empty() {
    197     // "<String>" is required to work around a javac 1.5 bug.
    198     Collection<String> c = MinimalCollection.<String>of();
    199     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(c);
    200     assertTrue(multiset.isEmpty());
    201   }
    202 
    203   public void testCopyOf_collection_oneElement() {
    204     Collection<String> c = MinimalCollection.of("a");
    205     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(c);
    206     assertEquals(HashMultiset.create(asList("a")), multiset);
    207   }
    208 
    209   public void testCopyOf_collection_general() {
    210     Collection<String> c = MinimalCollection.of("a", "b", "a");
    211     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(c);
    212     assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset);
    213   }
    214 
    215   public void testCopyOf_collectionContainingNull() {
    216     Collection<String> c = MinimalCollection.of("a", null, "b");
    217     try {
    218       ImmutableSortedMultiset.copyOf(c);
    219       fail();
    220     } catch (NullPointerException expected) {}
    221   }
    222 
    223   public void testCopyOf_multiset_empty() {
    224     Multiset<String> c = HashMultiset.create();
    225     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(c);
    226     assertTrue(multiset.isEmpty());
    227   }
    228 
    229   public void testCopyOf_multiset_oneElement() {
    230     Multiset<String> c = HashMultiset.create(asList("a"));
    231     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(c);
    232     assertEquals(HashMultiset.create(asList("a")), multiset);
    233   }
    234 
    235   public void testCopyOf_multiset_general() {
    236     Multiset<String> c = HashMultiset.create(asList("a", "b", "a"));
    237     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(c);
    238     assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset);
    239   }
    240 
    241   public void testCopyOf_multisetContainingNull() {
    242     Multiset<String> c = HashMultiset.create(asList("a", null, "b"));
    243     try {
    244       ImmutableSortedMultiset.copyOf(c);
    245       fail();
    246     } catch (NullPointerException expected) {}
    247   }
    248 
    249   public void testCopyOf_iterator_empty() {
    250     Iterator<String> iterator = Iterators.emptyIterator();
    251     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(iterator);
    252     assertTrue(multiset.isEmpty());
    253   }
    254 
    255   public void testCopyOf_iterator_oneElement() {
    256     Iterator<String> iterator = Iterators.singletonIterator("a");
    257     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(iterator);
    258     assertEquals(HashMultiset.create(asList("a")), multiset);
    259   }
    260 
    261   public void testCopyOf_iterator_general() {
    262     Iterator<String> iterator = asList("a", "b", "a").iterator();
    263     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(iterator);
    264     assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset);
    265   }
    266 
    267   public void testCopyOf_iteratorContainingNull() {
    268     Iterator<String> iterator = asList("a", null, "b").iterator();
    269     try {
    270       ImmutableSortedMultiset.copyOf(iterator);
    271       fail();
    272     } catch (NullPointerException expected) {}
    273   }
    274 
    275   private static class CountingIterable implements Iterable<String> {
    276     int count = 0;
    277 
    278     @Override
    279     public Iterator<String> iterator() {
    280       count++;
    281       return asList("a", "b", "a").iterator();
    282     }
    283   }
    284 
    285   public void testCopyOf_plainIterable() {
    286     CountingIterable iterable = new CountingIterable();
    287     Multiset<String> multiset = ImmutableSortedMultiset.copyOf(iterable);
    288     assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset);
    289     assertEquals(1, iterable.count);
    290   }
    291 
    292   public void testCopyOf_shortcut_empty() {
    293     Collection<String> c = ImmutableSortedMultiset.of();
    294     assertSame(c, ImmutableSortedMultiset.copyOf(c));
    295   }
    296 
    297   public void testCopyOf_shortcut_singleton() {
    298     Collection<String> c = ImmutableSortedMultiset.of("a");
    299     assertSame(c, ImmutableSortedMultiset.copyOf(c));
    300   }
    301 
    302   public void testCopyOf_shortcut_immutableMultiset() {
    303     Collection<String> c = ImmutableSortedMultiset.of("a", "b", "c");
    304     assertSame(c, ImmutableSortedMultiset.copyOf(c));
    305   }
    306 
    307   public void testBuilderAdd() {
    308     ImmutableSortedMultiset<String> multiset =
    309         ImmutableSortedMultiset.<String>naturalOrder().add("a").add("b").add("a").add("c").build();
    310     assertEquals(HashMultiset.create(asList("a", "b", "a", "c")), multiset);
    311   }
    312 
    313   public void testBuilderAddAll() {
    314     List<String> a = asList("a", "b");
    315     List<String> b = asList("c", "d");
    316     ImmutableSortedMultiset<String> multiset =
    317         ImmutableSortedMultiset.<String>naturalOrder().addAll(a).addAll(b).build();
    318     assertEquals(HashMultiset.create(asList("a", "b", "c", "d")), multiset);
    319   }
    320 
    321   public void testBuilderAddAllMultiset() {
    322     Multiset<String> a = HashMultiset.create(asList("a", "b", "b"));
    323     Multiset<String> b = HashMultiset.create(asList("c", "b"));
    324     ImmutableSortedMultiset<String> multiset =
    325         ImmutableSortedMultiset.<String>naturalOrder().addAll(a).addAll(b).build();
    326     assertEquals(HashMultiset.create(asList("a", "b", "b", "b", "c")), multiset);
    327   }
    328 
    329   public void testBuilderAddAllIterator() {
    330     Iterator<String> iterator = asList("a", "b", "a", "c").iterator();
    331     ImmutableSortedMultiset<String> multiset =
    332         ImmutableSortedMultiset.<String>naturalOrder().addAll(iterator).build();
    333     assertEquals(HashMultiset.create(asList("a", "b", "a", "c")), multiset);
    334   }
    335 
    336   public void testBuilderAddCopies() {
    337     ImmutableSortedMultiset<String> multiset =
    338         ImmutableSortedMultiset.<String>naturalOrder().addCopies("a", 2).addCopies("b", 3)
    339             .addCopies("c", 0).build();
    340     assertEquals(HashMultiset.create(asList("a", "a", "b", "b", "b")), multiset);
    341   }
    342 
    343   public void testBuilderSetCount() {
    344     ImmutableSortedMultiset<String> multiset =
    345         ImmutableSortedMultiset.<String>naturalOrder().add("a").setCount("a", 2).setCount("b", 3)
    346             .build();
    347     assertEquals(HashMultiset.create(asList("a", "a", "b", "b", "b")), multiset);
    348   }
    349 
    350   public void testBuilderAddHandlesNullsCorrectly() {
    351     ImmutableSortedMultiset.Builder<String> builder = ImmutableSortedMultiset.naturalOrder();
    352     try {
    353       builder.add((String) null);
    354       fail("expected NullPointerException");
    355     } catch (NullPointerException expected) {}
    356   }
    357 
    358   public void testBuilderAddAllHandlesNullsCorrectly() {
    359     ImmutableSortedMultiset.Builder<String> builder = ImmutableSortedMultiset.naturalOrder();
    360     try {
    361       builder.addAll((Collection<String>) null);
    362       fail("expected NullPointerException");
    363     } catch (NullPointerException expected) {}
    364 
    365     builder = ImmutableSortedMultiset.naturalOrder();
    366     List<String> listWithNulls = asList("a", null, "b");
    367     try {
    368       builder.addAll(listWithNulls);
    369       fail("expected NullPointerException");
    370     } catch (NullPointerException expected) {}
    371 
    372     builder = ImmutableSortedMultiset.naturalOrder();
    373     Multiset<String> multisetWithNull = LinkedHashMultiset.create(asList("a", null, "b"));
    374     try {
    375       builder.addAll(multisetWithNull);
    376       fail("expected NullPointerException");
    377     } catch (NullPointerException expected) {}
    378   }
    379 
    380   public void testBuilderAddCopiesHandlesNullsCorrectly() {
    381     ImmutableSortedMultiset.Builder<String> builder = ImmutableSortedMultiset.naturalOrder();
    382     try {
    383       builder.addCopies(null, 2);
    384       fail("expected NullPointerException");
    385     } catch (NullPointerException expected) {}
    386   }
    387 
    388   public void testBuilderAddCopiesIllegal() {
    389     ImmutableSortedMultiset.Builder<String> builder = ImmutableSortedMultiset.naturalOrder();
    390     try {
    391       builder.addCopies("a", -2);
    392       fail("expected IllegalArgumentException");
    393     } catch (IllegalArgumentException expected) {}
    394   }
    395 
    396   public void testBuilderSetCountHandlesNullsCorrectly() {
    397     ImmutableSortedMultiset.Builder<String> builder =
    398         new ImmutableSortedMultiset.Builder<String>(Ordering.natural().nullsFirst());
    399     try {
    400       builder.setCount(null, 2);
    401       fail("expected NullPointerException");
    402     } catch (NullPointerException expected) {}
    403   }
    404 
    405   public void testBuilderSetCountIllegal() {
    406     ImmutableSortedMultiset.Builder<String> builder = ImmutableSortedMultiset.naturalOrder();
    407     try {
    408       builder.setCount("a", -2);
    409       fail("expected IllegalArgumentException");
    410     } catch (IllegalArgumentException expected) {}
    411   }
    412 
    413   public void testNullPointers() {
    414     new NullPointerTester().testAllPublicStaticMethods(ImmutableSortedMultiset.class);
    415   }
    416 
    417   public void testSerialization_empty() {
    418     Collection<String> c = ImmutableSortedMultiset.of();
    419     assertSame(c, SerializableTester.reserialize(c));
    420   }
    421 
    422   public void testSerialization_multiple() {
    423     Collection<String> c = ImmutableSortedMultiset.of("a", "b", "a");
    424     Collection<String> copy = SerializableTester.reserializeAndAssert(c);
    425     assertThat(copy).has().exactly("a", "a", "b").inOrder();
    426   }
    427 
    428   public void testSerialization_elementSet() {
    429     Multiset<String> c = ImmutableSortedMultiset.of("a", "b", "a");
    430     Collection<String> copy = SerializableTester.reserializeAndAssert(c.elementSet());
    431     assertThat(copy).has().exactly("a", "b").inOrder();
    432   }
    433 
    434   public void testSerialization_entrySet() {
    435     Multiset<String> c = ImmutableSortedMultiset.of("a", "b", "c");
    436     SerializableTester.reserializeAndAssert(c.entrySet());
    437   }
    438 
    439   public void testEquals_immutableMultiset() {
    440     Collection<String> c = ImmutableSortedMultiset.of("a", "b", "a");
    441     assertEquals(c, ImmutableSortedMultiset.of("a", "b", "a"));
    442     assertEquals(c, ImmutableSortedMultiset.of("a", "a", "b"));
    443     assertThat(c).isNotEqualTo(ImmutableSortedMultiset.of("a", "b"));
    444     assertThat(c).isNotEqualTo(ImmutableSortedMultiset.of("a", "b", "c", "d"));
    445   }
    446 
    447   public void testIterationOrder() {
    448     Collection<String> c = ImmutableSortedMultiset.of("a", "b", "a");
    449     assertThat(c).has().exactly("a", "a", "b").inOrder();
    450   }
    451 
    452   public void testMultisetWrites() {
    453     Multiset<String> multiset = ImmutableSortedMultiset.of("a", "b", "a");
    454     UnmodifiableCollectionTests.assertMultisetIsUnmodifiable(multiset, "test");
    455   }
    456 
    457   public void testAsList() {
    458     ImmutableSortedMultiset<String> multiset = ImmutableSortedMultiset.of("a", "a", "b", "b", "b");
    459     ImmutableList<String> list = multiset.asList();
    460     assertEquals(ImmutableList.of("a", "a", "b", "b", "b"), list);
    461     assertTrue(list instanceof ImmutableAsList);
    462     ImmutableList<String> copy = SerializableTester.reserializeAndAssert(list);
    463     assertTrue(copy instanceof ImmutableAsList);
    464     assertEquals(2, list.indexOf("b"));
    465     assertEquals(4, list.lastIndexOf("b"));
    466   }
    467 
    468   public void testCopyOfDefensiveCopy() {
    469     // Depending on JDK version, either toArray() or toArray(T[]) may be called... use this class
    470     // rather than mocking to ensure that one of those methods is called.
    471     class TestArrayList<E> extends ArrayList<E> {
    472       boolean toArrayCalled = false;
    473 
    474       @Override
    475       public Object[] toArray() {
    476         toArrayCalled = true;
    477         return super.toArray();
    478       }
    479 
    480       @Override
    481       public <T> T[] toArray(T[] a) {
    482         toArrayCalled = true;
    483         return super.toArray(a);
    484       }
    485     }
    486 
    487     // Test that toArray() is used to make a defensive copy in copyOf(), so concurrently modified
    488     // synchronized collections can be safely copied.
    489     TestArrayList<String> toCopy = new TestArrayList<String>();
    490     ImmutableSortedMultiset<String> multiset =
    491         ImmutableSortedMultiset.copyOf(Ordering.natural(), toCopy);
    492     assertTrue(toCopy.toArrayCalled);
    493   }
    494 
    495   @SuppressWarnings("unchecked")
    496   public void testCopyOfSortedDefensiveCopy() {
    497     // Depending on JDK version, either toArray() or toArray(T[]) may be called... use this class
    498     // rather than mocking to ensure that one of those methods is called.
    499     class TestHashSet<E> extends HashSet<E> {
    500       boolean toArrayCalled = false;
    501 
    502       @Override
    503       public Object[] toArray() {
    504         toArrayCalled = true;
    505         return super.toArray();
    506       }
    507 
    508       @Override
    509       public <T> T[] toArray(T[] a) {
    510         toArrayCalled = true;
    511         return super.toArray(a);
    512       }
    513     }
    514 
    515     // Test that toArray() is used to make a defensive copy in copyOf(), so concurrently modified
    516     // synchronized collections can be safely copied.
    517     SortedMultiset<String> toCopy = EasyMock.createMock(SortedMultiset.class);
    518     TestHashSet<Entry<String>> entrySet = new TestHashSet<Entry<String>>();
    519     EasyMock.expect((Comparator<Comparable>) toCopy.comparator())
    520       .andReturn(Ordering.natural());
    521     EasyMock.expect(toCopy.entrySet()).andReturn(entrySet);
    522     EasyMock.replay(toCopy);
    523     ImmutableSortedMultiset<String> multiset =
    524         ImmutableSortedMultiset.copyOfSorted(toCopy);
    525     EasyMock.verify(toCopy);
    526     assertTrue(entrySet.toArrayCalled);
    527   }
    528 
    529   private static class IntegerDiv10 implements Comparable<IntegerDiv10> {
    530     final int value;
    531 
    532     IntegerDiv10(int value) {
    533       this.value = value;
    534     }
    535 
    536     @Override
    537     public int compareTo(IntegerDiv10 o) {
    538       return value / 10 - o.value / 10;
    539     }
    540 
    541     @Override public String toString() {
    542       return Integer.toString(value);
    543     }
    544   }
    545 
    546   public void testCopyOfDuplicateInconsistentWithEquals() {
    547     IntegerDiv10 three = new IntegerDiv10(3);
    548     IntegerDiv10 eleven = new IntegerDiv10(11);
    549     IntegerDiv10 twelve = new IntegerDiv10(12);
    550     IntegerDiv10 twenty = new IntegerDiv10(20);
    551 
    552     List<IntegerDiv10> original = ImmutableList.of(three, eleven, twelve, twenty);
    553 
    554     Multiset<IntegerDiv10> copy = ImmutableSortedMultiset.copyOf(original);
    555     assertTrue(copy.contains(eleven));
    556     assertTrue(copy.contains(twelve));
    557   }
    558 }
    559