/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static java.util.Arrays.asList;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.Multiset.Entry;
import com.google.common.collect.testing.google.UnmodifiableCollectionTests;
import com.google.common.testing.SerializableTester;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Common tests for a {@link Multiset}.
*
* @author Kevin Bourrillion
*/
@GwtCompatible(emulated = true)
public abstract class AbstractMultisetTest extends AbstractCollectionTest {
@Override protected abstract <E> Multiset<E> create();
protected Multiset<String> ms;
// public for GWT
@Override public void setUp() throws Exception {
super.setUp();
c = ms = create();
}
/**
* Validates that multiset size returned by {@code size()} is the same as the
* size generated by summing the counts of all multiset entries.
*/
protected void assertSize(Multiset<String> multiset) {
long size = 0;
for (Multiset.Entry<String> entry : multiset.entrySet()) {
size += entry.getCount();
}
assertEquals((int) Math.min(size, Integer.MAX_VALUE), multiset.size());
}
protected void assertSize() {
assertSize(ms);
}
@Override protected void assertContents(String... expected) {
super.assertContents(expected);
assertSize();
}
/**
* Don't run {@code NullPointerTester} on multisets, since they fail with
* Java 6 due to a bug in the JDK, as illustrated in the commented out
* method {@code HashMultisetTest#testAnnotations()}.
*/
// TODO: Figure out if this is still true...
@GwtIncompatible("NullPointerTester")
@Override public void testNullPointerExceptions() throws Exception {}
public void testCountZero() {
assertEquals(0, ms.count("a"));
assertSize();
}
public void testCountOne() {
ms.add("a");
assertEquals(1, ms.count("a"));
assertSize();
}
public void testCountTwo() {
ms.add("a");
ms.add("a");
assertEquals(2, ms.count("a"));
assertSize();
}
public void testCountAfterRemoval() {
ms.add("a");
ms.remove("a");
assertEquals(0, ms.count("a"));
assertSize();
}
public void testCountNull() {
assertEquals(0, ms.count(null));
}
public void testCountWrongType() {
assertEquals(0, ms.count(new WrongType()));
}
static class WrongType {}
public void testAddNoneToNone() {
assertEquals(0, ms.add("a", 0));
assertContents();
}
public void testAddNoneToSome() {
ms.add("a");
assertEquals(1, ms.add("a", 0));
assertContents("a");
}
public void testAddSeveralAtOnce() {
assertEquals(0, ms.add("a", 3));
assertContents("a", "a", "a");
}
public void testAddSomeToSome() {
ms.add("a", 2);
assertEquals(2, ms.add("a", 3));
assertContents("a", "a", "a", "a", "a");
}
@Override public void testAddSeveralTimes() {
assertTrue(ms.add("a"));
assertTrue(ms.add("b"));
assertTrue(ms.add("a"));
assertTrue(ms.add("b"));
assertContents("a", "b", "a", "b");
}
public void testAddNegative() {
try {
ms.add("a", -1);
fail();
} catch (IllegalArgumentException expected) {
}
assertSize();
}
@Override public void testEqualsNo() {
ms.add("a");
ms.add("b");
ms.add("b");
Multiset<String> ms2 = create();
ms2.add("a", 2);
ms2.add("b");
assertFalse(ms.equals(ms2));
assertSize();
}
public void testAddTooMany() {
ms.add("a", Integer.MAX_VALUE); // so far so good
ms.add("b", Integer.MAX_VALUE); // so far so good
try {
ms.add("a");
fail();
} catch (IllegalArgumentException expected) {
}
assertSize();
}
public void testAddAllEmptySet() {
c = ms = createSample();
assertFalse(ms.addAll(Collections.<String>emptySet()));
assertEquals(createSample(), ms);
assertSize();
}
public void testAddAllEmptyMultiset() {
c = ms = createSample();
Multiset<String> empty = create();
assertFalse(ms.addAll(empty));
assertEquals(createSample(), ms);
assertSize();
}
public void testAddAllSet() {
c = ms = createSample();
Set<String> more = ImmutableSet.of("c", "d", "e");
assertTrue(ms.addAll(more));
assertContents("a", "b", "b", "c", "c", "d", "d", "d", "d", "e");
}
public void testAddAllMultiset() {
c = ms = createSample();
Multiset<String> more = HashMultiset.create(
asList("c", "c", "d", "d", "e"));
assertTrue(ms.addAll(more));
assertContents("a", "b", "b", "c", "c", "c", "d", "d", "d", "d", "d", "e");
}
public void testRemoveNoneFromNone() {
assertEquals(0, ms.remove("a", 0));
assertContents();
}
public void testRemoveNoneFromSome() {
ms.add("a");
assertEquals(1, ms.remove("a", 0));
assertContents("a");
}
public void testRemoveOneFromNone() {
assertEquals(0, ms.remove("a", 1));
assertContents();
}
public void testRemoveOneFromOne() {
ms.add("a");
assertEquals(1, ms.remove("a", 1));
assertContents();
}
public void testRemoveSomeFromSome() {
ms.add("a", 5);
assertEquals(5, ms.remove("a", 3));
assertContents("a", "a");
}
public void testRemoveTooMany() {
ms.add("a", 3);
assertEquals(3, ms.remove("a", 5));
assertContents();
}
public void testRemoveNegative() {
try {
ms.remove("a", -1);
fail();
} catch (IllegalArgumentException expected) {
}
assertSize();
}
public void testContainsSeveral() {
ms.add("a", 3);
assertTrue(ms.contains(new String("a")));
assertSize();
}
public void testContainsAllNo() {
ms.add("a", 2);
ms.add("b", 3);
assertFalse(ms.containsAll(asList("a", "c")));
assertSize();
}
public void testContainsAllYes() {
ms.add("a", 2);
ms.add("b", 3);
ms.add("c", 4);
assertTrue(ms.containsAll(asList("a", "c")));
assertSize();
}
public void testRemoveAllOfOne() {
ms.add("a", 2);
ms.add("b");
assertTrue(ms.removeAll(asList("a", "c")));
assertContents("b");
}
public void testRemoveAllOfDisjoint() {
ms.add("a", 2);
ms.add("b");
assertFalse(ms.removeAll(asList("c", "d")));
assertContents("a", "a", "b");
}
public void testRemoveAllOfEverything() {
ms.add("a", 2);
ms.add("b");
assertTrue(ms.removeAll(asList("a", "b")));
assertContents();
}
public void testRetainAllOfOne() {
ms.add("a", 2);
ms.add("b");
assertTrue(ms.retainAll(asList("a", "c")));
assertContents("a", "a");
}
public void testRetainAllOfDisjoint() {
ms.add("a", 2);
ms.add("b");
assertTrue(ms.retainAll(asList("c", "d")));
assertContents();
}
public void testRetainAllOfEverything() {
ms.add("a", 2);
ms.add("b");
assertFalse(ms.retainAll(asList("a", "b")));
assertContents("a", "a", "b");
}
public void testContainsAllVacuousViaElementSet() {
assertTrue(ms.elementSet().containsAll(Collections.emptySet()));
}
public void testContainsAllNoViaElementSet() {
ms.add("a", 2);
ms.add("b", 3);
assertFalse(ms.elementSet().containsAll(asList("a", "c")));
assertSize();
}
public void testContainsAllYesViaElementSet() {
ms.add("a", 2);
ms.add("b", 3);
ms.add("c", 4);
assertTrue(ms.elementSet().containsAll(asList("a", "c")));
assertSize();
}
public void testRemoveAllVacuousViaElementSet() {
assertFalse(ms.elementSet().removeAll(Collections.emptySet()));
assertSize();
}
public void testRemoveAllOfOneViaElementSet() {
ms.add("a", 2);
ms.add("b");
assertTrue(ms.elementSet().removeAll(asList("a", "c")));
assertContents("b");
}
public void testRemoveAllOfDisjointViaElementSet() {
ms.add("a", 2);
ms.add("b");
assertFalse(ms.elementSet().removeAll(asList("c", "d")));
assertContents("a", "a", "b");
}
public void testRemoveAllOfEverythingViaElementSet() {
ms.add("a", 2);
ms.add("b");
assertTrue(ms.elementSet().removeAll(asList("a", "b")));
assertContents();
}
public void testRetainAllVacuousViaElementSet() {
assertFalse(ms.elementSet().retainAll(asList("a")));
assertContents();
}
public void testRetainAllOfNothingViaElementSet() {
ms.add("a");
assertTrue(ms.elementSet().retainAll(Collections.emptySet()));
assertContents();
}
public void testRetainAllOfOneViaElementSet() {
ms.add("a", 2);
ms.add("b");
assertTrue(ms.elementSet().retainAll(asList("a", "c")));
assertContents("a", "a");
}
public void testRetainAllOfDisjointViaElementSet() {
ms.add("a", 2);
ms.add("b");
assertTrue(ms.elementSet().retainAll(asList("c", "d")));
assertContents();
}
public void testRetainAllOfEverythingViaElementSet() {
ms.add("a", 2);
ms.add("b");
assertFalse(ms.elementSet().retainAll(asList("a", "b")));
assertContents("a", "a", "b");
}
public void testElementSetBasic() {
ms.add("a", 3);
ms.add("b", 2);
ms.add("c", 1);
HashSet<String> expected = Sets.newHashSet("a", "b", "c");
Set<String> actual = ms.elementSet();
assertEquals(expected, actual);
assertEquals(actual, expected);
assertSize();
}
public void testElementSetIsNotACopy() {
ms.add("a", 1);
ms.add("b", 2);
Set<String> elementSet = ms.elementSet();
ms.add("c", 3);
ms.setCount("b", 0);
assertEquals(Sets.newHashSet("a", "c"), elementSet);
assertSize();
}
public void testRemoveFromElementSetYes() {
ms.add("a", 1);
ms.add("b", 2);
Set<String> elementSet = ms.elementSet();
assertTrue(elementSet.remove("b"));
assertContents("a");
}
public void testRemoveFromElementSetNo() {
ms.add("a", 1);
Set<String> elementSet = ms.elementSet();
assertFalse(elementSet.remove("b"));
assertContents("a");
}
public void testRemoveFromElementSetNull() {
assertEquals(false, ms.elementSet().remove(null));
}
public void testRemoveFromElementSetWrongType() {
assertEquals(false, ms.elementSet().remove(new WrongType()));
}
public void testCantAddToElementSet() {
try {
ms.elementSet().add("a");
fail();
} catch (UnsupportedOperationException expected) {
}
assertSize();
}
public void testClearViaElementSet() {
ms = createSample();
ms.elementSet().clear();
assertContents();
}
public void testClearViaEntrySet() {
ms = createSample();
ms.entrySet().clear();
assertContents();
}
public void testEntrySet() {
ms = createSample();
for (Multiset.Entry<String> entry : ms.entrySet()) {
assertEquals(entry, entry);
String element = entry.getElement();
if (element.equals("a")) {
assertEquals(1, entry.getCount());
} else if (element.equals("b")) {
assertEquals(2, entry.getCount());
} else if (element.equals("c")) {
assertEquals(1, entry.getCount());
} else if (element.equals("d")) {
assertEquals(3, entry.getCount());
} else {
fail();
}
}
assertSize();
}
public void testEntrySetEmpty() {
assertEquals(Collections.emptySet(), ms.entrySet());
}
public void testReallyBig() {
ms.add("a", Integer.MAX_VALUE - 1);
assertEquals(Integer.MAX_VALUE - 1, ms.size());
ms.add("b", 3);
// See Collection.size() contract
assertEquals(Integer.MAX_VALUE, ms.size());
// Make sure we didn't forget our size
ms.remove("a", 4);
assertEquals(Integer.MAX_VALUE - 2, ms.size());
assertSize();
}
public void testToStringNull() {
ms.add("a", 3);
ms.add("c", 1);
ms.add("b", 2);
ms.add(null, 4);
// This test is brittle. The original test was meant to validate the
// contents of the string itself, but key ordering tended to change
// under unpredictable circumstances. Instead, we're just ensuring
// that the string not return null, and implicitly, not throw an exception.
assertNotNull(ms.toString());
assertSize();
}
@GwtIncompatible("SerializableTester")
public void testSerializable() {
ms = createSample();
assertEquals(ms, SerializableTester.reserialize(ms));
assertSize();
}
public void testIteratorRemove() {
ms.add("a");
ms.add("b");
ms.add("c");
Iterator<String> iterator = ms.iterator();
String element1 = iterator.next();
iterator.remove();
String element2 = iterator.next();
assertFalse(ms.contains(element1));
assertTrue(ms.contains(element2));
assertSize();
}
public void testIteratorRemoveRepeated() {
ms.add("a", 3);
ms.add("b", 1);
ms.add("c", 2);
Iterator<String> iterator = ms.iterator();
for (int i = 0; i < 6; i++) {
assertTrue(iterator.hasNext());
iterator.next();
iterator.remove();
}
assertFalse(iterator.hasNext());
assertTrue(ms.isEmpty());
assertSize();
}
public void testIteratorRemoveTooSoon() {
ms.add("a");
ms.add("b");
ms.add("c");
Iterator<String> iterator = ms.iterator();
try {
iterator.remove();
fail();
} catch (IllegalStateException expected) {}
assertSize();
}
public void testIteratorRemoveTwiceConsecutive() {
ms.add("a");
ms.add("b");
ms.add("c");
Iterator<String> iterator = ms.iterator();
iterator.next();
iterator.remove();
try {
iterator.remove();
fail();
} catch (IllegalStateException expected) {}
assertSize();
}
public void testIteratorNoSuchElementException() {
ms.add("a");
ms.add("b");
ms.add("c");
Iterator<String> iterator = ms.iterator();
iterator.next();
iterator.next();
iterator.next();
try {
iterator.next();
fail();
} catch (NoSuchElementException expected) {}
assertSize();
}
public void testEntryAfterRemove() {
ms.add("a", 8);
Multiset.Entry<String> entry = ms.entrySet().iterator().next();
assertEquals(8, entry.getCount());
ms.remove("a");
assertEquals(7, entry.getCount());
ms.remove("a", 4);
assertEquals(3, entry.getCount());
ms.elementSet().remove("a");
assertEquals(0, entry.getCount());
ms.add("a", 5);
assertEquals(5, entry.getCount());
}
public void testEntryAfterClear() {
ms.add("a", 3);
Multiset.Entry<String> entry = ms.entrySet().iterator().next();
ms.clear();
assertEquals(0, entry.getCount());
ms.add("a", 5);
assertEquals(5, entry.getCount());
}
public void testEntryAfterEntrySetClear() {
ms.add("a", 3);
Multiset.Entry<String> entry = ms.entrySet().iterator().next();
ms.entrySet().clear();
assertEquals(0, entry.getCount());
ms.add("a", 5);
assertEquals(5, entry.getCount());
}
public void testEntryAfterEntrySetIteratorRemove() {
ms.add("a", 3);
Iterator<Multiset.Entry<String>> iterator = ms.entrySet().iterator();
Multiset.Entry<String> entry = iterator.next();
iterator.remove();
assertEquals(0, entry.getCount());
try {
iterator.remove();
fail();
} catch (IllegalStateException expected) {}
ms.add("a", 5);
assertEquals(5, entry.getCount());
}
public void testEntryAfterElementSetIteratorRemove() {
ms.add("a", 3);
Multiset.Entry<String> entry = ms.entrySet().iterator().next();
Iterator<String> iterator = ms.elementSet().iterator();
iterator.next();
iterator.remove();
assertEquals(0, entry.getCount());
ms.add("a", 5);
assertEquals(5, entry.getCount());
}
public void testEntrySetContains() {
ms.add("a", 3);
Set<Entry<String>> es = ms.entrySet();
assertTrue(es.contains(Multisets.immutableEntry("a", 3)));
assertFalse(es.contains(null));
assertFalse(es.contains(Maps.immutableEntry("a", 3)));
assertFalse(es.contains(Multisets.immutableEntry("a", 2)));
assertFalse(es.contains(Multisets.immutableEntry("b", 3)));
assertFalse(es.contains(Multisets.immutableEntry("b", 0)));
}
public void testEntrySetRemove() {
ms.add("a", 3);
Set<Entry<String>> es = ms.entrySet();
assertFalse(es.remove(null));
assertFalse(es.remove(Maps.immutableEntry("a", 3)));
assertFalse(es.remove(Multisets.immutableEntry("a", 2)));
assertFalse(es.remove(Multisets.immutableEntry("b", 3)));
assertFalse(es.remove(Multisets.immutableEntry("b", 0)));
assertEquals(3, ms.count("a"));
assertTrue(es.remove(Multisets.immutableEntry("a", 3)));
assertEquals(0, ms.count("a"));
}
public void testEntrySetToArray() {
ms.add("a", 3);
Set<Multiset.Entry<String>> es = ms.entrySet();
Entry<?>[] array = new Entry<?>[3];
assertSame(array, es.toArray(array));
assertEquals(Multisets.immutableEntry("a", 3), array[0]);
assertNull(array[1]);
}
public void testUnmodifiableMultiset() {
ms.add("a", 3);
ms.add("b");
ms.add("c", 2);
Multiset<Object> unmodifiable = Multisets.<Object>unmodifiableMultiset(ms);
UnmodifiableCollectionTests.assertMultisetIsUnmodifiable(unmodifiable, "a");
}
@Override protected Multiset<String> createSample() {
Multiset<String> ms = create();
ms.add("a", 1);
ms.add("b", 2);
ms.add("c", 1);
ms.add("d", 3);
return ms;
}
}