001/* 002 * Copyright (C) 2012 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect.testing.google; 018 019import static com.google.common.collect.testing.Helpers.assertEqualIgnoringOrder; 020import static com.google.common.collect.testing.Helpers.mapEntry; 021import static java.util.Arrays.asList; 022 023import com.google.common.annotations.GwtCompatible; 024import com.google.common.collect.Multimap; 025import com.google.common.collect.testing.AbstractContainerTester; 026import com.google.common.collect.testing.SampleElements; 027import com.google.errorprone.annotations.CanIgnoreReturnValue; 028import java.util.Collection; 029import java.util.Iterator; 030import java.util.Map.Entry; 031import org.jspecify.annotations.NullMarked; 032import org.jspecify.annotations.Nullable; 033import org.junit.Ignore; 034 035/** 036 * Superclass for all {@code Multimap} testers. 037 * 038 * @author Louis Wasserman 039 */ 040@GwtCompatible 041@Ignore("test runners must not instantiate and run this directly, only via suites we build") 042// @Ignore affects the Android test runner, which respects JUnit 4 annotations on JUnit 3 tests. 043@SuppressWarnings("JUnit4ClassUsedInJUnit3") 044@NullMarked 045public abstract class AbstractMultimapTester< 046 K extends @Nullable Object, V extends @Nullable Object, M extends Multimap<K, V>> 047 extends AbstractContainerTester<M, Entry<K, V>> { 048 049 private M multimap; 050 051 protected M multimap() { 052 return multimap; 053 } 054 055 /** 056 * @return an array of the proper size with {@code null} as the key of the middle element. 057 */ 058 protected Entry<K, V>[] createArrayWithNullKey() { 059 Entry<K, V>[] array = createSamplesArray(); 060 int nullKeyLocation = getNullLocation(); 061 Entry<K, V> oldEntry = array[nullKeyLocation]; 062 array[nullKeyLocation] = mapEntry(null, oldEntry.getValue()); 063 return array; 064 } 065 066 /** 067 * @return an array of the proper size with {@code null} as the value of the middle element. 068 */ 069 protected Entry<K, V>[] createArrayWithNullValue() { 070 Entry<K, V>[] array = createSamplesArray(); 071 int nullValueLocation = getNullLocation(); 072 Entry<K, V> oldEntry = array[nullValueLocation]; 073 array[nullValueLocation] = mapEntry(oldEntry.getKey(), null); 074 return array; 075 } 076 077 /** 078 * @return an array of the proper size with {@code null} as the key and value of the middle 079 * element. 080 */ 081 protected Entry<K, V>[] createArrayWithNullKeyAndValue() { 082 Entry<K, V>[] array = createSamplesArray(); 083 int nullValueLocation = getNullLocation(); 084 array[nullValueLocation] = mapEntry(null, null); 085 return array; 086 } 087 088 protected V getValueForNullKey() { 089 return getEntryNullReplaces().getValue(); 090 } 091 092 protected K getKeyForNullValue() { 093 return getEntryNullReplaces().getKey(); 094 } 095 096 private Entry<K, V> getEntryNullReplaces() { 097 Iterator<Entry<K, V>> entries = getSampleElements().iterator(); 098 for (int i = 0; i < getNullLocation(); i++) { 099 entries.next(); 100 } 101 return entries.next(); 102 } 103 104 protected void initMultimapWithNullKey() { 105 resetContainer(getSubjectGenerator().create((Object[]) createArrayWithNullKey())); 106 } 107 108 protected void initMultimapWithNullValue() { 109 resetContainer(getSubjectGenerator().create((Object[]) createArrayWithNullValue())); 110 } 111 112 protected void initMultimapWithNullKeyAndValue() { 113 resetContainer(getSubjectGenerator().create((Object[]) createArrayWithNullKeyAndValue())); 114 } 115 116 protected SampleElements<K> sampleKeys() { 117 return ((TestMultimapGenerator<K, V, ? extends Multimap<K, V>>) 118 getSubjectGenerator().getInnerGenerator()) 119 .sampleKeys(); 120 } 121 122 protected SampleElements<V> sampleValues() { 123 return ((TestMultimapGenerator<K, V, ? extends Multimap<K, V>>) 124 getSubjectGenerator().getInnerGenerator()) 125 .sampleValues(); 126 } 127 128 @Override 129 protected Collection<Entry<K, V>> actualContents() { 130 return multimap.entries(); 131 } 132 133 // TODO: dispose of this once collection is encapsulated. 134 @Override 135 @CanIgnoreReturnValue 136 protected M resetContainer(M newContents) { 137 multimap = super.resetContainer(newContents); 138 return multimap; 139 } 140 141 @CanIgnoreReturnValue 142 protected Multimap<K, V> resetContainer(Entry<K, V>... newContents) { 143 multimap = super.resetContainer(getSubjectGenerator().create((Object[]) newContents)); 144 return multimap; 145 } 146 147 /** 148 * @see AbstractContainerTester#resetContainer() 149 */ 150 protected void resetCollection() { 151 resetContainer(); 152 } 153 154 protected void assertGet(K key, V... values) { 155 assertGet(key, asList(values)); 156 } 157 158 protected void assertGet(K key, Collection<? extends V> values) { 159 assertEqualIgnoringOrder(values, multimap().get(key)); 160 161 if (!values.isEmpty()) { 162 assertEqualIgnoringOrder(values, multimap().asMap().get(key)); 163 assertFalse(multimap().isEmpty()); 164 } else { 165 assertNull(multimap().asMap().get(key)); 166 } 167 168 assertEquals(values.size(), multimap().get(key).size()); 169 170 assertEquals(values.size() > 0, multimap().containsKey(key)); 171 assertEquals(values.size() > 0, multimap().keySet().contains(key)); 172 assertEquals(values.size() > 0, multimap().keys().contains(key)); 173 } 174 175 protected final K k0() { 176 return e0().getKey(); 177 } 178 179 protected final V v0() { 180 return e0().getValue(); 181 } 182 183 protected final K k1() { 184 return e1().getKey(); 185 } 186 187 protected final V v1() { 188 return e1().getValue(); 189 } 190 191 protected final K k2() { 192 return e2().getKey(); 193 } 194 195 protected final V v2() { 196 return e2().getValue(); 197 } 198 199 protected final K k3() { 200 return e3().getKey(); 201 } 202 203 protected final V v3() { 204 return e3().getValue(); 205 } 206 207 protected final K k4() { 208 return e4().getKey(); 209 } 210 211 protected final V v4() { 212 return e4().getValue(); 213 } 214}