• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import java.util.Collection;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.ListIterator;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import org.checkerframework.checker.nullness.qual.Nullable;
27 import org.junit.Ignore;
28 
29 /**
30  * Base class for map testers.
31  *
32  * <p>TODO: see how much of this is actually needed once Map testers are written. (It was cloned
33  * from AbstractCollectionTester.)
34  *
35  * @param <K> the key type of the map to be tested.
36  * @param <V> the value type of the map to be tested.
37  * @author George van den Driessche
38  */
39 @GwtCompatible
40 @Ignore // Affects only Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
41 public abstract class AbstractMapTester<K, V>
42     extends AbstractContainerTester<Map<K, V>, Entry<K, V>> {
getMap()43   protected Map<K, V> getMap() {
44     return container;
45   }
46 
47   @Override
actualContents()48   protected Collection<Entry<K, V>> actualContents() {
49     return getMap().entrySet();
50   }
51 
52   /** @see AbstractContainerTester#resetContainer() */
resetMap()53   protected final void resetMap() {
54     resetContainer();
55   }
56 
resetMap(Entry<K, V>[] entries)57   protected void resetMap(Entry<K, V>[] entries) {
58     resetContainer(getSubjectGenerator().create((Object[]) entries));
59   }
60 
expectMissingKeys(K... elements)61   protected void expectMissingKeys(K... elements) {
62     for (K element : elements) {
63       assertFalse("Should not contain key " + element, getMap().containsKey(element));
64     }
65   }
66 
expectMissingValues(V... elements)67   protected void expectMissingValues(V... elements) {
68     for (V element : elements) {
69       assertFalse("Should not contain value " + element, getMap().containsValue(element));
70     }
71   }
72 
73   /** @return an array of the proper size with {@code null} as the key of the middle element. */
createArrayWithNullKey()74   protected Entry<K, V>[] createArrayWithNullKey() {
75     Entry<K, V>[] array = createSamplesArray();
76     int nullKeyLocation = getNullLocation();
77     Entry<K, V> oldEntry = array[nullKeyLocation];
78     array[nullKeyLocation] = entry(null, oldEntry.getValue());
79     return array;
80   }
81 
getValueForNullKey()82   protected V getValueForNullKey() {
83     return getEntryNullReplaces().getValue();
84   }
85 
getKeyForNullValue()86   protected K getKeyForNullValue() {
87     return getEntryNullReplaces().getKey();
88   }
89 
getEntryNullReplaces()90   private Entry<K, V> getEntryNullReplaces() {
91     Iterator<Entry<K, V>> entries = getSampleElements().iterator();
92     for (int i = 0; i < getNullLocation(); i++) {
93       entries.next();
94     }
95     return entries.next();
96   }
97 
98   /** @return an array of the proper size with {@code null} as the value of the middle element. */
createArrayWithNullValue()99   protected Entry<K, V>[] createArrayWithNullValue() {
100     Entry<K, V>[] array = createSamplesArray();
101     int nullValueLocation = getNullLocation();
102     Entry<K, V> oldEntry = array[nullValueLocation];
103     array[nullValueLocation] = entry(oldEntry.getKey(), null);
104     return array;
105   }
106 
initMapWithNullKey()107   protected void initMapWithNullKey() {
108     resetMap(createArrayWithNullKey());
109   }
110 
initMapWithNullValue()111   protected void initMapWithNullValue() {
112     resetMap(createArrayWithNullValue());
113   }
114 
115   /**
116    * Equivalent to {@link #expectMissingKeys(Object[]) expectMissingKeys} {@code (null)} except that
117    * the call to {@code contains(null)} is permitted to throw a {@code NullPointerException}.
118    *
119    * @param message message to use upon assertion failure
120    */
expectNullKeyMissingWhenNullKeysUnsupported(String message)121   protected void expectNullKeyMissingWhenNullKeysUnsupported(String message) {
122     try {
123       assertFalse(message, getMap().containsKey(null));
124     } catch (NullPointerException tolerated) {
125       // Tolerated
126     }
127   }
128 
129   /**
130    * Equivalent to {@link #expectMissingValues(Object[]) expectMissingValues} {@code (null)} except
131    * that the call to {@code contains(null)} is permitted to throw a {@code NullPointerException}.
132    *
133    * @param message message to use upon assertion failure
134    */
expectNullValueMissingWhenNullValuesUnsupported(String message)135   protected void expectNullValueMissingWhenNullValuesUnsupported(String message) {
136     try {
137       assertFalse(message, getMap().containsValue(null));
138     } catch (NullPointerException tolerated) {
139       // Tolerated
140     }
141   }
142 
143   @SuppressWarnings("unchecked")
144   @Override
createDisjointCollection()145   protected MinimalCollection<Entry<K, V>> createDisjointCollection() {
146     return MinimalCollection.of(e3(), e4());
147   }
148 
getNumEntries()149   protected int getNumEntries() {
150     return getNumElements();
151   }
152 
getSampleEntries(int howMany)153   protected Collection<Entry<K, V>> getSampleEntries(int howMany) {
154     return getSampleElements(howMany);
155   }
156 
getSampleEntries()157   protected Collection<Entry<K, V>> getSampleEntries() {
158     return getSampleElements();
159   }
160 
161   @Override
expectMissing(Entry<K, V>.... entries)162   protected void expectMissing(Entry<K, V>... entries) {
163     for (Entry<K, V> entry : entries) {
164       assertFalse("Should not contain entry " + entry, actualContents().contains(entry));
165       assertFalse(
166           "Should not contain key " + entry.getKey() + " mapped to value " + entry.getValue(),
167           equal(getMap().get(entry.getKey()), entry.getValue()));
168     }
169   }
170 
equal(@ullable Object a, @Nullable Object b)171   private static boolean equal(@Nullable Object a, @Nullable Object b) {
172     return a == b || (a != null && a.equals(b));
173   }
174 
175   // This one-liner saves us from some ugly casts
entry(K key, V value)176   protected Entry<K, V> entry(K key, V value) {
177     return Helpers.mapEntry(key, value);
178   }
179 
180   @Override
expectContents(Collection<Entry<K, V>> expected)181   protected void expectContents(Collection<Entry<K, V>> expected) {
182     // TODO: move this to invariant checks once the appropriate hook exists?
183     super.expectContents(expected);
184     for (Entry<K, V> entry : expected) {
185       assertEquals(
186           "Wrong value for key " + entry.getKey(), entry.getValue(), getMap().get(entry.getKey()));
187     }
188   }
189 
expectReplacement(Entry<K, V> newEntry)190   protected final void expectReplacement(Entry<K, V> newEntry) {
191     List<Entry<K, V>> expected = Helpers.copyToList(getSampleElements());
192     replaceValue(expected, newEntry);
193     expectContents(expected);
194   }
195 
replaceValue(List<Entry<K, V>> expected, Entry<K, V> newEntry)196   private void replaceValue(List<Entry<K, V>> expected, Entry<K, V> newEntry) {
197     for (ListIterator<Entry<K, V>> i = expected.listIterator(); i.hasNext(); ) {
198       if (Helpers.equal(i.next().getKey(), newEntry.getKey())) {
199         i.set(newEntry);
200         return;
201       }
202     }
203 
204     throw new IllegalArgumentException(
205         Platform.format("key %s not found in entries %s", newEntry.getKey(), expected));
206   }
207 
208   /**
209    * Wrapper for {@link Map#get(Object)} that forces the caller to pass in a key of the same type as
210    * the map. Besides being slightly shorter than code that uses {@link #getMap()}, it also ensures
211    * that callers don't pass an {@link Entry} by mistake.
212    */
get(K key)213   protected V get(K key) {
214     return getMap().get(key);
215   }
216 
k0()217   protected final K k0() {
218     return e0().getKey();
219   }
220 
v0()221   protected final V v0() {
222     return e0().getValue();
223   }
224 
k1()225   protected final K k1() {
226     return e1().getKey();
227   }
228 
v1()229   protected final V v1() {
230     return e1().getValue();
231   }
232 
k2()233   protected final K k2() {
234     return e2().getKey();
235   }
236 
v2()237   protected final V v2() {
238     return e2().getValue();
239   }
240 
k3()241   protected final K k3() {
242     return e3().getKey();
243   }
244 
v3()245   protected final V v3() {
246     return e3().getValue();
247   }
248 
k4()249   protected final K k4() {
250     return e4().getKey();
251   }
252 
v4()253   protected final V v4() {
254     return e4().getValue();
255   }
256 }
257