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 
24 import com.google.common.annotations.GwtCompatible;
25 import com.google.common.collect.testing.AbstractMapTester;
26 import com.google.common.collect.testing.features.CollectionSize;
27 import com.google.common.collect.testing.features.MapFeature;
28 import java.util.Map;
29 import junit.framework.AssertionFailedError;
30 import org.junit.Ignore;
31 
32 /**
33  * A generic JUnit test which tests {@link Map#computeIfAbsent}. Can't be invoked directly; please
34  * see {@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 MapComputeIfAbsentTester<K, V> extends AbstractMapTester<K, V> {
41 
42   @MapFeature.Require(SUPPORTS_PUT)
testComputeIfAbsent_supportedAbsent()43   public void testComputeIfAbsent_supportedAbsent() {
44     assertEquals(
45         "computeIfAbsent(notPresent, function) should return new value",
46         v3(),
47         getMap()
48             .computeIfAbsent(
49                 k3(),
50                 k -> {
51                   assertEquals(k3(), k);
52                   return v3();
53                 }));
54     expectAdded(e3());
55   }
56 
57   @MapFeature.Require(SUPPORTS_PUT)
58   @CollectionSize.Require(absent = ZERO)
testComputeIfAbsent_supportedPresent()59   public void testComputeIfAbsent_supportedPresent() {
60     assertEquals(
61         "computeIfAbsent(present, function) should return existing value",
62         v0(),
63         getMap()
64             .computeIfAbsent(
65                 k0(),
66                 k -> {
67                   throw new AssertionFailedError();
68                 }));
69     expectUnchanged();
70   }
71 
72   @MapFeature.Require(SUPPORTS_PUT)
testComputeIfAbsent_functionReturnsNullNotInserted()73   public void testComputeIfAbsent_functionReturnsNullNotInserted() {
74     assertNull(
75         "computeIfAbsent(absent, returnsNull) should return null",
76         getMap()
77             .computeIfAbsent(
78                 k3(),
79                 k -> {
80                   assertEquals(k3(), k);
81                   return null;
82                 }));
83     expectUnchanged();
84   }
85 
86   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
87   @CollectionSize.Require(absent = ZERO)
testComputeIfAbsent_nullTreatedAsAbsent()88   public void testComputeIfAbsent_nullTreatedAsAbsent() {
89     initMapWithNullValue();
90     assertEquals(
91         "computeIfAbsent(presentAssignedToNull, function) should return newValue",
92         getValueForNullKey(),
93         getMap()
94             .computeIfAbsent(
95                 getKeyForNullValue(),
96                 k -> {
97                   assertEquals(getKeyForNullValue(), k);
98                   return getValueForNullKey();
99                 }));
100     expectReplacement(entry(getKeyForNullValue(), getValueForNullKey()));
101   }
102 
103   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
testComputeIfAbsent_nullKeySupported()104   public void testComputeIfAbsent_nullKeySupported() {
105     getMap()
106         .computeIfAbsent(
107             null,
108             k -> {
109               assertNull(k);
110               return v3();
111             });
112     expectAdded(entry(null, v3()));
113   }
114 
115   static class ExpectedException extends RuntimeException {}
116 
117   @MapFeature.Require(SUPPORTS_PUT)
testComputeIfAbsent_functionThrows()118   public void testComputeIfAbsent_functionThrows() {
119     try {
120       getMap()
121           .computeIfAbsent(
122               k3(),
123               k -> {
124                 assertEquals(k3(), k);
125                 throw new ExpectedException();
126               });
127       fail("Expected ExpectedException");
128     } catch (ExpectedException expected) {
129     }
130     expectUnchanged();
131   }
132 
133   @MapFeature.Require(absent = SUPPORTS_PUT)
testComputeIfAbsent_unsupportedAbsent()134   public void testComputeIfAbsent_unsupportedAbsent() {
135     try {
136       getMap()
137           .computeIfAbsent(
138               k3(),
139               k -> {
140                 // allowed to be called
141                 assertEquals(k3(), k);
142                 return v3();
143               });
144       fail("computeIfAbsent(notPresent, function) should throw");
145     } catch (UnsupportedOperationException expected) {
146     }
147     expectUnchanged();
148   }
149 
150   @MapFeature.Require(absent = SUPPORTS_PUT)
151   @CollectionSize.Require(absent = ZERO)
testComputeIfAbsent_unsupportedPresentExistingValue()152   public void testComputeIfAbsent_unsupportedPresentExistingValue() {
153     try {
154       assertEquals(
155           "computeIfAbsent(present, returnsCurrentValue) should return present or throw",
156           v0(),
157           getMap()
158               .computeIfAbsent(
159                   k0(),
160                   k -> {
161                     assertEquals(k0(), k);
162                     return v0();
163                   }));
164     } catch (UnsupportedOperationException tolerated) {
165     }
166     expectUnchanged();
167   }
168 
169   @MapFeature.Require(absent = SUPPORTS_PUT)
170   @CollectionSize.Require(absent = ZERO)
testComputeIfAbsent_unsupportedPresentDifferentValue()171   public void testComputeIfAbsent_unsupportedPresentDifferentValue() {
172     try {
173       assertEquals(
174           "computeIfAbsent(present, returnsDifferentValue) should return present or throw",
175           v0(),
176           getMap()
177               .computeIfAbsent(
178                   k0(),
179                   k -> {
180                     assertEquals(k0(), k);
181                     return v3();
182                   }));
183     } catch (UnsupportedOperationException tolerated) {
184     }
185     expectUnchanged();
186   }
187 
188   @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_KEYS)
testComputeIfAbsent_nullKeyUnsupported()189   public void testComputeIfAbsent_nullKeyUnsupported() {
190     try {
191       getMap()
192           .computeIfAbsent(
193               null,
194               k -> {
195                 assertNull(k);
196                 return v3();
197               });
198       fail("computeIfAbsent(null, function) should throw");
199     } catch (NullPointerException expected) {
200     }
201     expectUnchanged();
202     expectNullKeyMissingWhenNullKeysUnsupported(
203         "Should not contain null key after unsupported computeIfAbsent(null, function)");
204   }
205 }
206