View Javadoc
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  
31  /**
32   * A generic JUnit test which tests {@link Map#computeIfAbsent}. Can't be
33   * invoked directly; please see
34   * {@link com.google.common.collect.testing.MapTestSuiteBuilder}.
35   * 
36   * @author Louis Wasserman
37   */
38  @GwtCompatible
39  public class MapComputeIfAbsentTester<K, V> extends AbstractMapTester<K, V> {
40  
41    @MapFeature.Require(SUPPORTS_PUT)
42    public void testComputeIfAbsent_supportedAbsent() {
43      assertEquals("computeIfAbsent(notPresent, function) should return new value",
44          v3(),
45          getMap().computeIfAbsent(k3(), k -> {
46            assertEquals(k3(), k);
47            return v3();
48          }));
49      expectAdded(e3());
50    }
51    
52    @MapFeature.Require(SUPPORTS_PUT)
53    @CollectionSize.Require(absent = ZERO)
54    public void testComputeIfAbsent_supportedPresent() {
55      assertEquals("computeIfAbsent(present, function) should return existing value", 
56          v0(), getMap().computeIfAbsent(k0(), k -> { throw new AssertionFailedError(); }));
57      expectUnchanged();
58    }
59    
60    @MapFeature.Require(SUPPORTS_PUT)
61    public void testComputeIfAbsent_functionReturnsNullNotInserted() {
62      assertNull("computeIfAbsent(absent, returnsNull) should return null", 
63          getMap().computeIfAbsent(k3(), k -> { 
64            assertEquals(k3(), k);
65            return null;
66          }));
67      expectUnchanged();
68    }
69  
70    @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
71    @CollectionSize.Require(absent = ZERO)
72    public void testComputeIfAbsent_nullTreatedAsAbsent() {
73      initMapWithNullValue();
74      assertEquals("computeIfAbsent(presentAssignedToNull, function) should return newValue",
75          getValueForNullKey(),
76          getMap().computeIfAbsent(getKeyForNullValue(), k -> {
77            assertEquals(getKeyForNullValue(), k);
78            return getValueForNullKey();
79          }));
80      expectReplacement(entry(getKeyForNullValue(), getValueForNullKey()));
81    }
82  
83    @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
84    public void testComputeIfAbsent_nullKeySupported() {
85      getMap().computeIfAbsent(null, k -> {
86        assertNull(k);
87        return v3();
88      });
89      expectAdded(entry(null, v3()));
90    }
91  
92    static class ExpectedException extends RuntimeException {}
93  
94    @MapFeature.Require(SUPPORTS_PUT)
95    public void testComputeIfAbsent_functionThrows() {
96      try {
97        getMap()
98            .computeIfAbsent(
99                k3(),
100               k -> {
101                 assertEquals(k3(), k);
102                 throw new ExpectedException();
103               });
104       fail("Expected ExpectedException");
105     } catch (ExpectedException expected) {
106     }
107     expectUnchanged();
108   }
109 
110   @MapFeature.Require(absent = SUPPORTS_PUT)
111   public void testComputeIfAbsent_unsupportedAbsent() {
112     try {
113       getMap().computeIfAbsent(k3(), k -> {
114         // allowed to be called
115         assertEquals(k3(), k);
116         return v3();
117       });
118       fail("computeIfAbsent(notPresent, function) should throw");
119     } catch (UnsupportedOperationException expected) {}
120     expectUnchanged();
121   }
122 
123   @MapFeature.Require(absent = SUPPORTS_PUT)
124   @CollectionSize.Require(absent = ZERO)
125   public void testComputeIfAbsent_unsupportedPresentExistingValue() {
126     try {
127       assertEquals(
128           "computeIfAbsent(present, returnsCurrentValue) should return present or throw",
129           v0(), 
130           getMap().computeIfAbsent(k0(), k -> {
131             assertEquals(k0(), k);
132             return v0();
133           }));
134     } catch (UnsupportedOperationException tolerated) {}
135     expectUnchanged();
136   }
137 
138   @MapFeature.Require(absent = SUPPORTS_PUT)
139   @CollectionSize.Require(absent = ZERO)
140   public void testComputeIfAbsent_unsupportedPresentDifferentValue() {
141     try {
142       assertEquals(
143           "computeIfAbsent(present, returnsDifferentValue) should return present or throw",
144           v0(), getMap().computeIfAbsent(k0(), k -> {
145             assertEquals(k0(), k);
146             return v3();
147           }));
148     } catch (UnsupportedOperationException tolerated) {}
149     expectUnchanged();
150   }
151 
152   @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_KEYS)
153   public void testComputeIfAbsent_nullKeyUnsupported() {
154     try {
155       getMap().computeIfAbsent(null, k -> {
156         assertNull(k);
157         return v3();
158       });
159       fail("computeIfAbsent(null, function) should throw");
160     } catch (NullPointerException expected) {}
161     expectUnchanged();
162     expectNullKeyMissingWhenNullKeysUnsupported(
163         "Should not contain null key after unsupported computeIfAbsent(null, function)");
164   }
165 }