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.assertContains;
020import static com.google.common.collect.testing.Helpers.assertEmpty;
021import static com.google.common.collect.testing.Helpers.assertEqualIgnoringOrder;
022import static com.google.common.collect.testing.Helpers.copyToList;
023import static com.google.common.collect.testing.Helpers.mapEntry;
024import static com.google.common.collect.testing.features.CollectionSize.ZERO;
025import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
026import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
027import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
028import static com.google.common.collect.testing.google.ReflectionFreeAssertThrows.assertThrows;
029
030import com.google.common.annotations.GwtCompatible;
031import com.google.common.collect.ImmutableList;
032import com.google.common.collect.Lists;
033import com.google.common.collect.Multimap;
034import com.google.common.collect.testing.features.CollectionSize;
035import com.google.common.collect.testing.features.MapFeature;
036import java.util.Collection;
037import java.util.Iterator;
038import java.util.List;
039import java.util.Map.Entry;
040import org.jspecify.annotations.NullMarked;
041import org.jspecify.annotations.Nullable;
042import org.junit.Ignore;
043
044/**
045 * Tester for {@link Multimap#put}.
046 *
047 * @author Louis Wasserman
048 */
049@GwtCompatible
050@Ignore("test runners must not instantiate and run this directly, only via suites we build")
051// @Ignore affects the Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
052@SuppressWarnings("JUnit4ClassUsedInJUnit3")
053@NullMarked
054public class MultimapPutTester<K extends @Nullable Object, V extends @Nullable Object>
055    extends AbstractMultimapTester<K, V, Multimap<K, V>> {
056  @MapFeature.Require(absent = SUPPORTS_PUT)
057  public void testPutUnsupported() {
058    assertThrows(UnsupportedOperationException.class, () -> multimap().put(k3(), v3()));
059  }
060
061  @MapFeature.Require(SUPPORTS_PUT)
062  public void testPutEmpty() {
063    int size = getNumElements();
064
065    assertGet(k3(), ImmutableList.<V>of());
066
067    assertTrue(multimap().put(k3(), v3()));
068
069    assertGet(k3(), v3());
070    assertEquals(size + 1, multimap().size());
071  }
072
073  @MapFeature.Require(SUPPORTS_PUT)
074  @CollectionSize.Require(absent = ZERO)
075  public void testPutPresent() {
076    int size = getNumElements();
077
078    assertGet(k0(), v0());
079
080    assertTrue(multimap().put(k0(), v3()));
081
082    assertGet(k0(), v0(), v3());
083    assertEquals(size + 1, multimap().size());
084  }
085
086  @MapFeature.Require(SUPPORTS_PUT)
087  public void testPutTwoElements() {
088    int size = getNumElements();
089
090    List<V> values = copyToList(multimap().get(k0()));
091
092    assertTrue(multimap().put(k0(), v1()));
093    assertTrue(multimap().put(k0(), v2()));
094
095    values.add(v1());
096    values.add(v2());
097
098    assertGet(k0(), values);
099    assertEquals(size + 2, multimap().size());
100  }
101
102  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
103  public void testPutNullValue_supported() {
104    int size = getNumElements();
105
106    multimap().put(k3(), null);
107
108    assertGet(k3(), Lists.newArrayList((V) null)); // ImmutableList.of can't take null.
109    assertEquals(size + 1, multimap().size());
110  }
111
112  @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
113  public void testPutNullValue_unsupported() {
114    assertThrows(NullPointerException.class, () -> multimap().put(k1(), null));
115
116    expectUnchanged();
117  }
118
119  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
120  public void testPutNullKey() {
121    int size = getNumElements();
122
123    multimap().put(null, v3());
124
125    assertGet(null, v3());
126    assertEquals(size + 1, multimap().size());
127  }
128
129  @MapFeature.Require(SUPPORTS_PUT)
130  public void testPutNotPresentKeyPropagatesToGet() {
131    int size = getNumElements();
132    Collection<V> collection = multimap().get(k3());
133    assertEmpty(collection);
134    multimap().put(k3(), v3());
135    assertContains(collection, v3());
136    assertEquals(size + 1, multimap().size());
137  }
138
139  @MapFeature.Require(SUPPORTS_PUT)
140  public void testPutNotPresentKeyPropagatesToEntries() {
141    Collection<Entry<K, V>> entries = multimap().entries();
142    assertFalse(entries.contains(mapEntry(k3(), v3())));
143    multimap().put(k3(), v3());
144    assertContains(entries, mapEntry(k3(), v3()));
145  }
146
147  @CollectionSize.Require(absent = ZERO)
148  @MapFeature.Require(SUPPORTS_PUT)
149  public void testPutPresentKeyPropagatesToEntries() {
150    Collection<Entry<K, V>> entries = multimap().entries();
151    assertFalse(entries.contains(mapEntry(k0(), v3())));
152    multimap().put(k0(), v3());
153    assertContains(entries, mapEntry(k0(), v3()));
154  }
155
156  @MapFeature.Require(SUPPORTS_PUT)
157  @CollectionSize.Require(absent = ZERO)
158  public void testPutPresentKeyPropagatesToGet() {
159    List<K> keys = copyToList(multimap().keySet());
160    for (K key : keys) {
161      resetContainer();
162
163      int size = getNumElements();
164
165      Collection<V> collection = multimap().get(key);
166      Collection<V> expectedCollection = copyToList(collection);
167
168      multimap().put(key, v3());
169      expectedCollection.add(v3());
170      assertEqualIgnoringOrder(expectedCollection, collection);
171      assertEquals(size + 1, multimap().size());
172    }
173  }
174
175  @MapFeature.Require(SUPPORTS_PUT)
176  @CollectionSize.Require(absent = ZERO)
177  public void testPutPresentKeyPropagatesToAsMapGet() {
178    List<K> keys = copyToList(multimap().keySet());
179    for (K key : keys) {
180      resetContainer();
181
182      int size = getNumElements();
183
184      Collection<V> collection = multimap().asMap().get(key);
185      assertNotNull(collection);
186      Collection<V> expectedCollection = copyToList(collection);
187
188      multimap().put(key, v3());
189      expectedCollection.add(v3());
190      assertEqualIgnoringOrder(expectedCollection, collection);
191      assertEquals(size + 1, multimap().size());
192    }
193  }
194
195  @MapFeature.Require(SUPPORTS_PUT)
196  @CollectionSize.Require(absent = ZERO)
197  public void testPutPresentKeyPropagatesToAsMapEntrySet() {
198    List<K> keys = copyToList(multimap().keySet());
199    for (K key : keys) {
200      resetContainer();
201
202      int size = getNumElements();
203
204      Iterator<Entry<K, Collection<V>>> asMapItr = multimap().asMap().entrySet().iterator();
205      Collection<V> collection = null;
206      while (asMapItr.hasNext()) {
207        Entry<K, Collection<V>> asMapEntry = asMapItr.next();
208        if (key.equals(asMapEntry.getKey())) {
209          collection = asMapEntry.getValue();
210          break;
211        }
212      }
213      assertNotNull(collection);
214      Collection<V> expectedCollection = copyToList(collection);
215
216      multimap().put(key, v3());
217      expectedCollection.add(v3());
218      assertEqualIgnoringOrder(expectedCollection, collection);
219      assertEquals(size + 1, multimap().size());
220    }
221  }
222}