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