• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 
17 package com.google.common.collect;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import com.google.common.collect.testing.features.CollectionFeature;
22 import com.google.common.collect.testing.features.CollectionSize;
23 import com.google.common.collect.testing.features.MapFeature;
24 import com.google.common.collect.testing.google.SetMultimapTestSuiteBuilder;
25 import com.google.common.collect.testing.google.TestStringSetMultimapGenerator;
26 import java.io.Serializable;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.RandomAccess;
32 import java.util.Set;
33 import junit.framework.Test;
34 import junit.framework.TestCase;
35 import junit.framework.TestSuite;
36 import org.checkerframework.checker.nullness.qual.Nullable;
37 
38 /**
39  * Tests for {@code Synchronized#multimap}.
40  *
41  * @author Mike Bostock
42  */
43 public class SynchronizedMultimapTest extends TestCase {
44 
suite()45   public static Test suite() {
46     TestSuite suite = new TestSuite();
47     suite.addTestSuite(SynchronizedMultimapTest.class);
48     suite.addTest(
49         SetMultimapTestSuiteBuilder.using(
50                 new TestStringSetMultimapGenerator() {
51                   @Override
52                   protected SetMultimap<String, String> create(Entry<String, String>[] entries) {
53                     TestMultimap<String, String> inner = new TestMultimap<>();
54                     SetMultimap<String, String> outer =
55                         Synchronized.setMultimap(inner, inner.mutex);
56                     for (Entry<String, String> entry : entries) {
57                       outer.put(entry.getKey(), entry.getValue());
58                     }
59                     return outer;
60                   }
61                 })
62             .named("Synchronized.setMultimap")
63             .withFeatures(
64                 MapFeature.GENERAL_PURPOSE,
65                 CollectionSize.ANY,
66                 CollectionFeature.SERIALIZABLE,
67                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
68                 MapFeature.ALLOWS_NULL_KEYS,
69                 MapFeature.ALLOWS_NULL_VALUES,
70                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
71             .createTestSuite());
72     return suite;
73   }
74 
75   private static final class TestMultimap<K, V> extends ForwardingSetMultimap<K, V>
76       implements Serializable {
77     final SetMultimap<K, V> delegate = HashMultimap.create();
78     public final Object mutex = new Object[0]; // something Serializable
79 
80     @Override
delegate()81     protected SetMultimap<K, V> delegate() {
82       return delegate;
83     }
84 
85     @Override
toString()86     public String toString() {
87       assertTrue(Thread.holdsLock(mutex));
88       return super.toString();
89     }
90 
91     @Override
equals(@ullable Object o)92     public boolean equals(@Nullable Object o) {
93       assertTrue(Thread.holdsLock(mutex));
94       return super.equals(o);
95     }
96 
97     @Override
hashCode()98     public int hashCode() {
99       assertTrue(Thread.holdsLock(mutex));
100       return super.hashCode();
101     }
102 
103     @Override
size()104     public int size() {
105       assertTrue(Thread.holdsLock(mutex));
106       return super.size();
107     }
108 
109     @Override
isEmpty()110     public boolean isEmpty() {
111       assertTrue(Thread.holdsLock(mutex));
112       return super.isEmpty();
113     }
114 
115     @Override
containsKey(@ullable Object key)116     public boolean containsKey(@Nullable Object key) {
117       assertTrue(Thread.holdsLock(mutex));
118       return super.containsKey(key);
119     }
120 
121     @Override
containsValue(@ullable Object value)122     public boolean containsValue(@Nullable Object value) {
123       assertTrue(Thread.holdsLock(mutex));
124       return super.containsValue(value);
125     }
126 
127     @Override
containsEntry(@ullable Object key, @Nullable Object value)128     public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
129       assertTrue(Thread.holdsLock(mutex));
130       return super.containsEntry(key, value);
131     }
132 
133     @Override
get(@ullable K key)134     public Set<V> get(@Nullable K key) {
135       assertTrue(Thread.holdsLock(mutex));
136       /* TODO: verify that the Set is also synchronized? */
137       return super.get(key);
138     }
139 
140     @Override
put(K key, V value)141     public boolean put(K key, V value) {
142       assertTrue(Thread.holdsLock(mutex));
143       return super.put(key, value);
144     }
145 
146     @Override
putAll(@ullable K key, Iterable<? extends V> values)147     public boolean putAll(@Nullable K key, Iterable<? extends V> values) {
148       assertTrue(Thread.holdsLock(mutex));
149       return super.putAll(key, values);
150     }
151 
152     @Override
putAll(Multimap<? extends K, ? extends V> map)153     public boolean putAll(Multimap<? extends K, ? extends V> map) {
154       assertTrue(Thread.holdsLock(mutex));
155       return super.putAll(map);
156     }
157 
158     @Override
replaceValues(@ullable K key, Iterable<? extends V> values)159     public Set<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
160       assertTrue(Thread.holdsLock(mutex));
161       return super.replaceValues(key, values);
162     }
163 
164     @Override
remove(@ullable Object key, @Nullable Object value)165     public boolean remove(@Nullable Object key, @Nullable Object value) {
166       assertTrue(Thread.holdsLock(mutex));
167       return super.remove(key, value);
168     }
169 
170     @Override
removeAll(@ullable Object key)171     public Set<V> removeAll(@Nullable Object key) {
172       assertTrue(Thread.holdsLock(mutex));
173       return super.removeAll(key);
174     }
175 
176     @Override
clear()177     public void clear() {
178       assertTrue(Thread.holdsLock(mutex));
179       super.clear();
180     }
181 
182     @Override
keySet()183     public Set<K> keySet() {
184       assertTrue(Thread.holdsLock(mutex));
185       /* TODO: verify that the Set is also synchronized? */
186       return super.keySet();
187     }
188 
189     @Override
keys()190     public Multiset<K> keys() {
191       assertTrue(Thread.holdsLock(mutex));
192       /* TODO: verify that the Multiset is also synchronized? */
193       return super.keys();
194     }
195 
196     @Override
values()197     public Collection<V> values() {
198       assertTrue(Thread.holdsLock(mutex));
199       /* TODO: verify that the Collection is also synchronized? */
200       return super.values();
201     }
202 
203     @Override
entries()204     public Set<Entry<K, V>> entries() {
205       assertTrue(Thread.holdsLock(mutex));
206       /* TODO: verify that the Set is also synchronized? */
207       return super.entries();
208     }
209 
210     @Override
asMap()211     public Map<K, Collection<V>> asMap() {
212       assertTrue(Thread.holdsLock(mutex));
213       /* TODO: verify that the Map is also synchronized? */
214       return super.asMap();
215     }
216 
217     private static final long serialVersionUID = 0;
218   }
219 
testSynchronizedListMultimap()220   public void testSynchronizedListMultimap() {
221     ListMultimap<String, Integer> multimap =
222         Multimaps.synchronizedListMultimap(ArrayListMultimap.<String, Integer>create());
223     multimap.putAll("foo", Arrays.asList(3, -1, 2, 4, 1));
224     multimap.putAll("bar", Arrays.asList(1, 2, 3, 1));
225     assertThat(multimap.removeAll("foo")).containsExactly(3, -1, 2, 4, 1).inOrder();
226     assertFalse(multimap.containsKey("foo"));
227     assertThat(multimap.replaceValues("bar", Arrays.asList(6, 5)))
228         .containsExactly(1, 2, 3, 1)
229         .inOrder();
230     assertThat(multimap.get("bar")).containsExactly(6, 5).inOrder();
231   }
232 
testSynchronizedSortedSetMultimap()233   public void testSynchronizedSortedSetMultimap() {
234     SortedSetMultimap<String, Integer> multimap =
235         Multimaps.synchronizedSortedSetMultimap(TreeMultimap.<String, Integer>create());
236     multimap.putAll("foo", Arrays.asList(3, -1, 2, 4, 1));
237     multimap.putAll("bar", Arrays.asList(1, 2, 3, 1));
238     assertThat(multimap.removeAll("foo")).containsExactly(-1, 1, 2, 3, 4).inOrder();
239     assertFalse(multimap.containsKey("foo"));
240     assertThat(multimap.replaceValues("bar", Arrays.asList(6, 5)))
241         .containsExactly(1, 2, 3)
242         .inOrder();
243     assertThat(multimap.get("bar")).containsExactly(5, 6).inOrder();
244   }
245 
testSynchronizedArrayListMultimapRandomAccess()246   public void testSynchronizedArrayListMultimapRandomAccess() {
247     ListMultimap<String, Integer> delegate = ArrayListMultimap.create();
248     delegate.put("foo", 1);
249     delegate.put("foo", 3);
250     ListMultimap<String, Integer> multimap = Multimaps.synchronizedListMultimap(delegate);
251     assertTrue(multimap.get("foo") instanceof RandomAccess);
252     assertTrue(multimap.get("bar") instanceof RandomAccess);
253   }
254 
testSynchronizedLinkedListMultimapRandomAccess()255   public void testSynchronizedLinkedListMultimapRandomAccess() {
256     ListMultimap<String, Integer> delegate = LinkedListMultimap.create();
257     delegate.put("foo", 1);
258     delegate.put("foo", 3);
259     ListMultimap<String, Integer> multimap = Multimaps.synchronizedListMultimap(delegate);
260     assertFalse(multimap.get("foo") instanceof RandomAccess);
261     assertFalse(multimap.get("bar") instanceof RandomAccess);
262   }
263 }
264