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