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;
20import static com.google.common.collect.testing.testers.CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod;
21import static com.google.common.collect.testing.testers.CollectionIteratorTester.getIteratorUnknownOrderRemoveSupportedMethod;
22
23import com.google.common.annotations.GwtCompatible;
24import com.google.common.annotations.GwtIncompatible;
25import com.google.common.base.Function;
26import com.google.common.base.Functions;
27import com.google.common.collect.Table.Cell;
28import com.google.common.collect.testing.CollectionTestSuiteBuilder;
29import com.google.common.collect.testing.MapInterfaceTest;
30import com.google.common.collect.testing.SampleElements;
31import com.google.common.collect.testing.SetTestSuiteBuilder;
32import com.google.common.collect.testing.TestSetGenerator;
33import com.google.common.collect.testing.TestStringCollectionGenerator;
34import com.google.common.collect.testing.TestStringSetGenerator;
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;
50
51/**
52 * Collection tests for {@link Table} implementations.
53 *
54 * @author Jared Levy
55 * @author Louis Wasserman
56 */
57@GwtCompatible(emulated = true)
58public 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