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