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