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;
023
024import com.google.common.annotations.GwtCompatible;
025import com.google.common.collect.testing.AbstractMapTester;
026import com.google.common.collect.testing.features.CollectionSize;
027import com.google.common.collect.testing.features.MapFeature;
028import java.util.Map;
029import junit.framework.AssertionFailedError;
030import org.junit.Ignore;
031
032/**
033 * A generic JUnit test which tests {@link Map#computeIfAbsent}. Can't be invoked directly; please
034 * see {@link com.google.common.collect.testing.MapTestSuiteBuilder}.
035 *
036 * @author Louis Wasserman
037 */
038@GwtCompatible
039@Ignore // Affects only Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
040@SuppressWarnings("JUnit4ClassUsedInJUnit3")
041public class MapComputeIfAbsentTester<K, V> extends AbstractMapTester<K, V> {
042
043  @MapFeature.Require(SUPPORTS_PUT)
044  public void testComputeIfAbsent_supportedAbsent() {
045    assertEquals(
046        "computeIfAbsent(notPresent, function) should return new value",
047        v3(),
048        getMap()
049            .computeIfAbsent(
050                k3(),
051                k -> {
052                  assertEquals(k3(), k);
053                  return v3();
054                }));
055    expectAdded(e3());
056  }
057
058  @MapFeature.Require(SUPPORTS_PUT)
059  @CollectionSize.Require(absent = ZERO)
060  public void testComputeIfAbsent_supportedPresent() {
061    assertEquals(
062        "computeIfAbsent(present, function) should return existing value",
063        v0(),
064        getMap()
065            .computeIfAbsent(
066                k0(),
067                k -> {
068                  throw new AssertionFailedError();
069                }));
070    expectUnchanged();
071  }
072
073  @MapFeature.Require(SUPPORTS_PUT)
074  public void testComputeIfAbsent_functionReturnsNullNotInserted() {
075    assertNull(
076        "computeIfAbsent(absent, returnsNull) should return null",
077        getMap()
078            .computeIfAbsent(
079                k3(),
080                k -> {
081                  assertEquals(k3(), k);
082                  return null;
083                }));
084    expectUnchanged();
085  }
086
087  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
088  @CollectionSize.Require(absent = ZERO)
089  public void testComputeIfAbsent_nullTreatedAsAbsent() {
090    initMapWithNullValue();
091    assertEquals(
092        "computeIfAbsent(presentAssignedToNull, function) should return newValue",
093        getValueForNullKey(),
094        getMap()
095            .computeIfAbsent(
096                getKeyForNullValue(),
097                k -> {
098                  assertEquals(getKeyForNullValue(), k);
099                  return getValueForNullKey();
100                }));
101    expectReplacement(entry(getKeyForNullValue(), getValueForNullKey()));
102  }
103
104  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
105  public void testComputeIfAbsent_nullKeySupported() {
106    getMap()
107        .computeIfAbsent(
108            null,
109            k -> {
110              assertNull(k);
111              return v3();
112            });
113    expectAdded(entry(null, v3()));
114  }
115
116  static class ExpectedException extends RuntimeException {}
117
118  @MapFeature.Require(SUPPORTS_PUT)
119  public void testComputeIfAbsent_functionThrows() {
120    try {
121      getMap()
122          .computeIfAbsent(
123              k3(),
124              k -> {
125                assertEquals(k3(), k);
126                throw new ExpectedException();
127              });
128      fail("Expected ExpectedException");
129    } catch (ExpectedException expected) {
130    }
131    expectUnchanged();
132  }
133
134  @MapFeature.Require(absent = SUPPORTS_PUT)
135  public void testComputeIfAbsent_unsupportedAbsent() {
136    try {
137      getMap()
138          .computeIfAbsent(
139              k3(),
140              k -> {
141                // allowed to be called
142                assertEquals(k3(), k);
143                return v3();
144              });
145      fail("computeIfAbsent(notPresent, function) should throw");
146    } catch (UnsupportedOperationException expected) {
147    }
148    expectUnchanged();
149  }
150
151  @MapFeature.Require(absent = SUPPORTS_PUT)
152  @CollectionSize.Require(absent = ZERO)
153  public void testComputeIfAbsent_unsupportedPresentExistingValue() {
154    try {
155      assertEquals(
156          "computeIfAbsent(present, returnsCurrentValue) should return present or throw",
157          v0(),
158          getMap()
159              .computeIfAbsent(
160                  k0(),
161                  k -> {
162                    assertEquals(k0(), k);
163                    return v0();
164                  }));
165    } catch (UnsupportedOperationException tolerated) {
166    }
167    expectUnchanged();
168  }
169
170  @MapFeature.Require(absent = SUPPORTS_PUT)
171  @CollectionSize.Require(absent = ZERO)
172  public void testComputeIfAbsent_unsupportedPresentDifferentValue() {
173    try {
174      assertEquals(
175          "computeIfAbsent(present, returnsDifferentValue) should return present or throw",
176          v0(),
177          getMap()
178              .computeIfAbsent(
179                  k0(),
180                  k -> {
181                    assertEquals(k0(), k);
182                    return v3();
183                  }));
184    } catch (UnsupportedOperationException tolerated) {
185    }
186    expectUnchanged();
187  }
188
189  @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_KEYS)
190  public void testComputeIfAbsent_nullKeyUnsupported() {
191    try {
192      getMap()
193          .computeIfAbsent(
194              null,
195              k -> {
196                assertNull(k);
197                return v3();
198              });
199      fail("computeIfAbsent(null, function) should throw");
200    } catch (NullPointerException expected) {
201    }
202    expectUnchanged();
203    expectNullKeyMissingWhenNullKeysUnsupported(
204        "Should not contain null key after unsupported computeIfAbsent(null, function)");
205  }
206}