001/*
002 * Copyright (C) 2015 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.SUPPORTS_PUT;
023import static org.junit.Assert.assertThrows;
024
025import com.google.common.annotations.GwtCompatible;
026import com.google.common.collect.testing.AbstractMapTester;
027import com.google.common.collect.testing.features.CollectionSize;
028import com.google.common.collect.testing.features.MapFeature;
029import java.util.Map;
030import java.util.Map.Entry;
031
032/**
033 * A generic JUnit test which tests {@link Map#putIfAbsent}. Can't be invoked directly; please see
034 * {@link com.google.common.collect.testing.MapTestSuiteBuilder}.
035 *
036 * @author Louis Wasserman
037 */
038@GwtCompatible
039public class MapPutIfAbsentTester<K, V> extends AbstractMapTester<K, V> {
040
041  @MapFeature.Require(SUPPORTS_PUT)
042  public void testPutIfAbsent_supportedAbsent() {
043    assertNull(
044        "putIfAbsent(notPresent, value) should return null", getMap().putIfAbsent(k3(), v3()));
045    expectAdded(e3());
046  }
047
048  @MapFeature.Require(SUPPORTS_PUT)
049  @CollectionSize.Require(absent = ZERO)
050  public void testPutIfAbsent_supportedPresent() {
051    assertEquals(
052        "putIfAbsent(present, value) should return existing value",
053        v0(),
054        getMap().putIfAbsent(k0(), v3()));
055    expectUnchanged();
056  }
057
058  @MapFeature.Require(absent = SUPPORTS_PUT)
059  public void testPutIfAbsent_unsupportedAbsent() {
060    assertThrows(UnsupportedOperationException.class, () -> getMap().putIfAbsent(k3(), v3()));
061    expectUnchanged();
062    expectMissing(e3());
063  }
064
065  @MapFeature.Require(absent = SUPPORTS_PUT)
066  @CollectionSize.Require(absent = ZERO)
067  public void testPutIfAbsent_unsupportedPresentExistingValue() {
068    try {
069      assertEquals(
070          "putIfAbsent(present, existingValue) should return present or throw",
071          v0(),
072          getMap().putIfAbsent(k0(), v0()));
073    } catch (UnsupportedOperationException tolerated) {
074    }
075    expectUnchanged();
076  }
077
078  @MapFeature.Require(absent = SUPPORTS_PUT)
079  @CollectionSize.Require(absent = ZERO)
080  public void testPutIfAbsent_unsupportedPresentDifferentValue() {
081    try {
082      getMap().putIfAbsent(k0(), v3());
083    } catch (UnsupportedOperationException tolerated) {
084    }
085    expectUnchanged();
086  }
087
088  @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_KEYS)
089  public void testPutIfAbsent_nullKeyUnsupported() {
090    assertThrows(NullPointerException.class, () -> getMap().putIfAbsent(null, v3()));
091    expectUnchanged();
092    expectNullKeyMissingWhenNullKeysUnsupported(
093        "Should not contain null key after unsupported putIfAbsent(null, value)");
094  }
095
096  @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
097  public void testPutIfAbsent_nullValueUnsupportedAndKeyAbsent() {
098    assertThrows(NullPointerException.class, () -> getMap().putIfAbsent(k3(), null));
099    expectUnchanged();
100    expectNullValueMissingWhenNullValuesUnsupported(
101        "Should not contain null value after unsupported putIfAbsent(key, null)");
102  }
103
104  @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
105  @CollectionSize.Require(absent = ZERO)
106  public void testPutIfAbsent_nullValueUnsupportedAndKeyPresent() {
107    try {
108      getMap().putIfAbsent(k0(), null);
109    } catch (NullPointerException tolerated) {
110    }
111    expectUnchanged();
112    expectNullValueMissingWhenNullValuesUnsupported(
113        "Should not contain null after unsupported putIfAbsent(present, null)");
114  }
115
116  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
117  public void testPut_nullValueSupported() {
118    Entry<K, V> nullValueEntry = entry(k3(), null);
119    assertNull(
120        "putIfAbsent(key, null) should return null",
121        getMap().putIfAbsent(nullValueEntry.getKey(), nullValueEntry.getValue()));
122    expectAdded(nullValueEntry);
123  }
124
125  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
126  @CollectionSize.Require(absent = ZERO)
127  public void testPutIfAbsent_replacesNullValue() {
128    initMapWithNullValue();
129
130    // putIfAbsent should replace the null value with the new value
131    assertNull(
132        "putIfAbsent(existingKeyWithNullValue, value) should return null",
133        getMap().putIfAbsent(getKeyForNullValue(), v3()));
134    assertEquals("Map should now contain the new value", v3(), getMap().get(getKeyForNullValue()));
135  }
136}