1/*
2 * Copyright (C) 2010 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
17package com.google.common.collect;
18
19import com.google.common.collect.Synchronized.SynchronizedNavigableMap;
20import com.google.common.collect.Synchronized.SynchronizedNavigableSet;
21import com.google.common.collect.Synchronized.SynchronizedSortedMap;
22import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
23import com.google.common.collect.testing.SafeTreeMap;
24import com.google.common.collect.testing.TestStringSortedMapGenerator;
25import com.google.common.collect.testing.features.CollectionFeature;
26import com.google.common.collect.testing.features.CollectionSize;
27import com.google.common.collect.testing.features.MapFeature;
28import com.google.common.testing.SerializableTester;
29
30import junit.framework.TestSuite;
31
32import java.io.Serializable;
33import java.util.Comparator;
34import java.util.Map.Entry;
35import java.util.NavigableMap;
36import java.util.NavigableSet;
37import java.util.SortedMap;
38
39/**
40 * Tests for {@link Maps#synchronizedNavigableMap(NavigableMap)}.
41 *
42 * @author Louis Wasserman
43 */
44public class SynchronizedNavigableMapTest extends SynchronizedMapTest {
45  @Override protected <K, V> NavigableMap<K, V> create() {
46    @SuppressWarnings("unchecked")
47    NavigableMap<K, V> innermost = new SafeTreeMap<K, V>(
48        (Comparator<? super K>) Ordering.natural().nullsFirst());
49    TestMap<K, V> inner = new TestMap<K, V>(innermost, mutex);
50    NavigableMap<K, V> outer = Synchronized.navigableMap(inner, mutex);
51    return outer;
52  }
53
54  static class TestEntry<K, V> extends ForwardingMapEntry<K, V>
55      implements Serializable {
56    private final Entry<K, V> delegate;
57    private final Object mutex;
58
59    TestEntry(Entry<K, V> delegate, Object mutex) {
60      this.delegate = delegate;
61      this.mutex = mutex;
62    }
63
64    @Override protected Entry<K, V> delegate() {
65      return delegate;
66    }
67
68    @Override public boolean equals(Object object) {
69      assertTrue(Thread.holdsLock(mutex));
70      return super.equals(object);
71    }
72
73    @Override public K getKey() {
74      assertTrue(Thread.holdsLock(mutex));
75      return super.getKey();
76    }
77
78    @Override public V getValue() {
79      assertTrue(Thread.holdsLock(mutex));
80      return super.getValue();
81    }
82
83    @Override public int hashCode() {
84      assertTrue(Thread.holdsLock(mutex));
85      return super.hashCode();
86    }
87
88    @Override public V setValue(V value) {
89      assertTrue(Thread.holdsLock(mutex));
90      return super.setValue(value);
91    }
92
93    private static final long serialVersionUID = 0;
94  }
95
96  static class TestMap<K, V> extends SynchronizedMapTest.TestMap<K, V>
97      implements NavigableMap<K, V> {
98
99    public TestMap(NavigableMap<K, V> delegate, Object mutex) {
100      super(delegate, mutex);
101    }
102
103    @Override protected NavigableMap<K, V> delegate() {
104      return (NavigableMap<K, V>) super.delegate();
105    }
106
107    @Override public Entry<K, V> ceilingEntry(K key) {
108      assertTrue(Thread.holdsLock(mutex));
109      return delegate().ceilingEntry(key);
110    }
111
112    @Override public K ceilingKey(K key) {
113      assertTrue(Thread.holdsLock(mutex));
114      return delegate().ceilingKey(key);
115    }
116
117    @Override public NavigableSet<K> descendingKeySet() {
118      assertTrue(Thread.holdsLock(mutex));
119      return delegate().descendingKeySet();
120    }
121
122    @Override public NavigableMap<K, V> descendingMap() {
123      assertTrue(Thread.holdsLock(mutex));
124      return delegate().descendingMap();
125    }
126
127    @Override public Entry<K, V> firstEntry() {
128      assertTrue(Thread.holdsLock(mutex));
129      return delegate().firstEntry();
130    }
131
132    @Override public Entry<K, V> floorEntry(K key) {
133      assertTrue(Thread.holdsLock(mutex));
134      return delegate().floorEntry(key);
135    }
136
137    @Override public K floorKey(K key) {
138      assertTrue(Thread.holdsLock(mutex));
139      return delegate().floorKey(key);
140    }
141
142    @Override public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
143      assertTrue(Thread.holdsLock(mutex));
144      return delegate().headMap(toKey, inclusive);
145    }
146
147    @Override public SortedMap<K, V> headMap(K toKey) {
148      return headMap(toKey, false);
149    }
150
151    @Override public Entry<K, V> higherEntry(K key) {
152      assertTrue(Thread.holdsLock(mutex));
153      return delegate().higherEntry(key);
154    }
155
156    @Override public K higherKey(K key) {
157      assertTrue(Thread.holdsLock(mutex));
158      return delegate().higherKey(key);
159    }
160
161    @Override public Entry<K, V> lastEntry() {
162      assertTrue(Thread.holdsLock(mutex));
163      return delegate().lastEntry();
164    }
165
166    @Override public Entry<K, V> lowerEntry(K key) {
167      assertTrue(Thread.holdsLock(mutex));
168      return delegate().lowerEntry(key);
169    }
170
171    @Override public K lowerKey(K key) {
172      assertTrue(Thread.holdsLock(mutex));
173      return delegate().lowerKey(key);
174    }
175
176    @Override public NavigableSet<K> navigableKeySet() {
177      assertTrue(Thread.holdsLock(mutex));
178      return delegate().navigableKeySet();
179    }
180
181    @Override public Entry<K, V> pollFirstEntry() {
182      assertTrue(Thread.holdsLock(mutex));
183      return delegate().pollFirstEntry();
184    }
185
186    @Override public Entry<K, V> pollLastEntry() {
187      assertTrue(Thread.holdsLock(mutex));
188      return delegate().pollLastEntry();
189    }
190
191    @Override public NavigableMap<K, V> subMap(
192        K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
193      assertTrue(Thread.holdsLock(mutex));
194      return delegate().subMap(fromKey, fromInclusive, toKey, toInclusive);
195    }
196
197    @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
198      return delegate().subMap(fromKey, true, toKey, false);
199    }
200
201    @Override public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
202      assertTrue(Thread.holdsLock(mutex));
203      return delegate().tailMap(fromKey, inclusive);
204    }
205
206    @Override public SortedMap<K, V> tailMap(K fromKey) {
207      return tailMap(fromKey, true);
208    }
209
210    @Override public Comparator<? super K> comparator() {
211      assertTrue(Thread.holdsLock(mutex));
212      return delegate().comparator();
213    }
214
215    @Override public K firstKey() {
216      assertTrue(Thread.holdsLock(mutex));
217      return delegate().firstKey();
218    }
219
220    @Override public K lastKey() {
221      assertTrue(Thread.holdsLock(mutex));
222      return delegate().lastKey();
223    }
224
225    private static final long serialVersionUID = 0;
226  }
227
228  public static TestSuite suite() {
229    TestSuite suite = new TestSuite();
230    suite.addTestSuite(SynchronizedNavigableMapTest.class);
231    suite.addTest(
232        NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
233          private final Object mutex = new Integer(1);
234
235          @Override protected SortedMap<String, String> create(
236              Entry<String, String>[] entries) {
237            NavigableMap<String, String> innermost =
238                new SafeTreeMap<String, String>();
239            for (Entry<String, String> entry : entries) {
240              innermost.put(entry.getKey(), entry.getValue());
241            }
242            TestMap<String, String> inner =
243                new TestMap<String, String>(innermost, mutex);
244            NavigableMap<String, String> outer =
245                Synchronized.navigableMap(inner, mutex);
246            return outer;
247          }
248        }).named("Maps.synchronizedNavigableMap[SafeTreeMap]")
249            .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER,
250                MapFeature.GENERAL_PURPOSE, MapFeature.ALLOWS_NULL_VALUES,
251                CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
252            .createTestSuite());
253
254    return suite;
255  }
256
257  public void testComparator() {
258    create().comparator();
259  }
260
261  public void testCeilingEntry() {
262    create().ceilingEntry("a");
263  }
264
265  public void testCeilingKey() {
266    create().ceilingKey("a");
267  }
268
269  public void testDescendingKeySet() {
270    NavigableMap<String, Integer> map = create();
271    NavigableSet<String> descendingKeySet = map.descendingKeySet();
272    assertTrue(descendingKeySet instanceof SynchronizedNavigableSet);
273    assertSame(
274        mutex, ((SynchronizedNavigableSet<String>) descendingKeySet).mutex);
275  }
276
277  public void testDescendingMap() {
278    NavigableMap<String, Integer> map = create();
279    NavigableMap<String, Integer> descendingMap = map.descendingMap();
280    assertTrue(descendingMap instanceof SynchronizedNavigableMap);
281    assertSame(mutex,
282        ((SynchronizedNavigableMap<String, Integer>) descendingMap).mutex);
283  }
284
285  public void testFirstEntry() {
286    create().firstEntry();
287  }
288
289  public void testFirstKey() {
290    NavigableMap<String, Integer> map = create();
291    map.put("a", 1);
292    map.firstKey();
293  }
294
295  public void testFloorEntry() {
296    create().floorEntry("a");
297  }
298
299  public void testFloorKey() {
300    create().floorKey("a");
301  }
302
303  public void testHeadMap_K() {
304    NavigableMap<String, Integer> map = create();
305    SortedMap<String, Integer> headMap = map.headMap("a");
306    assertTrue(headMap instanceof SynchronizedSortedMap);
307    assertSame(mutex, ((SynchronizedSortedMap<String, Integer>) headMap).mutex);
308  }
309
310  public void testHeadMap_K_B() {
311    NavigableMap<String, Integer> map = create();
312    NavigableMap<String, Integer> headMap = map.headMap("a", true);
313    assertTrue(headMap instanceof SynchronizedNavigableMap);
314    assertSame(
315        mutex, ((SynchronizedNavigableMap<String, Integer>) headMap).mutex);
316  }
317
318  public void testHigherEntry() {
319    create().higherEntry("a");
320  }
321
322  public void testHigherKey() {
323    create().higherKey("a");
324  }
325
326  public void testLastEntry() {
327    create().lastEntry();
328  }
329
330  public void testLastKey() {
331    NavigableMap<String, Integer> map = create();
332    map.put("a", 1);
333    map.lastKey();
334  }
335
336  public void testLowerEntry() {
337    create().lowerEntry("a");
338  }
339
340  public void testLowerKey() {
341    create().lowerKey("a");
342  }
343
344  public void testNavigableKeySet() {
345    NavigableMap<String, Integer> map = create();
346    NavigableSet<String> navigableKeySet = map.navigableKeySet();
347    assertTrue(navigableKeySet instanceof SynchronizedNavigableSet);
348    assertSame(
349        mutex, ((SynchronizedNavigableSet<String>) navigableKeySet).mutex);
350  }
351
352  public void testPollFirstEntry() {
353    create().pollFirstEntry();
354  }
355
356  public void testPollLastEntry() {
357    create().pollLastEntry();
358  }
359
360  public void testSubMap_K_K() {
361    NavigableMap<String, Integer> map = create();
362    SortedMap<String, Integer> subMap = map.subMap("a", "b");
363    assertTrue(subMap instanceof SynchronizedSortedMap);
364    assertSame(mutex, ((SynchronizedSortedMap<String, Integer>) subMap).mutex);
365  }
366
367  public void testSubMap_K_B_K_B() {
368    NavigableMap<String, Integer> map = create();
369    NavigableMap<String, Integer> subMap = map.subMap("a", true, "b", false);
370    assertTrue(subMap instanceof SynchronizedNavigableMap);
371    assertSame(
372        mutex, ((SynchronizedNavigableMap<String, Integer>) subMap).mutex);
373  }
374
375  public void testTailMap_K() {
376    NavigableMap<String, Integer> map = create();
377    SortedMap<String, Integer> subMap = map.tailMap("a");
378    assertTrue(subMap instanceof SynchronizedSortedMap);
379    assertSame(mutex, ((SynchronizedSortedMap<String, Integer>) subMap).mutex);
380  }
381
382  public void testTailMap_K_B() {
383    NavigableMap<String, Integer> map = create();
384    NavigableMap<String, Integer> subMap = map.tailMap("a", true);
385    assertTrue(subMap instanceof SynchronizedNavigableMap);
386    assertSame(
387        mutex, ((SynchronizedNavigableMap<String, Integer>) subMap).mutex);
388  }
389
390  @Override public void testSerialization() {
391    SerializableTester.reserializeAndAssert(create());
392  }
393}
394