1 /* 2 * Copyright (C) 2009 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.truth.Truth.assertThat; 20 21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.annotations.GwtIncompatible; 23 import com.google.common.testing.SerializableTester; 24 25 /** 26 * Tests common methods in {@link ImmutableTable} 27 * 28 * @author Gregory Kick 29 */ 30 @GwtCompatible(emulated = true) 31 public class ImmutableTableTest extends AbstractTableReadTest { 32 @Override create(Object... data)33 protected Table<String, Integer, Character> create(Object... data) { 34 ImmutableTable.Builder<String, Integer, Character> builder = ImmutableTable.builder(); 35 for (int i = 0; i < data.length; i = i + 3) { 36 builder.put((String) data[i], (Integer) data[i + 1], (Character) data[i + 2]); 37 } 38 return builder.build(); 39 } 40 41 // TODO(b/172823566): Use mainline testToImmutableMap once CollectorTester is usable to java7. testToImmutableTable_java7_combine()42 public void testToImmutableTable_java7_combine() { 43 ImmutableTable.Builder<String, String, Integer> zis = 44 ImmutableTable.<String, String, Integer>builder().put("one", "uno", 1).put("two", "dos", 2); 45 ImmutableTable.Builder<String, String, Integer> zat = 46 ImmutableTable.<String, String, Integer>builder() 47 .put("one", "eins", 1) 48 .put("two", "twei", 2); 49 ImmutableTable<String, String, Integer> table = zis.combine(zat).build(); 50 ImmutableTable<String, String, Integer> expected = 51 ImmutableTable.<String, String, Integer>builder() 52 .put("one", "uno", 1) 53 .put("two", "dos", 2) 54 .put("one", "eins", 1) 55 .put("two", "twei", 2) 56 .build(); 57 assertThat(table).isEqualTo(expected); 58 } 59 testBuilder()60 public void testBuilder() { 61 ImmutableTable.Builder<Character, Integer, String> builder = new ImmutableTable.Builder<>(); 62 assertEquals(ImmutableTable.of(), builder.build()); 63 assertEquals(ImmutableTable.of('a', 1, "foo"), builder.put('a', 1, "foo").build()); 64 Table<Character, Integer, String> expectedTable = HashBasedTable.create(); 65 expectedTable.put('a', 1, "foo"); 66 expectedTable.put('b', 1, "bar"); 67 expectedTable.put('a', 2, "baz"); 68 Table<Character, Integer, String> otherTable = HashBasedTable.create(); 69 otherTable.put('b', 1, "bar"); 70 otherTable.put('a', 2, "baz"); 71 assertEquals(expectedTable, builder.putAll(otherTable).build()); 72 } 73 testBuilder_withImmutableCell()74 public void testBuilder_withImmutableCell() { 75 ImmutableTable.Builder<Character, Integer, String> builder = new ImmutableTable.Builder<>(); 76 assertEquals( 77 ImmutableTable.of('a', 1, "foo"), builder.put(Tables.immutableCell('a', 1, "foo")).build()); 78 } 79 testBuilder_withImmutableCellAndNullContents()80 public void testBuilder_withImmutableCellAndNullContents() { 81 ImmutableTable.Builder<Character, Integer, String> builder = new ImmutableTable.Builder<>(); 82 try { 83 builder.put(Tables.immutableCell((Character) null, 1, "foo")); 84 fail(); 85 } catch (NullPointerException e) { 86 // success 87 } 88 try { 89 builder.put(Tables.immutableCell('a', (Integer) null, "foo")); 90 fail(); 91 } catch (NullPointerException e) { 92 // success 93 } 94 try { 95 builder.put(Tables.immutableCell('a', 1, (String) null)); 96 fail(); 97 } catch (NullPointerException e) { 98 // success 99 } 100 } 101 102 private static class StringHolder { 103 String string; 104 } 105 testBuilder_withMutableCell()106 public void testBuilder_withMutableCell() { 107 ImmutableTable.Builder<Character, Integer, String> builder = new ImmutableTable.Builder<>(); 108 109 final StringHolder holder = new StringHolder(); 110 holder.string = "foo"; 111 Table.Cell<Character, Integer, String> mutableCell = 112 new Tables.AbstractCell<Character, Integer, String>() { 113 @Override 114 public Character getRowKey() { 115 return 'K'; 116 } 117 118 @Override 119 public Integer getColumnKey() { 120 return 42; 121 } 122 123 @Override 124 public String getValue() { 125 return holder.string; 126 } 127 }; 128 129 // Add the mutable cell to the builder 130 builder.put(mutableCell); 131 132 // Mutate the value 133 holder.string = "bar"; 134 135 // Make sure it uses the original value. 136 assertEquals(ImmutableTable.of('K', 42, "foo"), builder.build()); 137 } 138 testBuilder_noDuplicates()139 public void testBuilder_noDuplicates() { 140 ImmutableTable.Builder<Character, Integer, String> builder = 141 new ImmutableTable.Builder<Character, Integer, String>() 142 .put('a', 1, "foo") 143 .put('a', 1, "bar"); 144 try { 145 builder.build(); 146 fail(); 147 } catch (IllegalArgumentException e) { 148 // success 149 } 150 } 151 testBuilder_noNulls()152 public void testBuilder_noNulls() { 153 ImmutableTable.Builder<Character, Integer, String> builder = new ImmutableTable.Builder<>(); 154 try { 155 builder.put(null, 1, "foo"); 156 fail(); 157 } catch (NullPointerException e) { 158 // success 159 } 160 try { 161 builder.put('a', null, "foo"); 162 fail(); 163 } catch (NullPointerException e) { 164 // success 165 } 166 try { 167 builder.put('a', 1, null); 168 fail(); 169 } catch (NullPointerException e) { 170 // success 171 } 172 } 173 validateTableCopies(Table<R, C, V> original)174 private static <R, C, V> void validateTableCopies(Table<R, C, V> original) { 175 Table<R, C, V> copy = ImmutableTable.copyOf(original); 176 assertEquals(original, copy); 177 validateViewOrdering(original, copy); 178 179 Table<R, C, V> built = ImmutableTable.<R, C, V>builder().putAll(original).build(); 180 assertEquals(original, built); 181 validateViewOrdering(original, built); 182 } 183 validateViewOrdering(Table<R, C, V> original, Table<R, C, V> copy)184 private static <R, C, V> void validateViewOrdering(Table<R, C, V> original, Table<R, C, V> copy) { 185 assertThat(copy.cellSet()).containsExactlyElementsIn(original.cellSet()).inOrder(); 186 assertThat(copy.rowKeySet()).containsExactlyElementsIn(original.rowKeySet()).inOrder(); 187 assertThat(copy.values()).containsExactlyElementsIn(original.values()).inOrder(); 188 } 189 testCopyOf()190 public void testCopyOf() { 191 Table<Character, Integer, String> table = TreeBasedTable.create(); 192 validateTableCopies(table); 193 table.put('b', 2, "foo"); 194 validateTableCopies(table); 195 table.put('b', 1, "bar"); 196 table.put('a', 2, "baz"); 197 validateTableCopies(table); 198 // Even though rowKeySet, columnKeySet, and cellSet have the same 199 // iteration ordering, row has an inconsistent ordering. 200 assertThat(table.row('b').keySet()).containsExactly(1, 2).inOrder(); 201 assertThat(ImmutableTable.copyOf(table).row('b').keySet()).containsExactly(2, 1).inOrder(); 202 } 203 testCopyOfSparse()204 public void testCopyOfSparse() { 205 Table<Character, Integer, String> table = TreeBasedTable.create(); 206 table.put('x', 2, "foo"); 207 table.put('r', 1, "bar"); 208 table.put('c', 3, "baz"); 209 table.put('b', 7, "cat"); 210 table.put('e', 5, "dog"); 211 table.put('c', 0, "axe"); 212 table.put('e', 3, "tub"); 213 table.put('r', 4, "foo"); 214 table.put('x', 5, "bar"); 215 validateTableCopies(table); 216 } 217 testCopyOfDense()218 public void testCopyOfDense() { 219 Table<Character, Integer, String> table = TreeBasedTable.create(); 220 table.put('c', 3, "foo"); 221 table.put('c', 2, "bar"); 222 table.put('c', 1, "baz"); 223 table.put('b', 3, "cat"); 224 table.put('b', 1, "dog"); 225 table.put('a', 3, "foo"); 226 table.put('a', 2, "bar"); 227 table.put('a', 1, "baz"); 228 validateTableCopies(table); 229 } 230 testBuilder_orderRowsAndColumnsBy_putAll()231 public void testBuilder_orderRowsAndColumnsBy_putAll() { 232 Table<Character, Integer, String> table = HashBasedTable.create(); 233 table.put('b', 2, "foo"); 234 table.put('b', 1, "bar"); 235 table.put('a', 2, "baz"); 236 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 237 Table<Character, Integer, String> copy = 238 builder 239 .orderRowsBy(Ordering.natural()) 240 .orderColumnsBy(Ordering.natural()) 241 .putAll(table) 242 .build(); 243 assertThat(copy.rowKeySet()).containsExactly('a', 'b').inOrder(); 244 assertThat(copy.columnKeySet()).containsExactly(1, 2).inOrder(); 245 assertThat(copy.values()).containsExactly("baz", "bar", "foo").inOrder(); 246 assertThat(copy.row('b').keySet()).containsExactly(1, 2).inOrder(); 247 } 248 testBuilder_orderRowsAndColumnsBy_sparse()249 public void testBuilder_orderRowsAndColumnsBy_sparse() { 250 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 251 builder.orderRowsBy(Ordering.natural()); 252 builder.orderColumnsBy(Ordering.natural()); 253 builder.put('x', 2, "foo"); 254 builder.put('r', 1, "bar"); 255 builder.put('c', 3, "baz"); 256 builder.put('b', 7, "cat"); 257 builder.put('e', 5, "dog"); 258 builder.put('c', 0, "axe"); 259 builder.put('e', 3, "tub"); 260 builder.put('r', 4, "foo"); 261 builder.put('x', 5, "bar"); 262 Table<Character, Integer, String> table = builder.build(); 263 assertThat(table.rowKeySet()).containsExactly('b', 'c', 'e', 'r', 'x').inOrder(); 264 assertThat(table.columnKeySet()).containsExactly(0, 1, 2, 3, 4, 5, 7).inOrder(); 265 assertThat(table.values()) 266 .containsExactly("cat", "axe", "baz", "tub", "dog", "bar", "foo", "foo", "bar") 267 .inOrder(); 268 assertThat(table.row('c').keySet()).containsExactly(0, 3).inOrder(); 269 assertThat(table.column(5).keySet()).containsExactly('e', 'x').inOrder(); 270 } 271 testBuilder_orderRowsAndColumnsBy_dense()272 public void testBuilder_orderRowsAndColumnsBy_dense() { 273 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 274 builder.orderRowsBy(Ordering.natural()); 275 builder.orderColumnsBy(Ordering.natural()); 276 builder.put('c', 3, "foo"); 277 builder.put('c', 2, "bar"); 278 builder.put('c', 1, "baz"); 279 builder.put('b', 3, "cat"); 280 builder.put('b', 1, "dog"); 281 builder.put('a', 3, "foo"); 282 builder.put('a', 2, "bar"); 283 builder.put('a', 1, "baz"); 284 Table<Character, Integer, String> table = builder.build(); 285 assertThat(table.rowKeySet()).containsExactly('a', 'b', 'c').inOrder(); 286 assertThat(table.columnKeySet()).containsExactly(1, 2, 3).inOrder(); 287 assertThat(table.values()) 288 .containsExactly("baz", "bar", "foo", "dog", "cat", "baz", "bar", "foo") 289 .inOrder(); 290 assertThat(table.row('c').keySet()).containsExactly(1, 2, 3).inOrder(); 291 assertThat(table.column(1).keySet()).containsExactly('a', 'b', 'c').inOrder(); 292 } 293 testBuilder_orderRowsBy_sparse()294 public void testBuilder_orderRowsBy_sparse() { 295 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 296 builder.orderRowsBy(Ordering.natural()); 297 builder.put('x', 2, "foo"); 298 builder.put('r', 1, "bar"); 299 builder.put('c', 3, "baz"); 300 builder.put('b', 7, "cat"); 301 builder.put('e', 5, "dog"); 302 builder.put('c', 0, "axe"); 303 builder.put('e', 3, "tub"); 304 builder.put('r', 4, "foo"); 305 builder.put('x', 5, "bar"); 306 Table<Character, Integer, String> table = builder.build(); 307 assertThat(table.rowKeySet()).containsExactly('b', 'c', 'e', 'r', 'x').inOrder(); 308 assertThat(table.column(5).keySet()).containsExactly('e', 'x').inOrder(); 309 } 310 testBuilder_orderRowsBy_dense()311 public void testBuilder_orderRowsBy_dense() { 312 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 313 builder.orderRowsBy(Ordering.natural()); 314 builder.put('c', 3, "foo"); 315 builder.put('c', 2, "bar"); 316 builder.put('c', 1, "baz"); 317 builder.put('b', 3, "cat"); 318 builder.put('b', 1, "dog"); 319 builder.put('a', 3, "foo"); 320 builder.put('a', 2, "bar"); 321 builder.put('a', 1, "baz"); 322 Table<Character, Integer, String> table = builder.build(); 323 assertThat(table.rowKeySet()).containsExactly('a', 'b', 'c').inOrder(); 324 assertThat(table.column(1).keySet()).containsExactly('a', 'b', 'c').inOrder(); 325 } 326 testBuilder_orderColumnsBy_sparse()327 public void testBuilder_orderColumnsBy_sparse() { 328 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 329 builder.orderColumnsBy(Ordering.natural()); 330 builder.put('x', 2, "foo"); 331 builder.put('r', 1, "bar"); 332 builder.put('c', 3, "baz"); 333 builder.put('b', 7, "cat"); 334 builder.put('e', 5, "dog"); 335 builder.put('c', 0, "axe"); 336 builder.put('e', 3, "tub"); 337 builder.put('r', 4, "foo"); 338 builder.put('x', 5, "bar"); 339 Table<Character, Integer, String> table = builder.build(); 340 assertThat(table.columnKeySet()).containsExactly(0, 1, 2, 3, 4, 5, 7).inOrder(); 341 assertThat(table.row('c').keySet()).containsExactly(0, 3).inOrder(); 342 } 343 testBuilder_orderColumnsBy_dense()344 public void testBuilder_orderColumnsBy_dense() { 345 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 346 builder.orderColumnsBy(Ordering.natural()); 347 builder.put('c', 3, "foo"); 348 builder.put('c', 2, "bar"); 349 builder.put('c', 1, "baz"); 350 builder.put('b', 3, "cat"); 351 builder.put('b', 1, "dog"); 352 builder.put('a', 3, "foo"); 353 builder.put('a', 2, "bar"); 354 builder.put('a', 1, "baz"); 355 Table<Character, Integer, String> table = builder.build(); 356 assertThat(table.columnKeySet()).containsExactly(1, 2, 3).inOrder(); 357 assertThat(table.row('c').keySet()).containsExactly(1, 2, 3).inOrder(); 358 } 359 testSerialization_empty()360 public void testSerialization_empty() { 361 validateReserialization(ImmutableTable.of()); 362 } 363 testSerialization_singleElement()364 public void testSerialization_singleElement() { 365 validateReserialization(ImmutableTable.of('a', 2, "foo")); 366 } 367 testDenseSerialization_manualOrder()368 public void testDenseSerialization_manualOrder() { 369 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 370 builder.put('b', 2, "foo"); 371 builder.put('b', 1, "bar"); 372 builder.put('a', 2, "baz"); 373 Table<Character, Integer, String> table = builder.build(); 374 assertThat(table).isInstanceOf(DenseImmutableTable.class); 375 validateReserialization(table); 376 } 377 testDenseSerialization_rowOrder()378 public void testDenseSerialization_rowOrder() { 379 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 380 builder.orderRowsBy(Ordering.<Character>natural()); 381 builder.put('b', 2, "foo"); 382 builder.put('b', 1, "bar"); 383 builder.put('a', 2, "baz"); 384 Table<Character, Integer, String> table = builder.build(); 385 assertThat(table).isInstanceOf(DenseImmutableTable.class); 386 validateReserialization(table); 387 } 388 testDenseSerialization_columnOrder()389 public void testDenseSerialization_columnOrder() { 390 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 391 builder.orderColumnsBy(Ordering.<Integer>natural()); 392 builder.put('b', 2, "foo"); 393 builder.put('b', 1, "bar"); 394 builder.put('a', 2, "baz"); 395 Table<Character, Integer, String> table = builder.build(); 396 assertThat(table).isInstanceOf(DenseImmutableTable.class); 397 validateReserialization(table); 398 } 399 testDenseSerialization_bothOrders()400 public void testDenseSerialization_bothOrders() { 401 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 402 builder.orderRowsBy(Ordering.<Character>natural()); 403 builder.orderColumnsBy(Ordering.<Integer>natural()); 404 builder.put('b', 2, "foo"); 405 builder.put('b', 1, "bar"); 406 builder.put('a', 2, "baz"); 407 Table<Character, Integer, String> table = builder.build(); 408 assertThat(table).isInstanceOf(DenseImmutableTable.class); 409 validateReserialization(table); 410 } 411 testSparseSerialization_manualOrder()412 public void testSparseSerialization_manualOrder() { 413 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 414 builder.put('b', 2, "foo"); 415 builder.put('b', 1, "bar"); 416 builder.put('a', 2, "baz"); 417 builder.put('c', 3, "cat"); 418 builder.put('d', 4, "dog"); 419 Table<Character, Integer, String> table = builder.build(); 420 assertThat(table).isInstanceOf(SparseImmutableTable.class); 421 validateReserialization(table); 422 } 423 testSparseSerialization_rowOrder()424 public void testSparseSerialization_rowOrder() { 425 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 426 builder.orderRowsBy(Ordering.<Character>natural()); 427 builder.put('b', 2, "foo"); 428 builder.put('b', 1, "bar"); 429 builder.put('a', 2, "baz"); 430 builder.put('c', 3, "cat"); 431 builder.put('d', 4, "dog"); 432 Table<Character, Integer, String> table = builder.build(); 433 assertThat(table).isInstanceOf(SparseImmutableTable.class); 434 validateReserialization(table); 435 } 436 testSparseSerialization_columnOrder()437 public void testSparseSerialization_columnOrder() { 438 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 439 builder.orderColumnsBy(Ordering.<Integer>natural()); 440 builder.put('b', 2, "foo"); 441 builder.put('b', 1, "bar"); 442 builder.put('a', 2, "baz"); 443 builder.put('c', 3, "cat"); 444 builder.put('d', 4, "dog"); 445 Table<Character, Integer, String> table = builder.build(); 446 assertThat(table).isInstanceOf(SparseImmutableTable.class); 447 validateReserialization(table); 448 } 449 testSparseSerialization_bothOrders()450 public void testSparseSerialization_bothOrders() { 451 ImmutableTable.Builder<Character, Integer, String> builder = ImmutableTable.builder(); 452 builder.orderRowsBy(Ordering.<Character>natural()); 453 builder.orderColumnsBy(Ordering.<Integer>natural()); 454 builder.put('b', 2, "foo"); 455 builder.put('b', 1, "bar"); 456 builder.put('a', 2, "baz"); 457 builder.put('c', 3, "cat"); 458 builder.put('d', 4, "dog"); 459 Table<Character, Integer, String> table = builder.build(); 460 assertThat(table).isInstanceOf(SparseImmutableTable.class); 461 validateReserialization(table); 462 } 463 validateReserialization(Table<R, C, V> original)464 private static <R, C, V> void validateReserialization(Table<R, C, V> original) { 465 Table<R, C, V> copy = SerializableTester.reserializeAndAssert(original); 466 assertThat(copy.cellSet()).containsExactlyElementsIn(original.cellSet()).inOrder(); 467 assertThat(copy.rowKeySet()).containsExactlyElementsIn(original.rowKeySet()).inOrder(); 468 assertThat(copy.columnKeySet()).containsExactlyElementsIn(original.columnKeySet()).inOrder(); 469 } 470 471 @GwtIncompatible // Mind-bogglingly slow in GWT 472 @AndroidIncompatible // slow testOverflowCondition()473 public void testOverflowCondition() { 474 // See https://code.google.com/p/guava-libraries/issues/detail?id=1322 for details. 475 ImmutableTable.Builder<Integer, Integer, String> builder = ImmutableTable.builder(); 476 for (int i = 1; i < 0x10000; i++) { 477 builder.put(i, 0, "foo"); 478 builder.put(0, i, "bar"); 479 } 480 assertTrue(builder.build() instanceof SparseImmutableTable); 481 } 482 } 483