1 /*
2  * Copyright (C) 2012 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.common.collect.testing.google;
17 
18 import static com.google.common.base.Preconditions.checkState;
19 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
20 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
21 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
22 import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT;
23 import static org.truth0.Truth.ASSERT;
24 
25 import com.google.common.annotations.GwtCompatible;
26 import com.google.common.collect.Iterators;
27 import com.google.common.collect.Lists;
28 import com.google.common.collect.Multimap;
29 import com.google.common.collect.testing.features.CollectionSize;
30 import com.google.common.collect.testing.features.MapFeature;
31 
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.Iterator;
35 
36 /**
37  * Tests for {@link Multimap#putAll(Object, Iterable)}.
38  *
39  * @author Louis Wasserman
40  */
41 @GwtCompatible
42 public class MultimapPutIterableTester<K, V> extends AbstractMultimapTester<K, V, Multimap<K, V>> {
43   @CollectionSize.Require(absent = ZERO)
44   @MapFeature.Require(SUPPORTS_PUT)
testPutAllNonEmptyIterableOnPresentKey()45   public void testPutAllNonEmptyIterableOnPresentKey() {
46     assertTrue(multimap().putAll(sampleKeys().e0, new Iterable<V>() {
47       @Override
48       public Iterator<V> iterator() {
49         return Lists.newArrayList(sampleValues().e3, sampleValues().e4).iterator();
50       }
51     }));
52     assertGet(sampleKeys().e0, sampleValues().e0, sampleValues().e3, sampleValues().e4);
53   }
54 
55   @CollectionSize.Require(absent = ZERO)
56   @MapFeature.Require(SUPPORTS_PUT)
testPutAllNonEmptyCollectionOnPresentKey()57   public void testPutAllNonEmptyCollectionOnPresentKey() {
58     assertTrue(multimap().putAll(
59         sampleKeys().e0, Lists.newArrayList(sampleValues().e3, sampleValues().e4)));
60     assertGet(sampleKeys().e0, sampleValues().e0, sampleValues().e3, sampleValues().e4);
61   }
62 
63   @MapFeature.Require(SUPPORTS_PUT)
testPutAllNonEmptyIterableOnAbsentKey()64   public void testPutAllNonEmptyIterableOnAbsentKey() {
65     assertTrue(multimap().putAll(sampleKeys().e3, new Iterable<V>() {
66       @Override
67       public Iterator<V> iterator() {
68         return Lists.newArrayList(sampleValues().e3, sampleValues().e4).iterator();
69       }
70     }));
71     assertGet(sampleKeys().e3, sampleValues().e3, sampleValues().e4);
72   }
73 
74   @MapFeature.Require(SUPPORTS_PUT)
testPutAllNonEmptyCollectionOnAbsentKey()75   public void testPutAllNonEmptyCollectionOnAbsentKey() {
76     assertTrue(multimap().putAll(
77         sampleKeys().e3, Lists.newArrayList(sampleValues().e3, sampleValues().e4)));
78     assertGet(sampleKeys().e3, sampleValues().e3, sampleValues().e4);
79   }
80 
81   @CollectionSize.Require(absent = ZERO)
82   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
testPutAllNullValueOnPresentKey_supported()83   public void testPutAllNullValueOnPresentKey_supported() {
84     assertTrue(multimap().putAll(sampleKeys().e0, Lists.newArrayList(sampleValues().e3, null)));
85     assertGet(sampleKeys().e0, sampleValues().e0, sampleValues().e3, null);
86   }
87 
88   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
testPutAllNullValueOnAbsentKey_supported()89   public void testPutAllNullValueOnAbsentKey_supported() {
90     assertTrue(multimap().putAll(sampleKeys().e3, Lists.newArrayList(sampleValues().e3, null)));
91     assertGet(sampleKeys().e3, sampleValues().e3, null);
92   }
93 
94   @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
testPutAllNullValueSingle_unsupported()95   public void testPutAllNullValueSingle_unsupported() {
96     multimap().putAll(sampleKeys().e1, Lists.newArrayList((V) null));
97     expectUnchanged();
98   }
99 
100   // In principle, it would be nice to apply these two tests to keys with existing values, too.
101 
102   @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
testPutAllNullValueNullLast_unsupported()103   public void testPutAllNullValueNullLast_unsupported() {
104     int size = getNumElements();
105 
106     try {
107       multimap().putAll(sampleKeys().e3, Lists.newArrayList(sampleValues().e3, null));
108       fail();
109     } catch (NullPointerException expected) {
110     }
111 
112     Collection<V> values = multimap().get(sampleKeys().e3);
113     if (values.size() == 0) {
114       expectUnchanged();
115       // Be extra thorough in case internal state was corrupted by the expected null.
116       assertEquals(Lists.newArrayList(), Lists.newArrayList(values));
117       assertEquals(size, multimap().size());
118     } else {
119       assertEquals(Lists.newArrayList(sampleValues().e3), Lists.newArrayList(values));
120       assertEquals(size + 1, multimap().size());
121     }
122   }
123 
124   @MapFeature.Require(value = SUPPORTS_PUT, absent = ALLOWS_NULL_VALUES)
testPutAllNullValueNullFirst_unsupported()125   public void testPutAllNullValueNullFirst_unsupported() {
126     int size = getNumElements();
127 
128     try {
129       multimap().putAll(sampleKeys().e3, Lists.newArrayList(null, sampleValues().e3));
130       fail();
131     } catch (NullPointerException expected) {
132     }
133 
134     /*
135      * In principle, a Multimap implementation could add e3 first before failing on the null. But
136      * that seems unlikely enough to be worth complicating the test over, especially if there's any
137      * chance that a permissive test could mask a bug.
138      */
139     expectUnchanged();
140     // Be extra thorough in case internal state was corrupted by the expected null.
141     assertEquals(Lists.newArrayList(), Lists.newArrayList(multimap().get(sampleKeys().e3)));
142     assertEquals(size, multimap().size());
143   }
144 
145   @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})
testPutAllOnPresentNullKey()146   public void testPutAllOnPresentNullKey() {
147     assertTrue(multimap().putAll(null, Lists.newArrayList(sampleValues().e3, sampleValues().e4)));
148     assertGet(null, sampleValues().e3, sampleValues().e4);
149   }
150 
151   @MapFeature.Require(absent = ALLOWS_NULL_KEYS)
testPutAllNullForbidden()152   public void testPutAllNullForbidden() {
153     try {
154       multimap().putAll(null, Collections.singletonList(sampleValues().e3));
155       fail("Expected NullPointerException");
156     } catch (NullPointerException expected) {
157       // success
158     }
159   }
160 
161   private static final Object[] EMPTY = new Object[0];
162 
163   @MapFeature.Require(SUPPORTS_PUT)
testPutAllEmptyCollectionOnAbsentKey()164   public void testPutAllEmptyCollectionOnAbsentKey() {
165     assertFalse(multimap().putAll(sampleKeys().e3, Collections.<V>emptyList()));
166     expectUnchanged();
167   }
168 
169   @MapFeature.Require(SUPPORTS_PUT)
testPutAllEmptyIterableOnAbsentKey()170   public void testPutAllEmptyIterableOnAbsentKey() {
171     Iterable<V> iterable = new Iterable<V>() {
172       @Override
173       public Iterator<V> iterator() {
174         return Iterators.emptyIterator();
175       }
176     };
177 
178     assertFalse(multimap().putAll(sampleKeys().e3, iterable));
179     expectUnchanged();
180   }
181 
182   @CollectionSize.Require(absent = ZERO)
183   @MapFeature.Require(SUPPORTS_PUT)
testPutAllEmptyIterableOnPresentKey()184   public void testPutAllEmptyIterableOnPresentKey() {
185     multimap().putAll(sampleKeys().e0, Collections.<V>emptyList());
186     expectUnchanged();
187   }
188 
189   @MapFeature.Require(SUPPORTS_PUT)
testPutAllOnlyCallsIteratorOnce()190   public void testPutAllOnlyCallsIteratorOnce() {
191     Iterable<V> iterable = new Iterable<V>() {
192       private boolean calledIteratorAlready = false;
193 
194       @Override
195       public Iterator<V> iterator() {
196         checkState(!calledIteratorAlready);
197         calledIteratorAlready = true;
198         return Iterators.forArray(sampleValues().e3);
199       }
200     };
201 
202     multimap().putAll(sampleKeys().e3, iterable);
203   }
204 
205   @MapFeature.Require(SUPPORTS_PUT)
testPutAllPropagatesToGet()206   public void testPutAllPropagatesToGet() {
207     Collection<V> getCollection = multimap().get(sampleKeys().e0);
208     int getCollectionSize = getCollection.size();
209     assertTrue(multimap().putAll(
210         sampleKeys().e0, Lists.newArrayList(sampleValues().e3, sampleValues().e4)));
211     assertEquals(getCollectionSize + 2, getCollection.size());
212     ASSERT.that(getCollection).has().allOf(sampleValues().e3, sampleValues().e4);
213   }
214 }
215