SimpleAbstractMultisetTest.java revision 1d580d0f6ee4f21eb309ba7b509d2c6d671c4044
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
15package com.google.common.collect;
16
17import static com.google.common.base.Preconditions.checkArgument;
18
19import com.google.common.annotations.GwtCompatible;
20import com.google.common.collect.Multiset.Entry;
21
22import java.io.Serializable;
23import java.util.Iterator;
24import java.util.Map;
25import java.util.concurrent.atomic.AtomicInteger;
26
27/**
28 * Unit test for {@link AbstractMultiset}.
29 *
30 * @author Kevin Bourrillion
31 * @author Louis Wasserman
32 */
33@SuppressWarnings("serial") // No serialization is used in this test
34@GwtCompatible
35public class SimpleAbstractMultisetTest extends AbstractMultisetTest {
36
37  @Override protected <E> Multiset<E> create() {
38    return new SimpleAbstractMultiset<E>();
39  }
40
41  public void testFastAddAllMultiset() {
42    final AtomicInteger addCalls = new AtomicInteger();
43    Multiset<String> multiset = new NoRemoveMultiset<String>() {
44      @Override
45      public int add(String element, int occurrences) {
46        addCalls.incrementAndGet();
47        return super.add(element, occurrences);
48      }
49    };
50    ImmutableMultiset<String> adds =
51        new ImmutableMultiset.Builder<String>().addCopies("x", 10).build();
52    multiset.addAll(adds);
53    assertEquals(addCalls.get(), 1);
54  }
55
56  public void testRemoveUnsupported() {
57    Multiset<String> multiset = new NoRemoveMultiset<String>();
58    multiset.add("a");
59    try {
60      multiset.remove("a");
61      fail();
62    } catch (UnsupportedOperationException expected) {}
63    assertTrue(multiset.contains("a"));
64  }
65
66  private static class NoRemoveMultiset<E> extends AbstractMultiset<E>
67      implements Serializable {
68    final Map<E, Integer> backingMap = Maps.newHashMap();
69
70    @Override public int add(E element, int occurrences) {
71      checkArgument(occurrences >= 0);
72      Integer frequency = backingMap.get(element);
73      if (frequency == null) {
74        frequency = 0;
75      }
76      if (occurrences == 0) {
77        return frequency;
78      }
79      checkArgument(occurrences <= Integer.MAX_VALUE - frequency);
80      backingMap.put(element, frequency + occurrences);
81      return frequency;
82    }
83
84    @Override
85    Iterator<Entry<E>> entryIterator() {
86      final Iterator<Map.Entry<E, Integer>> backingEntries = backingMap.entrySet().iterator();
87      return new Iterator<Multiset.Entry<E>>() {
88        @Override
89        public boolean hasNext() {
90          return backingEntries.hasNext();
91        }
92
93        @Override
94        public Multiset.Entry<E> next() {
95          final Map.Entry<E, Integer> mapEntry = backingEntries.next();
96          return new Multisets.AbstractEntry<E>() {
97            @Override
98            public E getElement() {
99              return mapEntry.getKey();
100            }
101
102            @Override
103            public int getCount() {
104              Integer frequency = backingMap.get(getElement());
105              return (frequency == null) ? 0 : frequency;
106            }
107          };
108        }
109
110        @Override
111        public void remove() {
112          backingEntries.remove();
113        }
114      };
115    }
116
117    @Override
118    int distinctElements() {
119      return backingMap.size();
120    }
121  }
122
123  private static class SimpleAbstractMultiset<E> extends NoRemoveMultiset<E> {
124    @SuppressWarnings("unchecked")
125    @Override public int remove(Object element, int occurrences) {
126      checkArgument(occurrences >= 0);
127      Integer count = backingMap.get(element);
128      if (count == null) {
129        return 0;
130      } else if (count > occurrences) {
131        backingMap.put((E) element, count - occurrences);
132        return count;
133      } else {
134        return backingMap.remove(element);
135      }
136    }
137  }
138}
139