• 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.Collection;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.SortedSet;
44 import junit.framework.Test;
45 import junit.framework.TestCase;
46 import junit.framework.TestSuite;
47 import org.checkerframework.checker.nullness.qual.Nullable;
48 
49 /**
50  * Collection tests for {@link Table} implementations.
51  *
52  * @author Jared Levy
53  * @author Louis Wasserman
54  */
55 @GwtCompatible(emulated = true)
56 public class TableCollectionTest extends TestCase {
57 
58   private static final Feature<?>[] COLLECTION_FEATURES = {
59     CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES
60   };
61 
62   private static final Feature<?>[] COLLECTION_FEATURES_ORDER = {
63     CollectionSize.ANY, CollectionFeature.KNOWN_ORDER, CollectionFeature.ALLOWS_NULL_QUERIES
64   };
65 
66   private static final Feature<?>[] COLLECTION_FEATURES_REMOVE = {
67     CollectionSize.ANY, CollectionFeature.SUPPORTS_REMOVE, CollectionFeature.ALLOWS_NULL_QUERIES
68   };
69 
70   private static final Feature<?>[] COLLECTION_FEATURES_REMOVE_ORDER = {
71     CollectionSize.ANY,
72     CollectionFeature.KNOWN_ORDER,
73     CollectionFeature.SUPPORTS_REMOVE,
74     CollectionFeature.ALLOWS_NULL_QUERIES
75   };
76 
77   @GwtIncompatible // suite
suite()78   public static Test suite() {
79     TestSuite suite = new TestSuite();
80 
81     // Not testing rowKeySet() or columnKeySet() of Table.transformValues()
82     // since the transformation doesn't affect the row and column key sets.
83 
84     suite.addTest(
85         SetTestSuiteBuilder.using(
86                 new TestStringSetGenerator() {
87                   @Override
88                   protected Set<String> create(String[] elements) {
89                     Table<String, Integer, Character> table =
90                         ArrayTable.create(ImmutableList.copyOf(elements), ImmutableList.of(1, 2));
91                     populateForRowKeySet(table, elements);
92                     return table.rowKeySet();
93                   }
94                 })
95             .named("ArrayTable.rowKeySet")
96             .withFeatures(
97                 CollectionSize.ONE,
98                 CollectionSize.SEVERAL,
99                 CollectionFeature.KNOWN_ORDER,
100                 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
101                 CollectionFeature.ALLOWS_NULL_QUERIES)
102             .createTestSuite());
103 
104     suite.addTest(
105         SetTestSuiteBuilder.using(
106                 new TestStringSetGenerator() {
107                   @Override
108                   protected Set<String> create(String[] elements) {
109                     Table<String, Integer, Character> table = HashBasedTable.create();
110                     populateForRowKeySet(table, elements);
111                     return table.rowKeySet();
112                   }
113                 })
114             .named("HashBasedTable.rowKeySet")
115             .withFeatures(COLLECTION_FEATURES_REMOVE)
116             .withFeatures(CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
117             .createTestSuite());
118 
119     suite.addTest(
120         SortedSetTestSuiteBuilder.using(
121                 new TestStringSortedSetGenerator() {
122                   @Override
123                   protected SortedSet<String> create(String[] elements) {
124                     TreeBasedTable<String, Integer, Character> table = TreeBasedTable.create();
125                     populateForRowKeySet(table, elements);
126                     return table.rowKeySet();
127                   }
128 
129                   @Override
130                   public List<String> order(List<String> insertionOrder) {
131                     Collections.sort(insertionOrder);
132                     return insertionOrder;
133                   }
134                 })
135             .named("TreeBasedTable.rowKeySet")
136             .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
137             .withFeatures(CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
138             .createTestSuite());
139 
140     suite.addTest(
141         SetTestSuiteBuilder.using(
142                 new TestStringSetGenerator() {
143                   @Override
144                   protected Set<String> create(String[] elements) {
145                     Table<String, Integer, Character> table = HashBasedTable.create();
146                     populateForRowKeySet(table, elements);
147                     return Tables.unmodifiableTable(table).rowKeySet();
148                   }
149                 })
150             .named("unmodifiableTable[HashBasedTable].rowKeySet")
151             .withFeatures(COLLECTION_FEATURES)
152             .createTestSuite());
153 
154     suite.addTest(
155         SetTestSuiteBuilder.using(
156                 new TestStringSetGenerator() {
157                   @Override
158                   protected Set<String> create(String[] elements) {
159                     RowSortedTable<String, Integer, Character> table = TreeBasedTable.create();
160                     populateForRowKeySet(table, elements);
161                     return Tables.unmodifiableRowSortedTable(table).rowKeySet();
162                   }
163 
164                   @Override
165                   public List<String> order(List<String> insertionOrder) {
166                     Collections.sort(insertionOrder);
167                     return insertionOrder;
168                   }
169                 })
170             .named("unmodifiableRowSortedTable[TreeBasedTable].rowKeySet")
171             .withFeatures(COLLECTION_FEATURES_ORDER)
172             .createTestSuite());
173 
174     suite.addTest(
175         SetTestSuiteBuilder.using(
176                 new TestStringSetGenerator() {
177                   @Override
178                   protected Set<String> create(String[] elements) {
179                     Table<Integer, String, Character> table =
180                         ArrayTable.create(ImmutableList.of(1, 2), ImmutableList.copyOf(elements));
181                     populateForColumnKeySet(table, elements);
182                     return table.columnKeySet();
183                   }
184                 })
185             .named("ArrayTable.columnKeySet")
186             .withFeatures(
187                 CollectionSize.ONE,
188                 CollectionSize.SEVERAL,
189                 CollectionFeature.KNOWN_ORDER,
190                 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
191                 CollectionFeature.ALLOWS_NULL_QUERIES)
192             .createTestSuite());
193 
194     suite.addTest(
195         SetTestSuiteBuilder.using(
196                 new TestStringSetGenerator() {
197                   @Override
198                   protected Set<String> create(String[] elements) {
199                     Table<Integer, String, Character> table = HashBasedTable.create();
200                     populateForColumnKeySet(table, elements);
201                     return table.columnKeySet();
202                   }
203                 })
204             .named("HashBasedTable.columnKeySet")
205             .withFeatures(COLLECTION_FEATURES_REMOVE)
206             .createTestSuite());
207 
208     suite.addTest(
209         SetTestSuiteBuilder.using(
210                 new TestStringSetGenerator() {
211                   @Override
212                   protected Set<String> create(String[] elements) {
213                     Table<Integer, String, Character> table = TreeBasedTable.create();
214                     populateForColumnKeySet(table, elements);
215                     return table.columnKeySet();
216                   }
217 
218                   @Override
219                   public List<String> order(List<String> insertionOrder) {
220                     Collections.sort(insertionOrder);
221                     return insertionOrder;
222                   }
223                 })
224             .named("TreeBasedTable.columnKeySet")
225             .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
226             .createTestSuite());
227 
228     suite.addTest(
229         SetTestSuiteBuilder.using(
230                 new TestStringSetGenerator() {
231                   @Override
232                   protected Set<String> create(String[] elements) {
233                     Table<Integer, String, Character> table = HashBasedTable.create();
234                     populateForColumnKeySet(table, elements);
235                     return Tables.unmodifiableTable(table).columnKeySet();
236                   }
237                 })
238             .named("unmodifiableTable[HashBasedTable].columnKeySet")
239             .withFeatures(COLLECTION_FEATURES)
240             .createTestSuite());
241 
242     suite.addTest(
243         SetTestSuiteBuilder.using(
244                 new TestStringSetGenerator() {
245                   @Override
246                   protected Set<String> create(String[] elements) {
247                     RowSortedTable<Integer, String, Character> table = TreeBasedTable.create();
248                     populateForColumnKeySet(table, elements);
249                     return Tables.unmodifiableRowSortedTable(table).columnKeySet();
250                   }
251 
252                   @Override
253                   public List<String> order(List<String> insertionOrder) {
254                     Collections.sort(insertionOrder);
255                     return insertionOrder;
256                   }
257                 })
258             .named("unmodifiableRowSortedTable[TreeBasedTable].columnKeySet")
259             .withFeatures(COLLECTION_FEATURES_ORDER)
260             .createTestSuite());
261 
262     suite.addTest(
263         CollectionTestSuiteBuilder.using(
264                 new TestStringCollectionGenerator() {
265                   @Override
266                   protected Collection<String> create(String[] elements) {
267                     List<Integer> rowKeys = Lists.newArrayList();
268                     for (int i = 0; i < elements.length; i++) {
269                       rowKeys.add(i);
270                     }
271                     Table<Integer, Character, String> table =
272                         ArrayTable.create(rowKeys, ImmutableList.of('a'));
273                     populateForValues(table, elements);
274                     return table.values();
275                   }
276                 })
277             .named("ArrayTable.values")
278             .withFeatures(
279                 CollectionSize.ONE,
280                 CollectionSize.SEVERAL,
281                 CollectionFeature.ALLOWS_NULL_VALUES,
282                 CollectionFeature.KNOWN_ORDER)
283             .createTestSuite());
284 
285     suite.addTest(
286         CollectionTestSuiteBuilder.using(
287                 new TestStringCollectionGenerator() {
288                   @Override
289                   protected Collection<String> create(String[] elements) {
290                     Table<Integer, Character, String> table = HashBasedTable.create();
291                     table.put(1, 'a', "foo");
292                     table.clear();
293                     populateForValues(table, elements);
294                     return table.values();
295                   }
296                 })
297             .named("HashBasedTable.values")
298             .withFeatures(COLLECTION_FEATURES_REMOVE)
299             .withFeatures(CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
300             .createTestSuite());
301 
302     suite.addTest(
303         CollectionTestSuiteBuilder.using(
304                 new TestStringCollectionGenerator() {
305                   @Override
306                   protected Collection<String> create(String[] elements) {
307                     Table<Integer, Character, String> table = TreeBasedTable.create();
308                     table.put(1, 'a', "foo");
309                     table.clear();
310                     populateForValues(table, elements);
311                     return table.values();
312                   }
313                 })
314             .named("TreeBasedTable.values")
315             .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
316             .withFeatures(CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
317             .createTestSuite());
318 
319     final Function<String, String> removeFirstCharacter =
320         new Function<String, String>() {
321           @Override
322           public String apply(String input) {
323             return input.substring(1);
324           }
325         };
326 
327     suite.addTest(
328         CollectionTestSuiteBuilder.using(
329                 new TestStringCollectionGenerator() {
330                   @Override
331                   protected Collection<String> create(String[] elements) {
332                     Table<Integer, Character, String> table = HashBasedTable.create();
333                     for (int i = 0; i < elements.length; i++) {
334                       table.put(i, 'a', "x" + checkNotNull(elements[i]));
335                     }
336                     return Tables.transformValues(table, removeFirstCharacter).values();
337                   }
338                 })
339             .named("TransformValues.values")
340             .withFeatures(COLLECTION_FEATURES_REMOVE)
341             .withFeatures(CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
342             .createTestSuite());
343 
344     suite.addTest(
345         CollectionTestSuiteBuilder.using(
346                 new TestStringCollectionGenerator() {
347                   @Override
348                   protected Collection<String> create(String[] elements) {
349                     Table<Integer, Character, String> table = HashBasedTable.create();
350                     table.put(1, 'a', "foo");
351                     table.clear();
352                     populateForValues(table, elements);
353                     return Tables.unmodifiableTable(table).values();
354                   }
355                 })
356             .named("unmodifiableTable[HashBasedTable].values")
357             .withFeatures(COLLECTION_FEATURES)
358             .createTestSuite());
359 
360     suite.addTest(
361         CollectionTestSuiteBuilder.using(
362                 new TestStringCollectionGenerator() {
363                   @Override
364                   protected Collection<String> create(String[] elements) {
365                     RowSortedTable<Integer, Character, String> table = TreeBasedTable.create();
366                     table.put(1, 'a', "foo");
367                     table.clear();
368                     populateForValues(table, elements);
369                     return Tables.unmodifiableRowSortedTable(table).values();
370                   }
371                 })
372             .named("unmodifiableTable[TreeBasedTable].values")
373             .withFeatures(COLLECTION_FEATURES_ORDER)
374             .createTestSuite());
375 
376     suite.addTest(
377         SetTestSuiteBuilder.using(
378                 new TestCellSetGenerator() {
379                   @Override
380                   public SampleElements<Cell<String, Integer, Character>> samples() {
381                     return new SampleElements<>(
382                         Tables.immutableCell("bar", 1, 'a'),
383                         Tables.immutableCell("bar", 2, 'b'),
384                         Tables.immutableCell("bar", 3, (Character) null),
385                         Tables.immutableCell("bar", 4, 'b'),
386                         Tables.immutableCell("bar", 5, 'b'));
387                   }
388 
389                   @Override
390                   public Set<Cell<String, Integer, Character>> create(Object... elements) {
391                     List<Integer> columnKeys = Lists.newArrayList();
392                     for (Object element : elements) {
393                       @SuppressWarnings("unchecked")
394                       Cell<String, Integer, Character> cell =
395                           (Cell<String, Integer, Character>) element;
396                       columnKeys.add(cell.getColumnKey());
397                     }
398                     Table<String, Integer, Character> table =
399                         ArrayTable.create(ImmutableList.of("bar"), columnKeys);
400                     for (Object element : elements) {
401                       @SuppressWarnings("unchecked")
402                       Cell<String, Integer, Character> cell =
403                           (Cell<String, Integer, Character>) element;
404                       table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
405                     }
406                     return table.cellSet();
407                   }
408 
409                   @Override
410                   Table<String, Integer, Character> createTable() {
411                     throw new UnsupportedOperationException();
412                   }
413                 })
414             .named("ArrayTable.cellSet")
415             .withFeatures(
416                 CollectionSize.ONE,
417                 CollectionSize.SEVERAL,
418                 CollectionFeature.KNOWN_ORDER,
419                 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION,
420                 CollectionFeature.ALLOWS_NULL_QUERIES)
421             .createTestSuite());
422 
423     suite.addTest(
424         SetTestSuiteBuilder.using(
425                 new TestCellSetGenerator() {
426                   @Override
427                   Table<String, Integer, Character> createTable() {
428                     return HashBasedTable.create();
429                   }
430                 })
431             .named("HashBasedTable.cellSet")
432             .withFeatures(
433                 CollectionSize.ANY,
434                 CollectionFeature.REMOVE_OPERATIONS,
435                 CollectionFeature.ALLOWS_NULL_QUERIES)
436             .createTestSuite());
437 
438     suite.addTest(
439         SetTestSuiteBuilder.using(
440                 new TestCellSetGenerator() {
441                   @Override
442                   Table<String, Integer, Character> createTable() {
443                     return TreeBasedTable.create();
444                   }
445                 })
446             .named("TreeBasedTable.cellSet")
447             .withFeatures(
448                 CollectionSize.ANY,
449                 CollectionFeature.REMOVE_OPERATIONS,
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                     Table<Integer, String, Character> original = TreeBasedTable.create();
459                     return Tables.transpose(original);
460                   }
461                 })
462             .named("TransposedTable.cellSet")
463             .withFeatures(
464                 CollectionSize.ANY,
465                 CollectionFeature.REMOVE_OPERATIONS,
466                 CollectionFeature.ALLOWS_NULL_QUERIES)
467             .createTestSuite());
468 
469     suite.addTest(
470         SetTestSuiteBuilder.using(
471                 new TestCellSetGenerator() {
472                   @Override
473                   Table<String, Integer, Character> createTable() {
474                     return HashBasedTable.create();
475                   }
476 
477                   @Override
478                   public Set<Cell<String, Integer, Character>> create(Object... elements) {
479                     Table<String, Integer, Character> table = createTable();
480                     for (Object element : elements) {
481                       @SuppressWarnings("unchecked")
482                       Cell<String, Integer, Character> cell =
483                           (Cell<String, Integer, Character>) element;
484                       table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
485                     }
486                     return Tables.transformValues(table, Functions.<Character>identity()).cellSet();
487                   }
488                 })
489             .named("TransformValues.cellSet")
490             .withFeatures(
491                 CollectionSize.ANY,
492                 CollectionFeature.ALLOWS_NULL_QUERIES,
493                 CollectionFeature.REMOVE_OPERATIONS)
494             .createTestSuite());
495 
496     suite.addTest(
497         SetTestSuiteBuilder.using(
498                 new TestCellSetGenerator() {
499                   @Override
500                   Table<String, Integer, Character> createTable() {
501                     return Tables.unmodifiableTable(
502                         HashBasedTable.<String, Integer, Character>create());
503                   }
504 
505                   @Override
506                   public Set<Cell<String, Integer, Character>> create(Object... elements) {
507                     Table<String, Integer, Character> table = HashBasedTable.create();
508                     for (Object element : elements) {
509                       @SuppressWarnings("unchecked")
510                       Cell<String, Integer, Character> cell =
511                           (Cell<String, Integer, Character>) element;
512                       table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
513                     }
514                     return Tables.unmodifiableTable(table).cellSet();
515                   }
516                 })
517             .named("unmodifiableTable[HashBasedTable].cellSet")
518             .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES)
519             .createTestSuite());
520 
521     suite.addTest(
522         SetTestSuiteBuilder.using(
523                 new TestCellSetGenerator() {
524                   @Override
525                   RowSortedTable<String, Integer, Character> createTable() {
526                     return Tables.unmodifiableRowSortedTable(
527                         TreeBasedTable.<String, Integer, Character>create());
528                   }
529 
530                   @Override
531                   public Set<Cell<String, Integer, Character>> create(Object... elements) {
532                     RowSortedTable<String, Integer, Character> table = TreeBasedTable.create();
533                     for (Object element : elements) {
534                       @SuppressWarnings("unchecked")
535                       Cell<String, Integer, Character> cell =
536                           (Cell<String, Integer, Character>) element;
537                       table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
538                     }
539                     return Tables.unmodifiableRowSortedTable(table).cellSet();
540                   }
541                 })
542             .named("unmodifiableRowSortedTable[TreeBasedTable].cellSet")
543             .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES)
544             .createTestSuite());
545 
546     suite.addTest(
547         SetTestSuiteBuilder.using(
548                 new TestStringSetGenerator() {
549                   @Override
550                   protected Set<String> create(String[] elements) {
551                     Iterable<String> rowKeys = ImmutableSet.copyOf(elements);
552                     Iterable<Integer> columnKeys = ImmutableList.of(1, 2, 3);
553                     Table<String, Integer, Character> table =
554                         ArrayTable.create(rowKeys, columnKeys);
555                     populateForRowKeySet(table, elements);
556                     return table.column(1).keySet();
557                   }
558                 })
559             .named("ArrayTable.column.keySet")
560             .withFeatures(
561                 CollectionSize.ONE,
562                 CollectionSize.SEVERAL,
563                 CollectionFeature.KNOWN_ORDER,
564                 CollectionFeature.ALLOWS_NULL_QUERIES)
565             .createTestSuite());
566 
567     suite.addTest(
568         SetTestSuiteBuilder.using(
569                 new TestStringSetGenerator() {
570                   @Override
571                   protected Set<String> create(String[] elements) {
572                     Table<String, Integer, Character> table = HashBasedTable.create();
573                     populateForRowKeySet(table, elements);
574                     return table.column(1).keySet();
575                   }
576                 })
577             .named("HashBasedTable.column.keySet")
578             .withFeatures(COLLECTION_FEATURES_REMOVE)
579             .createTestSuite());
580 
581     suite.addTest(
582         SetTestSuiteBuilder.using(
583                 new TestStringSetGenerator() {
584                   @Override
585                   protected Set<String> create(String[] elements) {
586                     Table<String, Integer, Character> table = TreeBasedTable.create();
587                     populateForRowKeySet(table, elements);
588                     return table.column(1).keySet();
589                   }
590 
591                   @Override
592                   public List<String> order(List<String> insertionOrder) {
593                     Collections.sort(insertionOrder);
594                     return insertionOrder;
595                   }
596                 })
597             .named("TreeBasedTable.column.keySet")
598             .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
599             .createTestSuite());
600 
601     suite.addTest(
602         SetTestSuiteBuilder.using(
603                 new TestStringSetGenerator() {
604                   @Override
605                   protected Set<String> create(String[] elements) {
606                     Table<String, Integer, Character> table = HashBasedTable.create();
607                     populateForRowKeySet(table, elements);
608                     return Tables.transformValues(table, Functions.toStringFunction())
609                         .column(1)
610                         .keySet();
611                   }
612                 })
613             .named("TransformValues.column.keySet")
614             .withFeatures(COLLECTION_FEATURES_REMOVE)
615             .createTestSuite());
616 
617     suite.addTest(
618         SetTestSuiteBuilder.using(
619                 new TestStringSetGenerator() {
620                   @Override
621                   protected Set<String> create(String[] elements) {
622                     Table<String, Integer, Character> table = HashBasedTable.create();
623                     populateForRowKeySet(table, elements);
624                     return Tables.unmodifiableTable(table).column(1).keySet();
625                   }
626                 })
627             .named("unmodifiableTable[HashBasedTable].column.keySet")
628             .withFeatures(COLLECTION_FEATURES)
629             .createTestSuite());
630 
631     suite.addTest(
632         SetTestSuiteBuilder.using(
633                 new TestStringSetGenerator() {
634                   @Override
635                   protected Set<String> create(String[] elements) {
636                     RowSortedTable<String, Integer, Character> table = TreeBasedTable.create();
637                     populateForRowKeySet(table, elements);
638                     return Tables.unmodifiableRowSortedTable(table).column(1).keySet();
639                   }
640 
641                   @Override
642                   public List<String> order(List<String> insertionOrder) {
643                     Collections.sort(insertionOrder);
644                     return insertionOrder;
645                   }
646                 })
647             .named("unmodifiableRowSortedTable[TreeBasedTable].column.keySet")
648             .withFeatures(COLLECTION_FEATURES_ORDER)
649             .createTestSuite());
650 
651     return suite;
652   }
653 
populateForRowKeySet( Table<String, Integer, Character> table, String[] elements)654   private static void populateForRowKeySet(
655       Table<String, Integer, Character> table, String[] elements) {
656     for (String row : elements) {
657       table.put(row, 1, 'a');
658       table.put(row, 2, 'b');
659     }
660   }
661 
populateForColumnKeySet( Table<Integer, String, Character> table, String[] elements)662   private static void populateForColumnKeySet(
663       Table<Integer, String, Character> table, String[] elements) {
664     for (String column : elements) {
665       table.put(1, column, 'a');
666       table.put(2, column, 'b');
667     }
668   }
669 
populateForValues( Table<Integer, Character, String> table, String[] elements)670   private static void populateForValues(
671       Table<Integer, Character, String> table, String[] elements) {
672     for (int i = 0; i < elements.length; i++) {
673       table.put(i, 'a', elements[i]);
674     }
675   }
676 
677   private abstract static class TestCellSetGenerator
678       implements TestSetGenerator<Cell<String, Integer, Character>> {
679     @Override
samples()680     public SampleElements<Cell<String, Integer, Character>> samples() {
681       return new SampleElements<>(
682           Tables.immutableCell("bar", 1, 'a'),
683           Tables.immutableCell("bar", 2, 'b'),
684           Tables.immutableCell("foo", 3, 'c'),
685           Tables.immutableCell("bar", 1, 'b'),
686           Tables.immutableCell("cat", 2, 'b'));
687     }
688 
689     @Override
create(Object... elements)690     public Set<Cell<String, Integer, Character>> create(Object... elements) {
691       Table<String, Integer, Character> table = createTable();
692       for (Object element : elements) {
693         @SuppressWarnings("unchecked")
694         Cell<String, Integer, Character> cell = (Cell<String, Integer, Character>) element;
695         table.put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
696       }
697       return table.cellSet();
698     }
699 
createTable()700     abstract Table<String, Integer, Character> createTable();
701 
702     @Override
703     @SuppressWarnings("unchecked")
createArray(int length)704     public Cell<String, Integer, Character>[] createArray(int length) {
705       return (Cell<String, Integer, Character>[]) new Cell<?, ?, ?>[length];
706     }
707 
708     @Override
order( List<Cell<String, Integer, Character>> insertionOrder)709     public List<Cell<String, Integer, Character>> order(
710         List<Cell<String, Integer, Character>> insertionOrder) {
711       return insertionOrder;
712     }
713   }
714 
715   private abstract static class MapTests extends MapInterfaceTest<String, Integer> {
716 
MapTests( boolean allowsNullValues, boolean supportsPut, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)717     MapTests(
718         boolean allowsNullValues,
719         boolean supportsPut,
720         boolean supportsRemove,
721         boolean supportsClear,
722         boolean supportsIteratorRemove) {
723       super(
724           false,
725           allowsNullValues,
726           supportsPut,
727           supportsRemove,
728           supportsClear,
729           supportsIteratorRemove);
730     }
731 
732     @Override
getKeyNotInPopulatedMap()733     protected String getKeyNotInPopulatedMap() {
734       return "four";
735     }
736 
737     @Override
getValueNotInPopulatedMap()738     protected Integer getValueNotInPopulatedMap() {
739       return 4;
740     }
741   }
742 
743   abstract static class RowTests extends MapTests {
RowTests( boolean allowsNullValues, boolean supportsPut, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)744     RowTests(
745         boolean allowsNullValues,
746         boolean supportsPut,
747         boolean supportsRemove,
748         boolean supportsClear,
749         boolean supportsIteratorRemove) {
750       super(allowsNullValues, supportsPut, supportsRemove, supportsClear, supportsIteratorRemove);
751     }
752 
makeTable()753     abstract Table<Character, String, Integer> makeTable();
754 
755     @Override
makeEmptyMap()756     protected Map<String, Integer> makeEmptyMap() {
757       return makeTable().row('a');
758     }
759 
760     @Override
makePopulatedMap()761     protected Map<String, Integer> makePopulatedMap() {
762       Table<Character, String, Integer> table = makeTable();
763       table.put('a', "one", 1);
764       table.put('a', "two", 2);
765       table.put('a', "three", 3);
766       table.put('b', "four", 4);
767       return table.row('a');
768     }
769   }
770 
771   static final Function<@Nullable Integer, @Nullable Integer> DIVIDE_BY_2 =
772       new Function<@Nullable Integer, @Nullable Integer>() {
773         @Override
774         public @Nullable Integer apply(@Nullable Integer input) {
775           return (input == null) ? null : input / 2;
776         }
777       };
778 
779   abstract static class ColumnTests extends MapTests {
ColumnTests( boolean allowsNullValues, boolean supportsPut, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)780     ColumnTests(
781         boolean allowsNullValues,
782         boolean supportsPut,
783         boolean supportsRemove,
784         boolean supportsClear,
785         boolean supportsIteratorRemove) {
786       super(allowsNullValues, supportsPut, supportsRemove, supportsClear, supportsIteratorRemove);
787     }
788 
makeTable()789     abstract Table<String, Character, Integer> makeTable();
790 
791     @Override
makeEmptyMap()792     protected Map<String, Integer> makeEmptyMap() {
793       return makeTable().column('a');
794     }
795 
796     @Override
makePopulatedMap()797     protected Map<String, Integer> makePopulatedMap() {
798       Table<String, Character, Integer> table = makeTable();
799       table.put("one", 'a', 1);
800       table.put("two", 'a', 2);
801       table.put("three", 'a', 3);
802       table.put("four", 'b', 4);
803       return table.column('a');
804     }
805   }
806 
807   private abstract static class MapMapTests
808       extends MapInterfaceTest<String, Map<Integer, Character>> {
809 
MapMapTests( boolean allowsNullValues, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)810     MapMapTests(
811         boolean allowsNullValues,
812         boolean supportsRemove,
813         boolean supportsClear,
814         boolean supportsIteratorRemove) {
815       super(false, allowsNullValues, false, supportsRemove, supportsClear, supportsIteratorRemove);
816     }
817 
818     @Override
getKeyNotInPopulatedMap()819     protected String getKeyNotInPopulatedMap() {
820       return "cat";
821     }
822 
823     @Override
getValueNotInPopulatedMap()824     protected Map<Integer, Character> getValueNotInPopulatedMap() {
825       return ImmutableMap.of();
826     }
827 
828     /**
829      * The version of this test supplied by {@link MapInterfaceTest} fails for this particular map
830      * implementation, because {@code map.get()} returns a view collection that changes in the
831      * course of a call to {@code remove()}. Thus, the expectation doesn't hold that {@code
832      * map.remove(x)} returns the same value which {@code map.get(x)} did immediately beforehand.
833      */
834     @Override
testRemove()835     public void testRemove() {
836       final Map<String, Map<Integer, Character>> map;
837       final String keyToRemove;
838       try {
839         map = makePopulatedMap();
840       } catch (UnsupportedOperationException e) {
841         return;
842       }
843       keyToRemove = map.keySet().iterator().next();
844       if (supportsRemove) {
845         int initialSize = map.size();
846         map.get(keyToRemove);
847         map.remove(keyToRemove);
848         // This line doesn't hold - see the Javadoc comments above.
849         // assertEquals(expectedValue, oldValue);
850         assertFalse(map.containsKey(keyToRemove));
851         assertEquals(initialSize - 1, map.size());
852       } else {
853         try {
854           map.remove(keyToRemove);
855           fail("Expected UnsupportedOperationException.");
856         } catch (UnsupportedOperationException expected) {
857         }
858       }
859       assertInvariants(map);
860     }
861   }
862 
863   abstract static class RowMapTests extends MapMapTests {
RowMapTests( boolean allowsNullValues, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)864     RowMapTests(
865         boolean allowsNullValues,
866         boolean supportsRemove,
867         boolean supportsClear,
868         boolean supportsIteratorRemove) {
869       super(allowsNullValues, supportsRemove, supportsClear, supportsIteratorRemove);
870     }
871 
makeTable()872     abstract Table<String, Integer, Character> makeTable();
873 
874     @Override
makePopulatedMap()875     protected Map<String, Map<Integer, Character>> makePopulatedMap() {
876       Table<String, Integer, Character> table = makeTable();
877       populateTable(table);
878       return table.rowMap();
879     }
880 
populateTable(Table<String, Integer, Character> table)881     void populateTable(Table<String, Integer, Character> table) {
882       table.put("foo", 1, 'a');
883       table.put("bar", 1, 'b');
884       table.put("foo", 3, 'c');
885     }
886 
887     @Override
makeEmptyMap()888     protected Map<String, Map<Integer, Character>> makeEmptyMap() {
889       return makeTable().rowMap();
890     }
891   }
892 
893   static final Function<@Nullable String, @Nullable Character> FIRST_CHARACTER =
894       new Function<@Nullable String, @Nullable Character>() {
895         @Override
896         public @Nullable Character apply(@Nullable String input) {
897           return input == null ? null : input.charAt(0);
898         }
899       };
900 
901   abstract static class ColumnMapTests extends MapMapTests {
ColumnMapTests( boolean allowsNullValues, boolean supportsRemove, boolean supportsClear, boolean supportsIteratorRemove)902     ColumnMapTests(
903         boolean allowsNullValues,
904         boolean supportsRemove,
905         boolean supportsClear,
906         boolean supportsIteratorRemove) {
907       super(allowsNullValues, supportsRemove, supportsClear, supportsIteratorRemove);
908     }
909 
makeTable()910     abstract Table<Integer, String, Character> makeTable();
911 
912     @Override
makePopulatedMap()913     protected Map<String, Map<Integer, Character>> makePopulatedMap() {
914       Table<Integer, String, Character> table = makeTable();
915       table.put(1, "foo", 'a');
916       table.put(1, "bar", 'b');
917       table.put(3, "foo", 'c');
918       return table.columnMap();
919     }
920 
921     @Override
makeEmptyMap()922     protected Map<String, Map<Integer, Character>> makeEmptyMap() {
923       return makeTable().columnMap();
924     }
925   }
926 }
927