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