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.base.Preconditions.checkArgument;
20 
21 import com.google.common.collect.Synchronized.SynchronizedBiMap;
22 import com.google.common.collect.Synchronized.SynchronizedSet;
23 import com.google.common.collect.testing.features.CollectionFeature;
24 import com.google.common.collect.testing.features.CollectionSize;
25 import com.google.common.collect.testing.features.MapFeature;
26 import com.google.common.collect.testing.google.BiMapInverseTester;
27 import com.google.common.collect.testing.google.BiMapTestSuiteBuilder;
28 import com.google.common.collect.testing.google.TestStringBiMapGenerator;
29 
30 import junit.framework.TestSuite;
31 
32 import java.util.Map.Entry;
33 import java.util.Set;
34 
35 /**
36  * Tests for {@code Synchronized#biMap}.
37  *
38  * @author Mike Bostock
39  */
40 public class SynchronizedBiMapTest extends SynchronizedMapTest {
41 
42   public static TestSuite suite() {
43     TestSuite suite = new TestSuite(SynchronizedBiMapTest.class);
44     suite.addTest(BiMapTestSuiteBuilder.using(new SynchTestingBiMapGenerator())
45         .named("Synchronized.biMap[TestBiMap]")
46         .withFeatures(CollectionSize.ANY,
47             CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
48             MapFeature.ALLOWS_NULL_KEYS,
49             MapFeature.ALLOWS_NULL_VALUES,
50             MapFeature.ALLOWS_ANY_NULL_QUERIES,
51             MapFeature.GENERAL_PURPOSE,
52             MapFeature.REJECTS_DUPLICATES_AT_CREATION)
53         .createTestSuite());
54     suite.addTest(BiMapTestSuiteBuilder.using(new SynchronizedHashBiMapGenerator())
55         .named("synchronizedBiMap[HashBiMap]")
56         .withFeatures(CollectionSize.ANY,
57             CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
58             MapFeature.ALLOWS_NULL_KEYS,
59             MapFeature.ALLOWS_NULL_VALUES,
60             MapFeature.ALLOWS_ANY_NULL_QUERIES,
61             MapFeature.GENERAL_PURPOSE,
62             MapFeature.REJECTS_DUPLICATES_AT_CREATION,
63             CollectionFeature.SERIALIZABLE)
64         .suppressing(BiMapInverseTester.getInverseSameAfterSerializingMethods())
65         .createTestSuite());
66     return suite;
67   }
68 
69   @Override protected <K, V> BiMap<K, V> create() {
70     TestBiMap<K, V> inner =
71         new TestBiMap<K, V>(HashBiMap.<K, V>create(), mutex);
72     BiMap<K, V> outer = Synchronized.biMap(inner, mutex);
73     return outer;
74   }
75 
76   public static final class SynchronizedHashBiMapGenerator extends TestStringBiMapGenerator {
77     @Override
78     protected BiMap<String, String> create(Entry<String, String>[] entries) {
79       Object mutex = new Object();
80       BiMap<String, String> result = HashBiMap.create();
81       for (Entry<String, String> entry : entries) {
82         checkArgument(!result.containsKey(entry.getKey()));
83         result.put(entry.getKey(), entry.getValue());
84       }
85       return Maps.synchronizedBiMap(result);
86     }
87   }
88 
89   public static final class SynchTestingBiMapGenerator extends TestStringBiMapGenerator {
90     @Override
91     protected BiMap<String, String> create(Entry<String, String>[] entries) {
92       Object mutex = new Object();
93       BiMap<String, String> backing =
94           new TestBiMap<String, String>(HashBiMap.<String, String>create(), mutex);
95       BiMap<String, String> result = Synchronized.biMap(backing, mutex);
96       for (Entry<String, String> entry : entries) {
97         checkArgument(!result.containsKey(entry.getKey()));
98         result.put(entry.getKey(), entry.getValue());
99       }
100       return result;
101     }
102   }
103 
104   static class TestBiMap<K, V> extends TestMap<K, V> implements BiMap<K, V> {
105     private final BiMap<K, V> delegate;
106 
107     public TestBiMap(BiMap<K, V> delegate, Object mutex) {
108       super(delegate, mutex);
109       this.delegate = delegate;
110     }
111 
112     @Override
113     public V forcePut(K key, V value) {
114       assertTrue(Thread.holdsLock(mutex));
115       return delegate.forcePut(key, value);
116     }
117 
118     @Override
119     public BiMap<V, K> inverse() {
120       assertTrue(Thread.holdsLock(mutex));
121       return delegate.inverse();
122     }
123 
124     @Override public Set<V> values() {
125       assertTrue(Thread.holdsLock(mutex));
126       return delegate.values();
127     }
128 
129     private static final long serialVersionUID = 0;
130   }
131 
132   public void testForcePut() {
133     create().forcePut(null, null);
134   }
135 
136   public void testInverse() {
137     BiMap<String, Integer> bimap = create();
138     BiMap<Integer, String> inverse = bimap.inverse();
139     assertSame(bimap, inverse.inverse());
140     assertTrue(inverse instanceof SynchronizedBiMap);
141     assertSame(mutex, ((SynchronizedBiMap<?, ?>) inverse).mutex);
142   }
143 
144   @Override public void testValues() {
145     BiMap<String, Integer> map = create();
146     Set<Integer> values = map.values();
147     assertTrue(values instanceof SynchronizedSet);
148     assertSame(mutex, ((SynchronizedSet<?>) values).mutex);
149   }
150 }
151