1 /*
2  * Copyright (C) 2015 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect.testing.testers;
18 
19 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
20 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
21 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
22 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
23 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
24 
25 import com.google.common.annotations.GwtCompatible;
26 import com.google.common.collect.testing.AbstractMapTester;
27 import com.google.common.collect.testing.features.CollectionSize;
28 import com.google.common.collect.testing.features.MapFeature;
29 import java.util.Map;
30 import org.junit.Ignore;
31 
32 /**
33  * A generic JUnit test which tests {@link Map#compute}. Can't be invoked directly; please see
34  * {@link com.google.common.collect.testing.MapTestSuiteBuilder}.
35  *
36  * @author Louis Wasserman
37  */
38 @GwtCompatible
39 @Ignore // Affects only Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
40 public class MapComputeTester<K, V> extends AbstractMapTester<K, V> {
41   @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
testCompute_absentToPresent()42   public void testCompute_absentToPresent() {
43     assertEquals(
44         "Map.compute(absent, functionReturningValue) should return value",
45         v3(),
46         getMap()
47             .compute(
48                 k3(),
49                 (k, v) -> {
50                   assertEquals(k3(), k);
51                   assertNull(v);
52                   return v3();
53                 }));
54     expectAdded(e3());
55     assertEquals(getNumElements() + 1, getMap().size());
56   }
57 
58   @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
testCompute_absentToAbsent()59   public void testCompute_absentToAbsent() {
60     assertNull(
61         "Map.compute(absent, functionReturningNull) should return null",
62         getMap()
63             .compute(
64                 k3(),
65                 (k, v) -> {
66                   assertEquals(k3(), k);
67                   assertNull(v);
68                   return null;
69                 }));
70     expectUnchanged();
71     assertEquals(getNumElements(), getMap().size());
72   }
73 
74   @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
75   @CollectionSize.Require(absent = ZERO)
testCompute_presentToPresent()76   public void testCompute_presentToPresent() {
77     assertEquals(
78         "Map.compute(present, functionReturningValue) should return new value",
79         v3(),
80         getMap()
81             .compute(
82                 k0(),
83                 (k, v) -> {
84                   assertEquals(k0(), k);
85                   assertEquals(v0(), v);
86                   return v3();
87                 }));
88     expectReplacement(entry(k0(), v3()));
89     assertEquals(getNumElements(), getMap().size());
90   }
91 
92   @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
93   @CollectionSize.Require(absent = ZERO)
testCompute_presentToAbsent()94   public void testCompute_presentToAbsent() {
95     assertNull(
96         "Map.compute(present, functionReturningNull) should return null",
97         getMap()
98             .compute(
99                 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)
testCompute_presentNullToPresentNonnull()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)
testCompute_presentNullToNull()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)
testCompute_nullKeyPresentToPresent()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   static class ExpectedException extends RuntimeException {}
169 
170   @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
171   @CollectionSize.Require(absent = ZERO)
testCompute_presentFunctionThrows()172   public void testCompute_presentFunctionThrows() {
173     try {
174       getMap()
175           .compute(
176               k0(),
177               (k, v) -> {
178                 assertEquals(k0(), k);
179                 assertEquals(v0(), v);
180                 throw new ExpectedException();
181               });
182       fail("Expected ExpectedException");
183     } catch (ExpectedException expected) {
184     }
185     expectUnchanged();
186   }
187 
188   @MapFeature.Require({SUPPORTS_PUT, SUPPORTS_REMOVE})
testCompute_absentFunctionThrows()189   public void testCompute_absentFunctionThrows() {
190     try {
191       getMap()
192           .compute(
193               k3(),
194               (k, v) -> {
195                 assertEquals(k3(), k);
196                 assertNull(v);
197                 throw new ExpectedException();
198               });
199       fail("Expected ExpectedException");
200     } catch (ExpectedException expected) {
201     }
202     expectUnchanged();
203   }
204 }
205