• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.testing.testers.CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod;
21 import static com.google.common.collect.testing.testers.CollectionIteratorTester.getIteratorUnknownOrderRemoveSupportedMethod;
22 
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.annotations.GwtIncompatible;
25 import com.google.common.base.Function;
26 import com.google.common.base.Functions;
27 import com.google.common.collect.Table.Cell;
28 import com.google.common.collect.testing.CollectionTestSuiteBuilder;
29 import com.google.common.collect.testing.MapInterfaceTest;
30 import com.google.common.collect.testing.SampleElements;
31 import com.google.common.collect.testing.SetTestSuiteBuilder;
32 import com.google.common.collect.testing.TestSetGenerator;
33 import com.google.common.collect.testing.TestStringCollectionGenerator;
34 import com.google.common.collect.testing.TestStringSetGenerator;
35 import com.google.common.collect.testing.features.CollectionFeature;
36 import com.google.common.collect.testing.features.CollectionSize;
37 import com.google.common.collect.testing.features.Feature;
38 
39 import junit.framework.Test;
40 import junit.framework.TestCase;
41 import junit.framework.TestSuite;
42 
43 import java.util.Arrays;
44 import java.util.Collection;
45 import java.util.Collections;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.SortedMap;
50 
51 /**
52  * Collection tests for {@link Table} implementations.
53  *
54  * @author Jared Levy
55  * @author Louis Wasserman
56  */
57 @GwtCompatible(emulated = true)
58 public class TableCollectionTest extends TestCase {
59 
60   private static final Feature<?>[] COLLECTION_FEATURES = {
61     CollectionSize.ANY,
62     CollectionFeature.ALLOWS_NULL_QUERIES
63   };
64 
65   private static final Feature<?>[] COLLECTION_FEATURES_ORDER = {
66     CollectionSize.ANY,
67     CollectionFeature.KNOWN_ORDER,
68     CollectionFeature.ALLOWS_NULL_QUERIES
69   };
70 
71   private static final Feature<?>[] COLLECTION_FEATURES_REMOVE = {
72     CollectionSize.ANY,
73     CollectionFeature.REMOVE_OPERATIONS,
74     CollectionFeature.ALLOWS_NULL_QUERIES
75   };
76 
77   private static final Feature<?>[] COLLECTION_FEATURES_REMOVE_ORDER = {
78     CollectionSize.ANY,
79     CollectionFeature.KNOWN_ORDER,
80     CollectionFeature.REMOVE_OPERATIONS,
81     CollectionFeature.ALLOWS_NULL_QUERIES
82   };
83 
84   @GwtIncompatible("suite")
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 
populateForRowKeySet( Table<String, Integer, Character> table, String[] elements)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 
populateForColumnKeySet( Table<Integer, String, Character> table, String[] elements)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 
populateForValues( Table<Integer, Character, String> table, String[] elements)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
samples()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
create( Object... elements)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 
createTable()686     abstract Table<String, Integer, Character> createTable();
687 
688     @Override
689     @SuppressWarnings("unchecked")
createArray(int length)690     public Cell<String, Integer, Character>[] createArray(int length) {
691       return (Cell<String, Integer, Character>[]) new Cell<?, ?, ?>[length];
692     }
693 
694     @Override
order( List<Cell<String, Integer, Character>> insertionOrder)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 
MapTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)704     MapTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove,
705         boolean supportsClear, boolean supportsIteratorRemove) {
706       super(false, allowsNullValues, supportsPut, supportsRemove, supportsClear,
707           supportsIteratorRemove);
708     }
709 
getKeyNotInPopulatedMap()710     @Override protected String getKeyNotInPopulatedMap() {
711       return "four";
712     }
713 
getValueNotInPopulatedMap()714     @Override protected Integer getValueNotInPopulatedMap() {
715       return 4;
716     }
717   }
718 
719   private static abstract class RowTests extends MapTests {
RowTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)720     RowTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove,
721         boolean supportsClear, boolean supportsIteratorRemove) {
722       super(allowsNullValues, supportsPut, supportsRemove, supportsClear,
723           supportsIteratorRemove);
724     }
725 
makeTable()726     abstract Table<Character, String, Integer> makeTable();
727 
makeEmptyMap()728     @Override protected Map<String, Integer> makeEmptyMap() {
729       return makeTable().row('a');
730     }
731 
makePopulatedMap()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 {
ArrayRowTests()744     public ArrayRowTests() {
745       super(true, true, false, false, false);
746     }
747 
getKeyNotInPopulatedMap()748     @Override protected String getKeyNotInPopulatedMap() {
749       throw new UnsupportedOperationException();
750     }
751 
makeEmptyMap()752     @Override protected Map<String, Integer> makeEmptyMap() {
753       throw new UnsupportedOperationException();
754     }
755 
makeTable()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 {
HashRowTests()763     public HashRowTests() {
764       super(false, true, true, true, true);
765     }
766 
makeTable()767     @Override Table<Character, String, Integer> makeTable() {
768       return HashBasedTable.create();
769     }
770   }
771 
772   public static class TreeRowTests extends RowTests {
TreeRowTests()773     public TreeRowTests() {
774       super(false, true, true, true, true);
775     }
776 
makeTable()777     @Override Table<Character, String, Integer> makeTable() {
778       return TreeBasedTable.create();
779     }
780   }
781 
782   public static class TransposeRowTests extends RowTests {
TransposeRowTests()783     public TransposeRowTests() {
784       super(false, true, true, true, false);
785     }
786 
makeTable()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 {
TransformValueRowTests()801     public TransformValueRowTests() {
802       super(false, false, true, true, true);
803     }
804 
makeTable()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 
makePopulatedMap()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 {
UnmodifiableHashRowTests()821     public UnmodifiableHashRowTests() {
822       super(false, false, false, false, false);
823     }
824 
makeTable()825     @Override Table<Character, String, Integer> makeTable() {
826       Table<Character, String, Integer> table = HashBasedTable.create();
827       return Tables.unmodifiableTable(table);
828     }
829 
makePopulatedMap()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 {
UnmodifiableTreeRowTests()841     public UnmodifiableTreeRowTests() {
842       super(false, false, false, false, false);
843     }
844 
makeTable()845     @Override Table<Character, String, Integer> makeTable() {
846       RowSortedTable<Character, String, Integer> table = TreeBasedTable.create();
847       return Tables.unmodifiableRowSortedTable(table);
848     }
849 
makePopulatedMap()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 {
ColumnTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)861     ColumnTests(boolean allowsNullValues, boolean supportsPut, boolean supportsRemove,
862         boolean supportsClear, boolean supportsIteratorRemove) {
863       super(allowsNullValues, supportsPut, supportsRemove, supportsClear,
864           supportsIteratorRemove);
865     }
866 
makeTable()867     abstract Table<String, Character, Integer> makeTable();
868 
makeEmptyMap()869     @Override protected Map<String, Integer> makeEmptyMap() {
870       return makeTable().column('a');
871     }
872 
makePopulatedMap()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 {
ArrayColumnTests()885     public ArrayColumnTests() {
886       super(true, true, false, false, false);
887     }
888 
getKeyNotInPopulatedMap()889     @Override protected String getKeyNotInPopulatedMap() {
890       throw new UnsupportedOperationException();
891     }
892 
makeEmptyMap()893     @Override protected Map<String, Integer> makeEmptyMap() {
894       throw new UnsupportedOperationException();
895     }
896 
makeTable()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 {
HashColumnTests()904     public HashColumnTests() {
905       super(false, true, true, true, false);
906     }
907 
makeTable()908     @Override Table<String, Character, Integer> makeTable() {
909       return HashBasedTable.create();
910     }
911   }
912 
913   public static class TreeColumnTests extends ColumnTests {
TreeColumnTests()914     public TreeColumnTests() {
915       super(false, true, true, true, false);
916     }
917 
makeTable()918     @Override Table<String, Character, Integer> makeTable() {
919       return TreeBasedTable.create();
920     }
921   }
922 
923   public static class TransposeColumnTests extends ColumnTests {
TransposeColumnTests()924     public TransposeColumnTests() {
925       super(false, true, true, true, true);
926     }
927 
makeTable()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 {
TransformValueColumnTests()935     public TransformValueColumnTests() {
936       super(false, false, true, true, false);
937     }
938 
makeTable()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 
makePopulatedMap()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 {
UnmodifiableHashColumnTests()955     public UnmodifiableHashColumnTests() {
956       super(false, false, false, false, false);
957     }
958 
makeTable()959     @Override Table<String, Character, Integer> makeTable() {
960       Table<String, Character, Integer> table = HashBasedTable.create();
961       return Tables.unmodifiableTable(table);
962     }
963 
makePopulatedMap()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 {
UnmodifiableTreeColumnTests()975     public UnmodifiableTreeColumnTests() {
976       super(false, false, false, false, false);
977     }
978 
makeTable()979     @Override Table<String, Character, Integer> makeTable() {
980       RowSortedTable<String, Character, Integer> table = TreeBasedTable.create();
981       return Tables.unmodifiableRowSortedTable(table);
982     }
983 
makePopulatedMap()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 
MapMapTests(boolean allowsNullValues, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)997     MapMapTests(boolean allowsNullValues, boolean supportsRemove,
998         boolean supportsClear, boolean supportsIteratorRemove) {
999       super(false, allowsNullValues, false, supportsRemove, supportsClear,
1000           supportsIteratorRemove);
1001     }
1002 
getKeyNotInPopulatedMap()1003     @Override protected String getKeyNotInPopulatedMap() {
1004       return "cat";
1005     }
1006 
getValueNotInPopulatedMap()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      */
testRemove()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 {
RowMapTests(boolean allowsNullValues, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)1048     RowMapTests(boolean allowsNullValues, boolean supportsRemove,
1049         boolean supportsClear, boolean supportsIteratorRemove) {
1050       super(allowsNullValues, supportsRemove, supportsClear,
1051           supportsIteratorRemove);
1052     }
1053 
makeTable()1054     abstract Table<String, Integer, Character> makeTable();
1055 
1056     @Override protected Map<String, Map<Integer, Character>>
makePopulatedMap()1057         makePopulatedMap() {
1058       Table<String, Integer, Character> table = makeTable();
1059       populateTable(table);
1060       return table.rowMap();
1061     }
1062 
populateTable(Table<String, Integer, Character> table)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 
makeEmptyMap()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 {
ArrayRowMapTests()1076     public ArrayRowMapTests() {
1077       super(true, false, false, false);
1078     }
1079 
makeTable()1080     @Override Table<String, Integer, Character> makeTable() {
1081       return ArrayTable.create(Arrays.asList("foo", "bar", "dog"),
1082           Arrays.asList(1, 2, 3));
1083     }
1084 
makeEmptyMap()1085     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
1086       throw new UnsupportedOperationException();
1087     }
1088   }
1089 
1090   public static class HashRowMapTests extends RowMapTests {
HashRowMapTests()1091     public HashRowMapTests() {
1092       super(false, true, true, true);
1093     }
1094 
makeTable()1095     @Override Table<String, Integer, Character> makeTable() {
1096       return HashBasedTable.create();
1097     }
1098   }
1099 
1100   public static class TreeRowMapTests extends RowMapTests {
TreeRowMapTests()1101     public TreeRowMapTests() {
1102       super(false, true, true, true);
1103     }
1104 
makeTable()1105     @Override Table<String, Integer, Character> makeTable() {
1106       return TreeBasedTable.create();
1107     }
1108   }
1109 
1110   public static class TreeRowMapHeadMapTests extends RowMapTests {
TreeRowMapHeadMapTests()1111     public TreeRowMapHeadMapTests() {
1112       super(false, true, true, true);
1113     }
1114 
makeTable()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>>
makePopulatedMap()1123         makePopulatedMap() {
1124       TreeBasedTable<String, Integer, Character> table = makeTable();
1125       populateTable(table);
1126       return table.rowMap().headMap("x");
1127     }
1128 
makeEmptyMap()1129     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
1130       return makeTable().rowMap().headMap("x");
1131     }
1132 
getKeyNotInPopulatedMap()1133     @Override protected String getKeyNotInPopulatedMap() {
1134       return "z";
1135     }
1136   }
1137 
1138   public static class TreeRowMapTailMapTests extends RowMapTests {
TreeRowMapTailMapTests()1139     public TreeRowMapTailMapTests() {
1140       super(false, true, true, true);
1141     }
1142 
makeTable()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>>
makePopulatedMap()1151         makePopulatedMap() {
1152       TreeBasedTable<String, Integer, Character> table = makeTable();
1153       populateTable(table);
1154       return table.rowMap().tailMap("b");
1155     }
1156 
makeEmptyMap()1157     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
1158       return makeTable().rowMap().tailMap("b");
1159     }
1160 
getKeyNotInPopulatedMap()1161     @Override protected String getKeyNotInPopulatedMap() {
1162       return "a";
1163     }
1164   }
1165 
1166   public static class TreeRowMapSubMapTests extends RowMapTests {
TreeRowMapSubMapTests()1167     public TreeRowMapSubMapTests() {
1168       super(false, true, true, true);
1169     }
1170 
makeTable()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>>
makePopulatedMap()1180         makePopulatedMap() {
1181       TreeBasedTable<String, Integer, Character> table = makeTable();
1182       populateTable(table);
1183       return table.rowMap().subMap("b", "x");
1184     }
1185 
makeEmptyMap()1186     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
1187       return makeTable().rowMap().subMap("b", "x");
1188     }
1189 
getKeyNotInPopulatedMap()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 {
TransformValueRowMapTests()1204     public TransformValueRowMapTests() {
1205       super(false, true, true, true);
1206     }
1207 
makeTable()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
makePopulatedMap()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 {
UnmodifiableHashRowMapTests()1224     public UnmodifiableHashRowMapTests() {
1225       super(false, false, false, false);
1226     }
1227 
makeTable()1228     @Override Table<String, Integer, Character> makeTable() {
1229       Table<String, Integer, Character> original = HashBasedTable.create();
1230       return Tables.unmodifiableTable(original);
1231     }
1232 
1233     @Override
makePopulatedMap()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 {
UnmodifiableTreeRowMapTests()1244     public UnmodifiableTreeRowMapTests() {
1245       super(false, false, false, false);
1246     }
1247 
makeTable()1248     @Override RowSortedTable<String, Integer, Character> makeTable() {
1249       RowSortedTable<String, Integer, Character> original = TreeBasedTable.create();
1250       return Tables.unmodifiableRowSortedTable(original);
1251     }
1252 
1253     @Override
makePopulatedMap()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 {
ColumnMapTests(boolean allowsNullValues, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)1264     ColumnMapTests(boolean allowsNullValues, boolean supportsRemove,
1265         boolean supportsClear, boolean supportsIteratorRemove) {
1266       super(allowsNullValues, supportsRemove, supportsClear,
1267           supportsIteratorRemove);
1268     }
1269 
makeTable()1270     abstract Table<Integer, String, Character> makeTable();
1271 
1272     @Override protected Map<String, Map<Integer, Character>>
makePopulatedMap()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 
makeEmptyMap()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 {
ArrayColumnMapTests()1288     public ArrayColumnMapTests() {
1289       super(true, false, false, false);
1290     }
1291 
makeTable()1292     @Override Table<Integer, String, Character> makeTable() {
1293       return ArrayTable.create(Arrays.asList(1, 2, 3),
1294           Arrays.asList("foo", "bar", "dog"));
1295     }
1296 
makeEmptyMap()1297     @Override protected Map<String, Map<Integer, Character>> makeEmptyMap() {
1298       throw new UnsupportedOperationException();
1299     }
1300   }
1301 
1302   public static class HashColumnMapTests extends ColumnMapTests {
HashColumnMapTests()1303     public HashColumnMapTests() {
1304       super(false, true, true, false);
1305     }
1306 
makeTable()1307     @Override Table<Integer, String, Character> makeTable() {
1308       return HashBasedTable.create();
1309     }
1310   }
1311 
1312   public static class TreeColumnMapTests extends ColumnMapTests {
TreeColumnMapTests()1313     public TreeColumnMapTests() {
1314       super(false, true, true, false);
1315     }
1316 
makeTable()1317     @Override Table<Integer, String, Character> makeTable() {
1318       return TreeBasedTable.create();
1319     }
1320   }
1321 
1322   public static class TransformValueColumnMapTests extends ColumnMapTests {
TransformValueColumnMapTests()1323     public TransformValueColumnMapTests() {
1324       super(false, true, true, false);
1325     }
1326 
makeTable()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
makePopulatedMap()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 {
UnmodifiableHashColumnMapTests()1343     public UnmodifiableHashColumnMapTests() {
1344       super(false, false, false, false);
1345     }
1346 
makeTable()1347     @Override Table<Integer, String, Character> makeTable() {
1348       Table<Integer, String, Character> original = HashBasedTable.create();
1349       return Tables.unmodifiableTable(original);
1350     }
1351 
1352     @Override
makePopulatedMap()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 {
UnmodifiableTreeColumnMapTests()1363     public UnmodifiableTreeColumnMapTests() {
1364       super(false, false, false, false);
1365     }
1366 
makeTable()1367     @Override Table<Integer, String, Character> makeTable() {
1368       RowSortedTable<Integer, String, Character> original = TreeBasedTable.create();
1369       return Tables.unmodifiableRowSortedTable(original);
1370     }
1371 
1372     @Override
makePopulatedMap()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