1/*
2 * Copyright (C) 2011 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 static com.google.common.collect.Maps.immutableEntry;
20
21import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
22import com.google.common.collect.testing.SafeTreeMap;
23import com.google.common.collect.testing.TestStringSortedMapGenerator;
24import com.google.common.collect.testing.features.CollectionFeature;
25import com.google.common.collect.testing.features.CollectionSize;
26import com.google.common.collect.testing.features.MapFeature;
27
28import junit.framework.Test;
29import junit.framework.TestSuite;
30
31import java.util.Collection;
32import java.util.Iterator;
33import java.util.Map;
34import java.util.Map.Entry;
35import java.util.NavigableMap;
36import java.util.NavigableSet;
37import java.util.Set;
38import java.util.SortedMap;
39
40/**
41 * Tests for {@code ForwardingNavigableMap}.
42 *
43 * @author Robert Konigsberg
44 * @author Louis Wasserman
45 */
46public class ForwardingNavigableMapTest extends ForwardingSortedMapTest {
47  static class StandardImplForwardingNavigableMap<K, V>
48      extends ForwardingNavigableMap<K, V> {
49    private final NavigableMap<K, V> backingMap;
50
51    StandardImplForwardingNavigableMap(NavigableMap<K, V> backingMap) {
52      this.backingMap = backingMap;
53    }
54
55    @Override protected NavigableMap<K, V> delegate() {
56      return backingMap;
57    }
58
59    @Override public boolean containsKey(Object key) {
60      return standardContainsKey(key);
61    }
62
63    @Override public boolean containsValue(Object value) {
64      return standardContainsValue(value);
65    }
66
67    @Override public void putAll(Map<? extends K, ? extends V> map) {
68      standardPutAll(map);
69    }
70
71    @Override public V remove(Object object) {
72      return standardRemove(object);
73    }
74
75    @Override public boolean equals(Object object) {
76      return standardEquals(object);
77    }
78
79    @Override public int hashCode() {
80      return standardHashCode();
81    }
82
83    @Override public Set<K> keySet() {
84      /*
85       * We can't use StandardKeySet, as NavigableMapTestSuiteBuilder assumes that our keySet is a
86       * NavigableSet. We test StandardKeySet in the superclass, so it's still covered.
87       */
88      return navigableKeySet();
89    }
90
91    @Override public Collection<V> values() {
92      return new StandardValues();
93    }
94
95    @Override public String toString() {
96      return standardToString();
97    }
98
99    @Override public Set<Entry<K, V>> entrySet() {
100      return new StandardEntrySet() {
101        @Override
102        public Iterator<Entry<K, V>> iterator() {
103          return backingMap.entrySet().iterator();
104        }
105      };
106    }
107
108    @Override public void clear() {
109      standardClear();
110    }
111
112    @Override public boolean isEmpty() {
113      return standardIsEmpty();
114    }
115
116    @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
117      return standardSubMap(fromKey, toKey);
118    }
119
120    @Override
121    public Entry<K, V> lowerEntry(K key) {
122      return standardLowerEntry(key);
123    }
124
125    @Override
126    public K lowerKey(K key) {
127      return standardLowerKey(key);
128    }
129
130    @Override
131    public Entry<K, V> floorEntry(K key) {
132      return standardFloorEntry(key);
133    }
134
135    @Override
136    public K floorKey(K key) {
137      return standardFloorKey(key);
138    }
139
140    @Override
141    public Entry<K, V> ceilingEntry(K key) {
142      return standardCeilingEntry(key);
143    }
144
145    @Override
146    public K ceilingKey(K key) {
147      return standardCeilingKey(key);
148    }
149
150    @Override
151    public Entry<K, V> higherEntry(K key) {
152      return standardHigherEntry(key);
153    }
154
155    @Override
156    public K higherKey(K key) {
157      return standardHigherKey(key);
158    }
159
160    @Override
161    public Entry<K, V> firstEntry() {
162      return standardFirstEntry();
163    }
164
165    /*
166     * We can't override lastEntry to delegate to standardLastEntry, as it would create an infinite
167     * loop. Instead, we test standardLastEntry manually below.
168     */
169
170    @Override
171    public Entry<K, V> pollFirstEntry() {
172      return standardPollFirstEntry();
173    }
174
175    @Override
176    public Entry<K, V> pollLastEntry() {
177      return standardPollLastEntry();
178    }
179
180    @Override
181    public NavigableMap<K, V> descendingMap() {
182      return new StandardDescendingMap();
183    }
184
185    @Override
186    public NavigableSet<K> navigableKeySet() {
187      return new StandardNavigableKeySet();
188    }
189
190    @Override
191    public NavigableSet<K> descendingKeySet() {
192      return standardDescendingKeySet();
193    }
194
195    @Override
196    public K firstKey() {
197      return standardFirstKey();
198    }
199
200    @Override
201    public SortedMap<K, V> headMap(K toKey) {
202      return standardHeadMap(toKey);
203    }
204
205    @Override
206    public K lastKey() {
207      return standardLastKey();
208    }
209
210    @Override
211    public SortedMap<K, V> tailMap(K fromKey) {
212      return standardTailMap(fromKey);
213    }
214  }
215
216  static class StandardLastEntryForwardingNavigableMap<K, V>
217      extends ForwardingNavigableMap<K, V> {
218    private final NavigableMap<K, V> backingMap;
219
220    StandardLastEntryForwardingNavigableMap(NavigableMap<K, V> backingMap) {
221      this.backingMap = backingMap;
222    }
223
224    @Override protected NavigableMap<K, V> delegate() {
225      return backingMap;
226    }
227
228    @Override
229    public Entry<K, V> lastEntry() {
230      return standardLastEntry();
231    }
232  }
233
234  public static Test suite() {
235    TestSuite suite = new TestSuite();
236
237    suite.addTestSuite(ForwardingNavigableMapTest.class);
238    suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
239      @Override protected SortedMap<String, String> create(
240          Entry<String, String>[] entries) {
241        NavigableMap<String, String> map = new SafeTreeMap<String, String>();
242        for (Entry<String, String> entry : entries) {
243          map.put(entry.getKey(), entry.getValue());
244        }
245        return new StandardImplForwardingNavigableMap<String, String>(map);
246      }
247    }).named("ForwardingNavigableMap[SafeTreeMap] with no comparator and standard "
248        + "implementations").withFeatures(CollectionSize.ANY,
249        CollectionFeature.KNOWN_ORDER, MapFeature.ALLOWS_NULL_VALUES,
250        CollectionFeature.SUPPORTS_ITERATOR_REMOVE, MapFeature.GENERAL_PURPOSE)
251        .createTestSuite());
252    // TODO(user): add forwarding-to-ImmutableSortedMap test
253    return suite;
254  }
255
256  @Override public void setUp() throws Exception {
257    super.setUp();
258    /*
259     * Class parameters must be raw, so we can't create a proxy with generic
260     * type arguments. The created proxy only records calls and returns null, so
261     * the type is irrelevant at runtime.
262     */
263    @SuppressWarnings("unchecked")
264    final NavigableMap<String, Boolean> sortedMap =
265        createProxyInstance(NavigableMap.class);
266    forward = new ForwardingNavigableMap<String, Boolean>() {
267      @Override protected NavigableMap<String, Boolean> delegate() {
268        return sortedMap;
269      }
270    };
271  }
272
273  public void testStandardLastEntry() {
274    NavigableMap<String, Integer> forwarding =
275        new StandardLastEntryForwardingNavigableMap<String, Integer>(
276            new SafeTreeMap<String, Integer>());
277    assertNull(forwarding.lastEntry());
278    forwarding.put("b", 2);
279    assertEquals(immutableEntry("b", 2), forwarding.lastEntry());
280    forwarding.put("c", 3);
281    assertEquals(immutableEntry("c", 3), forwarding.lastEntry());
282    forwarding.put("a", 1);
283    assertEquals(immutableEntry("c", 3), forwarding.lastEntry());
284    forwarding.remove("c");
285    assertEquals(immutableEntry("b", 2), forwarding.lastEntry());
286  }
287
288  public void testLowerEntry() {
289    forward().lowerEntry("key");
290    assertEquals("[lowerEntry(Object)]", getCalls());
291  }
292
293  public void testLowerKey() {
294    forward().lowerKey("key");
295    assertEquals("[lowerKey(Object)]", getCalls());
296  }
297
298  public void testFloorEntry() {
299    forward().floorEntry("key");
300    assertEquals("[floorEntry(Object)]", getCalls());
301  }
302
303  public void testFloorKey() {
304    forward().floorKey("key");
305    assertEquals("[floorKey(Object)]", getCalls());
306  }
307
308  public void testCeilingEntry() {
309    forward().ceilingEntry("key");
310    assertEquals("[ceilingEntry(Object)]", getCalls());
311  }
312
313  public void testCeilingKey() {
314    forward().ceilingKey("key");
315    assertEquals("[ceilingKey(Object)]", getCalls());
316  }
317
318  public void testHigherEntry() {
319    forward().higherEntry("key");
320    assertEquals("[higherEntry(Object)]", getCalls());
321  }
322
323  public void testHigherKey() {
324    forward().higherKey("key");
325    assertEquals("[higherKey(Object)]", getCalls());
326  }
327
328  public void testPollFirstEntry() {
329    forward().pollFirstEntry();
330    assertEquals("[pollFirstEntry]", getCalls());
331  }
332
333  public void testPollLastEntry() {
334    forward().pollLastEntry();
335    assertEquals("[pollLastEntry]", getCalls());
336  }
337
338  public void testFirstEntry() {
339    forward().firstEntry();
340    assertEquals("[firstEntry]", getCalls());
341  }
342
343  public void testLastEntry() {
344    forward().lastEntry();
345    assertEquals("[lastEntry]", getCalls());
346  }
347
348  public void testDescendingMap() {
349    forward().descendingMap();
350    assertEquals("[descendingMap]", getCalls());
351  }
352
353  public void testNavigableKeySet() {
354    forward().navigableKeySet();
355    assertEquals("[navigableKeySet]", getCalls());
356  }
357
358  public void testDescendingKeySet() {
359    forward().descendingKeySet();
360    assertEquals("[descendingKeySet]", getCalls());
361  }
362
363  public void testSubMap_K_Bool_K_Bool() {
364    forward().subMap("a", false, "b", true);
365    assertEquals("[subMap(Object,boolean,Object,boolean)]", getCalls());
366  }
367
368  public void testHeadMap_K_Bool() {
369    forward().headMap("a", false);
370    assertEquals("[headMap(Object,boolean)]", getCalls());
371  }
372
373  public void testTailMap_K_Bool() {
374    forward().tailMap("a", false);
375    assertEquals("[tailMap(Object,boolean)]", getCalls());
376  }
377
378  @Override NavigableMap<String, Boolean> forward() {
379    return (NavigableMap<String, Boolean>) super.forward();
380  }
381}
382