001/* 002 * Copyright (C) 2007 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect.testing.testers; 018 019import static com.google.common.collect.testing.features.CollectionSize.ZERO; 020import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS; 021import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES; 022import static com.google.common.collect.testing.features.MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION; 023import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT; 024 025import com.google.common.annotations.GwtCompatible; 026import com.google.common.annotations.GwtIncompatible; 027import com.google.common.annotations.J2ktIncompatible; 028import com.google.common.collect.testing.AbstractMapTester; 029import com.google.common.collect.testing.Helpers; 030import com.google.common.collect.testing.features.CollectionSize; 031import com.google.common.collect.testing.features.MapFeature; 032import com.google.errorprone.annotations.CanIgnoreReturnValue; 033import java.lang.reflect.Method; 034import java.util.ConcurrentModificationException; 035import java.util.Iterator; 036import java.util.Map.Entry; 037import org.junit.Ignore; 038 039/** 040 * A generic JUnit test which tests {@code put} operations on a map. Can't be invoked directly; 041 * please see {@link com.google.common.collect.testing.MapTestSuiteBuilder}. 042 * 043 * @author Chris Povirk 044 * @author Kevin Bourrillion 045 */ 046@GwtCompatible(emulated = true) 047@Ignore // Affects only Android test runner, which respects JUnit 4 annotations on JUnit 3 tests. 048@SuppressWarnings("JUnit4ClassUsedInJUnit3") 049public class MapPutTester<K, V> extends AbstractMapTester<K, V> { 050 private Entry<K, V> nullKeyEntry; 051 private Entry<K, V> nullValueEntry; 052 private Entry<K, V> nullKeyValueEntry; 053 private Entry<K, V> presentKeyNullValueEntry; 054 055 @Override 056 public void setUp() throws Exception { 057 super.setUp(); 058 nullKeyEntry = entry(null, v3()); 059 nullValueEntry = entry(k3(), null); 060 nullKeyValueEntry = entry(null, null); 061 presentKeyNullValueEntry = entry(k0(), null); 062 } 063 064 @MapFeature.Require(SUPPORTS_PUT) 065 @CollectionSize.Require(absent = ZERO) 066 public void testPut_supportedPresent() { 067 assertEquals("put(present, value) should return the old value", v0(), getMap().put(k0(), v3())); 068 expectReplacement(entry(k0(), v3())); 069 } 070 071 @MapFeature.Require(SUPPORTS_PUT) 072 public void testPut_supportedNotPresent() { 073 assertNull("put(notPresent, value) should return null", put(e3())); 074 expectAdded(e3()); 075 } 076 077 @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_PUT}) 078 @CollectionSize.Require(absent = ZERO) 079 public void testPutAbsentConcurrentWithEntrySetIteration() { 080 try { 081 Iterator<Entry<K, V>> iterator = getMap().entrySet().iterator(); 082 put(e3()); 083 iterator.next(); 084 fail("Expected ConcurrentModificationException"); 085 } catch (ConcurrentModificationException expected) { 086 // success 087 } 088 } 089 090 @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_PUT}) 091 @CollectionSize.Require(absent = ZERO) 092 public void testPutAbsentConcurrentWithKeySetIteration() { 093 try { 094 Iterator<K> iterator = getMap().keySet().iterator(); 095 put(e3()); 096 iterator.next(); 097 fail("Expected ConcurrentModificationException"); 098 } catch (ConcurrentModificationException expected) { 099 // success 100 } 101 } 102 103 @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_PUT}) 104 @CollectionSize.Require(absent = ZERO) 105 public void testPutAbsentConcurrentWithValueIteration() { 106 try { 107 Iterator<V> iterator = getMap().values().iterator(); 108 put(e3()); 109 iterator.next(); 110 fail("Expected ConcurrentModificationException"); 111 } catch (ConcurrentModificationException expected) { 112 // success 113 } 114 } 115 116 @MapFeature.Require(absent = SUPPORTS_PUT) 117 public void testPut_unsupportedNotPresent() { 118 try { 119 put(e3()); 120 fail("put(notPresent, value) should throw"); 121 } catch (UnsupportedOperationException expected) { 122 } 123 expectUnchanged(); 124 expectMissing(e3()); 125 } 126 127 @MapFeature.Require(absent = SUPPORTS_PUT) 128 @CollectionSize.Require(absent = ZERO) 129 public void testPut_unsupportedPresentExistingValue() { 130 try { 131 assertEquals("put(present, existingValue) should return present or throw", v0(), put(e0())); 132 } catch (UnsupportedOperationException tolerated) { 133 } 134 expectUnchanged(); 135 } 136 137 @MapFeature.Require(absent = SUPPORTS_PUT) 138 @CollectionSize.Require(absent = ZERO) 139 public void testPut_unsupportedPresentDifferentValue() { 140 try { 141 getMap().put(k0(), v3()); 142 fail("put(present, differentValue) should throw"); 143 } catch (UnsupportedOperationException expected) { 144 } 145 expectUnchanged(); 146 } 147 148 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS}) 149 public void testPut_nullKeySupportedNotPresent() { 150 assertNull("put(null, value) should return null", put(nullKeyEntry)); 151 expectAdded(nullKeyEntry); 152 } 153 154 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS}) 155 @CollectionSize.Require(absent = ZERO) 156 public void testPut_nullKeySupportedPresent() { 157 Entry<K, V> newEntry = entry(null, v3()); 158 initMapWithNullKey(); 159 assertEquals( 160 "put(present, value) should return the associated value", 161 getValueForNullKey(), 162 put(newEntry)); 163 164 Entry<K, V>[] expected = createArrayWithNullKey(); 165 expected[getNullLocation()] = newEntry; 166 expectContents(expected); 167 } 168 169 @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_KEYS) 170 public void testPut_nullKeyUnsupported() { 171 try { 172 put(nullKeyEntry); 173 fail("put(null, value) should throw"); 174 } catch (NullPointerException expected) { 175 } 176 expectUnchanged(); 177 expectNullKeyMissingWhenNullKeysUnsupported( 178 "Should not contain null key after unsupported put(null, value)"); 179 } 180 181 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES}) 182 public void testPut_nullValueSupported() { 183 assertNull("put(key, null) should return null", put(nullValueEntry)); 184 expectAdded(nullValueEntry); 185 } 186 187 @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES) 188 public void testPut_nullValueUnsupported() { 189 try { 190 put(nullValueEntry); 191 fail("put(key, null) should throw"); 192 } catch (NullPointerException expected) { 193 } 194 expectUnchanged(); 195 expectNullValueMissingWhenNullValuesUnsupported( 196 "Should not contain null value after unsupported put(key, null)"); 197 } 198 199 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES}) 200 @CollectionSize.Require(absent = ZERO) 201 public void testPut_replaceWithNullValueSupported() { 202 assertEquals( 203 "put(present, null) should return the associated value", 204 v0(), 205 put(presentKeyNullValueEntry)); 206 expectReplacement(presentKeyNullValueEntry); 207 } 208 209 @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES) 210 @CollectionSize.Require(absent = ZERO) 211 public void testPut_replaceWithNullValueUnsupported() { 212 try { 213 put(presentKeyNullValueEntry); 214 fail("put(present, null) should throw"); 215 } catch (NullPointerException expected) { 216 } 217 expectUnchanged(); 218 expectNullValueMissingWhenNullValuesUnsupported( 219 "Should not contain null after unsupported put(present, null)"); 220 } 221 222 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES}) 223 @CollectionSize.Require(absent = ZERO) 224 public void testPut_replaceNullValueWithNullSupported() { 225 initMapWithNullValue(); 226 assertNull( 227 "put(present, null) should return the associated value (null)", 228 getMap().put(getKeyForNullValue(), null)); 229 expectContents(createArrayWithNullValue()); 230 } 231 232 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES}) 233 @CollectionSize.Require(absent = ZERO) 234 public void testPut_replaceNullValueWithNonNullSupported() { 235 Entry<K, V> newEntry = entry(getKeyForNullValue(), v3()); 236 initMapWithNullValue(); 237 assertNull("put(present, value) should return the associated value (null)", put(newEntry)); 238 239 Entry<K, V>[] expected = createArrayWithNullValue(); 240 expected[getNullLocation()] = newEntry; 241 expectContents(expected); 242 } 243 244 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS, ALLOWS_NULL_VALUES}) 245 public void testPut_nullKeyAndValueSupported() { 246 assertNull("put(null, null) should return null", put(nullKeyValueEntry)); 247 expectAdded(nullKeyValueEntry); 248 } 249 250 @CanIgnoreReturnValue 251 private V put(Entry<K, V> entry) { 252 return getMap().put(entry.getKey(), entry.getValue()); 253 } 254 255 /** 256 * Returns the {@link Method} instance for {@link #testPut_nullKeyUnsupported()} so that tests of 257 * {@link java.util.TreeMap} can suppress it with {@code 258 * FeatureSpecificTestSuiteBuilder.suppressing()} until <a 259 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045147">Sun bug 5045147</a> is fixed. 260 */ 261 @J2ktIncompatible 262 @GwtIncompatible // reflection 263 public static Method getPutNullKeyUnsupportedMethod() { 264 return Helpers.getMethod(MapPutTester.class, "testPut_nullKeyUnsupported"); 265 } 266}