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 org.junit.contrib.truth.Truth.ASSERT; 20 21 import java.io.Serializable; 22 import java.util.Arrays; 23 import java.util.Collection; 24 import java.util.Map; 25 import java.util.RandomAccess; 26 import java.util.Set; 27 28 import javax.annotation.Nullable; 29 30 /** 31 * Tests for {@code Synchronized#multimap}. 32 * 33 * @author Mike Bostock 34 */ 35 public class SynchronizedMultimapTest extends AbstractSetMultimapTest { 36 37 @Override protected Multimap<String, Integer> create() { 38 TestMultimap<String, Integer> inner = new TestMultimap<String, Integer>(); 39 Multimap<String, Integer> outer = Synchronized.multimap(inner, inner.mutex); 40 return outer; 41 } 42 43 private static final class TestMultimap<K, V> extends ForwardingMultimap<K, V> 44 implements Serializable { 45 final Multimap<K, V> delegate = HashMultimap.create(); 46 public final Object mutex = new Integer(1); // something Serializable 47 48 @Override protected Multimap<K, V> delegate() { 49 return delegate; 50 } 51 52 @Override public String toString() { 53 assertTrue(Thread.holdsLock(mutex)); 54 return super.toString(); 55 } 56 57 @Override public boolean equals(@Nullable Object o) { 58 assertTrue(Thread.holdsLock(mutex)); 59 return super.equals(o); 60 } 61 62 @Override public int hashCode() { 63 assertTrue(Thread.holdsLock(mutex)); 64 return super.hashCode(); 65 } 66 67 @Override public int size() { 68 assertTrue(Thread.holdsLock(mutex)); 69 return super.size(); 70 } 71 72 @Override public boolean isEmpty() { 73 assertTrue(Thread.holdsLock(mutex)); 74 return super.isEmpty(); 75 } 76 77 @Override public boolean containsKey(@Nullable Object key) { 78 assertTrue(Thread.holdsLock(mutex)); 79 return super.containsKey(key); 80 } 81 82 @Override public boolean containsValue(@Nullable Object value) { 83 assertTrue(Thread.holdsLock(mutex)); 84 return super.containsValue(value); 85 } 86 87 @Override public boolean containsEntry(@Nullable Object key, 88 @Nullable Object value) { 89 assertTrue(Thread.holdsLock(mutex)); 90 return super.containsEntry(key, value); 91 } 92 93 @Override public Collection<V> get(@Nullable K key) { 94 assertTrue(Thread.holdsLock(mutex)); 95 /* TODO: verify that the Collection is also synchronized? */ 96 return super.get(key); 97 } 98 99 @Override public boolean put(K key, V value) { 100 assertTrue(Thread.holdsLock(mutex)); 101 return super.put(key, value); 102 } 103 104 @Override public boolean putAll(@Nullable K key, 105 Iterable<? extends V> values) { 106 assertTrue(Thread.holdsLock(mutex)); 107 return super.putAll(key, values); 108 } 109 110 @Override public boolean putAll(Multimap<? extends K, ? extends V> map) { 111 assertTrue(Thread.holdsLock(mutex)); 112 return super.putAll(map); 113 } 114 115 @Override public Collection<V> replaceValues(@Nullable K key, 116 Iterable<? extends V> values) { 117 assertTrue(Thread.holdsLock(mutex)); 118 return super.replaceValues(key, values); 119 } 120 121 @Override public boolean remove(@Nullable Object key, 122 @Nullable Object value) { 123 assertTrue(Thread.holdsLock(mutex)); 124 return super.remove(key, value); 125 } 126 127 @Override public Collection<V> removeAll(@Nullable Object key) { 128 assertTrue(Thread.holdsLock(mutex)); 129 return super.removeAll(key); 130 } 131 132 @Override public void clear() { 133 assertTrue(Thread.holdsLock(mutex)); 134 super.clear(); 135 } 136 137 @Override public Set<K> keySet() { 138 assertTrue(Thread.holdsLock(mutex)); 139 /* TODO: verify that the Set is also synchronized? */ 140 return super.keySet(); 141 } 142 143 @Override public Multiset<K> keys() { 144 assertTrue(Thread.holdsLock(mutex)); 145 /* TODO: verify that the Set is also synchronized? */ 146 return super.keys(); 147 } 148 149 @Override public Collection<V> values() { 150 assertTrue(Thread.holdsLock(mutex)); 151 /* TODO: verify that the Collection is also synchronized? */ 152 return super.values(); 153 } 154 155 @Override public Collection<Map.Entry<K, V>> entries() { 156 assertTrue(Thread.holdsLock(mutex)); 157 /* TODO: verify that the Collection is also synchronized? */ 158 return super.entries(); 159 } 160 161 @Override public Map<K, Collection<V>> asMap() { 162 assertTrue(Thread.holdsLock(mutex)); 163 /* TODO: verify that the Map is also synchronized? */ 164 return super.asMap(); 165 } 166 167 private static final long serialVersionUID = 0; 168 } 169 170 public void testSynchronizedListMultimap() { 171 ListMultimap<String, Integer> multimap 172 = Multimaps.synchronizedListMultimap( 173 ArrayListMultimap.<String, Integer>create()); 174 multimap.putAll("foo", Arrays.asList(3, -1, 2, 4, 1)); 175 multimap.putAll("bar", Arrays.asList(1, 2, 3, 1)); 176 ASSERT.that(multimap.removeAll("foo")).hasContentsInOrder(3, -1, 2, 4, 1); 177 assertFalse(multimap.containsKey("foo")); 178 ASSERT.that(multimap.replaceValues("bar", Arrays.asList(6, 5))) 179 .hasContentsInOrder(1, 2, 3, 1); 180 ASSERT.that(multimap.get("bar")).hasContentsInOrder(6, 5); 181 } 182 183 public void testSynchronizedSortedSetMultimap() { 184 SortedSetMultimap<String, Integer> multimap 185 = Multimaps.synchronizedSortedSetMultimap( 186 TreeMultimap.<String, Integer>create()); 187 multimap.putAll("foo", Arrays.asList(3, -1, 2, 4, 1)); 188 multimap.putAll("bar", Arrays.asList(1, 2, 3, 1)); 189 ASSERT.that(multimap.removeAll("foo")).hasContentsInOrder(-1, 1, 2, 3, 4); 190 assertFalse(multimap.containsKey("foo")); 191 ASSERT.that(multimap.replaceValues("bar", Arrays.asList(6, 5))) 192 .hasContentsInOrder(1, 2, 3); 193 ASSERT.that(multimap.get("bar")).hasContentsInOrder(5, 6); 194 } 195 196 public void testSynchronizedArrayListMultimapRandomAccess() { 197 ListMultimap<String, Integer> delegate = ArrayListMultimap.create(); 198 delegate.put("foo", 1); 199 delegate.put("foo", 3); 200 ListMultimap<String, Integer> multimap 201 = Multimaps.synchronizedListMultimap(delegate); 202 assertTrue(multimap.get("foo") instanceof RandomAccess); 203 assertTrue(multimap.get("bar") instanceof RandomAccess); 204 } 205 206 public void testSynchronizedLinkedListMultimapRandomAccess() { 207 ListMultimap<String, Integer> delegate = LinkedListMultimap.create(); 208 delegate.put("foo", 1); 209 delegate.put("foo", 3); 210 ListMultimap<String, Integer> multimap 211 = Multimaps.synchronizedListMultimap(delegate); 212 assertFalse(multimap.get("foo") instanceof RandomAccess); 213 assertFalse(multimap.get("bar") instanceof RandomAccess); 214 } 215 } 216