• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.collect;
16 
17 import static com.google.common.base.Preconditions.checkArgument;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.annotations.GwtIncompatible;
21 import com.google.common.base.Objects;
22 import com.google.common.collect.testing.features.CollectionFeature;
23 import com.google.common.collect.testing.features.CollectionSize;
24 import com.google.common.collect.testing.google.MultisetTestSuiteBuilder;
25 import com.google.common.collect.testing.google.TestStringMultisetGenerator;
26 import java.io.Serializable;
27 import java.util.Collections;
28 import java.util.Iterator;
29 import java.util.Map;
30 import java.util.concurrent.atomic.AtomicInteger;
31 import junit.framework.Test;
32 import junit.framework.TestCase;
33 import junit.framework.TestSuite;
34 import org.checkerframework.checker.nullness.qual.Nullable;
35 
36 /**
37  * Unit test for {@link AbstractMultiset}.
38  *
39  * @author Kevin Bourrillion
40  * @author Louis Wasserman
41  */
42 @SuppressWarnings("serial") // No serialization is used in this test
43 @GwtCompatible(emulated = true)
44 public class SimpleAbstractMultisetTest extends TestCase {
45   @GwtIncompatible // suite
suite()46   public static Test suite() {
47     TestSuite suite = new TestSuite();
48     suite.addTestSuite(SimpleAbstractMultisetTest.class);
49     suite.addTest(
50         MultisetTestSuiteBuilder.using(
51                 new TestStringMultisetGenerator() {
52                   @Override
53                   protected Multiset<String> create(String[] elements) {
54                     Multiset<String> ms = new NoRemoveMultiset<>();
55                     Collections.addAll(ms, elements);
56                     return ms;
57                   }
58                 })
59             .named("NoRemoveMultiset")
60             .withFeatures(
61                 CollectionSize.ANY,
62                 CollectionFeature.ALLOWS_NULL_VALUES,
63                 CollectionFeature.SUPPORTS_ADD)
64             .createTestSuite());
65     return suite;
66   }
67 
testFastAddAllMultiset()68   public void testFastAddAllMultiset() {
69     final AtomicInteger addCalls = new AtomicInteger();
70     Multiset<String> multiset =
71         new NoRemoveMultiset<String>() {
72           @Override
73           public int add(String element, int occurrences) {
74             addCalls.incrementAndGet();
75             return super.add(element, occurrences);
76           }
77         };
78     ImmutableMultiset<String> adds =
79         new ImmutableMultiset.Builder<String>().addCopies("x", 10).build();
80     multiset.addAll(adds);
81     assertEquals(1, addCalls.get());
82   }
83 
testRemoveUnsupported()84   public void testRemoveUnsupported() {
85     Multiset<String> multiset = new NoRemoveMultiset<>();
86     multiset.add("a");
87     try {
88       multiset.remove("a");
89       fail();
90     } catch (UnsupportedOperationException expected) {
91     }
92     assertTrue(multiset.contains("a"));
93   }
94 
95   private static class NoRemoveMultiset<E> extends AbstractMultiset<E> implements Serializable {
96     final Map<E, Integer> backingMap = Maps.newHashMap();
97 
98     @Override
size()99     public int size() {
100       return Multisets.linearTimeSizeImpl(this);
101     }
102 
103     @Override
clear()104     public void clear() {
105       throw new UnsupportedOperationException();
106     }
107 
108     @Override
count(@ullable Object element)109     public int count(@Nullable Object element) {
110       for (Entry<E> entry : entrySet()) {
111         if (Objects.equal(entry.getElement(), element)) {
112           return entry.getCount();
113         }
114       }
115       return 0;
116     }
117 
118     @Override
add(@ullable E element, int occurrences)119     public int add(@Nullable E element, int occurrences) {
120       checkArgument(occurrences >= 0);
121       Integer frequency = backingMap.get(element);
122       if (frequency == null) {
123         frequency = 0;
124       }
125       if (occurrences == 0) {
126         return frequency;
127       }
128       checkArgument(occurrences <= Integer.MAX_VALUE - frequency);
129       backingMap.put(element, frequency + occurrences);
130       return frequency;
131     }
132 
133     @Override
elementIterator()134     Iterator<E> elementIterator() {
135       return Multisets.elementIterator(entryIterator());
136     }
137 
138     @Override
entryIterator()139     Iterator<Entry<E>> entryIterator() {
140       final Iterator<Map.Entry<E, Integer>> backingEntries = backingMap.entrySet().iterator();
141       return new UnmodifiableIterator<Multiset.Entry<E>>() {
142         @Override
143         public boolean hasNext() {
144           return backingEntries.hasNext();
145         }
146 
147         @Override
148         public Multiset.Entry<E> next() {
149           final Map.Entry<E, Integer> mapEntry = backingEntries.next();
150           return new Multisets.AbstractEntry<E>() {
151             @Override
152             public E getElement() {
153               return mapEntry.getKey();
154             }
155 
156             @Override
157             public int getCount() {
158               Integer frequency = backingMap.get(getElement());
159               return (frequency == null) ? 0 : frequency;
160             }
161           };
162         }
163       };
164     }
165 
166     @Override
167     public Iterator<E> iterator() {
168       return Multisets.iteratorImpl(this);
169     }
170 
171     @Override
172     int distinctElements() {
173       return backingMap.size();
174     }
175   }
176 }
177