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