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