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
17package com.google.common.collect.testing.testers;
18
19import static com.google.common.collect.testing.features.CollectionSize.ZERO;
20import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
21import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
22import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
23
24import com.google.common.collect.testing.AbstractMapTester;
25import com.google.common.collect.testing.features.CollectionSize;
26import com.google.common.collect.testing.features.MapFeature;
27
28import java.util.Map;
29import java.util.Map.Entry;
30
31/**
32 * A generic JUnit test which tests {@code put} operations on a map. Can't be
33 * invoked directly; please see
34 * {@link com.google.common.collect.testing.MapTestSuiteBuilder}.
35 *
36 * <p>This class is GWT compatible.
37 *
38 * @author Chris Povirk
39 * @author Kevin Bourrillion
40 */
41@SuppressWarnings("unchecked") // too many "unchecked generic array creations"
42public class MapPutTester<K, V> extends AbstractMapTester<K, V> {
43  private Entry<K, V> nullKeyEntry;
44  private Entry<K, V> nullValueEntry;
45  private Entry<K, V> nullKeyValueEntry;
46  private Entry<K, V> presentKeyNullValueEntry;
47
48  @Override public void setUp() throws Exception {
49    super.setUp();
50    nullKeyEntry = entry(null, samples.e3.getValue());
51    nullValueEntry = entry(samples.e3.getKey(), null);
52    nullKeyValueEntry = entry(null, null);
53    presentKeyNullValueEntry = entry(samples.e0.getKey(), null);
54  }
55
56  @MapFeature.Require(SUPPORTS_PUT)
57  public void testPut_supportedNotPresent() {
58    assertNull("put(notPresent, value) should return null", put(samples.e3));
59    expectAdded(samples.e3);
60  }
61
62  @MapFeature.Require(absent = SUPPORTS_PUT)
63  public void testPut_unsupportedNotPresent() {
64    try {
65      put(samples.e3);
66      fail("put(notPresent, value) should throw");
67    } catch (UnsupportedOperationException expected) {
68    }
69    expectUnchanged();
70    expectMissing(samples.e3);
71  }
72
73  @MapFeature.Require(absent = SUPPORTS_PUT)
74  @CollectionSize.Require(absent = ZERO)
75  public void testPut_unsupportedPresentExistingValue() {
76    try {
77      assertEquals("put(present, existingValue) should return present or throw",
78          samples.e0.getValue(), put(samples.e0));
79    } catch (UnsupportedOperationException tolerated) {
80    }
81    expectUnchanged();
82  }
83
84  @MapFeature.Require(absent = SUPPORTS_PUT)
85  @CollectionSize.Require(absent = ZERO)
86  public void testPut_unsupportedPresentDifferentValue() {
87    try {
88      getMap().put(samples.e0.getKey(), samples.e3.getValue());
89      fail("put(present, differentValue) should throw");
90    } catch (UnsupportedOperationException expected) {
91    }
92    expectUnchanged();
93  }
94
95  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
96  public void testPut_nullKeySupportedNotPresent() {
97    assertNull("put(null, value) should return null", put(nullKeyEntry));
98    expectAdded(nullKeyEntry);
99  }
100
101  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
102  @CollectionSize.Require(absent = ZERO)
103  public void testPut_nullKeySupportedPresent() {
104    Entry<K, V> newEntry = entry(null, samples.e3.getValue());
105    initMapWithNullKey();
106    assertEquals("put(present, value) should return the associated value",
107        getValueForNullKey(), put(newEntry));
108
109    Entry<K, V>[] expected = createArrayWithNullKey();
110    expected[getNullLocation()] = newEntry;
111    expectContents(expected);
112  }
113
114  @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_KEYS)
115  public void testPut_nullKeyUnsupported() {
116    try {
117      put(nullKeyEntry);
118      fail("put(null, value) should throw");
119    } catch (NullPointerException expected) {
120    }
121    expectUnchanged();
122    expectNullKeyMissingWhenNullKeysUnsupported(
123        "Should not contain null key after unsupported put(null, value)");
124  }
125
126  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
127  public void testPut_nullValueSupported() {
128    assertNull("put(key, null) should return null", put(nullValueEntry));
129    expectAdded(nullValueEntry);
130  }
131
132  @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
133  public void testPut_nullValueUnsupported() {
134    try {
135      put(nullValueEntry);
136      fail("put(key, null) should throw");
137    } catch (NullPointerException expected) {
138    }
139    expectUnchanged();
140    expectNullValueMissingWhenNullValuesUnsupported(
141        "Should not contain null value after unsupported put(key, null)");
142  }
143
144  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
145  @CollectionSize.Require(absent = ZERO)
146  public void testPut_replaceWithNullValueSupported() {
147    assertEquals("put(present, null) should return the associated value",
148        samples.e0.getValue(), put(presentKeyNullValueEntry));
149    expectReplacement(presentKeyNullValueEntry);
150  }
151
152  @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
153  @CollectionSize.Require(absent = ZERO)
154  public void testPut_replaceWithNullValueUnsupported() {
155    try {
156      put(presentKeyNullValueEntry);
157      fail("put(present, null) should throw");
158    } catch (NullPointerException expected) {
159    }
160    expectUnchanged();
161    expectNullValueMissingWhenNullValuesUnsupported(
162        "Should not contain null after unsupported put(present, null)");
163  }
164
165  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
166  @CollectionSize.Require(absent = ZERO)
167  public void testPut_replaceNullValueWithNullSupported() {
168    initMapWithNullValue();
169    assertNull("put(present, null) should return the associated value (null)",
170        getMap().put(getKeyForNullValue(), null));
171    expectContents(createArrayWithNullValue());
172  }
173
174  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
175  @CollectionSize.Require(absent = ZERO)
176  public void testPut_replaceNullValueWithNonNullSupported() {
177    Entry<K, V> newEntry = entry(getKeyForNullValue(), samples.e3.getValue());
178    initMapWithNullValue();
179    assertNull("put(present, value) should return the associated value (null)",
180        put(newEntry));
181
182    Entry<K, V>[] expected = createArrayWithNullValue();
183    expected[getNullLocation()] = newEntry;
184    expectContents(expected);
185  }
186
187  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS, ALLOWS_NULL_VALUES})
188  public void testPut_nullKeyAndValueSupported() {
189    assertNull("put(null, null) should return null", put(nullKeyValueEntry));
190    expectAdded(nullKeyValueEntry);
191  }
192
193  private V put(Map.Entry<K, V> entry) {
194    return getMap().put(entry.getKey(), entry.getValue());
195  }
196}
197