SortedMapInterfaceTest.java revision 3c77433663281544363151bf284b0240dfd22a42
1/*
2 * Copyright (C) 2009 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.testing;
18
19import com.google.common.annotations.GwtCompatible;
20
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.Collections;
24import java.util.Comparator;
25import java.util.Iterator;
26import java.util.List;
27import java.util.Map;
28import java.util.Map.Entry;
29import java.util.NoSuchElementException;
30import java.util.Set;
31import java.util.SortedMap;
32
33/**
34 * Tests representing the contract of {@link SortedMap}. Concrete subclasses of
35 * this base class test conformance of concrete {@link SortedMap} subclasses to
36 * that contract.
37 *
38 * <p>This class is GWT compatible.
39 *
40 * @author Jared Levy
41 */
42// TODO: Use this class to test classes besides ImmutableSortedMap.
43@GwtCompatible
44public abstract class SortedMapInterfaceTest<K, V>
45    extends MapInterfaceTest<K, V> {
46
47  /** A key type that is not assignable to any classes but Object. */
48  private static final class IncompatibleComparableKeyType
49      implements Comparable<IncompatibleComparableKeyType> {
50    @Override public String toString() {
51      return "IncompatibleComparableKeyType";
52    }
53    @Override
54    public int compareTo(IncompatibleComparableKeyType o) {
55      throw new ClassCastException();
56    }
57  }
58
59  protected SortedMapInterfaceTest(boolean allowsNullKeys,
60      boolean allowsNullValues, boolean supportsPut, boolean supportsRemove,
61      boolean supportsClear) {
62    super(allowsNullKeys, allowsNullValues, supportsPut, supportsRemove,
63        supportsClear);
64  }
65
66  @Override protected abstract SortedMap<K, V> makeEmptyMap()
67      throws UnsupportedOperationException;
68
69  @Override protected abstract SortedMap<K, V> makePopulatedMap()
70      throws UnsupportedOperationException;
71
72  @Override protected SortedMap<K, V> makeEitherMap() {
73    try {
74      return makePopulatedMap();
75    } catch (UnsupportedOperationException e) {
76      return makeEmptyMap();
77    }
78  }
79
80  @SuppressWarnings("unchecked") // Needed for null comparator
81  public void testOrdering() {
82    final SortedMap<K, V> map;
83    try {
84      map = makePopulatedMap();
85    } catch (UnsupportedOperationException e) {
86      return;
87    }
88    Iterator<K> iterator = map.keySet().iterator();
89    K prior = iterator.next();
90    Comparator<? super K> comparator = map.comparator();
91    while (iterator.hasNext()) {
92      K current = iterator.next();
93      if (comparator == null) {
94        Comparable comparable = (Comparable) prior;
95        assertTrue(comparable.compareTo(current) < 0);
96      } else {
97        assertTrue(map.comparator().compare(prior, current) < 0);
98      }
99      current = prior;
100    }
101  }
102
103  public void testEntrySetContainsEntryIncompatibleComparableKey() {
104    final Map<K, V> map;
105    final Set<Entry<K, V>> entrySet;
106    try {
107      map = makeEitherMap();
108    } catch (UnsupportedOperationException e) {
109      return;
110    }
111    assertInvariants(map);
112
113    entrySet = map.entrySet();
114    final V unmappedValue;
115    try {
116      unmappedValue = getValueNotInPopulatedMap();
117    } catch (UnsupportedOperationException e) {
118      return;
119    }
120    Entry<IncompatibleComparableKeyType, V> entry
121        = mapEntry(new IncompatibleComparableKeyType(), unmappedValue);
122    assertFalse(entrySet.contains(entry));
123  }
124
125  public void testFirstKeyEmpty() {
126    final SortedMap<K, V> map;
127    try {
128      map = makeEmptyMap();
129    } catch (UnsupportedOperationException e) {
130      return;
131    }
132    try {
133      map.firstKey();
134      fail("Expected NoSuchElementException");
135    } catch (NoSuchElementException expected) {}
136    assertInvariants(map);
137  }
138
139  public void testFirstKeyNonEmpty() {
140    final SortedMap<K, V> map;
141    try {
142      map = makePopulatedMap();
143    } catch (UnsupportedOperationException e) {
144      return;
145    }
146    K expected = map.keySet().iterator().next();
147    assertEquals(expected, map.firstKey());
148    assertInvariants(map);
149  }
150
151  public void testLastKeyEmpty() {
152    final SortedMap<K, V> map;
153    try {
154      map = makeEmptyMap();
155    } catch (UnsupportedOperationException e) {
156      return;
157    }
158    try {
159      map.lastKey();
160      fail("Expected NoSuchElementException");
161    } catch (NoSuchElementException expected) {}
162    assertInvariants(map);
163  }
164
165  public void testLastKeyNonEmpty() {
166    final SortedMap<K, V> map;
167    try {
168      map = makePopulatedMap();
169    } catch (UnsupportedOperationException e) {
170      return;
171    }
172    K expected = null;
173    for (K key : map.keySet()) {
174      expected = key;
175    }
176    assertEquals(expected, map.lastKey());
177    assertInvariants(map);
178  }
179
180  private static <E> List<E> toList(Collection<E> collection) {
181    return new ArrayList<E>(collection);
182  }
183
184  private static <E> List<E> subListSnapshot(
185      List<E> list, int fromIndex, int toIndex) {
186    List<E> subList = new ArrayList<E>();
187    for (int i = fromIndex; i < toIndex; i++) {
188      subList.add(list.get(i));
189    }
190    return Collections.unmodifiableList(subList);
191  }
192
193  public void testHeadMap() {
194    final SortedMap<K, V> map;
195    try {
196      map = makeEitherMap();
197    } catch (UnsupportedOperationException e) {
198      return;
199    }
200    List<Entry<K, V>> list = toList(map.entrySet());
201    for (int i = 0; i < list.size(); i++) {
202      List<Entry<K, V>> expected = subListSnapshot(list, 0, i);
203      SortedMap<K, V> headMap = map.headMap(list.get(i).getKey());
204      assertEquals(expected, toList(headMap.entrySet()));
205    }
206  }
207
208  public void testTailMap() {
209    final SortedMap<K, V> map;
210    try {
211      map = makeEitherMap();
212    } catch (UnsupportedOperationException e) {
213      return;
214    }
215    List<Entry<K, V>> list = toList(map.entrySet());
216    for (int i = 0; i < list.size(); i++) {
217      List<Entry<K, V>> expected = subListSnapshot(list, i, list.size());
218      SortedMap<K, V> tailMap = map.tailMap(list.get(i).getKey());
219      assertEquals(expected, toList(tailMap.entrySet()));
220    }
221  }
222
223  public void testSubMap() {
224    final SortedMap<K, V> map;
225    try {
226      map = makeEitherMap();
227    } catch (UnsupportedOperationException e) {
228      return;
229    }
230    List<Entry<K, V>> list = toList(map.entrySet());
231    for (int i = 0; i < list.size(); i++) {
232      for (int j = i; j < list.size(); j++) {
233        List<Entry<K, V>> expected = subListSnapshot(list, i, j);
234        SortedMap<K, V> subMap
235            = map.subMap(list.get(i).getKey(), list.get(j).getKey());
236        assertEquals(expected, toList(subMap.entrySet()));
237      }
238    }
239  }
240
241  public void testSubMapIllegal() {
242    final SortedMap<K, V> map;
243    try {
244      map = makePopulatedMap();
245    } catch (UnsupportedOperationException e) {
246      return;
247    }
248    if (map.size() < 2) {
249      return;
250    }
251    Iterator<K> iterator = map.keySet().iterator();
252    K first = iterator.next();
253    K second = iterator.next();
254    try {
255      map.subMap(second, first);
256      fail("Expected IllegalArgumentException");
257    } catch (IllegalArgumentException expected) {}
258  }
259
260  public void testTailMapEntrySet() {
261    final SortedMap<K, V> map;
262    try {
263      map = makePopulatedMap();
264    } catch (UnsupportedOperationException e) {
265      return;
266    }
267    if (map.size() < 3) {
268      return;
269    }
270    Iterator<Entry<K, V>> iterator = map.entrySet().iterator();
271    Entry<K, V> firstEntry = iterator.next();
272    Entry<K, V> secondEntry = iterator.next();
273    Entry<K, V> thirdEntry = iterator.next();
274    SortedMap<K, V> tail = map.tailMap(secondEntry.getKey());
275    Set<Entry<K, V>> tailEntrySet = tail.entrySet();
276    assertTrue(tailEntrySet.contains(thirdEntry));
277    assertTrue(tailEntrySet.contains(secondEntry));
278    assertFalse(tailEntrySet.contains(firstEntry));
279    assertEquals(tail.firstKey(), secondEntry.getKey());
280  }
281
282  public void testHeadMapEntrySet() {
283    final SortedMap<K, V> map;
284    try {
285      map = makePopulatedMap();
286    } catch (UnsupportedOperationException e) {
287      return;
288    }
289    if (map.size() < 3) {
290      return;
291    }
292    Iterator<Entry<K, V>> iterator = map.entrySet().iterator();
293    Entry<K, V> firstEntry = iterator.next();
294    Entry<K, V> secondEntry = iterator.next();
295    Entry<K, V> thirdEntry = iterator.next();
296    SortedMap<K, V> head = map.headMap(secondEntry.getKey());
297    Set<Entry<K, V>> headEntrySet = head.entrySet();
298    assertFalse(headEntrySet.contains(thirdEntry));
299    assertFalse(headEntrySet.contains(secondEntry));
300    assertTrue(headEntrySet.contains(firstEntry));
301    assertEquals(head.firstKey(), firstEntry.getKey());
302    assertEquals(head.lastKey(), firstEntry.getKey());
303  }
304
305  public void testTailMapWriteThrough() {
306    final SortedMap<K, V> map;
307    try {
308      map = makePopulatedMap();
309    } catch (UnsupportedOperationException e) {
310      return;
311    }
312    if (map.size() < 2 || !supportsPut) {
313      return;
314    }
315    Iterator<Entry<K, V>> iterator = map.entrySet().iterator();
316    Entry<K, V> firstEntry = iterator.next();
317    Entry<K, V> secondEntry = iterator.next();
318    K key = secondEntry.getKey();
319    SortedMap<K, V> subMap = map.tailMap(key);
320    V value = getValueNotInPopulatedMap();
321    subMap.put(key, value);
322    assertEquals(secondEntry.getValue(), value);
323    assertEquals(map.get(key), value);
324    try {
325      subMap.put(firstEntry.getKey(), value);
326      fail("Expected IllegalArgumentException");
327    } catch (IllegalArgumentException expected) {
328    }
329  }
330
331  public void testTailMapRemoveThrough() {
332    final SortedMap<K, V> map;
333    try {
334      map = makePopulatedMap();
335    } catch (UnsupportedOperationException e) {
336      return;
337    }
338    int oldSize = map.size();
339    if (map.size() < 2 || !supportsRemove) {
340      return;
341    }
342    Iterator<Entry<K, V>> iterator = map.entrySet().iterator();
343    Entry<K, V> firstEntry = iterator.next();
344    Entry<K, V> secondEntry = iterator.next();
345    K key = secondEntry.getKey();
346    SortedMap<K, V> subMap = map.tailMap(key);
347    subMap.remove(key);
348    assertNull(subMap.remove(firstEntry.getKey()));
349    assertEquals(map.size(), oldSize - 1);
350    assertFalse(map.containsKey(key));
351    assertEquals(subMap.size(), oldSize - 2);
352  }
353
354  public void testTailMapClearThrough() {
355    final SortedMap<K, V> map;
356    try {
357      map = makePopulatedMap();
358    } catch (UnsupportedOperationException e) {
359      return;
360    }
361    int oldSize = map.size();
362    if (map.size() < 2 || !supportsClear) {
363      return;
364    }
365    Iterator<Entry<K, V>> iterator = map.entrySet().iterator();
366    Entry<K, V> firstEntry = iterator.next();
367    Entry<K, V> secondEntry = iterator.next();
368    K key = secondEntry.getKey();
369    SortedMap<K, V> subMap = map.tailMap(key);
370    int subMapSize = subMap.size();
371    subMap.clear();
372    assertEquals(map.size(), oldSize - subMapSize);
373    assertTrue(subMap.isEmpty());
374  }
375}
376