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