001/*
002 * Copyright (C) 2011 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the
010 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
011 * express or implied. See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014
015package com.google.common.collect.testing.google;
016
017import static com.google.common.collect.BoundType.CLOSED;
018import static com.google.common.collect.BoundType.OPEN;
019import static com.google.common.collect.Lists.newArrayList;
020import static com.google.common.collect.testing.Helpers.copyToList;
021import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_ADD;
022import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
023import static com.google.common.collect.testing.features.CollectionSize.ONE;
024import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
025import static com.google.common.collect.testing.features.CollectionSize.ZERO;
026import static java.util.Arrays.asList;
027import static java.util.Collections.nCopies;
028import static java.util.Collections.singletonList;
029import static java.util.Collections.sort;
030import static org.junit.Assert.assertThrows;
031
032import com.google.common.annotations.GwtCompatible;
033import com.google.common.collect.BoundType;
034import com.google.common.collect.Multiset.Entry;
035import com.google.common.collect.Multisets;
036import com.google.common.collect.SortedMultiset;
037import com.google.common.collect.testing.features.CollectionFeature;
038import com.google.common.collect.testing.features.CollectionSize;
039import java.util.ArrayList;
040import java.util.Collections;
041import java.util.List;
042import java.util.NoSuchElementException;
043
044/**
045 * Tester for navigation of SortedMultisets.
046 *
047 * @author Louis Wasserman
048 */
049@GwtCompatible
050public class MultisetNavigationTester<E> extends AbstractMultisetTester<E> {
051  private SortedMultiset<E> sortedMultiset;
052  private List<E> entries;
053  private Entry<E> a;
054  private Entry<E> b;
055  private Entry<E> c;
056
057  @Override
058  public void setUp() throws Exception {
059    super.setUp();
060    sortedMultiset = (SortedMultiset<E>) getMultiset();
061    entries =
062        copyToList(
063            getSubjectGenerator()
064                .getSampleElements(getSubjectGenerator().getCollectionSize().getNumElements()));
065    sort(entries, sortedMultiset.comparator());
066
067    // some tests assume SEVERAL == 3
068    if (entries.size() >= 1) {
069      a = Multisets.immutableEntry(entries.get(0), sortedMultiset.count(entries.get(0)));
070      if (entries.size() >= 3) {
071        b = Multisets.immutableEntry(entries.get(1), sortedMultiset.count(entries.get(1)));
072        c = Multisets.immutableEntry(entries.get(2), sortedMultiset.count(entries.get(2)));
073      }
074    }
075  }
076
077  /** Resets the contents of sortedMultiset to have entries a, c, for the navigation tests. */
078  // Needed to stop Eclipse whining
079  private void resetWithHole() {
080    List<E> container = new ArrayList<>();
081    container.addAll(nCopies(a.getCount(), a.getElement()));
082    container.addAll(nCopies(c.getCount(), c.getElement()));
083    super.resetContainer(getSubjectGenerator().create(container.toArray()));
084    sortedMultiset = (SortedMultiset<E>) getMultiset();
085  }
086
087  @CollectionSize.Require(ZERO)
088  public void testEmptyMultisetFirst() {
089    assertNull(sortedMultiset.firstEntry());
090    assertThrows(NoSuchElementException.class, () -> sortedMultiset.elementSet().first());
091  }
092
093  @CollectionFeature.Require(SUPPORTS_REMOVE)
094  @CollectionSize.Require(ZERO)
095  public void testEmptyMultisetPollFirst() {
096    assertNull(sortedMultiset.pollFirstEntry());
097  }
098
099  @CollectionSize.Require(ZERO)
100  public void testEmptyMultisetNearby() {
101    for (BoundType type : BoundType.values()) {
102      assertNull(sortedMultiset.headMultiset(e0(), type).lastEntry());
103      assertNull(sortedMultiset.tailMultiset(e0(), type).firstEntry());
104    }
105  }
106
107  @CollectionSize.Require(ZERO)
108  public void testEmptyMultisetLast() {
109    assertNull(sortedMultiset.lastEntry());
110    assertThrows(
111        NoSuchElementException.class, () -> assertNull(sortedMultiset.elementSet().last()));
112  }
113
114  @CollectionFeature.Require(SUPPORTS_REMOVE)
115  @CollectionSize.Require(ZERO)
116  public void testEmptyMultisetPollLast() {
117    assertNull(sortedMultiset.pollLastEntry());
118  }
119
120  @CollectionSize.Require(ONE)
121  public void testSingletonMultisetFirst() {
122    assertEquals(a, sortedMultiset.firstEntry());
123  }
124
125  @CollectionFeature.Require(SUPPORTS_REMOVE)
126  @CollectionSize.Require(ONE)
127  public void testSingletonMultisetPollFirst() {
128    assertEquals(a, sortedMultiset.pollFirstEntry());
129    assertTrue(sortedMultiset.isEmpty());
130  }
131
132  @CollectionSize.Require(ONE)
133  public void testSingletonMultisetNearby() {
134    assertNull(sortedMultiset.headMultiset(e0(), OPEN).lastEntry());
135    assertNull(sortedMultiset.tailMultiset(e0(), OPEN).lastEntry());
136
137    assertEquals(a, sortedMultiset.headMultiset(e0(), CLOSED).lastEntry());
138    assertEquals(a, sortedMultiset.tailMultiset(e0(), CLOSED).firstEntry());
139  }
140
141  @CollectionSize.Require(ONE)
142  public void testSingletonMultisetLast() {
143    assertEquals(a, sortedMultiset.lastEntry());
144  }
145
146  @CollectionFeature.Require(SUPPORTS_REMOVE)
147  @CollectionSize.Require(ONE)
148  public void testSingletonMultisetPollLast() {
149    assertEquals(a, sortedMultiset.pollLastEntry());
150    assertTrue(sortedMultiset.isEmpty());
151  }
152
153  @CollectionSize.Require(SEVERAL)
154  public void testFirst() {
155    assertEquals(a, sortedMultiset.firstEntry());
156  }
157
158  @CollectionFeature.Require(SUPPORTS_REMOVE)
159  @CollectionSize.Require(SEVERAL)
160  public void testPollFirst() {
161    assertEquals(a, sortedMultiset.pollFirstEntry());
162    assertEquals(asList(b, c), copyToList(sortedMultiset.entrySet()));
163  }
164
165  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
166  public void testPollFirstUnsupported() {
167    assertThrows(UnsupportedOperationException.class, () -> sortedMultiset.pollFirstEntry());
168  }
169
170  @CollectionSize.Require(SEVERAL)
171  public void testLower() {
172    resetWithHole();
173    assertEquals(null, sortedMultiset.headMultiset(a.getElement(), OPEN).lastEntry());
174    assertEquals(a, sortedMultiset.headMultiset(b.getElement(), OPEN).lastEntry());
175    assertEquals(a, sortedMultiset.headMultiset(c.getElement(), OPEN).lastEntry());
176  }
177
178  @CollectionSize.Require(SEVERAL)
179  public void testFloor() {
180    resetWithHole();
181    assertEquals(a, sortedMultiset.headMultiset(a.getElement(), CLOSED).lastEntry());
182    assertEquals(a, sortedMultiset.headMultiset(b.getElement(), CLOSED).lastEntry());
183    assertEquals(c, sortedMultiset.headMultiset(c.getElement(), CLOSED).lastEntry());
184  }
185
186  @CollectionSize.Require(SEVERAL)
187  public void testCeiling() {
188    resetWithHole();
189
190    assertEquals(a, sortedMultiset.tailMultiset(a.getElement(), CLOSED).firstEntry());
191    assertEquals(c, sortedMultiset.tailMultiset(b.getElement(), CLOSED).firstEntry());
192    assertEquals(c, sortedMultiset.tailMultiset(c.getElement(), CLOSED).firstEntry());
193  }
194
195  @CollectionSize.Require(SEVERAL)
196  public void testHigher() {
197    resetWithHole();
198    assertEquals(c, sortedMultiset.tailMultiset(a.getElement(), OPEN).firstEntry());
199    assertEquals(c, sortedMultiset.tailMultiset(b.getElement(), OPEN).firstEntry());
200    assertEquals(null, sortedMultiset.tailMultiset(c.getElement(), OPEN).firstEntry());
201  }
202
203  @CollectionSize.Require(SEVERAL)
204  public void testLast() {
205    assertEquals(c, sortedMultiset.lastEntry());
206  }
207
208  @CollectionFeature.Require(SUPPORTS_REMOVE)
209  @CollectionSize.Require(SEVERAL)
210  public void testPollLast() {
211    assertEquals(c, sortedMultiset.pollLastEntry());
212    assertEquals(asList(a, b), copyToList(sortedMultiset.entrySet()));
213  }
214
215  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
216  @CollectionSize.Require(SEVERAL)
217  public void testPollLastUnsupported() {
218    assertThrows(UnsupportedOperationException.class, () -> sortedMultiset.pollLastEntry());
219  }
220
221  @CollectionSize.Require(SEVERAL)
222  public void testDescendingNavigation() {
223    List<Entry<E>> ascending = newArrayList(sortedMultiset.entrySet().iterator());
224    List<Entry<E>> descending =
225        newArrayList(sortedMultiset.descendingMultiset().entrySet().iterator());
226    Collections.reverse(descending);
227    assertEquals(ascending, descending);
228  }
229
230  void expectAddFailure(SortedMultiset<E> multiset, Entry<E> entry) {
231    assertThrows(
232        IllegalArgumentException.class, () -> multiset.add(entry.getElement(), entry.getCount()));
233
234    assertThrows(IllegalArgumentException.class, () -> multiset.add(entry.getElement()));
235
236    assertThrows(
237        IllegalArgumentException.class, () -> multiset.addAll(singletonList(entry.getElement())));
238  }
239
240  void expectRemoveZero(SortedMultiset<E> multiset, Entry<E> entry) {
241    assertEquals(0, multiset.remove(entry.getElement(), entry.getCount()));
242    assertFalse(multiset.remove(entry.getElement()));
243    assertFalse(multiset.elementSet().remove(entry.getElement()));
244  }
245
246  void expectSetCountFailure(SortedMultiset<E> multiset, Entry<E> entry) {
247    try {
248      multiset.setCount(entry.getElement(), multiset.count(entry.getElement()));
249    } catch (IllegalArgumentException acceptable) {
250    }
251    assertThrows(
252        IllegalArgumentException.class,
253        () -> multiset.setCount(entry.getElement(), multiset.count(entry.getElement()) + 1));
254  }
255
256  @CollectionSize.Require(ONE)
257  @CollectionFeature.Require(SUPPORTS_ADD)
258  public void testAddOutOfTailBoundsOne() {
259    expectAddFailure(sortedMultiset.tailMultiset(a.getElement(), OPEN), a);
260  }
261
262  @CollectionSize.Require(SEVERAL)
263  @CollectionFeature.Require(SUPPORTS_ADD)
264  public void testAddOutOfTailBoundsSeveral() {
265    expectAddFailure(sortedMultiset.tailMultiset(a.getElement(), OPEN), a);
266    expectAddFailure(sortedMultiset.tailMultiset(b.getElement(), CLOSED), a);
267    expectAddFailure(sortedMultiset.tailMultiset(b.getElement(), OPEN), a);
268    expectAddFailure(sortedMultiset.tailMultiset(b.getElement(), OPEN), b);
269    expectAddFailure(sortedMultiset.tailMultiset(c.getElement(), CLOSED), a);
270    expectAddFailure(sortedMultiset.tailMultiset(c.getElement(), CLOSED), b);
271    expectAddFailure(sortedMultiset.tailMultiset(c.getElement(), OPEN), a);
272    expectAddFailure(sortedMultiset.tailMultiset(c.getElement(), OPEN), b);
273    expectAddFailure(sortedMultiset.tailMultiset(c.getElement(), OPEN), c);
274  }
275
276  @CollectionSize.Require(ONE)
277  @CollectionFeature.Require(SUPPORTS_ADD)
278  public void testAddOutOfHeadBoundsOne() {
279    expectAddFailure(sortedMultiset.headMultiset(a.getElement(), OPEN), a);
280  }
281
282  @CollectionSize.Require(SEVERAL)
283  @CollectionFeature.Require(SUPPORTS_ADD)
284  public void testAddOutOfHeadBoundsSeveral() {
285    expectAddFailure(sortedMultiset.headMultiset(c.getElement(), OPEN), c);
286    expectAddFailure(sortedMultiset.headMultiset(b.getElement(), CLOSED), c);
287    expectAddFailure(sortedMultiset.headMultiset(b.getElement(), OPEN), c);
288    expectAddFailure(sortedMultiset.headMultiset(b.getElement(), OPEN), b);
289    expectAddFailure(sortedMultiset.headMultiset(a.getElement(), CLOSED), c);
290    expectAddFailure(sortedMultiset.headMultiset(a.getElement(), CLOSED), b);
291    expectAddFailure(sortedMultiset.headMultiset(a.getElement(), OPEN), c);
292    expectAddFailure(sortedMultiset.headMultiset(a.getElement(), OPEN), b);
293    expectAddFailure(sortedMultiset.headMultiset(a.getElement(), OPEN), a);
294  }
295
296  @CollectionSize.Require(ONE)
297  @CollectionFeature.Require(SUPPORTS_REMOVE)
298  public void testRemoveOutOfTailBoundsOne() {
299    expectRemoveZero(sortedMultiset.tailMultiset(a.getElement(), OPEN), a);
300  }
301
302  @CollectionSize.Require(SEVERAL)
303  @CollectionFeature.Require(SUPPORTS_REMOVE)
304  public void testRemoveOutOfTailBoundsSeveral() {
305    expectRemoveZero(sortedMultiset.tailMultiset(a.getElement(), OPEN), a);
306    expectRemoveZero(sortedMultiset.tailMultiset(b.getElement(), CLOSED), a);
307    expectRemoveZero(sortedMultiset.tailMultiset(b.getElement(), OPEN), a);
308    expectRemoveZero(sortedMultiset.tailMultiset(b.getElement(), OPEN), b);
309    expectRemoveZero(sortedMultiset.tailMultiset(c.getElement(), CLOSED), a);
310    expectRemoveZero(sortedMultiset.tailMultiset(c.getElement(), CLOSED), b);
311    expectRemoveZero(sortedMultiset.tailMultiset(c.getElement(), OPEN), a);
312    expectRemoveZero(sortedMultiset.tailMultiset(c.getElement(), OPEN), b);
313    expectRemoveZero(sortedMultiset.tailMultiset(c.getElement(), OPEN), c);
314  }
315
316  @CollectionSize.Require(ONE)
317  @CollectionFeature.Require(SUPPORTS_REMOVE)
318  public void testRemoveOutOfHeadBoundsOne() {
319    expectRemoveZero(sortedMultiset.headMultiset(a.getElement(), OPEN), a);
320  }
321
322  @CollectionSize.Require(SEVERAL)
323  @CollectionFeature.Require(SUPPORTS_REMOVE)
324  public void testRemoveOutOfHeadBoundsSeveral() {
325    expectRemoveZero(sortedMultiset.headMultiset(c.getElement(), OPEN), c);
326    expectRemoveZero(sortedMultiset.headMultiset(b.getElement(), CLOSED), c);
327    expectRemoveZero(sortedMultiset.headMultiset(b.getElement(), OPEN), c);
328    expectRemoveZero(sortedMultiset.headMultiset(b.getElement(), OPEN), b);
329    expectRemoveZero(sortedMultiset.headMultiset(a.getElement(), CLOSED), c);
330    expectRemoveZero(sortedMultiset.headMultiset(a.getElement(), CLOSED), b);
331    expectRemoveZero(sortedMultiset.headMultiset(a.getElement(), OPEN), c);
332    expectRemoveZero(sortedMultiset.headMultiset(a.getElement(), OPEN), b);
333    expectRemoveZero(sortedMultiset.headMultiset(a.getElement(), OPEN), a);
334  }
335
336  @CollectionSize.Require(ONE)
337  @CollectionFeature.Require({SUPPORTS_ADD, SUPPORTS_REMOVE})
338  public void testSetCountOutOfTailBoundsOne() {
339    expectSetCountFailure(sortedMultiset.tailMultiset(a.getElement(), OPEN), a);
340  }
341
342  @CollectionSize.Require(SEVERAL)
343  @CollectionFeature.Require({SUPPORTS_ADD, SUPPORTS_REMOVE})
344  public void testSetCountOutOfTailBoundsSeveral() {
345    expectSetCountFailure(sortedMultiset.tailMultiset(a.getElement(), OPEN), a);
346    expectSetCountFailure(sortedMultiset.tailMultiset(b.getElement(), CLOSED), a);
347    expectSetCountFailure(sortedMultiset.tailMultiset(b.getElement(), OPEN), a);
348    expectSetCountFailure(sortedMultiset.tailMultiset(b.getElement(), OPEN), b);
349    expectSetCountFailure(sortedMultiset.tailMultiset(c.getElement(), CLOSED), a);
350    expectSetCountFailure(sortedMultiset.tailMultiset(c.getElement(), CLOSED), b);
351    expectSetCountFailure(sortedMultiset.tailMultiset(c.getElement(), OPEN), a);
352    expectSetCountFailure(sortedMultiset.tailMultiset(c.getElement(), OPEN), b);
353    expectSetCountFailure(sortedMultiset.tailMultiset(c.getElement(), OPEN), c);
354  }
355
356  @CollectionSize.Require(ONE)
357  @CollectionFeature.Require({SUPPORTS_ADD, SUPPORTS_REMOVE})
358  public void testSetCountOutOfHeadBoundsOne() {
359    expectSetCountFailure(sortedMultiset.headMultiset(a.getElement(), OPEN), a);
360  }
361
362  @CollectionSize.Require(SEVERAL)
363  @CollectionFeature.Require({SUPPORTS_ADD, SUPPORTS_REMOVE})
364  public void testSetCountOutOfHeadBoundsSeveral() {
365    expectSetCountFailure(sortedMultiset.headMultiset(c.getElement(), OPEN), c);
366    expectSetCountFailure(sortedMultiset.headMultiset(b.getElement(), CLOSED), c);
367    expectSetCountFailure(sortedMultiset.headMultiset(b.getElement(), OPEN), c);
368    expectSetCountFailure(sortedMultiset.headMultiset(b.getElement(), OPEN), b);
369    expectSetCountFailure(sortedMultiset.headMultiset(a.getElement(), CLOSED), c);
370    expectSetCountFailure(sortedMultiset.headMultiset(a.getElement(), CLOSED), b);
371    expectSetCountFailure(sortedMultiset.headMultiset(a.getElement(), OPEN), c);
372    expectSetCountFailure(sortedMultiset.headMultiset(a.getElement(), OPEN), b);
373    expectSetCountFailure(sortedMultiset.headMultiset(a.getElement(), OPEN), a);
374  }
375
376  @CollectionSize.Require(SEVERAL)
377  @CollectionFeature.Require(SUPPORTS_ADD)
378  public void testAddWithConflictingBounds() {
379    testEmptyRangeSubMultisetSupportingAdd(
380        sortedMultiset.subMultiset(a.getElement(), CLOSED, a.getElement(), OPEN));
381    testEmptyRangeSubMultisetSupportingAdd(
382        sortedMultiset.subMultiset(a.getElement(), OPEN, a.getElement(), OPEN));
383    testEmptyRangeSubMultisetSupportingAdd(
384        sortedMultiset.subMultiset(a.getElement(), OPEN, a.getElement(), CLOSED));
385    testEmptyRangeSubMultisetSupportingAdd(
386        sortedMultiset.subMultiset(b.getElement(), CLOSED, a.getElement(), CLOSED));
387    testEmptyRangeSubMultisetSupportingAdd(
388        sortedMultiset.subMultiset(b.getElement(), CLOSED, a.getElement(), OPEN));
389    testEmptyRangeSubMultisetSupportingAdd(
390        sortedMultiset.subMultiset(b.getElement(), OPEN, a.getElement(), OPEN));
391  }
392
393  @CollectionSize.Require(SEVERAL)
394  @CollectionFeature.Require(SUPPORTS_ADD)
395  public void testConflictingBounds() {
396    testEmptyRangeSubMultiset(
397        sortedMultiset.subMultiset(a.getElement(), CLOSED, a.getElement(), OPEN));
398    testEmptyRangeSubMultiset(
399        sortedMultiset.subMultiset(a.getElement(), OPEN, a.getElement(), OPEN));
400    testEmptyRangeSubMultiset(
401        sortedMultiset.subMultiset(a.getElement(), OPEN, a.getElement(), CLOSED));
402    testEmptyRangeSubMultiset(
403        sortedMultiset.subMultiset(b.getElement(), CLOSED, a.getElement(), CLOSED));
404    testEmptyRangeSubMultiset(
405        sortedMultiset.subMultiset(b.getElement(), CLOSED, a.getElement(), OPEN));
406    testEmptyRangeSubMultiset(
407        sortedMultiset.subMultiset(b.getElement(), OPEN, a.getElement(), OPEN));
408  }
409
410  public void testEmptyRangeSubMultiset(SortedMultiset<E> multiset) {
411    assertTrue(multiset.isEmpty());
412    assertEquals(0, multiset.size());
413    assertEquals(0, multiset.toArray().length);
414    assertTrue(multiset.entrySet().isEmpty());
415    assertFalse(multiset.iterator().hasNext());
416    assertEquals(0, multiset.entrySet().size());
417    assertEquals(0, multiset.entrySet().toArray().length);
418    assertFalse(multiset.entrySet().iterator().hasNext());
419  }
420
421  public void testEmptyRangeSubMultisetSupportingAdd(SortedMultiset<E> multiset) {
422    for (Entry<E> entry : asList(a, b, c)) {
423      expectAddFailure(multiset, entry);
424    }
425  }
426
427  private static int totalSize(Iterable<? extends Entry<?>> entries) {
428    int sum = 0;
429    for (Entry<?> entry : entries) {
430      sum += entry.getCount();
431    }
432    return sum;
433  }
434
435  private enum SubMultisetSpec {
436    TAIL_CLOSED {
437      @Override
438      <E> List<Entry<E>> expectedEntries(int targetEntry, List<Entry<E>> entries) {
439        return entries.subList(targetEntry, entries.size());
440      }
441
442      @Override
443      <E> SortedMultiset<E> subMultiset(
444          SortedMultiset<E> multiset, List<Entry<E>> entries, int targetEntry) {
445        return multiset.tailMultiset(entries.get(targetEntry).getElement(), CLOSED);
446      }
447    },
448    TAIL_OPEN {
449      @Override
450      <E> List<Entry<E>> expectedEntries(int targetEntry, List<Entry<E>> entries) {
451        return entries.subList(targetEntry + 1, entries.size());
452      }
453
454      @Override
455      <E> SortedMultiset<E> subMultiset(
456          SortedMultiset<E> multiset, List<Entry<E>> entries, int targetEntry) {
457        return multiset.tailMultiset(entries.get(targetEntry).getElement(), OPEN);
458      }
459    },
460    HEAD_CLOSED {
461      @Override
462      <E> List<Entry<E>> expectedEntries(int targetEntry, List<Entry<E>> entries) {
463        return entries.subList(0, targetEntry + 1);
464      }
465
466      @Override
467      <E> SortedMultiset<E> subMultiset(
468          SortedMultiset<E> multiset, List<Entry<E>> entries, int targetEntry) {
469        return multiset.headMultiset(entries.get(targetEntry).getElement(), CLOSED);
470      }
471    },
472    HEAD_OPEN {
473      @Override
474      <E> List<Entry<E>> expectedEntries(int targetEntry, List<Entry<E>> entries) {
475        return entries.subList(0, targetEntry);
476      }
477
478      @Override
479      <E> SortedMultiset<E> subMultiset(
480          SortedMultiset<E> multiset, List<Entry<E>> entries, int targetEntry) {
481        return multiset.headMultiset(entries.get(targetEntry).getElement(), OPEN);
482      }
483    };
484
485    abstract <E> List<Entry<E>> expectedEntries(int targetEntry, List<Entry<E>> entries);
486
487    abstract <E> SortedMultiset<E> subMultiset(
488        SortedMultiset<E> multiset, List<Entry<E>> entries, int targetEntry);
489  }
490
491  private void testSubMultisetEntrySet(SubMultisetSpec spec) {
492    List<Entry<E>> entries = copyToList(sortedMultiset.entrySet());
493    for (int i = 0; i < entries.size(); i++) {
494      List<Entry<E>> expected = spec.expectedEntries(i, entries);
495      SortedMultiset<E> subMultiset = spec.subMultiset(sortedMultiset, entries, i);
496      assertEquals(expected, copyToList(subMultiset.entrySet()));
497    }
498  }
499
500  private void testSubMultisetSize(SubMultisetSpec spec) {
501    List<Entry<E>> entries = copyToList(sortedMultiset.entrySet());
502    for (int i = 0; i < entries.size(); i++) {
503      List<Entry<E>> expected = spec.expectedEntries(i, entries);
504      SortedMultiset<E> subMultiset = spec.subMultiset(sortedMultiset, entries, i);
505      assertEquals(totalSize(expected), subMultiset.size());
506    }
507  }
508
509  private void testSubMultisetDistinctElements(SubMultisetSpec spec) {
510    List<Entry<E>> entries = copyToList(sortedMultiset.entrySet());
511    for (int i = 0; i < entries.size(); i++) {
512      List<Entry<E>> expected = spec.expectedEntries(i, entries);
513      SortedMultiset<E> subMultiset = spec.subMultiset(sortedMultiset, entries, i);
514      assertEquals(expected.size(), subMultiset.entrySet().size());
515      assertEquals(expected.size(), subMultiset.elementSet().size());
516    }
517  }
518
519  public void testTailClosedEntrySet() {
520    testSubMultisetEntrySet(SubMultisetSpec.TAIL_CLOSED);
521  }
522
523  public void testTailClosedSize() {
524    testSubMultisetSize(SubMultisetSpec.TAIL_CLOSED);
525  }
526
527  public void testTailClosedDistinctElements() {
528    testSubMultisetDistinctElements(SubMultisetSpec.TAIL_CLOSED);
529  }
530
531  public void testTailOpenEntrySet() {
532    testSubMultisetEntrySet(SubMultisetSpec.TAIL_OPEN);
533  }
534
535  public void testTailOpenSize() {
536    testSubMultisetSize(SubMultisetSpec.TAIL_OPEN);
537  }
538
539  public void testTailOpenDistinctElements() {
540    testSubMultisetDistinctElements(SubMultisetSpec.TAIL_OPEN);
541  }
542
543  public void testHeadClosedEntrySet() {
544    testSubMultisetEntrySet(SubMultisetSpec.HEAD_CLOSED);
545  }
546
547  public void testHeadClosedSize() {
548    testSubMultisetSize(SubMultisetSpec.HEAD_CLOSED);
549  }
550
551  public void testHeadClosedDistinctElements() {
552    testSubMultisetDistinctElements(SubMultisetSpec.HEAD_CLOSED);
553  }
554
555  public void testHeadOpenEntrySet() {
556    testSubMultisetEntrySet(SubMultisetSpec.HEAD_OPEN);
557  }
558
559  public void testHeadOpenSize() {
560    testSubMultisetSize(SubMultisetSpec.HEAD_OPEN);
561  }
562
563  public void testHeadOpenDistinctElements() {
564    testSubMultisetDistinctElements(SubMultisetSpec.HEAD_OPEN);
565  }
566
567  @CollectionSize.Require(SEVERAL)
568  @CollectionFeature.Require(SUPPORTS_REMOVE)
569  public void testClearTailOpen() {
570    List<Entry<E>> expected =
571        copyToList(sortedMultiset.headMultiset(b.getElement(), CLOSED).entrySet());
572    sortedMultiset.tailMultiset(b.getElement(), OPEN).clear();
573    assertEquals(expected, copyToList(sortedMultiset.entrySet()));
574  }
575
576  @CollectionSize.Require(SEVERAL)
577  @CollectionFeature.Require(SUPPORTS_REMOVE)
578  public void testClearTailOpenEntrySet() {
579    List<Entry<E>> expected =
580        copyToList(sortedMultiset.headMultiset(b.getElement(), CLOSED).entrySet());
581    sortedMultiset.tailMultiset(b.getElement(), OPEN).entrySet().clear();
582    assertEquals(expected, copyToList(sortedMultiset.entrySet()));
583  }
584
585  @CollectionSize.Require(SEVERAL)
586  @CollectionFeature.Require(SUPPORTS_REMOVE)
587  public void testClearTailClosed() {
588    List<Entry<E>> expected =
589        copyToList(sortedMultiset.headMultiset(b.getElement(), OPEN).entrySet());
590    sortedMultiset.tailMultiset(b.getElement(), CLOSED).clear();
591    assertEquals(expected, copyToList(sortedMultiset.entrySet()));
592  }
593
594  @CollectionSize.Require(SEVERAL)
595  @CollectionFeature.Require(SUPPORTS_REMOVE)
596  public void testClearTailClosedEntrySet() {
597    List<Entry<E>> expected =
598        copyToList(sortedMultiset.headMultiset(b.getElement(), OPEN).entrySet());
599    sortedMultiset.tailMultiset(b.getElement(), CLOSED).entrySet().clear();
600    assertEquals(expected, copyToList(sortedMultiset.entrySet()));
601  }
602
603  @CollectionSize.Require(SEVERAL)
604  @CollectionFeature.Require(SUPPORTS_REMOVE)
605  public void testClearHeadOpen() {
606    List<Entry<E>> expected =
607        copyToList(sortedMultiset.tailMultiset(b.getElement(), CLOSED).entrySet());
608    sortedMultiset.headMultiset(b.getElement(), OPEN).clear();
609    assertEquals(expected, copyToList(sortedMultiset.entrySet()));
610  }
611
612  @CollectionSize.Require(SEVERAL)
613  @CollectionFeature.Require(SUPPORTS_REMOVE)
614  public void testClearHeadOpenEntrySet() {
615    List<Entry<E>> expected =
616        copyToList(sortedMultiset.tailMultiset(b.getElement(), CLOSED).entrySet());
617    sortedMultiset.headMultiset(b.getElement(), OPEN).entrySet().clear();
618    assertEquals(expected, copyToList(sortedMultiset.entrySet()));
619  }
620
621  @CollectionSize.Require(SEVERAL)
622  @CollectionFeature.Require(SUPPORTS_REMOVE)
623  public void testClearHeadClosed() {
624    List<Entry<E>> expected =
625        copyToList(sortedMultiset.tailMultiset(b.getElement(), OPEN).entrySet());
626    sortedMultiset.headMultiset(b.getElement(), CLOSED).clear();
627    assertEquals(expected, copyToList(sortedMultiset.entrySet()));
628  }
629
630  @CollectionSize.Require(SEVERAL)
631  @CollectionFeature.Require(SUPPORTS_REMOVE)
632  public void testClearHeadClosedEntrySet() {
633    List<Entry<E>> expected =
634        copyToList(sortedMultiset.tailMultiset(b.getElement(), OPEN).entrySet());
635    sortedMultiset.headMultiset(b.getElement(), CLOSED).entrySet().clear();
636    assertEquals(expected, copyToList(sortedMultiset.entrySet()));
637  }
638}