Home | History | Annotate | Download | only in testers
      1 /*
      2  * Copyright (C) 2007 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.testers;
     18 
     19 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
     20 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
     21 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
     22 import static com.google.common.collect.testing.features.MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION;
     23 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
     24 
     25 import com.google.common.annotations.GwtCompatible;
     26 import com.google.common.annotations.GwtIncompatible;
     27 import com.google.common.collect.testing.AbstractMapTester;
     28 import com.google.common.collect.testing.Helpers;
     29 import com.google.common.collect.testing.features.CollectionSize;
     30 import com.google.common.collect.testing.features.MapFeature;
     31 
     32 import java.lang.reflect.Method;
     33 import java.util.ConcurrentModificationException;
     34 import java.util.Iterator;
     35 import java.util.Map;
     36 import java.util.Map.Entry;
     37 
     38 /**
     39  * A generic JUnit test which tests {@code put} operations on a map. Can't be
     40  * invoked directly; please see
     41  * {@link com.google.common.collect.testing.MapTestSuiteBuilder}.
     42  *
     43  * @author Chris Povirk
     44  * @author Kevin Bourrillion
     45  */
     46 @SuppressWarnings("unchecked") // too many "unchecked generic array creations"
     47 @GwtCompatible(emulated = true)
     48 public class MapPutTester<K, V> extends AbstractMapTester<K, V> {
     49   private Entry<K, V> nullKeyEntry;
     50   private Entry<K, V> nullValueEntry;
     51   private Entry<K, V> nullKeyValueEntry;
     52   private Entry<K, V> presentKeyNullValueEntry;
     53 
     54   @Override public void setUp() throws Exception {
     55     super.setUp();
     56     nullKeyEntry = entry(null, samples.e3.getValue());
     57     nullValueEntry = entry(samples.e3.getKey(), null);
     58     nullKeyValueEntry = entry(null, null);
     59     presentKeyNullValueEntry = entry(samples.e0.getKey(), null);
     60   }
     61 
     62   @MapFeature.Require(SUPPORTS_PUT)
     63   public void testPut_supportedNotPresent() {
     64     assertNull("put(notPresent, value) should return null", put(samples.e3));
     65     expectAdded(samples.e3);
     66   }
     67 
     68   @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_PUT})
     69   @CollectionSize.Require(absent = ZERO)
     70   public void testPutAbsentConcurrentWithEntrySetIteration() {
     71     try {
     72       Iterator<Entry<K, V>> iterator = getMap().entrySet().iterator();
     73       put(samples.e3);
     74       iterator.next();
     75       fail("Expected ConcurrentModificationException");
     76     } catch (ConcurrentModificationException expected) {
     77       // success
     78     }
     79   }
     80 
     81   @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_PUT})
     82   @CollectionSize.Require(absent = ZERO)
     83   public void testPutAbsentConcurrentWithKeySetIteration() {
     84     try {
     85       Iterator<K> iterator = getMap().keySet().iterator();
     86       put(samples.e3);
     87       iterator.next();
     88       fail("Expected ConcurrentModificationException");
     89     } catch (ConcurrentModificationException expected) {
     90       // success
     91     }
     92   }
     93 
     94   @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_PUT})
     95   @CollectionSize.Require(absent = ZERO)
     96   public void testPutAbsentConcurrentWithValueIteration() {
     97     try {
     98       Iterator<V> iterator = getMap().values().iterator();
     99       put(samples.e3);
    100       iterator.next();
    101       fail("Expected ConcurrentModificationException");
    102     } catch (ConcurrentModificationException expected) {
    103       // success
    104     }
    105   }
    106 
    107   @MapFeature.Require(absent = SUPPORTS_PUT)
    108   public void testPut_unsupportedNotPresent() {
    109     try {
    110       put(samples.e3);
    111       fail("put(notPresent, value) should throw");
    112     } catch (UnsupportedOperationException expected) {
    113     }
    114     expectUnchanged();
    115     expectMissing(samples.e3);
    116   }
    117 
    118   @MapFeature.Require(absent = SUPPORTS_PUT)
    119   @CollectionSize.Require(absent = ZERO)
    120   public void testPut_unsupportedPresentExistingValue() {
    121     try {
    122       assertEquals("put(present, existingValue) should return present or throw",
    123           samples.e0.getValue(), put(samples.e0));
    124     } catch (UnsupportedOperationException tolerated) {
    125     }
    126     expectUnchanged();
    127   }
    128 
    129   @MapFeature.Require(absent = SUPPORTS_PUT)
    130   @CollectionSize.Require(absent = ZERO)
    131   public void testPut_unsupportedPresentDifferentValue() {
    132     try {
    133       getMap().put(samples.e0.getKey(), samples.e3.getValue());
    134       fail("put(present, differentValue) should throw");
    135     } catch (UnsupportedOperationException expected) {
    136     }
    137     expectUnchanged();
    138   }
    139 
    140   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
    141   public void testPut_nullKeySupportedNotPresent() {
    142     assertNull("put(null, value) should return null", put(nullKeyEntry));
    143     expectAdded(nullKeyEntry);
    144   }
    145 
    146   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
    147   @CollectionSize.Require(absent = ZERO)
    148   public void testPut_nullKeySupportedPresent() {
    149     Entry<K, V> newEntry = entry(null, samples.e3.getValue());
    150     initMapWithNullKey();
    151     assertEquals("put(present, value) should return the associated value",
    152         getValueForNullKey(), put(newEntry));
    153 
    154     Entry<K, V>[] expected = createArrayWithNullKey();
    155     expected[getNullLocation()] = newEntry;
    156     expectContents(expected);
    157   }
    158 
    159   @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_KEYS)
    160   public void testPut_nullKeyUnsupported() {
    161     try {
    162       put(nullKeyEntry);
    163       fail("put(null, value) should throw");
    164     } catch (NullPointerException expected) {
    165     }
    166     expectUnchanged();
    167     expectNullKeyMissingWhenNullKeysUnsupported(
    168         "Should not contain null key after unsupported put(null, value)");
    169   }
    170 
    171   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
    172   public void testPut_nullValueSupported() {
    173     assertNull("put(key, null) should return null", put(nullValueEntry));
    174     expectAdded(nullValueEntry);
    175   }
    176 
    177   @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
    178   public void testPut_nullValueUnsupported() {
    179     try {
    180       put(nullValueEntry);
    181       fail("put(key, null) should throw");
    182     } catch (NullPointerException expected) {
    183     }
    184     expectUnchanged();
    185     expectNullValueMissingWhenNullValuesUnsupported(
    186         "Should not contain null value after unsupported put(key, null)");
    187   }
    188 
    189   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
    190   @CollectionSize.Require(absent = ZERO)
    191   public void testPut_replaceWithNullValueSupported() {
    192     assertEquals("put(present, null) should return the associated value",
    193         samples.e0.getValue(), put(presentKeyNullValueEntry));
    194     expectReplacement(presentKeyNullValueEntry);
    195   }
    196 
    197   @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
    198   @CollectionSize.Require(absent = ZERO)
    199   public void testPut_replaceWithNullValueUnsupported() {
    200     try {
    201       put(presentKeyNullValueEntry);
    202       fail("put(present, null) should throw");
    203     } catch (NullPointerException expected) {
    204     }
    205     expectUnchanged();
    206     expectNullValueMissingWhenNullValuesUnsupported(
    207         "Should not contain null after unsupported put(present, null)");
    208   }
    209 
    210   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
    211   @CollectionSize.Require(absent = ZERO)
    212   public void testPut_replaceNullValueWithNullSupported() {
    213     initMapWithNullValue();
    214     assertNull("put(present, null) should return the associated value (null)",
    215         getMap().put(getKeyForNullValue(), null));
    216     expectContents(createArrayWithNullValue());
    217   }
    218 
    219   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
    220   @CollectionSize.Require(absent = ZERO)
    221   public void testPut_replaceNullValueWithNonNullSupported() {
    222     Entry<K, V> newEntry = entry(getKeyForNullValue(), samples.e3.getValue());
    223     initMapWithNullValue();
    224     assertNull("put(present, value) should return the associated value (null)",
    225         put(newEntry));
    226 
    227     Entry<K, V>[] expected = createArrayWithNullValue();
    228     expected[getNullLocation()] = newEntry;
    229     expectContents(expected);
    230   }
    231 
    232   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS, ALLOWS_NULL_VALUES})
    233   public void testPut_nullKeyAndValueSupported() {
    234     assertNull("put(null, null) should return null", put(nullKeyValueEntry));
    235     expectAdded(nullKeyValueEntry);
    236   }
    237 
    238   private V put(Map.Entry<K, V> entry) {
    239     return getMap().put(entry.getKey(), entry.getValue());
    240   }
    241 
    242   /**
    243    * Returns the {@link Method} instance for {@link
    244    * #testPut_nullKeyUnsupported()} so that tests of {@link java.util.TreeMap}
    245    * can suppress it with {@code FeatureSpecificTestSuiteBuilder.suppressing()}
    246    * until <a
    247    * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045147">Sun bug
    248    * 5045147</a> is fixed.
    249    */
    250   @GwtIncompatible("reflection")
    251   public static Method getPutNullKeyUnsupportedMethod() {
    252     return Helpers.getMethod(MapPutTester.class, "testPut_nullKeyUnsupported");
    253   }
    254 }
    255