1/*
2 * Copyright (C) 2008 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.collect.testing.google;
18
19import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_ADD;
20import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_CLEAR;
21import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
22import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE_ALL;
23import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_RETAIN_ALL;
24import static com.google.common.collect.testing.features.CollectionSize.ONE;
25import static com.google.common.collect.testing.features.CollectionSize.ZERO;
26
27import com.google.common.annotations.GwtCompatible;
28import com.google.common.collect.Multiset;
29import com.google.common.collect.Multisets;
30import com.google.common.collect.testing.WrongType;
31import com.google.common.collect.testing.features.CollectionFeature;
32import com.google.common.collect.testing.features.CollectionSize;
33
34import java.lang.reflect.Method;
35import java.util.Collections;
36import java.util.Iterator;
37
38/**
39 * A generic JUnit test which tests multiset-specific write operations.
40 * Can't be invoked directly; please see {@link MultisetTestSuiteBuilder}.
41 *
42 * @author Jared Levy
43 */
44@GwtCompatible
45public class MultisetWritesTester<E> extends AbstractMultisetTester<E> {
46  /**
47   * Returns the {@link Method} instance for
48   * {@link #testEntrySet_iterator()} so that tests of
49   * classes with unmodifiable iterators can suppress it.
50   */
51  public static Method getEntrySetIteratorMethod() {
52    return Platform.getMethod(
53        MultisetWritesTester.class, "testEntrySet_iterator");
54  }
55
56  @CollectionFeature.Require(SUPPORTS_ADD)
57  public void testAddOccurrences() {
58    int oldCount = getMultiset().count(samples.e0);
59    assertEquals("multiset.add(E, int) should return the old count",
60        oldCount, getMultiset().add(samples.e0, 2));
61    assertEquals("multiset.count() incorrect after add(E, int)",
62        oldCount + 2, getMultiset().count(samples.e0));
63  }
64
65  @CollectionFeature.Require(absent = SUPPORTS_ADD)
66  public void testAddOccurrences_unsupported() {
67    try {
68      getMultiset().add(samples.e0, 2);
69      fail("unsupported multiset.add(E, int) didn't throw exception");
70    } catch (UnsupportedOperationException required) {}
71  }
72
73  @CollectionSize.Require(absent = ZERO)
74  @CollectionFeature.Require(SUPPORTS_REMOVE)
75  public void testRemove_occurrences_present() {
76    assertEquals("multiset.remove(present, 2) didn't return the old count",
77        1, getMultiset().remove(samples.e0, 2));
78    assertFalse("multiset contains present after multiset.remove(present, 2)",
79        getMultiset().contains(samples.e0));
80  }
81
82  @CollectionFeature.Require(SUPPORTS_REMOVE)
83  public void testRemove_occurrences_absent() {
84    assertEquals("multiset.remove(absent, 0) didn't return 0",
85        0, getMultiset().remove(samples.e3, 2));
86  }
87
88  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
89  public void testRemove_occurrences_unsupported_absent() {
90    // notice: we don't care whether it succeeds, or fails with UOE
91    try {
92      assertEquals(
93          "multiset.remove(absent, 2) didn't return 0 or throw an exception",
94          0, getMultiset().remove(samples.e3, 2));
95    } catch (UnsupportedOperationException ok) {}
96  }
97
98  @CollectionFeature.Require(SUPPORTS_REMOVE)
99  public void testRemove_occurrences_0() {
100    int oldCount = getMultiset().count(samples.e0);
101    assertEquals("multiset.remove(E, 0) didn't return the old count",
102        oldCount, getMultiset().remove(samples.e0, 0));
103  }
104
105  @CollectionFeature.Require(SUPPORTS_REMOVE)
106  public void testRemove_occurrences_negative() {
107    try {
108      getMultiset().remove(samples.e0, -1);
109      fail("multiset.remove(E, -1) didn't throw an exception");
110    } catch (IllegalArgumentException required) {}
111  }
112
113  @CollectionFeature.Require(SUPPORTS_REMOVE)
114  public void testRemove_occurrences_wrongType() {
115    assertEquals("multiset.remove(wrongType, 1) didn't return 0",
116        0, getMultiset().remove(WrongType.VALUE, 1));
117  }
118
119  @CollectionFeature.Require(SUPPORTS_CLEAR)
120  public void testEntrySet_clear() {
121    getMultiset().entrySet().clear();
122    assertTrue("multiset not empty after entrySet().clear()",
123        getMultiset().isEmpty());
124  }
125
126  @CollectionSize.Require(ONE)
127  @CollectionFeature.Require(SUPPORTS_REMOVE)
128  public void testEntrySet_iterator() {
129    Iterator<Multiset.Entry<E>> iterator = getMultiset().entrySet().iterator();
130    assertTrue(
131        "non-empty multiset.entrySet() iterator.hasNext() returned false",
132        iterator.hasNext());
133    assertEquals("multiset.entrySet() iterator.next() returned incorrect entry",
134        Multisets.immutableEntry(samples.e0, 1), iterator.next());
135    assertFalse(
136        "size 1 multiset.entrySet() iterator.hasNext() returned true "
137            + "after next()",
138        iterator.hasNext());
139    iterator.remove();
140    assertTrue(
141        "multiset isn't empty after multiset.entrySet() iterator.remove()",
142        getMultiset().isEmpty());
143  }
144
145  @CollectionSize.Require(absent = ZERO)
146  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
147  public void testEntrySet_iterator_remove_unsupported() {
148    Iterator<Multiset.Entry<E>> iterator = getMultiset().entrySet().iterator();
149    assertTrue(
150        "non-empty multiset.entrySet() iterator.hasNext() returned false",
151        iterator.hasNext());
152    try {
153      iterator.remove();
154      fail("multiset.entrySet() iterator.remove() didn't throw an exception");
155    } catch (UnsupportedOperationException expected) {}
156  }
157
158  @CollectionSize.Require(absent = ZERO)
159  @CollectionFeature.Require(SUPPORTS_REMOVE)
160  public void testEntrySet_remove_present() {
161    assertTrue(
162        "multiset.entrySet.remove(presentEntry) returned false",
163        getMultiset().entrySet().remove(
164            Multisets.immutableEntry(samples.e0, 1)));
165    assertFalse(
166        "multiset contains element after removing its entry",
167        getMultiset().contains(samples.e0));
168  }
169
170  @CollectionSize.Require(absent = ZERO)
171  @CollectionFeature.Require(SUPPORTS_REMOVE)
172  public void testEntrySet_remove_missing() {
173    assertFalse(
174        "multiset.entrySet.remove(missingEntry) returned true",
175        getMultiset().entrySet().remove(
176            Multisets.immutableEntry(samples.e0, 2)));
177    assertTrue(
178        "multiset didn't contain element after removing a missing entry",
179        getMultiset().contains(samples.e0));
180  }
181
182  @CollectionSize.Require(absent = ZERO)
183  @CollectionFeature.Require(SUPPORTS_REMOVE_ALL)
184  public void testEntrySet_removeAll_present() {
185    assertTrue(
186        "multiset.entrySet.removeAll(presentEntry) returned false",
187        getMultiset().entrySet().removeAll(
188            Collections.singleton(Multisets.immutableEntry(samples.e0, 1))));
189    assertFalse(
190        "multiset contains element after removing its entry",
191        getMultiset().contains(samples.e0));
192  }
193
194  @CollectionSize.Require(absent = ZERO)
195  @CollectionFeature.Require(SUPPORTS_REMOVE_ALL)
196  public void testEntrySet_removeAll_missing() {
197    assertFalse(
198        "multiset.entrySet.remove(missingEntry) returned true",
199        getMultiset().entrySet().removeAll(
200            Collections.singleton(Multisets.immutableEntry(samples.e0, 2))));
201    assertTrue(
202        "multiset didn't contain element after removing a missing entry",
203        getMultiset().contains(samples.e0));
204  }
205
206  @CollectionFeature.Require(SUPPORTS_REMOVE_ALL)
207  public void testEntrySet_removeAll_null() {
208    try {
209      getMultiset().entrySet().removeAll(null);
210      fail("multiset.entrySet.removeAll(null) didn't throw an exception");
211    } catch (NullPointerException expected) {}
212  }
213
214  @CollectionSize.Require(ONE)
215  @CollectionFeature.Require(SUPPORTS_RETAIN_ALL)
216  public void testEntrySet_retainAll_present() {
217    assertFalse(
218        "multiset.entrySet.retainAll(presentEntry) returned false",
219        getMultiset().entrySet().retainAll(
220            Collections.singleton(Multisets.immutableEntry(samples.e0, 1))));
221    assertTrue(
222        "multiset doesn't contains element after retaining its entry",
223        getMultiset().contains(samples.e0));
224  }
225
226  @CollectionSize.Require(ONE)
227  @CollectionFeature.Require(SUPPORTS_RETAIN_ALL)
228  public void testEntrySet_retainAll_missing() {
229    assertTrue(
230        "multiset.entrySet.retainAll(missingEntry) returned true",
231        getMultiset().entrySet().retainAll(
232            Collections.singleton(Multisets.immutableEntry(samples.e0, 2))));
233    assertFalse(
234        "multiset contains element after retaining a different entry",
235        getMultiset().contains(samples.e0));
236  }
237
238  @CollectionFeature.Require(SUPPORTS_RETAIN_ALL)
239  public void testEntrySet_retainAll_null() {
240    try {
241      getMultiset().entrySet().retainAll(null);
242      // Returning successfully is not ideal, but tolerated.
243    } catch (NullPointerException expected) {}
244  }
245}
246