/*
* Copyright (C) 2008 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static org.junit.contrib.truth.Truth.ASSERT;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.testing.MapTestSuiteBuilder;
import com.google.common.collect.testing.SortedMapInterfaceTest;
import com.google.common.collect.testing.TestStringMapGenerator;
import com.google.common.collect.testing.features.CollectionSize;
import com.google.common.collect.testing.features.MapFeature;
import com.google.common.testing.SerializableTester;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
/**
* Test cases for {@link TreeBasedTable}.
*
* @author Jared Levy
* @author Louis Wasserman
*/
@GwtCompatible(emulated = true)
public class TreeBasedTableTest extends AbstractTableTest {
public static Test suite(){
TestSuite suite = new TestSuite();
suite.addTestSuite(TreeBasedTableTest.class);
suite.addTestSuite(TreeRowTest.class);
suite.addTest(MapTestSuiteBuilder
.using(new TestStringMapGenerator() {
@Override protected Map<String, String> create(
Entry<String, String>[] entries) {
TreeBasedTable<String, String, String> table =
TreeBasedTable.create();
table.put("a", "b", "c");
table.put("c", "b", "a");
table.put("a", "a", "d");
for (Entry<String, String> entry : entries) {
table.put("b", entry.getKey(), entry.getValue());
}
return table.row("b");
}
}).withFeatures(MapFeature.GENERAL_PURPOSE, CollectionSize.ANY)
.named("RowMapTestSuite").createTestSuite());
return suite;
}
public static class TreeRowTest extends
SortedMapInterfaceTest<String, String> {
public TreeRowTest() {
super(false, false, true, true, true);
}
@Override protected SortedMap<String, String> makeEmptyMap() {
TreeBasedTable<String, String, String> table = TreeBasedTable.create();
table.put("a", "b", "c");
table.put("c", "b", "a");
table.put("a", "a", "d");
return table.row("b");
}
@Override protected SortedMap<String, String> makePopulatedMap() {
TreeBasedTable<String, String, String> table = TreeBasedTable.create();
table.put("a", "b", "c");
table.put("c", "b", "a");
table.put("b", "b", "x");
table.put("b", "c", "y");
table.put("b", "x", "n");
table.put("a", "a", "d");
return table.row("b");
}
@Override protected String getKeyNotInPopulatedMap() {
return "q";
}
@Override protected String getValueNotInPopulatedMap() {
return "p";
}
public void testClearSubMapOfRowMap() {
TreeBasedTable<String, String, String> table = TreeBasedTable.create();
table.put("a", "b", "c");
table.put("c", "b", "a");
table.put("b", "b", "x");
table.put("b", "c", "y");
table.put("b", "x", "n");
table.put("a", "a", "d");
table.row("b").subMap("c", "x").clear();
assertEquals(table.row("b"), ImmutableMap.of("b", "x", "x", "n"));
table.row("b").subMap("b", "y").clear();
assertEquals(table.row("b"), ImmutableMap.of());
assertFalse(table.backingMap.containsKey("b"));
}
}
private TreeBasedTable<String, Integer, Character> sortedTable;
protected TreeBasedTable<String, Integer, Character> create(
Comparator<? super String> rowComparator,
Comparator<? super Integer> columnComparator,
Object... data) {
TreeBasedTable<String, Integer, Character> table =
TreeBasedTable.create(rowComparator, columnComparator);
table.put("foo", 4, 'a');
table.put("cat", 1, 'b');
table.clear();
populate(table, data);
return table;
}
@Override protected TreeBasedTable<String, Integer, Character> create(
Object... data) {
TreeBasedTable<String, Integer, Character> table = TreeBasedTable.create();
table.put("foo", 4, 'a');
table.put("cat", 1, 'b');
table.clear();
populate(table, data);
return table;
}
public void testCreateExplicitComparators() {
table = TreeBasedTable.create(
Collections.reverseOrder(), Ordering.usingToString());
table.put("foo", 3, 'a');
table.put("foo", 12, 'b');
table.put("bar", 5, 'c');
table.put("cat", 8, 'd');
ASSERT.that(table.rowKeySet()).hasContentsInOrder("foo", "cat", "bar");
ASSERT.that(table.row("foo").keySet()).hasContentsInOrder(12, 3);
}
public void testCreateCopy() {
TreeBasedTable<String, Integer, Character> original = TreeBasedTable.create(
Collections.reverseOrder(), Ordering.usingToString());
original.put("foo", 3, 'a');
original.put("foo", 12, 'b');
original.put("bar", 5, 'c');
original.put("cat", 8, 'd');
table = TreeBasedTable.create(original);
ASSERT.that(table.rowKeySet()).hasContentsInOrder("foo", "cat", "bar");
ASSERT.that(table.row("foo").keySet()).hasContentsInOrder(12, 3);
assertEquals(original, table);
}
@GwtIncompatible("SerializableTester")
public void testSerialization() {
table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
SerializableTester.reserializeAndAssert(table);
}
public void testToString_ordered() {
table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
assertEquals("{bar={1=b}, foo={1=a, 3=c}}", table.toString());
assertEquals("{bar={1=b}, foo={1=a, 3=c}}", table.rowMap().toString());
}
public void testCellSetToString_ordered() {
table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
assertEquals("[(bar,1)=b, (foo,1)=a, (foo,3)=c]",
table.cellSet().toString());
}
public void testRowKeySetToString_ordered() {
table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
assertEquals("[bar, foo]", table.rowKeySet().toString());
}
public void testValuesToString_ordered() {
table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
assertEquals("[b, a, c]", table.values().toString());
}
public void testRowComparator() {
sortedTable = TreeBasedTable.create();
assertSame(Ordering.natural(), sortedTable.rowComparator());
sortedTable = TreeBasedTable.create(
Collections.reverseOrder(), Ordering.usingToString());
assertSame(Collections.reverseOrder(), sortedTable.rowComparator());
}
public void testColumnComparator() {
sortedTable = TreeBasedTable.create();
assertSame(Ordering.natural(), sortedTable.columnComparator());
sortedTable = TreeBasedTable.create(
Collections.reverseOrder(), Ordering.usingToString());
assertSame(Ordering.usingToString(), sortedTable.columnComparator());
}
public void testRowKeySetComparator() {
sortedTable = TreeBasedTable.create();
assertSame(Ordering.natural(),
sortedTable.rowKeySet().comparator());
sortedTable = TreeBasedTable.create(
Collections.reverseOrder(), Ordering.usingToString());
assertSame(Collections.reverseOrder(),
sortedTable.rowKeySet().comparator());
}
public void testRowKeySetFirst() {
sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
assertSame("bar", sortedTable.rowKeySet().first());
}
public void testRowKeySetLast() {
sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
assertSame("foo", sortedTable.rowKeySet().last());
}
public void testRowKeySetHeadSet() {
sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
Set<String> set = sortedTable.rowKeySet().headSet("cat");
assertEquals(Collections.singleton("bar"), set);
set.clear();
assertTrue(set.isEmpty());
assertEquals(Collections.singleton("foo"), sortedTable.rowKeySet());
}
public void testRowKeySetTailSet() {
sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
Set<String> set = sortedTable.rowKeySet().tailSet("cat");
assertEquals(Collections.singleton("foo"), set);
set.clear();
assertTrue(set.isEmpty());
assertEquals(Collections.singleton("bar"), sortedTable.rowKeySet());
}
public void testRowKeySetSubSet() {
sortedTable = create(
"foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c', "dog", 2, 'd');
Set<String> set = sortedTable.rowKeySet().subSet("cat", "egg");
assertEquals(Collections.singleton("dog"), set);
set.clear();
assertTrue(set.isEmpty());
assertEquals(ImmutableSet.of("bar", "foo"), sortedTable.rowKeySet());
}
public void testRowMapComparator() {
sortedTable = TreeBasedTable.create();
assertSame(Ordering.natural(), sortedTable.rowMap().comparator());
sortedTable = TreeBasedTable.create(
Collections.reverseOrder(), Ordering.usingToString());
assertSame(Collections.reverseOrder(), sortedTable.rowMap().comparator());
}
public void testRowMapFirstKey() {
sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
assertSame("bar", sortedTable.rowMap().firstKey());
}
public void testRowMapLastKey() {
sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
assertSame("foo", sortedTable.rowMap().lastKey());
}
public void testRowKeyMapHeadMap() {
sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
Map<String, Map<Integer, Character>> map
= sortedTable.rowMap().headMap("cat");
assertEquals(1, map.size());
assertEquals(ImmutableMap.of(1, 'b'), map.get("bar"));
map.clear();
assertTrue(map.isEmpty());
assertEquals(Collections.singleton("foo"), sortedTable.rowKeySet());
}
public void testRowKeyMapTailMap() {
sortedTable = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
Map<String, Map<Integer, Character>> map
= sortedTable.rowMap().tailMap("cat");
assertEquals(1, map.size());
assertEquals(ImmutableMap.of(1, 'a', 3, 'c'), map.get("foo"));
map.clear();
assertTrue(map.isEmpty());
assertEquals(Collections.singleton("bar"), sortedTable.rowKeySet());
}
public void testRowKeyMapSubMap() {
sortedTable = create(
"foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c', "dog", 2, 'd');
Map<String, Map<Integer, Character>> map
= sortedTable.rowMap().subMap("cat", "egg");
assertEquals(ImmutableMap.of(2, 'd'), map.get("dog"));
map.clear();
assertTrue(map.isEmpty());
assertEquals(ImmutableSet.of("bar", "foo"), sortedTable.rowKeySet());
}
public void testRowMapValuesAreSorted(){
sortedTable = create(
"foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c', "dog", 2, 'd');
assertTrue(sortedTable.rowMap().get("foo") instanceof SortedMap);
}
public void testColumnKeySet_isSorted() {
table = create("a", 2, 'X',
"a", 2, 'X',
"b", 3, 'X',
"b", 2, 'X',
"c", 10, 'X',
"c", 10, 'X',
"c", 20, 'X',
"d", 15, 'X',
"d", 20, 'X',
"d", 1, 'X',
"e", 5, 'X'
);
assertEquals("[1, 2, 3, 5, 10, 15, 20]", table.columnKeySet().toString());
}
public void testColumnKeySet_isSortedWithRealComparator() {
table = create(String.CASE_INSENSITIVE_ORDER,
Ordering.natural().reverse(),
"a", 2, 'X',
"a", 2, 'X',
"b", 3, 'X',
"b", 2, 'X',
"c", 10, 'X',
"c", 10, 'X',
"c", 20, 'X',
"d", 15, 'X',
"d", 20, 'X',
"d", 1, 'X',
"e", 5, 'X'
);
assertEquals("[20, 15, 10, 5, 3, 2, 1]", table.columnKeySet().toString());
}
public void testColumnKeySet_empty() {
table = create();
assertEquals("[]", table.columnKeySet().toString());
}
public void testColumnKeySet_oneRow() {
table = create("a", 2, 'X',
"a", 1, 'X'
);
assertEquals("[1, 2]", table.columnKeySet().toString());
}
public void testColumnKeySet_oneColumn() {
table = create("a", 1, 'X',
"b", 1, 'X'
);
assertEquals("[1]", table.columnKeySet().toString());
}
public void testColumnKeySet_oneEntry() {
table = create("a", 1, 'X');
assertEquals("[1]", table.columnKeySet().toString());
}
public void testRowEntrySetContains(){
table =
sortedTable =
create("a", 2, 'X', "a", 2, 'X', "b", 3, 'X', "b", 2, 'X', "c", 10,
'X', "c", 10, 'X', "c", 20, 'X', "d", 15, 'X', "d", 20, 'X',
"d", 1, 'X', "e", 5, 'X');
SortedMap<Integer, Character> row = sortedTable.row("c");
Set<Map.Entry<Integer, Character>> entrySet = row.entrySet();
assertTrue(entrySet.contains(Maps.immutableEntry(10, 'X')));
assertTrue(entrySet.contains(Maps.immutableEntry(20, 'X')));
assertFalse(entrySet.contains(Maps.immutableEntry(15, 'X')));
entrySet = row.tailMap(15).entrySet();
assertFalse(entrySet.contains(Maps.immutableEntry(10, 'X')));
assertTrue(entrySet.contains(Maps.immutableEntry(20, 'X')));
assertFalse(entrySet.contains(Maps.immutableEntry(15, 'X')));
}
public void testRowEntrySetRemove(){
table =
sortedTable =
create("a", 2, 'X', "a", 2, 'X', "b", 3, 'X', "b", 2, 'X', "c", 10,
'X', "c", 10, 'X', "c", 20, 'X', "d", 15, 'X', "d", 20, 'X',
"d", 1, 'X', "e", 5, 'X');
SortedMap<Integer, Character> row = sortedTable.row("c");
Set<Map.Entry<Integer, Character>> entrySet = row.tailMap(15).entrySet();
assertFalse(entrySet.remove(Maps.immutableEntry(10, 'X')));
assertTrue(entrySet.remove(Maps.immutableEntry(20, 'X')));
assertFalse(entrySet.remove(Maps.immutableEntry(15, 'X')));
entrySet = row.entrySet();
assertTrue(entrySet.remove(Maps.immutableEntry(10, 'X')));
assertFalse(entrySet.remove(Maps.immutableEntry(20, 'X')));
assertFalse(entrySet.remove(Maps.immutableEntry(15, 'X')));
}
public void testRowSize(){
table =
sortedTable =
create("a", 2, 'X', "a", 2, 'X', "b", 3, 'X', "b", 2, 'X', "c", 10,
'X', "c", 10, 'X', "c", 20, 'X', "d", 15, 'X', "d", 20, 'X',
"d", 1, 'X', "e", 5, 'X');
SortedMap<Integer, Character> row = sortedTable.row("c");
assertEquals(row.size(), 2);
assertEquals(row.tailMap(15).size(), 1);
}
public void testSubRowClearAndPut() {
table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
SortedMap<Integer, Character> row = (SortedMap<Integer, Character>) table.row("foo");
SortedMap<Integer, Character> subRow = row.tailMap(2);
assertEquals(ImmutableMap.of(1, 'a', 3, 'c'), row);
assertEquals(ImmutableMap.of(3, 'c'), subRow);
table.remove("foo", 3);
assertEquals(ImmutableMap.of(1, 'a'), row);
assertEquals(ImmutableMap.of(), subRow);
table.remove("foo", 1);
assertEquals(ImmutableMap.of(), row);
assertEquals(ImmutableMap.of(), subRow);
table.put("foo", 2, 'b');
assertEquals(ImmutableMap.of(2, 'b'), row);
assertEquals(ImmutableMap.of(2, 'b'), subRow);
row.clear();
assertEquals(ImmutableMap.of(), row);
assertEquals(ImmutableMap.of(), subRow);
table.put("foo", 5, 'x');
assertEquals(ImmutableMap.of(5, 'x'), row);
assertEquals(ImmutableMap.of(5, 'x'), subRow);
}
}