/* * 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; } }