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