| /* |
| * Copyright (C) 2007 The Guava Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.google.common.collect.testing; |
| |
| import com.google.common.annotations.GwtCompatible; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import org.junit.Ignore; |
| |
| /** |
| * Base class for map testers. |
| * |
| * <p>TODO: see how much of this is actually needed once Map testers are written. (It was cloned |
| * from AbstractCollectionTester.) |
| * |
| * @param <K> the key type of the map to be tested. |
| * @param <V> the value type of the map to be tested. |
| * @author George van den Driessche |
| */ |
| @GwtCompatible |
| @Ignore // Affects only Android test runner, which respects JUnit 4 annotations on JUnit 3 tests. |
| public abstract class AbstractMapTester<K, V> |
| extends AbstractContainerTester<Map<K, V>, Entry<K, V>> { |
| protected Map<K, V> getMap() { |
| return container; |
| } |
| |
| @Override |
| protected Collection<Entry<K, V>> actualContents() { |
| return getMap().entrySet(); |
| } |
| |
| /** @see AbstractContainerTester#resetContainer() */ |
| protected final void resetMap() { |
| resetContainer(); |
| } |
| |
| protected void resetMap(Entry<K, V>[] entries) { |
| resetContainer(getSubjectGenerator().create((Object[]) entries)); |
| } |
| |
| protected void expectMissingKeys(K... elements) { |
| for (K element : elements) { |
| assertFalse("Should not contain key " + element, getMap().containsKey(element)); |
| } |
| } |
| |
| protected void expectMissingValues(V... elements) { |
| for (V element : elements) { |
| assertFalse("Should not contain value " + element, getMap().containsValue(element)); |
| } |
| } |
| |
| /** @return an array of the proper size with {@code null} as the key of the middle element. */ |
| protected Entry<K, V>[] createArrayWithNullKey() { |
| Entry<K, V>[] array = createSamplesArray(); |
| final int nullKeyLocation = getNullLocation(); |
| final Entry<K, V> oldEntry = array[nullKeyLocation]; |
| array[nullKeyLocation] = entry(null, oldEntry.getValue()); |
| return array; |
| } |
| |
| protected V getValueForNullKey() { |
| return getEntryNullReplaces().getValue(); |
| } |
| |
| protected K getKeyForNullValue() { |
| return getEntryNullReplaces().getKey(); |
| } |
| |
| private Entry<K, V> getEntryNullReplaces() { |
| Iterator<Entry<K, V>> entries = getSampleElements().iterator(); |
| for (int i = 0; i < getNullLocation(); i++) { |
| entries.next(); |
| } |
| return entries.next(); |
| } |
| |
| /** @return an array of the proper size with {@code null} as the value of the middle element. */ |
| protected Entry<K, V>[] createArrayWithNullValue() { |
| Entry<K, V>[] array = createSamplesArray(); |
| final int nullValueLocation = getNullLocation(); |
| final Entry<K, V> oldEntry = array[nullValueLocation]; |
| array[nullValueLocation] = entry(oldEntry.getKey(), null); |
| return array; |
| } |
| |
| protected void initMapWithNullKey() { |
| resetMap(createArrayWithNullKey()); |
| } |
| |
| protected void initMapWithNullValue() { |
| resetMap(createArrayWithNullValue()); |
| } |
| |
| /** |
| * Equivalent to {@link #expectMissingKeys(Object[]) expectMissingKeys} {@code (null)} except that |
| * the call to {@code contains(null)} is permitted to throw a {@code NullPointerException}. |
| * |
| * @param message message to use upon assertion failure |
| */ |
| protected void expectNullKeyMissingWhenNullKeysUnsupported(String message) { |
| try { |
| assertFalse(message, getMap().containsKey(null)); |
| } catch (NullPointerException tolerated) { |
| // Tolerated |
| } |
| } |
| |
| /** |
| * Equivalent to {@link #expectMissingValues(Object[]) expectMissingValues} {@code (null)} except |
| * that the call to {@code contains(null)} is permitted to throw a {@code NullPointerException}. |
| * |
| * @param message message to use upon assertion failure |
| */ |
| protected void expectNullValueMissingWhenNullValuesUnsupported(String message) { |
| try { |
| assertFalse(message, getMap().containsValue(null)); |
| } catch (NullPointerException tolerated) { |
| // Tolerated |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| protected MinimalCollection<Entry<K, V>> createDisjointCollection() { |
| return MinimalCollection.of(e3(), e4()); |
| } |
| |
| protected int getNumEntries() { |
| return getNumElements(); |
| } |
| |
| protected Collection<Entry<K, V>> getSampleEntries(int howMany) { |
| return getSampleElements(howMany); |
| } |
| |
| protected Collection<Entry<K, V>> getSampleEntries() { |
| return getSampleElements(); |
| } |
| |
| @Override |
| protected void expectMissing(Entry<K, V>... entries) { |
| for (Entry<K, V> entry : entries) { |
| assertFalse("Should not contain entry " + entry, actualContents().contains(entry)); |
| assertFalse( |
| "Should not contain key " + entry.getKey() + " mapped to value " + entry.getValue(), |
| equal(getMap().get(entry.getKey()), entry.getValue())); |
| } |
| } |
| |
| private static boolean equal(Object a, Object b) { |
| return a == b || (a != null && a.equals(b)); |
| } |
| |
| // This one-liner saves us from some ugly casts |
| protected Entry<K, V> entry(K key, V value) { |
| return Helpers.mapEntry(key, value); |
| } |
| |
| @Override |
| protected void expectContents(Collection<Entry<K, V>> expected) { |
| // TODO: move this to invariant checks once the appropriate hook exists? |
| super.expectContents(expected); |
| for (Entry<K, V> entry : expected) { |
| assertEquals( |
| "Wrong value for key " + entry.getKey(), entry.getValue(), getMap().get(entry.getKey())); |
| } |
| } |
| |
| protected final void expectReplacement(Entry<K, V> newEntry) { |
| List<Entry<K, V>> expected = Helpers.copyToList(getSampleElements()); |
| replaceValue(expected, newEntry); |
| expectContents(expected); |
| } |
| |
| private void replaceValue(List<Entry<K, V>> expected, Entry<K, V> newEntry) { |
| for (ListIterator<Entry<K, V>> i = expected.listIterator(); i.hasNext(); ) { |
| if (Helpers.equal(i.next().getKey(), newEntry.getKey())) { |
| i.set(newEntry); |
| return; |
| } |
| } |
| |
| throw new IllegalArgumentException( |
| Platform.format("key %s not found in entries %s", newEntry.getKey(), expected)); |
| } |
| |
| /** |
| * Wrapper for {@link Map#get(Object)} that forces the caller to pass in a key of the same type as |
| * the map. Besides being slightly shorter than code that uses {@link #getMap()}, it also ensures |
| * that callers don't pass an {@link Entry} by mistake. |
| */ |
| protected V get(K key) { |
| return getMap().get(key); |
| } |
| |
| protected final K k0() { |
| return e0().getKey(); |
| } |
| |
| protected final V v0() { |
| return e0().getValue(); |
| } |
| |
| protected final K k1() { |
| return e1().getKey(); |
| } |
| |
| protected final V v1() { |
| return e1().getValue(); |
| } |
| |
| protected final K k2() { |
| return e2().getKey(); |
| } |
| |
| protected final V v2() { |
| return e2().getValue(); |
| } |
| |
| protected final K k3() { |
| return e3().getKey(); |
| } |
| |
| protected final V v3() { |
| return e3().getValue(); |
| } |
| |
| protected final K k4() { |
| return e4().getKey(); |
| } |
| |
| protected final V v4() { |
| return e4().getValue(); |
| } |
| } |