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 static org.junit.contrib.truth.Truth.ASSERT;
20
21import com.google.common.annotations.GwtCompatible;
22import com.google.common.annotations.GwtIncompatible;
23import com.google.common.base.Function;
24import com.google.common.base.Predicate;
25import com.google.common.collect.Maps.EntryTransformer;
26import com.google.common.collect.testing.SortedMapInterfaceTest;
27import com.google.common.testing.NullPointerTester;
28
29import junit.framework.TestCase;
30
31import java.util.Comparator;
32import java.util.Map;
33import java.util.Map.Entry;
34import java.util.SortedMap;
35
36/**
37 * Tests for SortedMaps.
38 *
39 * @author Louis Wasserman
40 */
41@GwtCompatible(emulated = true)
42@SuppressWarnings("deprecation")
43public class SortedMapsTest extends TestCase {
44
45  private static final EntryTransformer<Object, Object, Object> ALWAYS_NULL =
46      new EntryTransformer<Object, Object, Object>() {
47        @Override
48        public Object transformEntry(Object k, Object v1) {
49          return null;
50        }
51      };
52
53  @GwtIncompatible("NullPointerTester")
54  public void testNullPointer() throws Exception {
55    NullPointerTester nullPointerTester = new NullPointerTester();
56    nullPointerTester.setDefault(EntryTransformer.class, ALWAYS_NULL);
57    nullPointerTester.setDefault(
58        SortedMap.class, Maps.<String, String>newTreeMap());
59    nullPointerTester.testAllPublicStaticMethods(SortedMaps.class);
60  }
61
62  public void testTransformSortedValues() {
63    SortedMap<String, Integer> map = ImmutableSortedMap.of("a", 4, "b", 9);
64    Function<Integer, Double> sqrt = new Function<Integer, Double>() {
65      @Override
66      public Double apply(Integer in) {
67        return Math.sqrt(in);
68      }
69    };
70    SortedMap<String, Double> transformed =
71        SortedMaps.transformValues(map, sqrt);
72
73    assertEquals(ImmutableSortedMap.of("a", 2.0, "b", 3.0), transformed);
74  }
75
76  public void testTransformSortedEntries() {
77    SortedMap<String, String> map = ImmutableSortedMap.of("a", "4", "b", "9");
78    EntryTransformer<String, String, String> concat =
79        new EntryTransformer<String, String, String>() {
80          @Override
81          public String transformEntry(String key, String value) {
82            return key + value;
83          }
84        };
85    SortedMap<String, String> transformed =
86        SortedMaps.transformEntries(map, concat);
87
88    assertEquals(ImmutableSortedMap.of("a", "a4", "b", "b9"), transformed);
89  }
90
91  // Not testing Map methods of SortedMaps.filter*, since the implementation
92  // doesn't override Maps.FilteredEntryMap, which is already tested.
93
94  private static final Predicate<Integer> EVEN =
95      new Predicate<Integer>() {
96        @Override
97        public boolean apply(Integer input) {
98          return input % 2 == 0;
99        }
100      };
101
102  public void testFilterKeys() {
103    Comparator<Integer> comparator = Ordering.natural();
104    SortedMap<Integer, String> unfiltered = Maps.newTreeMap(comparator);
105    unfiltered.put(1, "one");
106    unfiltered.put(2, "two");
107    unfiltered.put(3, "three");
108    unfiltered.put(4, "four");
109    unfiltered.put(5, "five");
110    unfiltered.put(6, "six");
111    unfiltered.put(7, "seven");
112    SortedMap<Integer, String> filtered
113        = SortedMaps.filterKeys(unfiltered, EVEN);
114    ASSERT.that(filtered.keySet()).hasContentsInOrder(2, 4, 6);
115    assertSame(comparator, filtered.comparator());
116    assertEquals((Integer) 2, filtered.firstKey());
117    assertEquals((Integer) 6, filtered.lastKey());
118    ASSERT.that(filtered.headMap(5).keySet()).hasContentsInOrder(2, 4);
119    ASSERT.that(filtered.tailMap(3).keySet()).hasContentsInOrder(4, 6);
120    ASSERT.that(filtered.subMap(3, 5).keySet()).hasContentsInOrder(4);
121  }
122
123  private static final Predicate<String> NOT_LENGTH_3 =
124      new Predicate<String>() {
125        @Override
126        public boolean apply(String input) {
127          return input == null || input.length() != 3;
128        }
129      };
130
131  public void testFilterValues() {
132    Comparator<Integer> comparator = Ordering.natural();
133    SortedMap<Integer, String> unfiltered = Maps.newTreeMap(comparator);
134    unfiltered.put(1, "one");
135    unfiltered.put(2, "two");
136    unfiltered.put(3, "three");
137    unfiltered.put(4, "four");
138    unfiltered.put(5, "five");
139    unfiltered.put(6, "six");
140    unfiltered.put(7, "seven");
141    SortedMap<Integer, String> filtered
142        = SortedMaps.filterValues(unfiltered, NOT_LENGTH_3);
143    ASSERT.that(filtered.keySet()).hasContentsInOrder(3, 4, 5, 7);
144    assertSame(comparator, filtered.comparator());
145    assertEquals((Integer) 3, filtered.firstKey());
146    assertEquals((Integer) 7, filtered.lastKey());
147    ASSERT.that(filtered.headMap(5).keySet()).hasContentsInOrder(3, 4);
148    ASSERT.that(filtered.tailMap(4).keySet()).hasContentsInOrder(4, 5, 7);
149    ASSERT.that(filtered.subMap(4, 6).keySet()).hasContentsInOrder(4, 5);
150  }
151
152  private static final Predicate<Map.Entry<Integer, String>>
153      EVEN_AND_LENGTH_3 = new Predicate<Map.Entry<Integer, String>>() {
154        @Override public boolean apply(Entry<Integer, String> entry) {
155          return (entry.getKey() == null || entry.getKey() % 2 == 0)
156              && (entry.getValue() == null || entry.getValue().length() == 3);
157        }
158    };
159
160  private static class ContainsKeySafeSortedMap
161      extends ForwardingSortedMap<Integer, String> {
162    SortedMap<Integer, String> delegate
163        = Maps.newTreeMap(Ordering.natural().nullsFirst());
164
165    @Override protected SortedMap<Integer, String> delegate() {
166      return delegate;
167    }
168
169    // Needed by MapInterfaceTest.testContainsKey()
170    @Override public boolean containsKey(Object key) {
171      try {
172        return super.containsKey(key);
173      } catch (ClassCastException e) {
174        return false;
175      }
176    }
177  }
178
179  public static class FilteredEntriesSortedMapInterfaceTest
180      extends SortedMapInterfaceTest<Integer, String> {
181    public FilteredEntriesSortedMapInterfaceTest() {
182      super(true, true, true, true, true);
183    }
184
185    @Override protected SortedMap<Integer, String> makeEmptyMap() {
186      SortedMap<Integer, String> unfiltered = new ContainsKeySafeSortedMap();
187      unfiltered.put(1, "one");
188      unfiltered.put(3, "three");
189      unfiltered.put(4, "four");
190      unfiltered.put(5, "five");
191      return SortedMaps.filterEntries(unfiltered, EVEN_AND_LENGTH_3);
192    }
193
194    @Override protected SortedMap<Integer, String> makePopulatedMap() {
195      SortedMap<Integer, String> unfiltered = new ContainsKeySafeSortedMap();
196      unfiltered.put(1, "one");
197      unfiltered.put(2, "two");
198      unfiltered.put(3, "three");
199      unfiltered.put(4, "four");
200      unfiltered.put(5, "five");
201      unfiltered.put(6, "six");
202      return SortedMaps.filterEntries(unfiltered, EVEN_AND_LENGTH_3);
203    }
204
205    @Override protected Integer getKeyNotInPopulatedMap() {
206      return 10;
207    }
208
209    @Override protected String getValueNotInPopulatedMap() {
210      return "ten";
211    }
212
213    // Iterators don't support remove.
214    @Override public void testEntrySetIteratorRemove() {}
215    @Override public void testValuesIteratorRemove() {}
216
217    // These tests fail on GWT.
218    // TODO: Investigate why.
219    @Override public void testEntrySetRemoveAll() {}
220    @Override public void testEntrySetRetainAll() {}
221  }
222}
223