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 com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
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 org.junit.Ignore;
031
032/**
033 * A generic JUnit test which tests {@link Map#compute}. Can't be invoked directly; please see
034 * {@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 MapComputeTester<K, V> extends AbstractMapTester<K, V> {
042  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
043  public void testCompute_absentToPresent() {
044    assertEquals(
045        "Map.compute(absent, functionReturningValue) should return value",
046        v3(),
047        getMap()
048            .compute(
049                k3(),
050                (k, v) -> {
051                  assertEquals(k3(), k);
052                  assertNull(v);
053                  return v3();
054                }));
055    expectAdded(e3());
056    assertEquals(getNumElements() + 1, getMap().size());
057  }
058
059  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
060  public void testCompute_absentToAbsent() {
061    assertNull(
062        "Map.compute(absent, functionReturningNull) should return null",
063        getMap()
064            .compute(
065                k3(),
066                (k, v) -> {
067                  assertEquals(k3(), k);
068                  assertNull(v);
069                  return null;
070                }));
071    expectUnchanged();
072    assertEquals(getNumElements(), getMap().size());
073  }
074
075  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
076  @CollectionSize.Require(absent = ZERO)
077  public void testCompute_presentToPresent() {
078    assertEquals(
079        "Map.compute(present, functionReturningValue) should return new value",
080        v3(),
081        getMap()
082            .compute(
083                k0(),
084                (k, v) -> {
085                  assertEquals(k0(), k);
086                  assertEquals(v0(), v);
087                  return v3();
088                }));
089    expectReplacement(entry(k0(), v3()));
090    assertEquals(getNumElements(), getMap().size());
091  }
092
093  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
094  @CollectionSize.Require(absent = ZERO)
095  public void testCompute_presentToAbsent() {
096    assertNull(
097        "Map.compute(present, functionReturningNull) should return null",
098        getMap()
099            .compute(
100                k0(),
101                (k, v) -> {
102                  assertEquals(k0(), k);
103                  assertEquals(v0(), v);
104                  return null;
105                }));
106    expectMissing(e0());
107    expectMissingKeys(k0());
108    assertEquals(getNumElements() - 1, getMap().size());
109  }
110
111  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
112  @CollectionSize.Require(absent = ZERO)
113  public void testCompute_presentNullToPresentNonnull() {
114    initMapWithNullValue();
115    V value = getValueForNullKey();
116    assertEquals(
117        "Map.compute(presentMappedToNull, functionReturningValue) should return new value",
118        value,
119        getMap()
120            .compute(
121                getKeyForNullValue(),
122                (k, v) -> {
123                  assertEquals(getKeyForNullValue(), k);
124                  assertNull(v);
125                  return value;
126                }));
127    expectReplacement(entry(getKeyForNullValue(), value));
128    assertEquals(getNumElements(), getMap().size());
129  }
130
131  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
132  @CollectionSize.Require(absent = ZERO)
133  public void testCompute_presentNullToNull() {
134    // The spec is somewhat ambiguous about this case, but the actual default implementation
135    // in Map will remove a present null.
136    initMapWithNullValue();
137    assertNull(
138        "Map.compute(presentMappedToNull, functionReturningNull) should return null",
139        getMap()
140            .compute(
141                getKeyForNullValue(),
142                (k, v) -> {
143                  assertEquals(getKeyForNullValue(), k);
144                  assertNull(v);
145                  return null;
146                }));
147    expectMissingKeys(getKeyForNullValue());
148    assertEquals(getNumElements() - 1, getMap().size());
149  }
150
151  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE, ALLOWS_NULL_KEYS})
152  @CollectionSize.Require(absent = ZERO)
153  public void testCompute_nullKeyPresentToPresent() {
154    initMapWithNullKey();
155    assertEquals(
156        "Map.compute(present, functionReturningValue) should return new value",
157        v3(),
158        getMap()
159            .compute(
160                null,
161                (k, v) -> {
162                  assertNull(k);
163                  assertEquals(getValueForNullKey(), v);
164                  return v3();
165                }));
166    assertEquals(getNumElements(), getMap().size());
167  }
168
169  static class ExpectedException extends RuntimeException {}
170
171  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
172  @CollectionSize.Require(absent = ZERO)
173  public void testCompute_presentFunctionThrows() {
174    try {
175      getMap()
176          .compute(
177              k0(),
178              (k, v) -> {
179                assertEquals(k0(), k);
180                assertEquals(v0(), v);
181                throw new ExpectedException();
182              });
183      fail("Expected ExpectedException");
184    } catch (ExpectedException expected) {
185    }
186    expectUnchanged();
187  }
188
189  @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
190  public void testCompute_absentFunctionThrows() {
191    try {
192      getMap()
193          .compute(
194              k3(),
195              (k, v) -> {
196                assertEquals(k3(), k);
197                assertNull(v);
198                throw new ExpectedException();
199              });
200      fail("Expected ExpectedException");
201    } catch (ExpectedException expected) {
202    }
203    expectUnchanged();
204  }
205}