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