Home | History | Annotate | Download | only in collect
      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.base.Preconditions.checkNotNull;
     20 import static com.google.common.collect.testing.testers.CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod;
     21 import static com.google.common.collect.testing.testers.CollectionIteratorTester.getIteratorUnknownOrderRemoveSupportedMethod;
     22 
     23 import com.google.common.annotations.GwtCompatible;
     24 import com.google.common.annotations.GwtIncompatible;
     25 import com.google.common.base.Function;
     26 import com.google.common.base.Functions;
     27 import com.google.common.collect.Table.Cell;
     28 import com.google.common.collect.testing.CollectionTestSuiteBuilder;
     29 import com.google.common.collect.testing.MapInterfaceTest;
     30 import com.google.common.collect.testing.SampleElements;
     31 import com.google.common.collect.testing.SetTestSuiteBuilder;
     32 import com.google.common.collect.testing.TestSetGenerator;
     33 import com.google.common.collect.testing.TestStringCollectionGenerator;
     34 import com.google.common.collect.testing.TestStringSetGenerator;
     35 import com.google.common.collect.testing.features.CollectionFeature;
     36 import com.google.common.collect.testing.features.CollectionSize;
     37 import com.google.common.collect.testing.features.Feature;
     38 
     39 import junit.framework.Test;
     40 import junit.framework.TestCase;
     41 import junit.framework.TestSuite;
     42 
     43 import java.util.Arrays;
     44 import java.util.Collection;
     45 import java.util.Collections;
     46 import java.util.List;
     47 import java.util.Map;
     48 import java.util.Set;
     49 import java.util.SortedMap;
     50 
     51 /**
     52  * Collection tests for {@link Table} implementations.
     53  *
     54  * @author Jared Levy
     55  * @author Louis Wasserman
     56  */
     57 @GwtCompatible(emulated = true)
     58 public class TableCollectionTest extends TestCase {
     59 
     60   private static final Feature<?>[] COLLECTION_FEATURES = {
     61     CollectionSize.ANY,
     62     CollectionFeature.ALLOWS_NULL_QUERIES
     63   };
     64 
     65   private static final Feature<?>[] COLLECTION_FEATURES_ORDER = {
     66     CollectionSize.ANY,
     67     CollectionFeature.KNOWN_ORDER,
     68     CollectionFeature.ALLOWS_NULL_QUERIES
     69   };
     70 
     71   private static final Feature<?>[] COLLECTION_FEATURES_REMOVE = {
     72     CollectionSize.ANY,
     73     CollectionFeature.REMOVE_OPERATIONS,
     74     CollectionFeature.ALLOWS_NULL_QUERIES
     75   };
     76 
     77   private static final Feature<?>[] COLLECTION_FEATURES_REMOVE_ORDER = {
     78     CollectionSize.ANY,
     79     CollectionFeature.KNOWN_ORDER,
     80     CollectionFeature.REMOVE_OPERATIONS,
     81     CollectionFeature.ALLOWS_NULL_QUERIES
     82   };
     83 
     84   @GwtIncompatible("suite")
     85   public static Test suite() {
     86     TestSuite suite = new TestSuite();
     87     suite.addTestSuite(ArrayRowTests.class);
     88     suite.addTestSuite(HashRowTests.class);
     89     suite.addTestSuite(TreeRowTests.class);
     90     suite.addTestSuite(TransposeRowTests.class);
     91     suite.addTestSuite(TransformValueRowTests.class);
     92     suite.addTestSuite(UnmodifiableHashRowTests.class);
     93     suite.addTestSuite(UnmodifiableTreeRowTests.class);
     94     suite.addTestSuite(ArrayColumnTests.class);
     95     suite.addTestSuite(HashColumnTests.class);
     96     suite.addTestSuite(TreeColumnTests.class);
     97     suite.addTestSuite(TransposeColumnTests.class);
     98     suite.addTestSuite(TransformValueColumnTests.class);
     99     suite.addTestSuite(UnmodifiableHashColumnTests.class);
    100     suite.addTestSuite(UnmodifiableTreeColumnTests.class);
    101     suite.addTestSuite(ArrayRowMapTests.class);
    102     suite.addTestSuite(HashRowMapTests.class);
    103     suite.addTestSuite(TreeRowMapTests.class);
    104     suite.addTestSuite(TreeRowMapHeadMapTests.class);
    105     suite.addTestSuite(TreeRowMapTailMapTests.class);
    106     suite.addTestSuite(TreeRowMapSubMapTests.class);
    107     suite.addTestSuite(TransformValueRowMapTests.class);
    108     suite.addTestSuite(UnmodifiableHashRowMapTests.class);
    109     suite.addTestSuite(UnmodifiableTreeRowMapTests.class);
    110     suite.addTestSuite(ArrayColumnMapTests.class);
    111     suite.addTestSuite(HashColumnMapTests.class);
    112     suite.addTestSuite(TreeColumnMapTests.class);
    113     suite.addTestSuite(TransformValueColumnMapTests.class);
    114     suite.addTestSuite(UnmodifiableHashColumnMapTests.class);
    115     suite.addTestSuite(UnmodifiableTreeColumnMapTests.class);
    116 
    117     // Not testing rowKeySet() or columnKeySet() of Table.transformValues()
    118     // since the transformation doesn't affect the row and column key sets.
    119 
    120     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    121           @Override protected Set<String> create(String[] elements) {
    122             Table<String, Integer, Character> table
    123                 = ArrayTable.create(
    124                     ImmutableList.copyOf(elements), ImmutableList.of(1, 2));
    125             populateForRowKeySet(table, elements);
    126             return table.rowKeySet();
    127           }
    128         })
    129         .named("ArrayTable.rowKeySet")
    130         .withFeatures(CollectionSize.ONE, CollectionSize.SEVERAL,
    131             CollectionFeature.KNOWN_ORDER,
    132             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
    133             CollectionFeature.ALLOWS_NULL_QUERIES)
    134         .createTestSuite());
    135 
    136     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    137           @Override protected Set<String> create(String[] elements) {
    138             Table<String, Integer, Character> table = HashBasedTable.create();
    139             populateForRowKeySet(table, elements);
    140             return table.rowKeySet();
    141           }
    142         })
    143         .named("HashBasedTable.rowKeySet")
    144         .withFeatures(COLLECTION_FEATURES_REMOVE)
    145         .createTestSuite());
    146 
    147     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    148           @Override protected Set<String> create(String[] elements) {
    149             Table<String, Integer, Character> table = TreeBasedTable.create();
    150             populateForRowKeySet(table, elements);
    151             return table.rowKeySet();
    152           }
    153 
    154           @Override public List<String> order(List<String> insertionOrder) {
    155             Collections.sort(insertionOrder);
    156             return insertionOrder;
    157           }
    158         })
    159         .named("TreeBasedTable.rowKeySet")
    160         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
    161         .createTestSuite());
    162 
    163     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    164           @Override protected Set<String> create(String[] elements) {
    165             TreeBasedTable<String, Integer, Character> table
    166                 = TreeBasedTable.create();
    167             populateForRowKeySet(table, elements);
    168             table.put("z", 1, 'a');
    169             return table.rowKeySet().headSet("x");
    170           }
    171 
    172           @Override public List<String> order(List<String> insertionOrder) {
    173             Collections.sort(insertionOrder);
    174             return insertionOrder;
    175           }
    176         })
    177         .named("TreeBasedTable.rowKeySet.headSet")
    178         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
    179         .createTestSuite());
    180 
    181     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    182           @Override protected Set<String> create(String[] elements) {
    183             TreeBasedTable<String, Integer, Character> table
    184                 = TreeBasedTable.create();
    185             populateForRowKeySet(table, elements);
    186             table.put("\0", 1, 'a');
    187             return table.rowKeySet().tailSet("a");
    188           }
    189 
    190           @Override public List<String> order(List<String> insertionOrder) {
    191             Collections.sort(insertionOrder);
    192             return insertionOrder;
    193           }
    194         })
    195         .named("TreeBasedTable.rowKeySet.tailSet")
    196         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
    197         .createTestSuite());
    198 
    199     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    200           @Override protected Set<String> create(String[] elements) {
    201             TreeBasedTable<String, Integer, Character> table
    202                 = TreeBasedTable.create();
    203             populateForRowKeySet(table, elements);
    204             table.put("\0", 1, 'a');
    205             table.put("z", 1, 'a');
    206             return table.rowKeySet().subSet("a", "x");
    207           }
    208 
    209           @Override public List<String> order(List<String> insertionOrder) {
    210             Collections.sort(insertionOrder);
    211             return insertionOrder;
    212           }
    213         })
    214         .named("TreeBasedTable.rowKeySet.subSet")
    215         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
    216         .createTestSuite());
    217 
    218     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    219           @Override protected Set<String> create(String[] elements) {
    220             Table<String, Integer, Character> table = HashBasedTable.create();
    221             populateForRowKeySet(table, elements);
    222             return Tables.unmodifiableTable(table).rowKeySet();
    223           }
    224         })
    225         .named("unmodifiableTable[HashBasedTable].rowKeySet")
    226         .withFeatures(COLLECTION_FEATURES)
    227         .createTestSuite());
    228 
    229     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    230           @Override protected Set<String> create(String[] elements) {
    231             RowSortedTable<String, Integer, Character> table = TreeBasedTable.create();
    232             populateForRowKeySet(table, elements);
    233             return Tables.unmodifiableRowSortedTable(table).rowKeySet();
    234           }
    235 
    236           @Override public List<String> order(List<String> insertionOrder) {
    237             Collections.sort(insertionOrder);
    238             return insertionOrder;
    239           }
    240         })
    241         .named("unmodifiableRowSortedTable[TreeBasedTable].rowKeySet")
    242         .withFeatures(COLLECTION_FEATURES_ORDER)
    243         .createTestSuite());
    244 
    245     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    246           @Override protected Set<String> create(String[] elements) {
    247             Table<Integer, String, Character> table
    248                 = ArrayTable.create(
    249                     ImmutableList.of(1, 2), ImmutableList.copyOf(elements));
    250             populateForColumnKeySet(table, elements);
    251             return table.columnKeySet();
    252           }
    253         })
    254         .named("ArrayTable.columnKeySet")
    255         .withFeatures(CollectionSize.ONE, CollectionSize.SEVERAL,
    256             CollectionFeature.KNOWN_ORDER,
    257             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
    258             CollectionFeature.ALLOWS_NULL_QUERIES)
    259         .createTestSuite());
    260 
    261     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    262           @Override protected Set<String> create(String[] elements) {
    263             Table<Integer, String, Character> table = HashBasedTable.create();
    264             populateForColumnKeySet(table, elements);
    265             return table.columnKeySet();
    266           }
    267         })
    268         .named("HashBasedTable.columnKeySet")
    269         .withFeatures(COLLECTION_FEATURES_REMOVE)
    270         .suppressing(getIteratorUnknownOrderRemoveSupportedMethod())
    271         .createTestSuite());
    272 
    273     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    274           @Override protected Set<String> create(String[] elements) {
    275             Table<Integer, String, Character> table = TreeBasedTable.create();
    276             populateForColumnKeySet(table, elements);
    277             return table.columnKeySet();
    278           }
    279 
    280           @Override public List<String> order(List<String> insertionOrder) {
    281             Collections.sort(insertionOrder);
    282             return insertionOrder;
    283           }
    284         })
    285         .named("TreeBasedTable.columnKeySet")
    286         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
    287         .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
    288         .createTestSuite());
    289 
    290     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    291           @Override protected Set<String> create(String[] elements) {
    292             Table<Integer, String, Character> table = HashBasedTable.create();
    293             populateForColumnKeySet(table, elements);
    294             return Tables.unmodifiableTable(table).columnKeySet();
    295           }
    296         })
    297         .named("unmodifiableTable[HashBasedTable].columnKeySet")
    298         .withFeatures(COLLECTION_FEATURES)
    299         .suppressing(getIteratorUnknownOrderRemoveSupportedMethod())
    300         .createTestSuite());
    301 
    302     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    303           @Override protected Set<String> create(String[] elements) {
    304             RowSortedTable<Integer, String, Character> table = TreeBasedTable.create();
    305             populateForColumnKeySet(table, elements);
    306             return Tables.unmodifiableRowSortedTable(table).columnKeySet();
    307           }
    308 
    309           @Override public List<String> order(List<String> insertionOrder) {
    310             Collections.sort(insertionOrder);
    311             return insertionOrder;
    312           }
    313         })
    314         .named("unmodifiableRowSortedTable[TreeBasedTable].columnKeySet")
    315         .withFeatures(COLLECTION_FEATURES_ORDER)
    316         .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
    317         .createTestSuite());
    318 
    319     suite.addTest(CollectionTestSuiteBuilder.using(
    320         new TestStringCollectionGenerator() {
    321           @Override protected Collection<String> create(String[] elements) {
    322             List<Integer> rowKeys = Lists.newArrayList();
    323             for (int i = 0; i < elements.length; i++) {
    324               rowKeys.add(i);
    325             }
    326             Table<Integer, Character, String> table
    327                 = ArrayTable.create(rowKeys, ImmutableList.of('a'));
    328             populateForValues(table, elements);
    329             return table.values();
    330           }
    331         })
    332         .named("ArrayTable.values")
    333         .withFeatures(CollectionSize.ONE, CollectionSize.SEVERAL,
    334             CollectionFeature.ALLOWS_NULL_VALUES,
    335             CollectionFeature.KNOWN_ORDER)
    336         .createTestSuite());
    337 
    338     suite.addTest(CollectionTestSuiteBuilder.using(
    339         new TestStringCollectionGenerator() {
    340           @Override protected Collection<String> create(String[] elements) {
    341             Table<Integer, Character, String> table = HashBasedTable.create();
    342             table.put(1, 'a', "foo");
    343             table.clear();
    344             populateForValues(table, elements);
    345             return table.values();
    346           }
    347         })
    348         .named("HashBasedTable.values")
    349         .withFeatures(COLLECTION_FEATURES_REMOVE)
    350         .createTestSuite());
    351 
    352     suite.addTest(CollectionTestSuiteBuilder.using(
    353         new TestStringCollectionGenerator() {
    354           @Override protected Collection<String> create(String[] elements) {
    355             Table<Integer, Character, String> table = TreeBasedTable.create();
    356             table.put(1, 'a', "foo");
    357             table.clear();
    358             populateForValues(table, elements);
    359             return table.values();
    360           }
    361         })
    362         .named("TreeBasedTable.values")
    363         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
    364         .createTestSuite());
    365 
    366     final Function<String, String> removeFirstCharacter
    367         = new Function<String, String>() {
    368           @Override public String apply(String input) {
    369             return input.substring(1);
    370           }
    371         };
    372 
    373     suite.addTest(CollectionTestSuiteBuilder.using(
    374         new TestStringCollectionGenerator() {
    375           @Override protected Collection<String> create(String[] elements) {
    376             Table<Integer, Character, String> table = HashBasedTable.create();
    377             for (int i = 0; i < elements.length; i++) {
    378               table.put(i, 'a', "x" + checkNotNull(elements[i]));
    379             }
    380             return Tables.transformValues(table, removeFirstCharacter).values();
    381           }
    382         })
    383         .named("TransformValues.values")
    384         .withFeatures(COLLECTION_FEATURES_REMOVE)
    385         .createTestSuite());
    386 
    387     suite.addTest(CollectionTestSuiteBuilder.using(
    388         new TestStringCollectionGenerator() {
    389           @Override protected Collection<String> create(String[] elements) {
    390             Table<Integer, Character, String> table = HashBasedTable.create();
    391             table.put(1, 'a', "foo");
    392             table.clear();
    393             populateForValues(table, elements);
    394             return Tables.unmodifiableTable(table).values();
    395           }
    396         })
    397         .named("unmodifiableTable[HashBasedTable].values")
    398         .withFeatures(COLLECTION_FEATURES)
    399         .createTestSuite());
    400 
    401     suite.addTest(CollectionTestSuiteBuilder.using(
    402         new TestStringCollectionGenerator() {
    403           @Override protected Collection<String> create(String[] elements) {
    404             RowSortedTable<Integer, Character, String> table = TreeBasedTable.create();
    405             table.put(1, 'a', "foo");
    406             table.clear();
    407             populateForValues(table, elements);
    408             return Tables.unmodifiableRowSortedTable(table).values();
    409           }
    410         })
    411         .named("unmodifiableTable[TreeBasedTable].values")
    412         .withFeatures(COLLECTION_FEATURES_ORDER)
    413         .createTestSuite());
    414 
    415     suite.addTest(SetTestSuiteBuilder.using(new TestCellSetGenerator() {
    416           @Override public SampleElements<Cell<String, Integer, Character>>
    417               samples() {
    418             return new SampleElements<Cell<String, Integer, Character>>(
    419                 Tables.immutableCell("bar", 1, 'a'),
    420                 Tables.immutableCell("bar", 2, 'b'),
    421                 Tables.immutableCell("bar", 3, (Character) null),
    422                 Tables.immutableCell("bar", 4, 'b'),
    423                 Tables.immutableCell("bar", 5, 'b'));
    424           }
    425           @Override public Set<Cell<String, Integer, Character>> create(
    426               Object... elements) {
    427             List<Integer> columnKeys = Lists.newArrayList();
    428             for (Object element : elements) {
    429               @SuppressWarnings("unchecked")
    430               Cell<String, Integer, Character> cell
    431                   = (Cell<String, Integer, Character>) element;
    432               columnKeys.add(cell.getColumnKey());
    433             }
    434             Table<String, Integer, Character> table
    435                 = ArrayTable.create(ImmutableList.of("bar"), columnKeys);
    436             for (Object element : elements) {
    437               @SuppressWarnings("unchecked")
    438               Cell<String, Integer, Character> cell
    439                   = (Cell<String, Integer, Character>) element;
    440               table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
    441             }
    442             return table.cellSet();
    443           }
    444           @Override Table<String, Integer, Character> createTable() {
    445             throw new UnsupportedOperationException();
    446           }
    447         })
    448         .named("ArrayTable.cellSet")
    449         .withFeatures(CollectionSize.ONE, CollectionSize.SEVERAL,
    450             CollectionFeature.KNOWN_ORDER,
    451             CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
    452             CollectionFeature.ALLOWS_NULL_QUERIES)
    453         .createTestSuite());
    454 
    455     suite.addTest(SetTestSuiteBuilder.using(new TestCellSetGenerator() {
    456           @Override Table<String, Integer, Character> createTable() {
    457             return HashBasedTable.create();
    458           }
    459         })
    460         .named("HashBasedTable.cellSet")
    461         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS,
    462             CollectionFeature.ALLOWS_NULL_QUERIES)
    463         .createTestSuite());
    464 
    465     suite.addTest(SetTestSuiteBuilder.using(new TestCellSetGenerator() {
    466           @Override Table<String, Integer, Character> createTable() {
    467             return TreeBasedTable.create();
    468           }
    469         })
    470         .named("TreeBasedTable.cellSet")
    471         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS,
    472             CollectionFeature.ALLOWS_NULL_QUERIES)
    473         .createTestSuite());
    474 
    475     suite.addTest(SetTestSuiteBuilder.using(new TestCellSetGenerator() {
    476           @Override Table<String, Integer, Character> createTable() {
    477             Table<Integer, String, Character> original
    478                 = TreeBasedTable.create();
    479             return Tables.transpose(original);
    480           }
    481         })
    482         .named("TransposedTable.cellSet")
    483         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS,
    484             CollectionFeature.ALLOWS_NULL_QUERIES)
    485         .createTestSuite());
    486 
    487     suite.addTest(SetTestSuiteBuilder.using(new TestCellSetGenerator() {
    488           @Override Table<String, Integer, Character> createTable() {
    489             return HashBasedTable.create();
    490           }
    491           @Override
    492           public Set<Cell<String, Integer, Character>> create(
    493               Object... elements) {
    494             Table<String, Integer, Character> table = createTable();
    495             for (Object element : elements) {
    496               @SuppressWarnings("unchecked")
    497               Cell<String, Integer, Character> cell
    498                   = (Cell<String, Integer, Character>) element;
    499               table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
    500             }
    501             return Tables.transformValues(table, Functions.<Character>identity()).cellSet();
    502           }
    503         })
    504         .named("TransformValues.cellSet")
    505         .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES)
    506         .createTestSuite());
    507 
    508     suite.addTest(SetTestSuiteBuilder.using(new TestCellSetGenerator() {
    509           @Override Table<String, Integer, Character> createTable() {
    510             return Tables.unmodifiableTable(HashBasedTable.<String, Integer, Character> create());
    511           }
    512           @Override
    513           public Set<Cell<String, Integer, Character>> create(
    514               Object... elements) {
    515             Table<String, Integer, Character> table = HashBasedTable.create();
    516             for (Object element : elements) {
    517               @SuppressWarnings("unchecked")
    518               Cell<String, Integer, Character> cell
    519                   = (Cell<String, Integer, Character>) element;
    520               table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
    521             }
    522             return Tables.unmodifiableTable(table).cellSet();
    523           }
    524         })
    525         .named("unmodifiableTable[HashBasedTable].cellSet")
    526         .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES)
    527         .createTestSuite());
    528 
    529     suite.addTest(SetTestSuiteBuilder.using(new TestCellSetGenerator() {
    530           @Override RowSortedTable<String, Integer, Character> createTable() {
    531             return Tables.unmodifiableRowSortedTable(TreeBasedTable
    532                 .<String, Integer, Character> create());
    533           }
    534           @Override
    535           public Set<Cell<String, Integer, Character>> create(
    536               Object... elements) {
    537             RowSortedTable<String, Integer, Character> table = TreeBasedTable.create();
    538             for (Object element : elements) {
    539               @SuppressWarnings("unchecked")
    540               Cell<String, Integer, Character> cell
    541                   = (Cell<String, Integer, Character>) element;
    542               table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
    543             }
    544             return Tables.unmodifiableRowSortedTable(table).cellSet();
    545           }
    546         })
    547         .named("unmodifiableRowSortedTable[TreeBasedTable].cellSet")
    548         .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES)
    549         .createTestSuite());
    550 
    551     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    552           @Override protected Set<String> create(String[] elements) {
    553             Iterable<String> rowKeys = ImmutableSet.copyOf(elements);
    554             Iterable<Integer> columnKeys = ImmutableList.of(1, 2, 3);
    555             Table<String, Integer, Character> table
    556                 = ArrayTable.create(rowKeys, columnKeys);
    557             populateForRowKeySet(table, elements);
    558             return table.column(1).keySet();
    559           }
    560         })
    561         .named("ArrayTable.column.keySet")
    562         .withFeatures(CollectionSize.ONE, CollectionSize.SEVERAL,
    563             CollectionFeature.KNOWN_ORDER,
    564             CollectionFeature.ALLOWS_NULL_QUERIES)
    565         .createTestSuite());
    566 
    567     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    568           @Override protected Set<String> create(String[] elements) {
    569             Table<String, Integer, Character> table = HashBasedTable.create();
    570             populateForRowKeySet(table, elements);
    571             return table.column(1).keySet();
    572           }
    573         })
    574         .named("HashBasedTable.column.keySet")
    575         .withFeatures(COLLECTION_FEATURES_REMOVE)
    576         .suppressing(getIteratorUnknownOrderRemoveSupportedMethod())
    577     .createTestSuite());
    578 
    579     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    580           @Override protected Set<String> create(String[] elements) {
    581             Table<String, Integer, Character> table = TreeBasedTable.create();
    582             populateForRowKeySet(table, elements);
    583             return table.column(1).keySet();
    584           }
    585           @Override public List<String> order(List<String> insertionOrder) {
    586             Collections.sort(insertionOrder);
    587             return insertionOrder;
    588           }
    589         })
    590         .named("TreeBasedTable.column.keySet")
    591         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
    592         .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
    593         .createTestSuite());
    594 
    595     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    596           @Override protected Set<String> create(String[] elements) {
    597             Table<String, Integer, Character> table = HashBasedTable.create();
    598             populateForRowKeySet(table, elements);
    599             return Tables.transformValues(table, Functions.toStringFunction()).column(1).keySet();
    600           }
    601         })
    602         .named("TransformValues.column.keySet")
    603         .withFeatures(COLLECTION_FEATURES_REMOVE)
    604         .suppressing(getIteratorUnknownOrderRemoveSupportedMethod())
    605     .createTestSuite());
    606 
    607     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    608           @Override protected Set<String> create(String[] elements) {
    609             Table<String, Integer, Character> table = HashBasedTable.create();
    610             populateForRowKeySet(table, elements);
    611             return Tables.unmodifiableTable(table).column(1).keySet();
    612           }
    613         })
    614         .named("unmodifiableTable[HashBasedTable].column.keySet")
    615         .withFeatures(COLLECTION_FEATURES)
    616         .suppressing(getIteratorUnknownOrderRemoveSupportedMethod())
    617     .createTestSuite());
    618 
    619     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
    620           @Override protected Set<String> create(String[] elements) {
    621             RowSortedTable<String, Integer, Character> table = TreeBasedTable.create();
    622             populateForRowKeySet(table, elements);
    623             return Tables.unmodifiableRowSortedTable(table).column(1).keySet();
    624           }
    625           @Override public List<String> order(List<String> insertionOrder) {
    626             Collections.sort(insertionOrder);
    627             return insertionOrder;
    628           }
    629         })
    630         .named("unmodifiableRowSortedTable[TreeBasedTable].column.keySet")
    631         .withFeatures(COLLECTION_FEATURES_ORDER)
    632         .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
    633         .createTestSuite());
    634 
    635     return suite;
    636   }
    637 
    638   private static void populateForRowKeySet(
    639       Table<String, Integer, Character> table, String[] elements) {
    640     for (String row : elements) {
    641       table.put(row, 1, 'a');
    642       table.put(row, 2, 'b');
    643     }
    644   }
    645 
    646   private static void populateForColumnKeySet(
    647       Table<Integer, String, Character> table, String[] elements) {
    648     for (String column : elements) {
    649       table.put(1, column, 'a');
    650       table.put(2, column, 'b');
    651     }
    652   }
    653 
    654   private static void populateForValues(
    655       Table<Integer, Character, String> table, String[] elements) {
    656     for (int i = 0; i < elements.length; i++) {
    657       table.put(i, 'a', elements[i]);
    658     }
    659   }
    660 
    661   private static abstract class TestCellSetGenerator
    662       implements TestSetGenerator<Cell<String, Integer, Character>> {
    663     @Override
    664     public SampleElements<Cell<String, Integer, Character>> samples() {
    665       return new SampleElements<Cell<String, Integer, Character>>(
    666           Tables.immutableCell("bar", 1, 'a'),
    667           Tables.immutableCell("bar", 2, 'b'),
    668           Tables.immutableCell("foo", 3, 'c'),
    669           Tables.immutableCell("bar", 1, 'b'),
    670           Tables.immutableCell("cat", 2, 'b'));
    671     }
    672 
    673     @Override
    674     public Set<Cell<String, Integer, Character>> create(
    675         Object... elements) {
    676       Table<String, Integer, Character> table = createTable();
    677       for (Object element : elements) {
    678         @SuppressWarnings("unchecked")
    679         Cell<String, Integer, Character> cell
    680             = (Cell<String, Integer, Character>) element;
    681         table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
    682       }
    683       return table.cellSet();
    684     }
    685 
    686     abstract Table<String, Integer, Character> createTable();
    687 
    688     @Override
    689     @SuppressWarnings("unchecked")
    690     public Cell<String, Integer, Character>[] createArray(int length) {
    691       return (Cell<String, Integer, Character>[]) new Cell<?, ?, ?>[length];
    692     }
    693 
    694     @Override
    695     public List<Cell<String, Integer, Character>> order(
    696         List<Cell<String, Integer, Character>> insertionOrder) {
    697       return insertionOrder;
    698     }
    699   }
    700 
    701   private static abstract class MapTests
    702       extends MapInterfaceTest<String, Integer> {
    703 
    704     MapTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove,
    705         boolean supportsClear, boolean supportsIteratorRemove) {
    706       super(false, allowsNullValues, supportsPut, supportsRemove, supportsClear,
    707           supportsIteratorRemove);
    708     }
    709 
    710     @Override protected String getKeyNotInPopulatedMap() {
    711       return "four";
    712     }
    713 
    714     @Override protected Integer getValueNotInPopulatedMap() {
    715       return 4;
    716     }
    717   }
    718 
    719   private static abstract class RowTests extends MapTests {
    720     RowTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove,
    721         boolean supportsClear, boolean supportsIteratorRemove) {
    722       super(allowsNullValues, supportsPut, supportsRemove, supportsClear,
    723           supportsIteratorRemove);
    724     }
    725 
    726     abstract Table<Character, String, Integer> makeTable();
    727 
    728     @Override protected Map<String, Integer> makeEmptyMap() {
    729       return makeTable().row('a');
    730     }
    731 
    732     @Override protected Map<String, Integer> makePopulatedMap() {
    733       Table<Character, String, Integer> table = makeTable();
    734       table.put('a', "one", 1);
    735       table.put('a', "two", 2);
    736       table.put('a', "three", 3);
    737       table.put('b', "four", 4);
    738       return table.row('a');
    739     }
    740   }
    741 
    742   @GwtIncompatible("TODO(hhchan): ArrayTable")
    743   public static class ArrayRowTests extends RowTests {
    744     public ArrayRowTests() {
    745       super(true, true, false, false, false);
    746     }
    747 
    748     @Override protected String getKeyNotInPopulatedMap() {
    749       throw new UnsupportedOperationException();
    750     }
    751 
    752     @Override protected Map<String, Integer> makeEmptyMap() {
    753       throw new UnsupportedOperationException();
    754     }
    755 
    756     @Override protected Table<Character, String, Integer> makeTable() {
    757       return ArrayTable.create(Arrays.asList('a', 'b', 'c'),
    758           Arrays.asList("one", "two", "three", "four"));
    759     }
    760   }
    761 
    762   public static class HashRowTests extends RowTests {
    763     public HashRowTests() {
    764       super(false, true, true, true, true);
    765     }
    766 
    767     @Override Table<Character, String, Integer> makeTable() {
    768       return HashBasedTable.create();
    769     }
    770   }
    771 
    772   public static class TreeRowTests extends RowTests {
    773     public TreeRowTests() {
    774       super(false, true, true, true, true);
    775     }
    776 
    777     @Override Table<Character, String, Integer> makeTable() {
    778       return TreeBasedTable.create();
    779     }
    780   }
    781 
    782   public static class TransposeRowTests extends RowTests {
    783     public TransposeRowTests() {
    784       super(false, true, true, true, false);
    785     }
    786 
    787     @Override Table<Character, String, Integer> makeTable() {
    788       Table<String, Character, Integer> original = TreeBasedTable.create();
    789       return Tables.transpose(original);
    790     }
    791   }
    792 
    793   private static final Function<Integer, Integer> DIVIDE_BY_2
    794       = new Function<Integer, Integer>() {
    795         @Override public Integer apply(Integer input) {
    796           return (input == null) ? null : input / 2;
    797         }
    798   };
    799 
    800   public static class TransformValueRowTests extends RowTests {
    801     public TransformValueRowTests() {
    802       super(false, false, true, true, true);
    803     }
    804 
    805     @Override Table<Character, String, Integer> makeTable() {
    806       Table<Character, String, Integer> table = HashBasedTable.create();
    807       return Tables.transformValues(table, DIVIDE_BY_2);
    808     }
    809 
    810     @Override protected Map<String, Integer> makePopulatedMap() {
    811       Table<Character, String, Integer> table = HashBasedTable.create();
    812       table.put('a', "one", 2);
    813       table.put('a', "two", 4);
    814       table.put('a', "three", 6);
    815       table.put('b', "four", 8);
    816       return Tables.transformValues(table, DIVIDE_BY_2).row('a');
    817     }
    818   }
    819 
    820   public static class UnmodifiableHashRowTests extends RowTests {
    821     public UnmodifiableHashRowTests() {
    822       super(false, false, false, false, false);
    823     }
    824 
    825     @Override Table<Character, String, Integer> makeTable() {
    826       Table<Character, String, Integer> table = HashBasedTable.create();
    827       return Tables.unmodifiableTable(table);
    828     }
    829 
    830     @Override protected Map<String, Integer> makePopulatedMap() {
    831       Table<Character, String, Integer> table = HashBasedTable.create();
    832       table.put('a', "one", 1);
    833       table.put('a', "two", 2);
    834       table.put('a', "three", 3);
    835       table.put('b', "four", 4);
    836       return Tables.unmodifiableTable(table).row('a');
    837     }
    838   }
    839 
    840   public static class UnmodifiableTreeRowTests extends RowTests {
    841     public UnmodifiableTreeRowTests() {
    842       super(false, false, false, false, false);
    843     }
    844 
    845     @Override Table<Character, String, Integer> makeTable() {
    846       RowSortedTable<Character, String, Integer> table = TreeBasedTable.create();
    847       return Tables.unmodifiableRowSortedTable(table);
    848     }
    849 
    850     @Override protected Map<String, Integer> makePopulatedMap() {
    851       RowSortedTable<Character, String, Integer> table = TreeBasedTable.create();
    852       table.put('a', "one", 1);
    853       table.put('a', "two", 2);
    854       table.put('a', "three", 3);
    855       table.put('b', "four", 4);
    856       return Tables.unmodifiableRowSortedTable(table).row('a');
    857     }
    858   }
    859 
    860   private static abstract class ColumnTests extends MapTests {
    861     ColumnTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove,
    862         boolean supportsClear, boolean supportsIteratorRemove) {
    863       super(allowsNullValues, supportsPut, supportsRemove, supportsClear,
    864           supportsIteratorRemove);
    865     }
    866 
    867     abstract Table<String, Character, Integer> makeTable();
    868 
    869     @Override protected Map<String, Integer> makeEmptyMap() {
    870       return makeTable().column('a');
    871     }
    872 
    873     @Override protected Map<String, Integer> makePopulatedMap() {
    874       Table<String, Character, Integer> table = makeTable();
    875       table.put("one", 'a', 1);
    876       table.put("two", 'a', 2);
    877       table.put("three", 'a', 3);
    878       table.put("four", 'b', 4);
    879       return table.column('a');
    880     }
    881   }
    882 
    883   @GwtIncompatible("TODO(hhchan): ArrayTable")
    884   public static class ArrayColumnTests extends ColumnTests {
    885     public ArrayColumnTests() {
    886       super(true, true, false, false, false);
    887     }
    888 
    889     @Override protected String getKeyNotInPopulatedMap() {
    890       throw new UnsupportedOperationException();
    891     }
    892 
    893     @Override protected Map<String, Integer> makeEmptyMap() {
    894       throw new UnsupportedOperationException();
    895     }
    896 
    897     @Override Table<String, Character, Integer> makeTable() {
    898       return ArrayTable.create(Arrays.asList("one", "two", "three", "four"),
    899           Arrays.asList('a', 'b', 'c'));
    900     }
    901   }
    902 
    903   public static class HashColumnTests extends ColumnTests {
    904     public HashColumnTests() {
    905       super(false, true, true, true, false);
    906     }
    907 
    908     @Override Table<String, Character, Integer> makeTable() {
    909       return HashBasedTable.create();
    910     }
    911   }
    912 
    913   public static class TreeColumnTests extends ColumnTests {
    914     public TreeColumnTests() {
    915       super(false, true, true, true, false);
    916     }
    917 
    918     @Override Table<String, Character, Integer> makeTable() {
    919       return TreeBasedTable.create();
    920     }
    921   }
    922 
    923   public static class TransposeColumnTests extends ColumnTests {
    924     public TransposeColumnTests() {
    925       super(false, true, true, true, true);
    926     }
    927 
    928     @Override Table<String, Character, Integer> makeTable() {
    929       Table<Character, String, Integer> original = TreeBasedTable.create();
    930       return Tables.transpose(original);
    931     }
    932   }
    933 
    934   public static class TransformValueColumnTests extends ColumnTests {
    935     public TransformValueColumnTests() {
    936       super(false, false, true, true, false);
    937     }
    938 
    939     @Override Table<String, Character, Integer> makeTable() {
    940       Table<String, Character, Integer> table = HashBasedTable.create();
    941       return Tables.transformValues(table, DIVIDE_BY_2);
    942     }
    943 
    944     @Override protected Map<String, Integer> makePopulatedMap() {
    945       Table<String, Character, Integer> table = HashBasedTable.create();
    946       table.put("one", 'a', 1);
    947       table.put("two", 'a', 2);
    948       table.put("three", 'a', 3);
    949       table.put("four", 'b', 4);
    950       return Tables.transformValues(table, DIVIDE_BY_2).column('a');
    951     }
    952   }
    953 
    954   public static class UnmodifiableHashColumnTests extends ColumnTests {
    955     public UnmodifiableHashColumnTests() {
    956       super(false, false, false, false, false);
    957     }
    958 
    959     @Override Table<String, Character, Integer> makeTable() {
    960       Table<String, Character, Integer> table = HashBasedTable.create();
    961       return Tables.unmodifiableTable(table);
    962     }
    963 
    964     @Override protected Map<String, Integer> makePopulatedMap() {
    965       Table<String, Character, Integer> table = HashBasedTable.create();
    966       table.put("one", 'a', 1);
    967       table.put("two", 'a', 2);
    968       table.put("three", 'a', 3);
    969       table.put("four", 'b', 4);
    970       return Tables.unmodifiableTable(table).column('a');
    971     }
    972   }
    973 
    974   public static class UnmodifiableTreeColumnTests extends ColumnTests {
    975     public UnmodifiableTreeColumnTests() {
    976       super(false, false, false, false, false);
    977     }
    978 
    979     @Override Table<String, Character, Integer> makeTable() {
    980       RowSortedTable<String, Character, Integer> table = TreeBasedTable.create();
    981       return Tables.unmodifiableRowSortedTable(table);
    982     }
    983 
    984     @Override protected Map<String, Integer> makePopulatedMap() {
    985       RowSortedTable<String, Character, Integer> table = TreeBasedTable.create();
    986       table.put("one", 'a', 1);
    987       table.put("two", 'a', 2);
    988       table.put("three", 'a', 3);
    989       table.put("four", 'b', 4);
    990       return Tables.unmodifiableRowSortedTable(table).column('a');
    991     }
    992   }
    993 
    994   private static abstract class MapMapTests
    995       extends MapInterfaceTest<String, Map<Integer, Character>> {
    996 
    997     MapMapTests(boolean allowsNullValues, boolean supportsRemove,
    998         boolean supportsClear, boolean supportsIteratorRemove) {
    999       super(false, allowsNullValues, false, supportsRemove, supportsClear,
   1000           supportsIteratorRemove);
   1001     }
   1002 
   1003     @Override protected String getKeyNotInPopulatedMap() {
   1004       return "cat";
   1005     }
   1006 
   1007     @Override protected Map<Integer, Character> getValueNotInPopulatedMap() {
   1008       return ImmutableMap.of();
   1009     }
   1010 
   1011     /**
   1012      * The version of this test supplied by {@link MapInterfaceTest} fails for
   1013      * this particular map implementation, because {@code map.get()} returns a
   1014      * view collection that changes in the course of a call to {@code remove()}.
   1015      * Thus, the expectation doesn't hold that {@code map.remove(x)} returns the
   1016      * same value which {@code map.get(x)} did immediately beforehand.
   1017      */
   1018     @Override public void testRemove() {
   1019       final Map<String, Map<Integer, Character>> map;
   1020       final String keyToRemove;
   1021       try {
   1022         map = makePopulatedMap();
   1023       } catch (UnsupportedOperationException e) {
   1024         return;
   1025       }
   1026       keyToRemove = map.keySet().iterator().next();
   1027       if (supportsRemove) {
   1028         int initialSize = map.size();
   1029         map.get(keyToRemove);
   1030         map.remove(keyToRemove);
   1031         // This line doesn't hold - see the Javadoc comments above.
   1032         // assertEquals(expectedValue, oldValue);
   1033         assertFalse(map.containsKey(keyToRemove));
   1034         assertEquals(initialSize - 1, map.size());
   1035       } else {
   1036         try {
   1037           map.remove(keyToRemove);
   1038           fail("Expected UnsupportedOperationException.");
   1039         } catch (UnsupportedOperationException e) {
   1040           // Expected.
   1041         }
   1042       }
   1043       assertInvariants(map);
   1044     }
   1045   }
   1046 
   1047   private static abstract class RowMapTests extends MapMapTests {
   1048     RowMapTests(boolean allowsNullValues, boolean supportsRemove,
   1049         boolean supportsClear, boolean supportsIteratorRemove) {
   1050       super(allowsNullValues, supportsRemove, supportsClear,
   1051           supportsIteratorRemove);
   1052     }
   1053 
   1054     abstract Table<String, Integer, Character> makeTable();
   1055 
   1056     @Override protected Map<String, Map<Integer, Character>>
   1057         makePopulatedMap() {
   1058       Table<String, Integer, Character> table = makeTable();
   1059       populateTable(table);
   1060       return table.rowMap();
   1061     }
   1062 
   1063     void populateTable(Table<String, Integer, Character> table) {
   1064       table.put("foo", 1, 'a');
   1065       table.put("bar", 1, 'b');
   1066       table.put("foo", 3, 'c');
   1067     }
   1068 
   1069     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
   1070       return makeTable().rowMap();
   1071     }
   1072   }
   1073 
   1074   @GwtIncompatible("TODO(hhchan): ArrayTable")
   1075   public static class ArrayRowMapTests extends RowMapTests {
   1076     public ArrayRowMapTests() {
   1077       super(true, false, false, false);
   1078     }
   1079 
   1080     @Override Table<String, Integer, Character> makeTable() {
   1081       return ArrayTable.create(Arrays.asList("foo", "bar", "dog"),
   1082           Arrays.asList(1, 2, 3));
   1083     }
   1084 
   1085     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
   1086       throw new UnsupportedOperationException();
   1087     }
   1088   }
   1089 
   1090   public static class HashRowMapTests extends RowMapTests {
   1091     public HashRowMapTests() {
   1092       super(false, true, true, true);
   1093     }
   1094 
   1095     @Override Table<String, Integer, Character> makeTable() {
   1096       return HashBasedTable.create();
   1097     }
   1098   }
   1099 
   1100   public static class TreeRowMapTests extends RowMapTests {
   1101     public TreeRowMapTests() {
   1102       super(false, true, true, true);
   1103     }
   1104 
   1105     @Override Table<String, Integer, Character> makeTable() {
   1106       return TreeBasedTable.create();
   1107     }
   1108   }
   1109 
   1110   public static class TreeRowMapHeadMapTests extends RowMapTests {
   1111     public TreeRowMapHeadMapTests() {
   1112       super(false, true, true, true);
   1113     }
   1114 
   1115     @Override TreeBasedTable<String, Integer, Character> makeTable() {
   1116       TreeBasedTable<String, Integer, Character> table =
   1117           TreeBasedTable.create();
   1118       table.put("z", 1, 'a');
   1119       return table;
   1120     }
   1121 
   1122     @Override protected Map<String, Map<Integer, Character>>
   1123         makePopulatedMap() {
   1124       TreeBasedTable<String, Integer, Character> table = makeTable();
   1125       populateTable(table);
   1126       return table.rowMap().headMap("x");
   1127     }
   1128 
   1129     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
   1130       return makeTable().rowMap().headMap("x");
   1131     }
   1132 
   1133     @Override protected String getKeyNotInPopulatedMap() {
   1134       return "z";
   1135     }
   1136   }
   1137 
   1138   public static class TreeRowMapTailMapTests extends RowMapTests {
   1139     public TreeRowMapTailMapTests() {
   1140       super(false, true, true, true);
   1141     }
   1142 
   1143     @Override TreeBasedTable<String, Integer, Character> makeTable() {
   1144       TreeBasedTable<String, Integer, Character> table =
   1145           TreeBasedTable.create();
   1146       table.put("a", 1, 'a');
   1147       return table;
   1148     }
   1149 
   1150     @Override protected Map<String, Map<Integer, Character>>
   1151         makePopulatedMap() {
   1152       TreeBasedTable<String, Integer, Character> table = makeTable();
   1153       populateTable(table);
   1154       return table.rowMap().tailMap("b");
   1155     }
   1156 
   1157     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
   1158       return makeTable().rowMap().tailMap("b");
   1159     }
   1160 
   1161     @Override protected String getKeyNotInPopulatedMap() {
   1162       return "a";
   1163     }
   1164   }
   1165 
   1166   public static class TreeRowMapSubMapTests extends RowMapTests {
   1167     public TreeRowMapSubMapTests() {
   1168       super(false, true, true, true);
   1169     }
   1170 
   1171     @Override TreeBasedTable<String, Integer, Character> makeTable() {
   1172       TreeBasedTable<String, Integer, Character> table =
   1173           TreeBasedTable.create();
   1174       table.put("a", 1, 'a');
   1175       table.put("z", 1, 'a');
   1176       return table;
   1177     }
   1178 
   1179     @Override protected Map<String, Map<Integer, Character>>
   1180         makePopulatedMap() {
   1181       TreeBasedTable<String, Integer, Character> table = makeTable();
   1182       populateTable(table);
   1183       return table.rowMap().subMap("b", "x");
   1184     }
   1185 
   1186     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
   1187       return makeTable().rowMap().subMap("b", "x");
   1188     }
   1189 
   1190     @Override protected String getKeyNotInPopulatedMap() {
   1191       return "z";
   1192     }
   1193   }
   1194 
   1195   private static final Function<String, Character> FIRST_CHARACTER =
   1196       new Function<String, Character>() {
   1197         @Override
   1198         public Character apply(String input) {
   1199           return input == null ? null : input.charAt(0);
   1200         }
   1201       };
   1202 
   1203   public static class TransformValueRowMapTests extends RowMapTests {
   1204     public TransformValueRowMapTests() {
   1205       super(false, true, true, true);
   1206     }
   1207 
   1208     @Override Table<String, Integer, Character> makeTable() {
   1209       Table<String, Integer, String> original = HashBasedTable.create();
   1210       return Tables.transformValues(original, FIRST_CHARACTER);
   1211     }
   1212 
   1213     @Override
   1214     protected Map<String, Map<Integer, Character>> makePopulatedMap() {
   1215       Table<String, Integer, String> table = HashBasedTable.create();
   1216       table.put("foo", 1, "apple");
   1217       table.put("bar", 1, "banana");
   1218       table.put("foo", 3, "cat");
   1219       return Tables.transformValues(table, FIRST_CHARACTER).rowMap();
   1220     }
   1221   }
   1222 
   1223   public static class UnmodifiableHashRowMapTests extends RowMapTests {
   1224     public UnmodifiableHashRowMapTests() {
   1225       super(false, false, false, false);
   1226     }
   1227 
   1228     @Override Table<String, Integer, Character> makeTable() {
   1229       Table<String, Integer, Character> original = HashBasedTable.create();
   1230       return Tables.unmodifiableTable(original);
   1231     }
   1232 
   1233     @Override
   1234     protected Map<String, Map<Integer, Character>> makePopulatedMap() {
   1235       Table<String, Integer, Character> table = HashBasedTable.create();
   1236       table.put("foo", 1, 'a');
   1237       table.put("bar", 1, 'b');
   1238       table.put("foo", 3, 'c');
   1239       return Tables.unmodifiableTable(table).rowMap();
   1240     }
   1241   }
   1242 
   1243   public static class UnmodifiableTreeRowMapTests extends RowMapTests {
   1244     public UnmodifiableTreeRowMapTests() {
   1245       super(false, false, false, false);
   1246     }
   1247 
   1248     @Override RowSortedTable<String, Integer, Character> makeTable() {
   1249       RowSortedTable<String, Integer, Character> original = TreeBasedTable.create();
   1250       return Tables.unmodifiableRowSortedTable(original);
   1251     }
   1252 
   1253     @Override
   1254     protected SortedMap<String, Map<Integer, Character>> makePopulatedMap() {
   1255       RowSortedTable<String, Integer, Character> table = TreeBasedTable.create();
   1256       table.put("foo", 1, 'a');
   1257       table.put("bar", 1, 'b');
   1258       table.put("foo", 3, 'c');
   1259       return Tables.unmodifiableRowSortedTable(table).rowMap();
   1260     }
   1261   }
   1262 
   1263   private static abstract class ColumnMapTests extends MapMapTests {
   1264     ColumnMapTests(boolean allowsNullValues, boolean supportsRemove,
   1265         boolean supportsClear, boolean supportsIteratorRemove) {
   1266       super(allowsNullValues, supportsRemove, supportsClear,
   1267           supportsIteratorRemove);
   1268     }
   1269 
   1270     abstract Table<Integer, String, Character> makeTable();
   1271 
   1272     @Override protected Map<String, Map<Integer, Character>>
   1273         makePopulatedMap() {
   1274       Table<Integer, String, Character> table = makeTable();
   1275       table.put(1, "foo", 'a');
   1276       table.put(1, "bar", 'b');
   1277       table.put(3, "foo", 'c');
   1278       return table.columnMap();
   1279     }
   1280 
   1281     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
   1282       return makeTable().columnMap();
   1283     }
   1284   }
   1285 
   1286   @GwtIncompatible("TODO(hhchan): ArrayTable")
   1287   public static class ArrayColumnMapTests extends ColumnMapTests {
   1288     public ArrayColumnMapTests() {
   1289       super(true, false, false, false);
   1290     }
   1291 
   1292     @Override Table<Integer, String, Character> makeTable() {
   1293       return ArrayTable.create(Arrays.asList(1, 2, 3),
   1294           Arrays.asList("foo", "bar", "dog"));
   1295     }
   1296 
   1297     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
   1298       throw new UnsupportedOperationException();
   1299     }
   1300   }
   1301 
   1302   public static class HashColumnMapTests extends ColumnMapTests {
   1303     public HashColumnMapTests() {
   1304       super(false, true, true, false);
   1305     }
   1306 
   1307     @Override Table<Integer, String, Character> makeTable() {
   1308       return HashBasedTable.create();
   1309     }
   1310   }
   1311 
   1312   public static class TreeColumnMapTests extends ColumnMapTests {
   1313     public TreeColumnMapTests() {
   1314       super(false, true, true, false);
   1315     }
   1316 
   1317     @Override Table<Integer, String, Character> makeTable() {
   1318       return TreeBasedTable.create();
   1319     }
   1320   }
   1321 
   1322   public static class TransformValueColumnMapTests extends ColumnMapTests {
   1323     public TransformValueColumnMapTests() {
   1324       super(false, true, true, false);
   1325     }
   1326 
   1327     @Override Table<Integer, String, Character> makeTable() {
   1328       Table<Integer, String, String> original = HashBasedTable.create();
   1329       return Tables.transformValues(original, FIRST_CHARACTER);
   1330     }
   1331 
   1332     @Override
   1333     protected Map<String, Map<Integer, Character>> makePopulatedMap() {
   1334       Table<Integer, String, String> table = HashBasedTable.create();
   1335       table.put(1, "foo", "apple");
   1336       table.put(1, "bar", "banana");
   1337       table.put(3, "foo", "cat");
   1338       return Tables.transformValues(table, FIRST_CHARACTER).columnMap();
   1339     }
   1340   }
   1341 
   1342   public static class UnmodifiableHashColumnMapTests extends ColumnMapTests {
   1343     public UnmodifiableHashColumnMapTests() {
   1344       super(false, false, false, false);
   1345     }
   1346 
   1347     @Override Table<Integer, String, Character> makeTable() {
   1348       Table<Integer, String, Character> original = HashBasedTable.create();
   1349       return Tables.unmodifiableTable(original);
   1350     }
   1351 
   1352     @Override
   1353     protected Map<String, Map<Integer, Character>> makePopulatedMap() {
   1354       Table<Integer, String, Character> table = HashBasedTable.create();
   1355       table.put(1, "foo", 'a');
   1356       table.put(1, "bar", 'b');
   1357       table.put(3, "foo", 'c');
   1358       return Tables.unmodifiableTable(table).columnMap();
   1359     }
   1360   }
   1361 
   1362   public static class UnmodifiableTreeColumnMapTests extends ColumnMapTests {
   1363     public UnmodifiableTreeColumnMapTests() {
   1364       super(false, false, false, false);
   1365     }
   1366 
   1367     @Override Table<Integer, String, Character> makeTable() {
   1368       RowSortedTable<Integer, String, Character> original = TreeBasedTable.create();
   1369       return Tables.unmodifiableRowSortedTable(original);
   1370     }
   1371 
   1372     @Override
   1373     protected Map<String, Map<Integer, Character>> makePopulatedMap() {
   1374       RowSortedTable<Integer, String, Character> table = TreeBasedTable.create();
   1375       table.put(1, "foo", 'a');
   1376       table.put(1, "bar", 'b');
   1377       table.put(3, "foo", 'c');
   1378       return Tables.unmodifiableRowSortedTable(table).columnMap();
   1379     }
   1380   }
   1381 }
   1382