View Javadoc
1   /*
2    * Copyright (C) 2008 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.truth.Truth.assertThat;
20  
21  import com.google.common.annotations.GwtCompatible;
22  import com.google.common.annotations.GwtIncompatible;
23  import com.google.common.collect.testing.SortedMapInterfaceTest;
24  import com.google.common.collect.testing.SortedMapTestSuiteBuilder;
25  import com.google.common.collect.testing.TestStringSortedMapGenerator;
26  import com.google.common.collect.testing.features.CollectionFeature;
27  import com.google.common.collect.testing.features.CollectionSize;
28  import com.google.common.collect.testing.features.MapFeature;
29  import com.google.common.testing.SerializableTester;
30  
31  import junit.framework.Test;
32  import junit.framework.TestSuite;
33  
34  import java.util.Collections;
35  import java.util.Comparator;
36  import java.util.Map;
37  import java.util.Map.Entry;
38  import java.util.Set;
39  import java.util.SortedMap;
40  
41  /**
42   * Test cases for {@link TreeBasedTable}.
43   *
44   * @author Jared Levy
45   * @author Louis Wasserman
46   */
47  @GwtCompatible(emulated = true)
48  public class TreeBasedTableTest extends AbstractTableTest {
49    @GwtIncompatible("suite")
50    public static Test suite() {
51      TestSuite suite = new TestSuite();
52      suite.addTestSuite(TreeBasedTableTest.class);
53      suite.addTestSuite(TreeRowTest.class);
54      suite.addTest(SortedMapTestSuiteBuilder
55          .using(new TestStringSortedMapGenerator() {
56            @Override protected SortedMap<String, String> create(
57                Entry<String, String>[] entries) {
58              TreeBasedTable<String, String, String> table =
59                  TreeBasedTable.create();
60              table.put("a", "b", "c");
61              table.put("c", "b", "a");
62              table.put("a", "a", "d");
63              for (Entry<String, String> entry : entries) {
64                table.put("b", entry.getKey(), entry.getValue());
65              }
66              return table.row("b");
67            }
68          }).withFeatures(
69              MapFeature.GENERAL_PURPOSE,
70              CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
71              CollectionSize.ANY)
72          .named("RowMapTestSuite").createTestSuite());
73      return suite;
74    }
75  
76    public static class TreeRowTest extends
77        SortedMapInterfaceTest<String, String> {
78      public TreeRowTest() {
79        super(false, false, true, true, true);
80      }
81  
82      @Override protected SortedMap<String, String> makeEmptyMap() {
83        TreeBasedTable<String, String, String> table = TreeBasedTable.create();
84        table.put("a", "b", "c");
85        table.put("c", "b", "a");
86        table.put("a", "a", "d");
87        return table.row("b");
88      }
89  
90      @Override protected SortedMap<String, String> makePopulatedMap() {
91        TreeBasedTable<String, String, String> table = TreeBasedTable.create();
92        table.put("a", "b", "c");
93        table.put("c", "b", "a");
94        table.put("b", "b", "x");
95        table.put("b", "c", "y");
96        table.put("b", "x", "n");
97        table.put("a", "a", "d");
98        return table.row("b");
99      }
100 
101     @Override protected String getKeyNotInPopulatedMap() {
102       return "q";
103     }
104 
105     @Override protected String getValueNotInPopulatedMap() {
106       return "p";
107     }
108 
109     public void testClearSubMapOfRowMap() {
110       TreeBasedTable<String, String, String> table = TreeBasedTable.create();
111       table.put("a", "b", "c");
112       table.put("c", "b", "a");
113       table.put("b", "b", "x");
114       table.put("b", "c", "y");
115       table.put("b", "x", "n");
116       table.put("a", "a", "d");
117       table.row("b").subMap("c", "x").clear();
118       assertEquals(table.row("b"), ImmutableMap.of("b", "x", "x", "n"));
119       table.row("b").subMap("b", "y").clear();
120       assertEquals(table.row("b"), ImmutableMap.of());
121       assertFalse(table.backingMap.containsKey("b"));
122     }
123   }
124 
125   private TreeBasedTable<String, Integer, Character> sortedTable;
126 
127   protected TreeBasedTable<String, Integer, Character> create(
128     Comparator<? super String> rowComparator,
129     Comparator<? super Integer> columnComparator,
130     Object... data) {
131     TreeBasedTable<String, Integer, Character> table =
132         TreeBasedTable.create(rowComparator, columnComparator);
133     table.put("foo", 4, 'a');
134     table.put("cat", 1, 'b');
135     table.clear();
136     populate(table, data);
137     return table;
138   }
139 
140   @Override protected TreeBasedTable<String, Integer, Character> create(
141       Object... data) {
142     TreeBasedTable<String, Integer, Character> table = TreeBasedTable.create();
143     table.put("foo", 4, 'a');
144     table.put("cat", 1, 'b');
145     table.clear();
146     populate(table, data);
147     return table;
148   }
149 
150   public void testCreateExplicitComparators() {
151     table = TreeBasedTable.create(
152         Collections.reverseOrder(), Ordering.usingToString());
153     table.put("foo", 3, 'a');
154     table.put("foo", 12, 'b');
155     table.put("bar", 5, 'c');
156     table.put("cat", 8, 'd');
157     assertThat(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
158     assertThat(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
159   }
160 
161   public void testCreateCopy() {
162     TreeBasedTable<String, Integer, Character> original = TreeBasedTable.create(
163         Collections.reverseOrder(), Ordering.usingToString());
164     original.put("foo", 3, 'a');
165     original.put("foo", 12, 'b');
166     original.put("bar", 5, 'c');
167     original.put("cat", 8, 'd');
168     table = TreeBasedTable.create(original);
169     assertThat(table.rowKeySet()).has().exactly("foo", "cat", "bar").inOrder();
170     assertThat(table.row("foo").keySet()).has().exactly(12, 3).inOrder();
171     assertEquals(original, table);
172   }
173 
174   @GwtIncompatible("SerializableTester")
175   public void testSerialization() {
176     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
177     SerializableTester.reserializeAndAssert(table);
178   }
179 
180   public void testToString_ordered() {
181     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
182     assertEquals("{bar={1=b}, foo={1=a, 3=c}}", table.toString());
183     assertEquals("{bar={1=b}, foo={1=a, 3=c}}", table.rowMap().toString());
184   }
185 
186   public void testCellSetToString_ordered() {
187     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
188     assertEquals("[(bar,1)=b, (foo,1)=a, (foo,3)=c]",
189         table.cellSet().toString());
190   }
191 
192   public void testRowKeySetToString_ordered() {
193     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
194     assertEquals("[bar, foo]", table.rowKeySet().toString());
195   }
196 
197   public void testValuesToString_ordered() {
198     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
199     assertEquals("[b, a, c]", table.values().toString());
200   }
201 
202   public void testRowComparator() {
203     sortedTable = TreeBasedTable.create();
204     assertSame(Ordering.natural(), sortedTable.rowComparator());
205 
206     sortedTable = TreeBasedTable.create(
207         Collections.reverseOrder(), Ordering.usingToString());
208     assertSame(Collections.reverseOrder(), sortedTable.rowComparator());
209   }
210 
211   public void testColumnComparator() {
212     sortedTable = TreeBasedTable.create();
213     assertSame(Ordering.natural(), sortedTable.columnComparator());
214 
215     sortedTable = TreeBasedTable.create(
216         Collections.reverseOrder(), Ordering.usingToString());
217     assertSame(Ordering.usingToString(), sortedTable.columnComparator());
218   }
219 
220   public void testRowKeySetComparator() {
221     sortedTable = TreeBasedTable.create();
222     assertSame(Ordering.natural(),
223         sortedTable.rowKeySet().comparator());
224 
225     sortedTable = TreeBasedTable.create(
226         Collections.reverseOrder(), Ordering.usingToString());
227     assertSame(Collections.reverseOrder(),
228         sortedTable.rowKeySet().comparator());
229   }
230 
231   public void testRowKeySetFirst() {
232     sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
233     assertSame("bar", sortedTable.rowKeySet().first());
234   }
235 
236   public void testRowKeySetLast() {
237     sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
238     assertSame("foo", sortedTable.rowKeySet().last());
239   }
240 
241   public void testRowKeySetHeadSet() {
242     sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
243     Set<String> set = sortedTable.rowKeySet().headSet("cat");
244     assertEquals(Collections.singleton("bar"), set);
245     set.clear();
246     assertTrue(set.isEmpty());
247     assertEquals(Collections.singleton("foo"), sortedTable.rowKeySet());
248   }
249 
250   public void testRowKeySetTailSet() {
251     sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
252     Set<String> set = sortedTable.rowKeySet().tailSet("cat");
253     assertEquals(Collections.singleton("foo"), set);
254     set.clear();
255     assertTrue(set.isEmpty());
256     assertEquals(Collections.singleton("bar"), sortedTable.rowKeySet());
257   }
258 
259   public void testRowKeySetSubSet() {
260     sortedTable = create(
261         "foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c', "dog", 2, 'd');
262     Set<String> set = sortedTable.rowKeySet().subSet("cat", "egg");
263     assertEquals(Collections.singleton("dog"), set);
264     set.clear();
265     assertTrue(set.isEmpty());
266     assertEquals(ImmutableSet.of("bar", "foo"), sortedTable.rowKeySet());
267   }
268 
269   public void testRowMapComparator() {
270     sortedTable = TreeBasedTable.create();
271     assertSame(Ordering.natural(), sortedTable.rowMap().comparator());
272 
273     sortedTable = TreeBasedTable.create(
274         Collections.reverseOrder(), Ordering.usingToString());
275     assertSame(Collections.reverseOrder(), sortedTable.rowMap().comparator());
276   }
277 
278   public void testRowMapFirstKey() {
279     sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
280     assertSame("bar", sortedTable.rowMap().firstKey());
281   }
282 
283   public void testRowMapLastKey() {
284     sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
285     assertSame("foo", sortedTable.rowMap().lastKey());
286   }
287 
288   public void testRowKeyMapHeadMap() {
289     sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
290     Map<String, Map<Integer, Character>> map
291         = sortedTable.rowMap().headMap("cat");
292     assertEquals(1, map.size());
293     assertEquals(ImmutableMap.of(1, 'b'), map.get("bar"));
294     map.clear();
295     assertTrue(map.isEmpty());
296     assertEquals(Collections.singleton("foo"), sortedTable.rowKeySet());
297   }
298 
299   public void testRowKeyMapTailMap() {
300     sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
301     Map<String, Map<Integer, Character>> map
302         = sortedTable.rowMap().tailMap("cat");
303     assertEquals(1, map.size());
304     assertEquals(ImmutableMap.of(1, 'a', 3, 'c'), map.get("foo"));
305     map.clear();
306     assertTrue(map.isEmpty());
307     assertEquals(Collections.singleton("bar"), sortedTable.rowKeySet());
308   }
309 
310   public void testRowKeyMapSubMap() {
311     sortedTable = create(
312         "foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c', "dog", 2, 'd');
313     Map<String, Map<Integer, Character>> map
314         = sortedTable.rowMap().subMap("cat", "egg");
315     assertEquals(ImmutableMap.of(2, 'd'), map.get("dog"));
316     map.clear();
317     assertTrue(map.isEmpty());
318     assertEquals(ImmutableSet.of("bar", "foo"), sortedTable.rowKeySet());
319   }
320 
321   public void testRowMapValuesAreSorted() {
322     sortedTable = create(
323         "foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c', "dog", 2, 'd');
324     assertTrue(sortedTable.rowMap().get("foo") instanceof SortedMap);
325   }
326 
327   public void testColumnKeySet_isSorted() {
328     table = create("a", 2,  'X',
329                    "a", 2,  'X',
330                    "b", 3,  'X',
331                    "b", 2,  'X',
332                    "c", 10, 'X',
333                    "c", 10, 'X',
334                    "c", 20, 'X',
335                    "d", 15, 'X',
336                    "d", 20, 'X',
337                    "d", 1,  'X',
338                    "e", 5,  'X'
339                   );
340     assertEquals("[1, 2, 3, 5, 10, 15, 20]", table.columnKeySet().toString());
341   }
342 
343   public void testColumnKeySet_isSortedWithRealComparator() {
344     table = create(String.CASE_INSENSITIVE_ORDER,
345                    Ordering.natural().reverse(),
346                    "a", 2,  'X',
347                    "a", 2,  'X',
348                    "b", 3,  'X',
349                    "b", 2,  'X',
350                    "c", 10, 'X',
351                    "c", 10, 'X',
352                    "c", 20, 'X',
353                    "d", 15, 'X',
354                    "d", 20, 'X',
355                    "d", 1,  'X',
356                    "e", 5,  'X'
357                   );
358     assertEquals("[20, 15, 10, 5, 3, 2, 1]", table.columnKeySet().toString());
359   }
360 
361   public void testColumnKeySet_empty() {
362     table = create();
363     assertEquals("[]", table.columnKeySet().toString());
364   }
365 
366   public void testColumnKeySet_oneRow() {
367     table = create("a", 2,  'X',
368                    "a", 1,  'X'
369                   );
370     assertEquals("[1, 2]", table.columnKeySet().toString());
371   }
372 
373   public void testColumnKeySet_oneColumn() {
374     table = create("a", 1,  'X',
375                    "b", 1,  'X'
376                   );
377     assertEquals("[1]", table.columnKeySet().toString());
378   }
379 
380   public void testColumnKeySet_oneEntry() {
381     table = create("a", 1,  'X');
382     assertEquals("[1]", table.columnKeySet().toString());
383   }
384 
385   public void testRowEntrySetContains() {
386     table =
387         sortedTable =
388             create("a", 2, 'X', "a", 2, 'X', "b", 3, 'X', "b", 2, 'X', "c", 10,
389                 'X', "c", 10, 'X', "c", 20, 'X', "d", 15, 'X', "d", 20, 'X',
390                 "d", 1, 'X', "e", 5, 'X');
391     SortedMap<Integer, Character> row = sortedTable.row("c");
392     Set<Map.Entry<Integer, Character>> entrySet = row.entrySet();
393     assertTrue(entrySet.contains(Maps.immutableEntry(10, 'X')));
394     assertTrue(entrySet.contains(Maps.immutableEntry(20, 'X')));
395     assertFalse(entrySet.contains(Maps.immutableEntry(15, 'X')));
396     entrySet = row.tailMap(15).entrySet();
397     assertFalse(entrySet.contains(Maps.immutableEntry(10, 'X')));
398     assertTrue(entrySet.contains(Maps.immutableEntry(20, 'X')));
399     assertFalse(entrySet.contains(Maps.immutableEntry(15, 'X')));
400   }
401 
402   public void testRowEntrySetRemove() {
403     table =
404         sortedTable =
405             create("a", 2, 'X', "a", 2, 'X', "b", 3, 'X', "b", 2, 'X', "c", 10,
406                 'X', "c", 10, 'X', "c", 20, 'X', "d", 15, 'X', "d", 20, 'X',
407                 "d", 1, 'X', "e", 5, 'X');
408     SortedMap<Integer, Character> row = sortedTable.row("c");
409     Set<Map.Entry<Integer, Character>> entrySet = row.tailMap(15).entrySet();
410     assertFalse(entrySet.remove(Maps.immutableEntry(10, 'X')));
411     assertTrue(entrySet.remove(Maps.immutableEntry(20, 'X')));
412     assertFalse(entrySet.remove(Maps.immutableEntry(15, 'X')));
413     entrySet = row.entrySet();
414     assertTrue(entrySet.remove(Maps.immutableEntry(10, 'X')));
415     assertFalse(entrySet.remove(Maps.immutableEntry(20, 'X')));
416     assertFalse(entrySet.remove(Maps.immutableEntry(15, 'X')));
417   }
418 
419   public void testRowSize() {
420     table =
421         sortedTable =
422             create("a", 2, 'X', "a", 2, 'X', "b", 3, 'X', "b", 2, 'X', "c", 10,
423                 'X', "c", 10, 'X', "c", 20, 'X', "d", 15, 'X', "d", 20, 'X',
424                 "d", 1, 'X', "e", 5, 'X');
425     SortedMap<Integer, Character> row = sortedTable.row("c");
426     assertEquals(row.size(), 2);
427     assertEquals(row.tailMap(15).size(), 1);
428   }
429 
430   public void testSubRowClearAndPut() {
431     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
432     SortedMap<Integer, Character> row = (SortedMap<Integer, Character>) table.row("foo");
433     SortedMap<Integer, Character> subRow = row.tailMap(2);
434     assertEquals(ImmutableMap.of(1, 'a', 3, 'c'), row);
435     assertEquals(ImmutableMap.of(3, 'c'), subRow);
436     table.remove("foo", 3);
437     assertEquals(ImmutableMap.of(1, 'a'), row);
438     assertEquals(ImmutableMap.of(), subRow);
439     table.remove("foo", 1);
440     assertEquals(ImmutableMap.of(), row);
441     assertEquals(ImmutableMap.of(), subRow);
442     table.put("foo", 2, 'b');
443     assertEquals(ImmutableMap.of(2, 'b'), row);
444     assertEquals(ImmutableMap.of(2, 'b'), subRow);
445     row.clear();
446     assertEquals(ImmutableMap.of(), row);
447     assertEquals(ImmutableMap.of(), subRow);
448     table.put("foo", 5, 'x');
449     assertEquals(ImmutableMap.of(5, 'x'), row);
450     assertEquals(ImmutableMap.of(5, 'x'), subRow);
451   }
452 }