Home | History | Annotate | Download | only in collect
      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 
     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 
     79     @Override protected SetMultimap<K, V> delegate() {
     80       return delegate;
     81     }
     82 
     83     @Override public String toString() {
     84       assertTrue(Thread.holdsLock(mutex));
     85       return super.toString();
     86     }
     87 
     88     @Override public boolean equals(@Nullable Object o) {
     89       assertTrue(Thread.holdsLock(mutex));
     90       return super.equals(o);
     91     }
     92 
     93     @Override public int hashCode() {
     94       assertTrue(Thread.holdsLock(mutex));
     95       return super.hashCode();
     96     }
     97 
     98     @Override public int size() {
     99       assertTrue(Thread.holdsLock(mutex));
    100       return super.size();
    101     }
    102 
    103     @Override public boolean isEmpty() {
    104       assertTrue(Thread.holdsLock(mutex));
    105       return super.isEmpty();
    106     }
    107 
    108     @Override public boolean containsKey(@Nullable Object key) {
    109       assertTrue(Thread.holdsLock(mutex));
    110       return super.containsKey(key);
    111     }
    112 
    113     @Override public boolean containsValue(@Nullable Object value) {
    114       assertTrue(Thread.holdsLock(mutex));
    115       return super.containsValue(value);
    116     }
    117 
    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 
    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 
    130     @Override public boolean put(K key, V value) {
    131       assertTrue(Thread.holdsLock(mutex));
    132       return super.put(key, value);
    133     }
    134 
    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 
    141     @Override public boolean putAll(Multimap<? extends K, ? extends V> map) {
    142       assertTrue(Thread.holdsLock(mutex));
    143       return super.putAll(map);
    144     }
    145 
    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 
    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 
    158     @Override public Set<V> removeAll(@Nullable Object key) {
    159       assertTrue(Thread.holdsLock(mutex));
    160       return super.removeAll(key);
    161     }
    162 
    163     @Override public void clear() {
    164       assertTrue(Thread.holdsLock(mutex));
    165       super.clear();
    166     }
    167 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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