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