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