/* * 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 com.google.common.base.Preconditions.checkArgument; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.common.base.Objects; import com.google.common.collect.testing.features.CollectionFeature; import com.google.common.collect.testing.features.CollectionSize; import com.google.common.collect.testing.google.MultisetTestSuiteBuilder; import com.google.common.collect.testing.google.TestStringMultisetGenerator; import java.io.Serializable; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.checkerframework.checker.nullness.qual.Nullable; /** * Unit test for {@link AbstractMultiset}. * * @author Kevin Bourrillion * @author Louis Wasserman */ @SuppressWarnings("serial") // No serialization is used in this test @GwtCompatible(emulated = true) public class SimpleAbstractMultisetTest extends TestCase { @GwtIncompatible // suite public static Test suite() { TestSuite suite = new TestSuite(); suite.addTestSuite(SimpleAbstractMultisetTest.class); suite.addTest( MultisetTestSuiteBuilder.using( new TestStringMultisetGenerator() { @Override protected Multiset create(String[] elements) { Multiset ms = new NoRemoveMultiset<>(); Collections.addAll(ms, elements); return ms; } }) .named("NoRemoveMultiset") .withFeatures( CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_VALUES, CollectionFeature.SUPPORTS_ADD) .createTestSuite()); return suite; } public void testFastAddAllMultiset() { final AtomicInteger addCalls = new AtomicInteger(); Multiset multiset = new NoRemoveMultiset() { @Override public int add(String element, int occurrences) { addCalls.incrementAndGet(); return super.add(element, occurrences); } }; ImmutableMultiset adds = new ImmutableMultiset.Builder().addCopies("x", 10).build(); multiset.addAll(adds); assertEquals(1, addCalls.get()); } public void testRemoveUnsupported() { Multiset multiset = new NoRemoveMultiset<>(); multiset.add("a"); try { multiset.remove("a"); fail(); } catch (UnsupportedOperationException expected) { } assertTrue(multiset.contains("a")); } private static class NoRemoveMultiset extends AbstractMultiset implements Serializable { final Map backingMap = Maps.newHashMap(); @Override public int size() { return Multisets.linearTimeSizeImpl(this); } @Override public void clear() { throw new UnsupportedOperationException(); } @Override public int count(@Nullable Object element) { for (Entry entry : entrySet()) { if (Objects.equal(entry.getElement(), element)) { return entry.getCount(); } } return 0; } @Override public int add(@Nullable E element, int occurrences) { checkArgument(occurrences >= 0); Integer frequency = backingMap.get(element); if (frequency == null) { frequency = 0; } if (occurrences == 0) { return frequency; } checkArgument(occurrences <= Integer.MAX_VALUE - frequency); backingMap.put(element, frequency + occurrences); return frequency; } @Override Iterator elementIterator() { return Multisets.elementIterator(entryIterator()); } @Override Iterator> entryIterator() { final Iterator> backingEntries = backingMap.entrySet().iterator(); return new UnmodifiableIterator>() { @Override public boolean hasNext() { return backingEntries.hasNext(); } @Override public Multiset.Entry next() { final Map.Entry mapEntry = backingEntries.next(); return new Multisets.AbstractEntry() { @Override public E getElement() { return mapEntry.getKey(); } @Override public int getCount() { Integer frequency = backingMap.get(getElement()); return (frequency == null) ? 0 : frequency; } }; } }; } @Override public Iterator iterator() { return Multisets.iteratorImpl(this); } @Override int distinctElements() { return backingMap.size(); } } }