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
17package com.google.common.collect;
18
19import static com.google.common.collect.BoundType.CLOSED;
20import static java.util.Collections.sort;
21import static org.truth0.Truth.ASSERT;
22
23import com.google.common.annotations.GwtCompatible;
24import com.google.common.annotations.GwtIncompatible;
25import com.google.common.collect.testing.Helpers.NullsBeforeB;
26import com.google.common.collect.testing.SortedSetTestSuiteBuilder;
27import com.google.common.collect.testing.TestStringSetGenerator;
28import com.google.common.collect.testing.features.CollectionFeature;
29import com.google.common.collect.testing.features.CollectionSize;
30import com.google.common.collect.testing.google.MultisetFeature;
31import com.google.common.collect.testing.google.SortedMultisetTestSuiteBuilder;
32import com.google.common.collect.testing.google.TestStringMultisetGenerator;
33
34import junit.framework.Test;
35import junit.framework.TestCase;
36import junit.framework.TestSuite;
37
38import java.lang.reflect.Method;
39import java.util.Arrays;
40import java.util.Collections;
41import java.util.Comparator;
42import java.util.List;
43import java.util.Set;
44import java.util.SortedSet;
45
46/**
47 * Unit test for {@link TreeMultiset}.
48 *
49 * @author Neal Kanodia
50 */
51@GwtCompatible(emulated = true)
52public class TreeMultisetTest extends TestCase {
53
54  @GwtIncompatible("suite")
55  public static Test suite() {
56    TestSuite suite = new TestSuite();
57    suite.addTest(SortedMultisetTestSuiteBuilder
58        .using(new TestStringMultisetGenerator() {
59          @Override
60          protected Multiset<String> create(String[] elements) {
61            return TreeMultiset.create(Arrays.asList(elements));
62          }
63
64          @Override
65          public List<String> order(List<String> insertionOrder) {
66            return Ordering.natural().sortedCopy(insertionOrder);
67          }
68        })
69        .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
70            CollectionFeature.GENERAL_PURPOSE,
71            CollectionFeature.SERIALIZABLE,
72            CollectionFeature.ALLOWS_NULL_QUERIES,
73            MultisetFeature.ENTRIES_ARE_VIEWS)
74        .named("TreeMultiset, Ordering.natural")
75        .createTestSuite());
76    suite.addTest(SortedMultisetTestSuiteBuilder
77        .using(new TestStringMultisetGenerator() {
78          @Override
79          protected Multiset<String> create(String[] elements) {
80            Multiset<String> result = TreeMultiset.create(NullsBeforeB.INSTANCE);
81            Collections.addAll(result, elements);
82            return result;
83          }
84
85          @Override
86          public List<String> order(List<String> insertionOrder) {
87            sort(insertionOrder, NullsBeforeB.INSTANCE);
88            return insertionOrder;
89          }
90        })
91        .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
92            CollectionFeature.GENERAL_PURPOSE,
93            CollectionFeature.SERIALIZABLE,
94            CollectionFeature.ALLOWS_NULL_VALUES,
95            MultisetFeature.ENTRIES_ARE_VIEWS)
96        .named("TreeMultiset, NullsBeforeB")
97        .createTestSuite());
98    suite.addTest(SortedSetTestSuiteBuilder.using(new TestStringSetGenerator() {
99        @Override
100        protected Set<String> create(String[] elements) {
101          return TreeMultiset.create(Arrays.asList(elements)).elementSet();
102        }
103
104        @Override
105        public List<String> order(List<String> insertionOrder) {
106          return Lists.newArrayList(Sets.newTreeSet(insertionOrder));
107        }
108      })
109      .named("TreeMultiset[Ordering.natural].elementSet")
110      .withFeatures(
111          CollectionSize.ANY,
112          CollectionFeature.REMOVE_OPERATIONS,
113          CollectionFeature.ALLOWS_NULL_QUERIES)
114      .createTestSuite());
115    suite.addTestSuite(TreeMultisetTest.class);
116    return suite;
117  }
118
119  public void testCreate() {
120    TreeMultiset<String> multiset = TreeMultiset.create();
121    multiset.add("foo", 2);
122    multiset.add("bar");
123    assertEquals(3, multiset.size());
124    assertEquals(2, multiset.count("foo"));
125    assertEquals(Ordering.natural(), multiset.comparator());
126    assertEquals("[bar, foo x 2]", multiset.toString());
127  }
128
129  public void testCreateWithComparator() {
130    Multiset<String> multiset = TreeMultiset.create(Collections.reverseOrder());
131    multiset.add("foo", 2);
132    multiset.add("bar");
133    assertEquals(3, multiset.size());
134    assertEquals(2, multiset.count("foo"));
135    assertEquals("[foo x 2, bar]", multiset.toString());
136  }
137
138  public void testCreateFromIterable() {
139    Multiset<String> multiset
140        = TreeMultiset.create(Arrays.asList("foo", "bar", "foo"));
141    assertEquals(3, multiset.size());
142    assertEquals(2, multiset.count("foo"));
143    assertEquals("[bar, foo x 2]", multiset.toString());
144  }
145
146  public void testToString() {
147    Multiset<String> ms = TreeMultiset.create();
148    ms.add("a", 3);
149    ms.add("c", 1);
150    ms.add("b", 2);
151
152    assertEquals("[a x 3, b x 2, c]", ms.toString());
153  }
154
155  public void testElementSetSortedSetMethods() {
156    TreeMultiset<String> ms = TreeMultiset.create();
157    ms.add("c", 1);
158    ms.add("a", 3);
159    ms.add("b", 2);
160    SortedSet<String> elementSet = ms.elementSet();
161
162    assertEquals("a", elementSet.first());
163    assertEquals("c", elementSet.last());
164    assertEquals(Ordering.natural(), elementSet.comparator());
165
166    ASSERT.that(elementSet.headSet("b")).has().exactly("a").inOrder();
167    ASSERT.that(elementSet.tailSet("b")).has().exactly("b", "c").inOrder();
168    ASSERT.that(elementSet.subSet("a", "c")).has().exactly("a", "b").inOrder();
169  }
170
171  public void testElementSetSubsetRemove() {
172    TreeMultiset<String> ms = TreeMultiset.create();
173    ms.add("a", 1);
174    ms.add("b", 3);
175    ms.add("c", 2);
176    ms.add("d", 1);
177    ms.add("e", 3);
178    ms.add("f", 2);
179
180    SortedSet<String> elementSet = ms.elementSet();
181    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
182    SortedSet<String> subset = elementSet.subSet("b", "f");
183    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
184
185    assertTrue(subset.remove("c"));
186    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
187    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
188    assertEquals(10, ms.size());
189
190    assertFalse(subset.remove("a"));
191    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
192    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
193    assertEquals(10, ms.size());
194  }
195
196  public void testElementSetSubsetRemoveAll() {
197    TreeMultiset<String> ms = TreeMultiset.create();
198    ms.add("a", 1);
199    ms.add("b", 3);
200    ms.add("c", 2);
201    ms.add("d", 1);
202    ms.add("e", 3);
203    ms.add("f", 2);
204
205    SortedSet<String> elementSet = ms.elementSet();
206    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
207    SortedSet<String> subset = elementSet.subSet("b", "f");
208    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
209
210    assertTrue(subset.removeAll(Arrays.asList("a", "c")));
211    ASSERT.that(elementSet).has().exactly("a", "b", "d", "e", "f").inOrder();
212    ASSERT.that(subset).has().exactly("b", "d", "e").inOrder();
213    assertEquals(10, ms.size());
214  }
215
216  public void testElementSetSubsetRetainAll() {
217    TreeMultiset<String> ms = TreeMultiset.create();
218    ms.add("a", 1);
219    ms.add("b", 3);
220    ms.add("c", 2);
221    ms.add("d", 1);
222    ms.add("e", 3);
223    ms.add("f", 2);
224
225    SortedSet<String> elementSet = ms.elementSet();
226    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
227    SortedSet<String> subset = elementSet.subSet("b", "f");
228    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
229
230    assertTrue(subset.retainAll(Arrays.asList("a", "c")));
231    ASSERT.that(elementSet).has().exactly("a", "c", "f").inOrder();
232    ASSERT.that(subset).has().exactly("c").inOrder();
233    assertEquals(5, ms.size());
234  }
235
236  public void testElementSetSubsetClear() {
237    TreeMultiset<String> ms = TreeMultiset.create();
238    ms.add("a", 1);
239    ms.add("b", 3);
240    ms.add("c", 2);
241    ms.add("d", 1);
242    ms.add("e", 3);
243    ms.add("f", 2);
244
245    SortedSet<String> elementSet = ms.elementSet();
246    ASSERT.that(elementSet).has().exactly("a", "b", "c", "d", "e", "f").inOrder();
247    SortedSet<String> subset = elementSet.subSet("b", "f");
248    ASSERT.that(subset).has().exactly("b", "c", "d", "e").inOrder();
249
250    subset.clear();
251    ASSERT.that(elementSet).has().exactly("a", "f").inOrder();
252    ASSERT.that(subset).isEmpty();
253    assertEquals(3, ms.size());
254  }
255
256  public void testCustomComparator() throws Exception {
257    Comparator<String> comparator = new Comparator<String>() {
258      @Override
259      public int compare(String o1, String o2) {
260        return o2.compareTo(o1);
261      }
262    };
263    TreeMultiset<String> ms = TreeMultiset.create(comparator);
264
265    ms.add("b");
266    ms.add("c");
267    ms.add("a");
268    ms.add("b");
269    ms.add("d");
270
271    ASSERT.that(ms).has().exactly("d", "c", "b", "b", "a").inOrder();
272
273    SortedSet<String> elementSet = ms.elementSet();
274    assertEquals("d", elementSet.first());
275    assertEquals("a", elementSet.last());
276    assertEquals(comparator, elementSet.comparator());
277  }
278
279  public void testNullAcceptingComparator() throws Exception {
280    Comparator<String> comparator = Ordering.<String>natural().nullsFirst();
281    TreeMultiset<String> ms = TreeMultiset.create(comparator);
282
283    ms.add("b");
284    ms.add(null);
285    ms.add("a");
286    ms.add("b");
287    ms.add(null, 2);
288
289    ASSERT.that(ms).has().exactly(null, null, null, "a", "b", "b").inOrder();
290    assertEquals(3, ms.count(null));
291
292    SortedSet<String> elementSet = ms.elementSet();
293    assertEquals(null, elementSet.first());
294    assertEquals("b", elementSet.last());
295    assertEquals(comparator, elementSet.comparator());
296  }
297
298  private static final Comparator<String> DEGENERATE_COMPARATOR =
299      new Comparator<String>() {
300        @Override
301        public int compare(String o1, String o2) {
302          return o1.length() - o2.length();
303        }
304      };
305
306  /**
307   * Test a TreeMultiset with a comparator that can return 0 when comparing
308   * unequal values.
309   */
310  public void testDegenerateComparator() throws Exception {
311    TreeMultiset<String> ms = TreeMultiset.create(DEGENERATE_COMPARATOR);
312
313    ms.add("foo");
314    ms.add("a");
315    ms.add("bar");
316    ms.add("b");
317    ms.add("c");
318
319    assertEquals(2, ms.count("bar"));
320    assertEquals(3, ms.count("b"));
321
322    Multiset<String> ms2 = TreeMultiset.create(DEGENERATE_COMPARATOR);
323
324    ms2.add("cat", 2);
325    ms2.add("x", 3);
326
327    assertEquals(ms, ms2);
328    assertEquals(ms2, ms);
329
330    SortedSet<String> elementSet = ms.elementSet();
331    assertEquals("a", elementSet.first());
332    assertEquals("foo", elementSet.last());
333    assertEquals(DEGENERATE_COMPARATOR, elementSet.comparator());
334  }
335
336  public void testSubMultisetSize() {
337    TreeMultiset<String> ms = TreeMultiset.create();
338    ms.add("a", Integer.MAX_VALUE);
339    ms.add("b", Integer.MAX_VALUE);
340    ms.add("c", 3);
341
342    assertEquals(Integer.MAX_VALUE, ms.count("a"));
343    assertEquals(Integer.MAX_VALUE, ms.count("b"));
344    assertEquals(3, ms.count("c"));
345
346    assertEquals(Integer.MAX_VALUE, ms.headMultiset("c", CLOSED).size());
347    assertEquals(Integer.MAX_VALUE, ms.headMultiset("b", CLOSED).size());
348    assertEquals(Integer.MAX_VALUE, ms.headMultiset("a", CLOSED).size());
349
350    assertEquals(3, ms.tailMultiset("c", CLOSED).size());
351    assertEquals(Integer.MAX_VALUE, ms.tailMultiset("b", CLOSED).size());
352    assertEquals(Integer.MAX_VALUE, ms.tailMultiset("a", CLOSED).size());
353  }
354
355  @GwtIncompatible("reflection")
356  public void testElementSetBridgeMethods() {
357    for (Method m : TreeMultiset.class.getMethods()) {
358      if (m.getName().equals("elementSet") && m.getReturnType().equals(SortedSet.class)) {
359        return;
360      }
361    }
362    fail("No bridge method found");
363  }
364}
365