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; 033 034/** 035 * Superclass for all {@code Multimap} testers. 036 * 037 * @author Louis Wasserman 038 */ 039@GwtCompatible 040@NullMarked 041public abstract class AbstractMultimapTester< 042 K extends @Nullable Object, V extends @Nullable Object, M extends Multimap<K, V>> 043 extends AbstractContainerTester<M, Entry<K, V>> { 044 045 private M multimap; 046 047 protected M multimap() { 048 return multimap; 049 } 050 051 /** 052 * @return an array of the proper size with {@code null} as the key of the middle element. 053 */ 054 protected Entry<K, V>[] createArrayWithNullKey() { 055 Entry<K, V>[] array = createSamplesArray(); 056 int nullKeyLocation = getNullLocation(); 057 Entry<K, V> oldEntry = array[nullKeyLocation]; 058 array[nullKeyLocation] = mapEntry(null, oldEntry.getValue()); 059 return array; 060 } 061 062 /** 063 * @return an array of the proper size with {@code null} as the value of the middle element. 064 */ 065 protected Entry<K, V>[] createArrayWithNullValue() { 066 Entry<K, V>[] array = createSamplesArray(); 067 int nullValueLocation = getNullLocation(); 068 Entry<K, V> oldEntry = array[nullValueLocation]; 069 array[nullValueLocation] = mapEntry(oldEntry.getKey(), null); 070 return array; 071 } 072 073 /** 074 * @return an array of the proper size with {@code null} as the key and value of the middle 075 * element. 076 */ 077 protected Entry<K, V>[] createArrayWithNullKeyAndValue() { 078 Entry<K, V>[] array = createSamplesArray(); 079 int nullValueLocation = getNullLocation(); 080 array[nullValueLocation] = mapEntry(null, null); 081 return array; 082 } 083 084 protected V getValueForNullKey() { 085 return getEntryNullReplaces().getValue(); 086 } 087 088 protected K getKeyForNullValue() { 089 return getEntryNullReplaces().getKey(); 090 } 091 092 private Entry<K, V> getEntryNullReplaces() { 093 Iterator<Entry<K, V>> entries = getSampleElements().iterator(); 094 for (int i = 0; i < getNullLocation(); i++) { 095 entries.next(); 096 } 097 return entries.next(); 098 } 099 100 protected void initMultimapWithNullKey() { 101 resetContainer(getSubjectGenerator().create((Object[]) createArrayWithNullKey())); 102 } 103 104 protected void initMultimapWithNullValue() { 105 resetContainer(getSubjectGenerator().create((Object[]) createArrayWithNullValue())); 106 } 107 108 protected void initMultimapWithNullKeyAndValue() { 109 resetContainer(getSubjectGenerator().create((Object[]) createArrayWithNullKeyAndValue())); 110 } 111 112 protected SampleElements<K> sampleKeys() { 113 return ((TestMultimapGenerator<K, V, ? extends Multimap<K, V>>) 114 getSubjectGenerator().getInnerGenerator()) 115 .sampleKeys(); 116 } 117 118 protected SampleElements<V> sampleValues() { 119 return ((TestMultimapGenerator<K, V, ? extends Multimap<K, V>>) 120 getSubjectGenerator().getInnerGenerator()) 121 .sampleValues(); 122 } 123 124 @Override 125 protected Collection<Entry<K, V>> actualContents() { 126 return multimap.entries(); 127 } 128 129 // TODO: dispose of this once collection is encapsulated. 130 @Override 131 @CanIgnoreReturnValue 132 protected M resetContainer(M newContents) { 133 multimap = super.resetContainer(newContents); 134 return multimap; 135 } 136 137 @CanIgnoreReturnValue 138 protected Multimap<K, V> resetContainer(Entry<K, V>... newContents) { 139 multimap = super.resetContainer(getSubjectGenerator().create((Object[]) newContents)); 140 return multimap; 141 } 142 143 /** 144 * @see AbstractContainerTester#resetContainer() 145 */ 146 protected void resetCollection() { 147 resetContainer(); 148 } 149 150 protected void assertGet(K key, V... values) { 151 assertGet(key, asList(values)); 152 } 153 154 protected void assertGet(K key, Collection<? extends V> values) { 155 assertEqualIgnoringOrder(values, multimap().get(key)); 156 157 if (!values.isEmpty()) { 158 assertEqualIgnoringOrder(values, multimap().asMap().get(key)); 159 assertFalse(multimap().isEmpty()); 160 } else { 161 assertNull(multimap().asMap().get(key)); 162 } 163 164 assertEquals(values.size(), multimap().get(key).size()); 165 166 assertEquals(values.size() > 0, multimap().containsKey(key)); 167 assertEquals(values.size() > 0, multimap().keySet().contains(key)); 168 assertEquals(values.size() > 0, multimap().keys().contains(key)); 169 } 170 171 protected final K k0() { 172 return e0().getKey(); 173 } 174 175 protected final V v0() { 176 return e0().getValue(); 177 } 178 179 protected final K k1() { 180 return e1().getKey(); 181 } 182 183 protected final V v1() { 184 return e1().getValue(); 185 } 186 187 protected final K k2() { 188 return e2().getKey(); 189 } 190 191 protected final V v2() { 192 return e2().getValue(); 193 } 194 195 protected final K k3() { 196 return e3().getKey(); 197 } 198 199 protected final V v3() { 200 return e3().getValue(); 201 } 202 203 protected final K k4() { 204 return e4().getKey(); 205 } 206 207 protected final V v4() { 208 return e4().getValue(); 209 } 210}