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