• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 
17 package com.google.common.collect.testing.google;
18 
19 import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_VALUES;
20 import static com.google.common.collect.testing.features.CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION;
21 import static com.google.common.collect.testing.features.CollectionFeature.RESTRICTS_ELEMENTS;
22 import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_ADD;
23 import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
24 import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
25 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
26 
27 import com.google.common.annotations.GwtCompatible;
28 import com.google.common.annotations.GwtIncompatible;
29 import com.google.common.collect.Multiset;
30 import com.google.common.collect.Multiset.Entry;
31 import com.google.common.collect.testing.Helpers;
32 import com.google.common.collect.testing.features.CollectionFeature;
33 import com.google.common.collect.testing.features.CollectionSize;
34 
35 import java.lang.reflect.Method;
36 import java.util.Arrays;
37 import java.util.ConcurrentModificationException;
38 import java.util.Iterator;
39 import java.util.List;
40 
41 /**
42  * Common superclass for {@link MultisetSetCountUnconditionallyTester} and
43  * {@link MultisetSetCountConditionallyTester}. It is used by those testers to
44  * test calls to the unconditional {@code setCount()} method and calls to the
45  * conditional {@code setCount()} method when the expected present count is
46  * correct.
47  *
48  * @author Chris Povirk
49  */
50 @GwtCompatible(emulated = true)
51 public abstract class AbstractMultisetSetCountTester<E>
52     extends AbstractMultisetTester<E> {
53   /*
54    * TODO: consider adding MultisetFeatures.SUPPORTS_SET_COUNT. Currently we
55    * assume that using setCount() to increase the count is permitted iff add()
56    * is permitted and similarly for decrease/remove(). We assume that a
57    * setCount() no-op is permitted if either add() or remove() is permitted,
58    * though we also allow it to "succeed" if neither is permitted.
59    */
60 
assertSetCount(E element, int count)61   private void assertSetCount(E element, int count) {
62     setCountCheckReturnValue(element, count);
63 
64     assertEquals(
65         "multiset.count() should return the value passed to setCount()",
66         count, getMultiset().count(element));
67 
68     int size = 0;
69     for (Multiset.Entry<E> entry : getMultiset().entrySet()) {
70       size += entry.getCount();
71     }
72     assertEquals(
73         "multiset.size() should be the sum of the counts of all entries",
74         size, getMultiset().size());
75   }
76 
77   /**
78    * Call the {@code setCount()} method under test, and check its return value.
79    */
setCountCheckReturnValue(E element, int count)80   abstract void setCountCheckReturnValue(E element, int count);
81 
82   /**
83    * Call the {@code setCount()} method under test, but do not check its return
84    * value. Callers should use this method over
85    * {@link #setCountCheckReturnValue(Object, int)} when they expect
86    * {@code setCount()} to throw an exception, as checking the return value
87    * could produce an incorrect error message like
88    * "setCount() should return the original count" instead of the message passed
89    * to a later invocation of {@code fail()}, like "setCount should throw
90    * UnsupportedOperationException."
91    */
setCountNoCheckReturnValue(E element, int count)92   abstract void setCountNoCheckReturnValue(E element, int count);
93 
assertSetCountIncreasingFailure(E element, int count)94   private void assertSetCountIncreasingFailure(E element, int count) {
95     try {
96       setCountNoCheckReturnValue(element, count);
97       fail("a call to multiset.setCount() to increase an element's count "
98           + "should throw");
99     } catch (UnsupportedOperationException expected) {
100     }
101   }
102 
assertSetCountDecreasingFailure(E element, int count)103   private void assertSetCountDecreasingFailure(E element, int count) {
104     try {
105       setCountNoCheckReturnValue(element, count);
106       fail("a call to multiset.setCount() to decrease an element's count "
107           + "should throw");
108     } catch (UnsupportedOperationException expected) {
109     }
110   }
111 
112   // Unconditional setCount no-ops.
113 
assertZeroToZero()114   private void assertZeroToZero() {
115     assertSetCount(samples.e3, 0);
116   }
117 
assertOneToOne()118   private void assertOneToOne() {
119     assertSetCount(samples.e0, 1);
120   }
121 
assertThreeToThree()122   private void assertThreeToThree() {
123     initThreeCopies();
124     assertSetCount(samples.e0, 3);
125   }
126 
127   @CollectionFeature.Require(SUPPORTS_ADD)
testSetCount_zeroToZero_addSupported()128   public void testSetCount_zeroToZero_addSupported() {
129     assertZeroToZero();
130   }
131 
132   @CollectionFeature.Require(SUPPORTS_REMOVE)
testSetCount_zeroToZero_removeSupported()133   public void testSetCount_zeroToZero_removeSupported() {
134     assertZeroToZero();
135   }
136 
137   @CollectionFeature.Require(absent = {SUPPORTS_ADD, SUPPORTS_REMOVE})
testSetCount_zeroToZero_unsupported()138   public void testSetCount_zeroToZero_unsupported() {
139     try {
140       assertZeroToZero();
141     } catch (UnsupportedOperationException tolerated) {
142     }
143   }
144 
145   @CollectionSize.Require(absent = ZERO)
146   @CollectionFeature.Require(SUPPORTS_ADD)
testSetCount_oneToOne_addSupported()147   public void testSetCount_oneToOne_addSupported() {
148     assertOneToOne();
149   }
150 
151   @CollectionSize.Require(absent = ZERO)
152   @CollectionFeature.Require(SUPPORTS_REMOVE)
testSetCount_oneToOne_removeSupported()153   public void testSetCount_oneToOne_removeSupported() {
154     assertOneToOne();
155   }
156 
157   @CollectionSize.Require(absent = ZERO)
158   @CollectionFeature.Require(absent = {SUPPORTS_ADD, SUPPORTS_REMOVE})
testSetCount_oneToOne_unsupported()159   public void testSetCount_oneToOne_unsupported() {
160     try {
161       assertOneToOne();
162     } catch (UnsupportedOperationException tolerated) {
163     }
164   }
165 
166   @CollectionSize.Require(SEVERAL)
167   @CollectionFeature.Require(SUPPORTS_ADD)
testSetCount_threeToThree_addSupported()168   public void testSetCount_threeToThree_addSupported() {
169     assertThreeToThree();
170   }
171 
172   @CollectionSize.Require(SEVERAL)
173   @CollectionFeature.Require(SUPPORTS_REMOVE)
testSetCount_threeToThree_removeSupported()174   public void testSetCount_threeToThree_removeSupported() {
175     assertThreeToThree();
176   }
177 
178   @CollectionSize.Require(SEVERAL)
179   @CollectionFeature.Require(absent = {SUPPORTS_ADD, SUPPORTS_REMOVE})
testSetCount_threeToThree_unsupported()180   public void testSetCount_threeToThree_unsupported() {
181     try {
182       assertThreeToThree();
183     } catch (UnsupportedOperationException tolerated) {
184     }
185   }
186 
187   // Unconditional setCount size increases:
188 
189   @CollectionFeature.Require(SUPPORTS_ADD)
testSetCount_zeroToOne_supported()190   public void testSetCount_zeroToOne_supported() {
191     assertSetCount(samples.e3, 1);
192   }
193 
194   @CollectionFeature.Require({SUPPORTS_ADD,
195       FAILS_FAST_ON_CONCURRENT_MODIFICATION})
testSetCountZeroToOneConcurrentWithIteration()196   public void testSetCountZeroToOneConcurrentWithIteration() {
197     try {
198       Iterator<E> iterator = collection.iterator();
199       assertSetCount(samples.e3, 1);
200       iterator.next();
201       fail("Expected ConcurrentModificationException");
202     } catch (ConcurrentModificationException expected) {
203       // success
204     }
205   }
206 
207   @CollectionFeature.Require({SUPPORTS_ADD,
208       FAILS_FAST_ON_CONCURRENT_MODIFICATION})
testSetCountZeroToOneConcurrentWithEntrySetIteration()209   public void testSetCountZeroToOneConcurrentWithEntrySetIteration() {
210     try {
211       Iterator<Entry<E>> iterator = getMultiset().entrySet().iterator();
212       assertSetCount(samples.e3, 1);
213       iterator.next();
214       fail("Expected ConcurrentModificationException");
215     } catch (ConcurrentModificationException expected) {
216       // success
217     }
218   }
219 
220   @CollectionFeature.Require(SUPPORTS_ADD)
testSetCount_zeroToThree_supported()221   public void testSetCount_zeroToThree_supported() {
222     assertSetCount(samples.e3, 3);
223   }
224 
225   @CollectionSize.Require(absent = ZERO)
226   @CollectionFeature.Require(SUPPORTS_ADD)
testSetCount_oneToThree_supported()227   public void testSetCount_oneToThree_supported() {
228     assertSetCount(samples.e0, 3);
229   }
230 
231   @CollectionFeature.Require(absent = SUPPORTS_ADD)
testSetCount_zeroToOne_unsupported()232   public void testSetCount_zeroToOne_unsupported() {
233     assertSetCountIncreasingFailure(samples.e3, 1);
234   }
235 
236   @CollectionFeature.Require(absent = SUPPORTS_ADD)
testSetCount_zeroToThree_unsupported()237   public void testSetCount_zeroToThree_unsupported() {
238     assertSetCountIncreasingFailure(samples.e3, 3);
239   }
240 
241   @CollectionSize.Require(absent = ZERO)
242   @CollectionFeature.Require(absent = SUPPORTS_ADD)
testSetCount_oneToThree_unsupported()243   public void testSetCount_oneToThree_unsupported() {
244     assertSetCountIncreasingFailure(samples.e3, 3);
245   }
246 
247   // Unconditional setCount size decreases:
248 
249   @CollectionSize.Require(absent = ZERO)
250   @CollectionFeature.Require(SUPPORTS_REMOVE)
testSetCount_oneToZero_supported()251   public void testSetCount_oneToZero_supported() {
252     assertSetCount(samples.e0, 0);
253   }
254 
255   @CollectionFeature.Require({SUPPORTS_REMOVE,
256       FAILS_FAST_ON_CONCURRENT_MODIFICATION})
257   @CollectionSize.Require(absent = ZERO)
testSetCountOneToZeroConcurrentWithIteration()258   public void testSetCountOneToZeroConcurrentWithIteration() {
259     try {
260       Iterator<E> iterator = collection.iterator();
261       assertSetCount(samples.e0, 0);
262       iterator.next();
263       fail("Expected ConcurrentModificationException");
264     } catch (ConcurrentModificationException expected) {
265       // success
266     }
267   }
268 
269   @CollectionFeature.Require({SUPPORTS_REMOVE,
270       FAILS_FAST_ON_CONCURRENT_MODIFICATION})
271   @CollectionSize.Require(absent = ZERO)
testSetCountOneToZeroConcurrentWithEntrySetIteration()272   public void testSetCountOneToZeroConcurrentWithEntrySetIteration() {
273     try {
274       Iterator<Entry<E>> iterator = getMultiset().entrySet().iterator();
275       assertSetCount(samples.e0, 0);
276       iterator.next();
277       fail("Expected ConcurrentModificationException");
278     } catch (ConcurrentModificationException expected) {
279       // success
280     }
281   }
282 
283   @CollectionSize.Require(SEVERAL)
284   @CollectionFeature.Require(SUPPORTS_REMOVE)
testSetCount_threeToZero_supported()285   public void testSetCount_threeToZero_supported() {
286     initThreeCopies();
287     assertSetCount(samples.e0, 0);
288   }
289 
290   @CollectionSize.Require(SEVERAL)
291   @CollectionFeature.Require(SUPPORTS_REMOVE)
testSetCount_threeToOne_supported()292   public void testSetCount_threeToOne_supported() {
293     initThreeCopies();
294     assertSetCount(samples.e0, 1);
295   }
296 
297   @CollectionSize.Require(absent = ZERO)
298   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
testSetCount_oneToZero_unsupported()299   public void testSetCount_oneToZero_unsupported() {
300     assertSetCountDecreasingFailure(samples.e0, 0);
301   }
302 
303   @CollectionSize.Require(SEVERAL)
304   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
testSetCount_threeToZero_unsupported()305   public void testSetCount_threeToZero_unsupported() {
306     initThreeCopies();
307     assertSetCountDecreasingFailure(samples.e0, 0);
308   }
309 
310   @CollectionSize.Require(SEVERAL)
311   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
testSetCount_threeToOne_unsupported()312   public void testSetCount_threeToOne_unsupported() {
313     initThreeCopies();
314     assertSetCountDecreasingFailure(samples.e0, 1);
315   }
316 
317   // setCount with nulls:
318 
319   @CollectionSize.Require(absent = ZERO)
320   @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
testSetCount_removeNull_nullSupported()321   public void testSetCount_removeNull_nullSupported() {
322     initCollectionWithNullElement();
323     assertSetCount(null, 0);
324   }
325 
326   @CollectionFeature.Require(value = {SUPPORTS_ADD, ALLOWS_NULL_VALUES},
327       absent = RESTRICTS_ELEMENTS)
testSetCount_addNull_nullSupported()328   public void testSetCount_addNull_nullSupported() {
329     assertSetCount(null, 1);
330   }
331 
332   @CollectionFeature.Require(value = SUPPORTS_ADD, absent = ALLOWS_NULL_VALUES)
testSetCount_addNull_nullUnsupported()333   public void testSetCount_addNull_nullUnsupported() {
334     try {
335       setCountNoCheckReturnValue(null, 1);
336       fail("adding null with setCount() should throw NullPointerException");
337     } catch (NullPointerException expected) {
338     }
339   }
340 
341   @CollectionFeature.Require(ALLOWS_NULL_VALUES)
testSetCount_noOpNull_nullSupported()342   public void testSetCount_noOpNull_nullSupported() {
343     try {
344       assertSetCount(null, 0);
345     } catch (UnsupportedOperationException tolerated) {
346     }
347   }
348 
349   @CollectionFeature.Require(absent = ALLOWS_NULL_VALUES)
testSetCount_noOpNull_nullUnsupported()350   public void testSetCount_noOpNull_nullUnsupported() {
351     try {
352       assertSetCount(null, 0);
353     } catch (NullPointerException tolerated) {
354     } catch (UnsupportedOperationException tolerated) {
355     }
356   }
357 
358   @CollectionSize.Require(absent = ZERO)
359   @CollectionFeature.Require(ALLOWS_NULL_VALUES)
testSetCount_existingNoNopNull_nullSupported()360   public void testSetCount_existingNoNopNull_nullSupported() {
361     initCollectionWithNullElement();
362     try {
363       assertSetCount(null, 1);
364     } catch (UnsupportedOperationException tolerated) {
365     }
366   }
367 
368   // Negative count.
369 
370   @CollectionFeature.Require(SUPPORTS_REMOVE)
testSetCount_negative_removeSupported()371   public void testSetCount_negative_removeSupported() {
372     try {
373       setCountNoCheckReturnValue(samples.e3, -1);
374       fail("calling setCount() with a negative count should throw "
375           + "IllegalArgumentException");
376     } catch (IllegalArgumentException expected) {
377     }
378   }
379 
380   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
testSetCount_negative_removeUnsupported()381   public void testSetCount_negative_removeUnsupported() {
382     try {
383       setCountNoCheckReturnValue(samples.e3, -1);
384       fail("calling setCount() with a negative count should throw "
385           + "IllegalArgumentException or UnsupportedOperationException");
386     } catch (IllegalArgumentException expected) {
387     } catch (UnsupportedOperationException expected) {
388     }
389   }
390 
391   // TODO: test adding element of wrong type
392 
393   /**
394    * Returns {@link Method} instances for the {@code setCount()} tests that
395    * assume multisets support duplicates so that the test of {@code
396    * Multisets.forSet()} can suppress them.
397    */
398   @GwtIncompatible("reflection")
getSetCountDuplicateInitializingMethods()399   public static List<Method> getSetCountDuplicateInitializingMethods() {
400     return Arrays.asList(
401         getMethod("testSetCount_threeToThree_removeSupported"),
402         getMethod("testSetCount_threeToZero_supported"),
403         getMethod("testSetCount_threeToOne_supported"));
404   }
405 
406   @GwtIncompatible("reflection")
getMethod(String methodName)407   private static Method getMethod(String methodName) {
408     return Helpers.getMethod(AbstractMultisetSetCountTester.class, methodName);
409   }
410 }
411