• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.google.common.collect;
18 
19 import static com.google.common.collect.Maps.immutableEntry;
20 
21 import com.google.common.base.Function;
22 import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
23 import com.google.common.collect.testing.SafeTreeMap;
24 import com.google.common.collect.testing.TestStringSortedMapGenerator;
25 import com.google.common.collect.testing.features.CollectionFeature;
26 import com.google.common.collect.testing.features.CollectionSize;
27 import com.google.common.collect.testing.features.MapFeature;
28 import com.google.common.collect.testing.testers.MapEntrySetTester;
29 import com.google.common.testing.EqualsTester;
30 import com.google.common.testing.ForwardingWrapperTester;
31 import java.util.Collection;
32 import java.util.Iterator;
33 import java.util.Map;
34 import java.util.Map.Entry;
35 import java.util.NavigableMap;
36 import java.util.NavigableSet;
37 import java.util.Set;
38 import java.util.SortedMap;
39 import junit.framework.Test;
40 import junit.framework.TestCase;
41 import junit.framework.TestSuite;
42 import org.checkerframework.checker.nullness.qual.Nullable;
43 
44 /**
45  * Tests for {@code ForwardingNavigableMap}.
46  *
47  * @author Robert Konigsberg
48  * @author Louis Wasserman
49  */
50 public class ForwardingNavigableMapTest extends TestCase {
51   static class StandardImplForwardingNavigableMap<K, V> extends ForwardingNavigableMap<K, V> {
52     private final NavigableMap<K, V> backingMap;
53 
StandardImplForwardingNavigableMap(NavigableMap<K, V> backingMap)54     StandardImplForwardingNavigableMap(NavigableMap<K, V> backingMap) {
55       this.backingMap = backingMap;
56     }
57 
58     @Override
delegate()59     protected NavigableMap<K, V> delegate() {
60       return backingMap;
61     }
62 
63     @Override
containsKey(Object key)64     public boolean containsKey(Object key) {
65       return standardContainsKey(key);
66     }
67 
68     @Override
containsValue(Object value)69     public boolean containsValue(Object value) {
70       return standardContainsValue(value);
71     }
72 
73     @Override
putAll(Map<? extends K, ? extends V> map)74     public void putAll(Map<? extends K, ? extends V> map) {
75       standardPutAll(map);
76     }
77 
78     @Override
remove(Object object)79     public @Nullable V remove(Object object) {
80       return standardRemove(object);
81     }
82 
83     @Override
equals(@ullable Object object)84     public boolean equals(@Nullable Object object) {
85       return standardEquals(object);
86     }
87 
88     @Override
hashCode()89     public int hashCode() {
90       return standardHashCode();
91     }
92 
93     @Override
keySet()94     public Set<K> keySet() {
95       /*
96        * We can't use StandardKeySet, as NavigableMapTestSuiteBuilder assumes that our keySet is a
97        * NavigableSet. We test StandardKeySet in the superclass, so it's still covered.
98        */
99       return navigableKeySet();
100     }
101 
102     @Override
values()103     public Collection<V> values() {
104       return new StandardValues();
105     }
106 
107     @Override
toString()108     public String toString() {
109       return standardToString();
110     }
111 
112     @Override
entrySet()113     public Set<Entry<K, V>> entrySet() {
114       return new StandardEntrySet() {
115         @Override
116         public Iterator<Entry<K, V>> iterator() {
117           return backingMap.entrySet().iterator();
118         }
119       };
120     }
121 
122     @Override
clear()123     public void clear() {
124       standardClear();
125     }
126 
127     @Override
isEmpty()128     public boolean isEmpty() {
129       return standardIsEmpty();
130     }
131 
132     @Override
subMap(K fromKey, K toKey)133     public SortedMap<K, V> subMap(K fromKey, K toKey) {
134       return standardSubMap(fromKey, toKey);
135     }
136 
137     @Override
lowerEntry(K key)138     public @Nullable Entry<K, V> lowerEntry(K key) {
139       return standardLowerEntry(key);
140     }
141 
142     @Override
lowerKey(K key)143     public @Nullable K lowerKey(K key) {
144       return standardLowerKey(key);
145     }
146 
147     @Override
floorEntry(K key)148     public @Nullable Entry<K, V> floorEntry(K key) {
149       return standardFloorEntry(key);
150     }
151 
152     @Override
floorKey(K key)153     public @Nullable K floorKey(K key) {
154       return standardFloorKey(key);
155     }
156 
157     @Override
ceilingEntry(K key)158     public @Nullable Entry<K, V> ceilingEntry(K key) {
159       return standardCeilingEntry(key);
160     }
161 
162     @Override
ceilingKey(K key)163     public @Nullable K ceilingKey(K key) {
164       return standardCeilingKey(key);
165     }
166 
167     @Override
higherEntry(K key)168     public @Nullable Entry<K, V> higherEntry(K key) {
169       return standardHigherEntry(key);
170     }
171 
172     @Override
higherKey(K key)173     public @Nullable K higherKey(K key) {
174       return standardHigherKey(key);
175     }
176 
177     @Override
firstEntry()178     public @Nullable Entry<K, V> firstEntry() {
179       return standardFirstEntry();
180     }
181 
182     /*
183      * We can't override lastEntry to delegate to standardLastEntry, as it would create an infinite
184      * loop. Instead, we test standardLastEntry manually below.
185      */
186 
187     @Override
pollFirstEntry()188     public @Nullable Entry<K, V> pollFirstEntry() {
189       return standardPollFirstEntry();
190     }
191 
192     @Override
pollLastEntry()193     public @Nullable Entry<K, V> pollLastEntry() {
194       return standardPollLastEntry();
195     }
196 
197     @Override
descendingMap()198     public NavigableMap<K, V> descendingMap() {
199       return new StandardDescendingMap();
200     }
201 
202     @Override
navigableKeySet()203     public NavigableSet<K> navigableKeySet() {
204       return new StandardNavigableKeySet();
205     }
206 
207     @Override
descendingKeySet()208     public NavigableSet<K> descendingKeySet() {
209       return standardDescendingKeySet();
210     }
211 
212     @Override
firstKey()213     public K firstKey() {
214       return standardFirstKey();
215     }
216 
217     @Override
headMap(K toKey)218     public SortedMap<K, V> headMap(K toKey) {
219       return standardHeadMap(toKey);
220     }
221 
222     @Override
lastKey()223     public K lastKey() {
224       return standardLastKey();
225     }
226 
227     @Override
tailMap(K fromKey)228     public SortedMap<K, V> tailMap(K fromKey) {
229       return standardTailMap(fromKey);
230     }
231   }
232 
233   static class StandardLastEntryForwardingNavigableMap<K, V> extends ForwardingNavigableMap<K, V> {
234     private final NavigableMap<K, V> backingMap;
235 
236     StandardLastEntryForwardingNavigableMap(NavigableMap<K, V> backingMap) {
237       this.backingMap = backingMap;
238     }
239 
240     @Override
241     protected NavigableMap<K, V> delegate() {
242       return backingMap;
243     }
244 
245     @Override
246     public @Nullable Entry<K, V> lastEntry() {
247       return standardLastEntry();
248     }
249   }
250 
251   public static Test suite() {
252     TestSuite suite = new TestSuite();
253 
254     suite.addTestSuite(ForwardingNavigableMapTest.class);
255     suite.addTest(
256         NavigableMapTestSuiteBuilder.using(
257                 new TestStringSortedMapGenerator() {
258                   @Override
259                   protected SortedMap<String, String> create(Entry<String, String>[] entries) {
260                     NavigableMap<String, String> map = new SafeTreeMap<>();
261                     for (Entry<String, String> entry : entries) {
262                       map.put(entry.getKey(), entry.getValue());
263                     }
264                     return new StandardImplForwardingNavigableMap<>(map);
265                   }
266                 })
267             .named(
268                 "ForwardingNavigableMap[SafeTreeMap] with no comparator and standard "
269                     + "implementations")
270             .withFeatures(
271                 CollectionSize.ANY,
272                 CollectionFeature.KNOWN_ORDER,
273                 MapFeature.ALLOWS_NULL_VALUES,
274                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
275                 MapFeature.GENERAL_PURPOSE)
276             /*
277              * StandardDescendingMap uses lowerEntry(), and TreeMap.lowerEntry() deliberately
278              * produces immutable entries.
279              *
280              * TODO(cpovirk): Consider making StandardDescendingMap return a ForwardingEntry that
281              * supports setValue().
282              */
283             .suppressing(
284                 MapEntrySetTester.getSetValueMethod(),
285                 MapEntrySetTester.getSetValueWithNullValuesAbsentMethod(),
286                 MapEntrySetTester.getSetValueWithNullValuesPresentMethod())
287             .createTestSuite());
288     // TODO(lowasser): add forwarding-to-ImmutableSortedMap test
289     return suite;
290   }
291 
292   public void testStandardLastEntry() {
293     NavigableMap<String, Integer> forwarding =
294         new StandardLastEntryForwardingNavigableMap<>(new SafeTreeMap<String, Integer>());
295     assertNull(forwarding.lastEntry());
296     forwarding.put("b", 2);
297     assertEquals(immutableEntry("b", 2), forwarding.lastEntry());
298     forwarding.put("c", 3);
299     assertEquals(immutableEntry("c", 3), forwarding.lastEntry());
300     forwarding.put("a", 1);
301     assertEquals(immutableEntry("c", 3), forwarding.lastEntry());
302     forwarding.remove("c");
303     assertEquals(immutableEntry("b", 2), forwarding.lastEntry());
304   }
305 
306   @SuppressWarnings({"rawtypes", "unchecked"})
307   public void testForwarding() {
308     new ForwardingWrapperTester()
309         .testForwarding(
310             NavigableMap.class,
311             new Function<NavigableMap, NavigableMap>() {
312               @Override
313               public NavigableMap apply(NavigableMap delegate) {
314                 return wrap(delegate);
315               }
316             });
317   }
318 
319   public void testEquals() {
320     NavigableMap<Integer, String> map1 = ImmutableSortedMap.of(1, "one");
321     NavigableMap<Integer, String> map2 = ImmutableSortedMap.of(2, "two");
322     new EqualsTester()
323         .addEqualityGroup(map1, wrap(map1), wrap(map1))
324         .addEqualityGroup(map2, wrap(map2))
325         .testEquals();
326   }
327 
328   private static <K, V> NavigableMap<K, V> wrap(final NavigableMap<K, V> delegate) {
329     return new ForwardingNavigableMap<K, V>() {
330       @Override
331       protected NavigableMap<K, V> delegate() {
332         return delegate;
333       }
334     };
335   }
336 }
337