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 17package com.google.common.collect; 18 19import static org.truth0.Truth.ASSERT; 20 21import com.google.common.annotations.GwtCompatible; 22import com.google.common.annotations.GwtIncompatible; 23 24/** 25 * Tests common methods in {@link ImmutableTable} 26 * 27 * @author Gregory Kick 28 */ 29@GwtCompatible(emulated = true) 30public class ImmutableTableTest extends AbstractTableReadTest { 31 @Override protected Table<String, Integer, Character> create(Object... data) { 32 ImmutableTable.Builder<String, Integer, Character> builder = 33 ImmutableTable.builder(); 34 for (int i = 0; i < data.length; i = i + 3) { 35 builder.put((String) data[i], (Integer) data[i + 1], 36 (Character) data[i + 2]); 37 } 38 return builder.build(); 39 } 40 41 public void testBuilder() { 42 ImmutableTable.Builder<Character, Integer, String> builder = 43 new ImmutableTable.Builder<Character, Integer, String>(); 44 assertEquals(ImmutableTable.of(), builder.build()); 45 assertEquals(ImmutableTable.of('a', 1, "foo"), builder 46 .put('a', 1, "foo") 47 .build()); 48 Table<Character, Integer, String> expectedTable = HashBasedTable.create(); 49 expectedTable.put('a', 1, "foo"); 50 expectedTable.put('b', 1, "bar"); 51 expectedTable.put('a', 2, "baz"); 52 Table<Character, Integer, String> otherTable = HashBasedTable.create(); 53 otherTable.put('b', 1, "bar"); 54 otherTable.put('a', 2, "baz"); 55 assertEquals(expectedTable, builder 56 .putAll(otherTable) 57 .build()); 58 } 59 60 public void testBuilder_withImmutableCell() { 61 ImmutableTable.Builder<Character, Integer, String> builder = 62 new ImmutableTable.Builder<Character, Integer, String>(); 63 assertEquals(ImmutableTable.of('a', 1, "foo"), builder 64 .put(Tables.immutableCell('a', 1, "foo")) 65 .build()); 66 } 67 68 public void testBuilder_withImmutableCellAndNullContents() { 69 ImmutableTable.Builder<Character, Integer, String> builder = 70 new ImmutableTable.Builder<Character, Integer, String>(); 71 try { 72 builder.put(Tables.immutableCell((Character) null, 1, "foo")); 73 fail(); 74 } catch (NullPointerException e) { 75 // success 76 } 77 try { 78 builder.put(Tables.immutableCell('a', (Integer) null, "foo")); 79 fail(); 80 } catch (NullPointerException e) { 81 // success 82 } 83 try { 84 builder.put(Tables.immutableCell('a', 1, (String) null)); 85 fail(); 86 } catch (NullPointerException e) { 87 // success 88 } 89 } 90 91 private static class StringHolder { 92 String string; 93 } 94 95 public void testBuilder_withMutableCell() { 96 ImmutableTable.Builder<Character, Integer, String> builder = 97 new ImmutableTable.Builder<Character, Integer, String>(); 98 99 final StringHolder holder = new StringHolder(); 100 holder.string = "foo"; 101 Table.Cell<Character, Integer, String> mutableCell = 102 new Tables.AbstractCell<Character, Integer, String>() { 103 @Override public Character getRowKey() { 104 return 'K'; 105 } 106 @Override public Integer getColumnKey() { 107 return 42; 108 } 109 @Override public String getValue() { 110 return holder.string; 111 } 112 }; 113 114 // Add the mutable cell to the builder 115 builder.put(mutableCell); 116 117 // Mutate the value 118 holder.string = "bar"; 119 120 // Make sure it uses the original value. 121 assertEquals(ImmutableTable.of('K', 42, "foo"), builder.build()); 122 } 123 124 public void testBuilder_noDuplicates() { 125 ImmutableTable.Builder<Character, Integer, String> builder = 126 new ImmutableTable.Builder<Character, Integer, String>() 127 .put('a', 1, "foo") 128 .put('a', 1, "bar"); 129 try { 130 builder.build(); 131 fail(); 132 } catch (IllegalArgumentException e) { 133 // success 134 } 135 } 136 137 public void testBuilder_noNulls() { 138 ImmutableTable.Builder<Character, Integer, String> builder = 139 new ImmutableTable.Builder<Character, Integer, String>(); 140 try { 141 builder.put(null, 1, "foo"); 142 fail(); 143 } catch (NullPointerException e) { 144 // success 145 } 146 try { 147 builder.put('a', null, "foo"); 148 fail(); 149 } catch (NullPointerException e) { 150 // success 151 } 152 try { 153 builder.put('a', 1, null); 154 fail(); 155 } catch (NullPointerException e) { 156 // success 157 } 158 } 159 160 private static <R, C, V> void validateTableCopies(Table<R, C, V> original) { 161 Table<R, C, V> copy = ImmutableTable.copyOf(original); 162 assertEquals(original, copy); 163 validateViewOrdering(original, copy); 164 165 Table<R, C, V> built 166 = ImmutableTable.<R, C, V>builder().putAll(original).build(); 167 assertEquals(original, built); 168 validateViewOrdering(original, built); 169 } 170 171 private static <R, C, V> void validateViewOrdering( 172 Table<R, C, V> original, Table<R, C, V> copy) { 173 assertTrue(Iterables.elementsEqual(original.cellSet(), copy.cellSet())); 174 assertTrue(Iterables.elementsEqual(original.rowKeySet(), copy.rowKeySet())); 175 assertTrue(Iterables.elementsEqual(original.values(), copy.values())); 176 } 177 178 public void testCopyOf() { 179 Table<Character, Integer, String> table = TreeBasedTable.create(); 180 validateTableCopies(table); 181 table.put('b', 2, "foo"); 182 validateTableCopies(table); 183 table.put('b', 1, "bar"); 184 table.put('a', 2, "baz"); 185 validateTableCopies(table); 186 // Even though rowKeySet, columnKeySet, and cellSet have the same 187 // iteration ordering, row has an inconsistent ordering. 188 ASSERT.that(table.row('b').keySet()).has().exactly(1, 2).inOrder(); 189 ASSERT.that(ImmutableTable.copyOf(table).row('b').keySet()) 190 .has().exactly(2, 1).inOrder(); 191 } 192 193 public void testCopyOfSparse() { 194 Table<Character, Integer, String> table = TreeBasedTable.create(); 195 table.put('x', 2, "foo"); 196 table.put('r', 1, "bar"); 197 table.put('c', 3, "baz"); 198 table.put('b', 7, "cat"); 199 table.put('e', 5, "dog"); 200 table.put('c', 0, "axe"); 201 table.put('e', 3, "tub"); 202 table.put('r', 4, "foo"); 203 table.put('x', 5, "bar"); 204 validateTableCopies(table); 205 } 206 207 public void testCopyOfDense() { 208 Table<Character, Integer, String> table = TreeBasedTable.create(); 209 table.put('c', 3, "foo"); 210 table.put('c', 2, "bar"); 211 table.put('c', 1, "baz"); 212 table.put('b', 3, "cat"); 213 table.put('b', 1, "dog"); 214 table.put('a', 3, "foo"); 215 table.put('a', 2, "bar"); 216 table.put('a', 1, "baz"); 217 validateTableCopies(table); 218 } 219 220 public void testBuilder_orderRowsAndColumnsBy_putAll() { 221 Table<Character, Integer, String> table = HashBasedTable.create(); 222 table.put('b', 2, "foo"); 223 table.put('b', 1, "bar"); 224 table.put('a', 2, "baz"); 225 ImmutableTable.Builder<Character, Integer, String> builder 226 = ImmutableTable.builder(); 227 Table<Character, Integer, String> copy 228 = builder.orderRowsBy(Ordering.natural()) 229 .orderColumnsBy(Ordering.natural()) 230 .putAll(table).build(); 231 ASSERT.that(copy.rowKeySet()).has().exactly('a', 'b').inOrder(); 232 ASSERT.that(copy.columnKeySet()).has().exactly(1, 2).inOrder(); 233 ASSERT.that(copy.values()).has().exactly("baz", "bar", "foo").inOrder(); 234 ASSERT.that(copy.row('b').keySet()).has().exactly(1, 2).inOrder(); 235 } 236 237 public void testBuilder_orderRowsAndColumnsBy_sparse() { 238 ImmutableTable.Builder<Character, Integer, String> builder 239 = ImmutableTable.builder(); 240 builder.orderRowsBy(Ordering.natural()); 241 builder.orderColumnsBy(Ordering.natural()); 242 builder.put('x', 2, "foo"); 243 builder.put('r', 1, "bar"); 244 builder.put('c', 3, "baz"); 245 builder.put('b', 7, "cat"); 246 builder.put('e', 5, "dog"); 247 builder.put('c', 0, "axe"); 248 builder.put('e', 3, "tub"); 249 builder.put('r', 4, "foo"); 250 builder.put('x', 5, "bar"); 251 Table<Character, Integer, String> table = builder.build(); 252 ASSERT.that(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder(); 253 ASSERT.that(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder(); 254 ASSERT.that(table.values()).has().exactly("cat", "axe", "baz", "tub", 255 "dog", "bar", "foo", "foo", "bar").inOrder(); 256 ASSERT.that(table.row('c').keySet()).has().exactly(0, 3).inOrder(); 257 ASSERT.that(table.column(5).keySet()).has().exactly('e', 'x').inOrder(); 258 } 259 260 public void testBuilder_orderRowsAndColumnsBy_dense() { 261 ImmutableTable.Builder<Character, Integer, String> builder 262 = ImmutableTable.builder(); 263 builder.orderRowsBy(Ordering.natural()); 264 builder.orderColumnsBy(Ordering.natural()); 265 builder.put('c', 3, "foo"); 266 builder.put('c', 2, "bar"); 267 builder.put('c', 1, "baz"); 268 builder.put('b', 3, "cat"); 269 builder.put('b', 1, "dog"); 270 builder.put('a', 3, "foo"); 271 builder.put('a', 2, "bar"); 272 builder.put('a', 1, "baz"); 273 Table<Character, Integer, String> table = builder.build(); 274 ASSERT.that(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder(); 275 ASSERT.that(table.columnKeySet()).has().exactly(1, 2, 3).inOrder(); 276 ASSERT.that(table.values()).has().exactly("baz", "bar", "foo", "dog", 277 "cat", "baz", "bar", "foo").inOrder(); 278 ASSERT.that(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder(); 279 ASSERT.that(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder(); 280 } 281 282 public void testBuilder_orderRowsBy_sparse() { 283 ImmutableTable.Builder<Character, Integer, String> builder 284 = ImmutableTable.builder(); 285 builder.orderRowsBy(Ordering.natural()); 286 builder.put('x', 2, "foo"); 287 builder.put('r', 1, "bar"); 288 builder.put('c', 3, "baz"); 289 builder.put('b', 7, "cat"); 290 builder.put('e', 5, "dog"); 291 builder.put('c', 0, "axe"); 292 builder.put('e', 3, "tub"); 293 builder.put('r', 4, "foo"); 294 builder.put('x', 5, "bar"); 295 Table<Character, Integer, String> table = builder.build(); 296 ASSERT.that(table.rowKeySet()).has().exactly('b', 'c', 'e', 'r', 'x').inOrder(); 297 ASSERT.that(table.column(5).keySet()).has().exactly('e', 'x').inOrder(); 298 } 299 300 public void testBuilder_orderRowsBy_dense() { 301 ImmutableTable.Builder<Character, Integer, String> builder 302 = ImmutableTable.builder(); 303 builder.orderRowsBy(Ordering.natural()); 304 builder.put('c', 3, "foo"); 305 builder.put('c', 2, "bar"); 306 builder.put('c', 1, "baz"); 307 builder.put('b', 3, "cat"); 308 builder.put('b', 1, "dog"); 309 builder.put('a', 3, "foo"); 310 builder.put('a', 2, "bar"); 311 builder.put('a', 1, "baz"); 312 Table<Character, Integer, String> table = builder.build(); 313 ASSERT.that(table.rowKeySet()).has().exactly('a', 'b', 'c').inOrder(); 314 ASSERT.that(table.column(1).keySet()).has().exactly('a', 'b', 'c').inOrder(); 315 } 316 317 public void testBuilder_orderColumnsBy_sparse() { 318 ImmutableTable.Builder<Character, Integer, String> builder 319 = ImmutableTable.builder(); 320 builder.orderColumnsBy(Ordering.natural()); 321 builder.put('x', 2, "foo"); 322 builder.put('r', 1, "bar"); 323 builder.put('c', 3, "baz"); 324 builder.put('b', 7, "cat"); 325 builder.put('e', 5, "dog"); 326 builder.put('c', 0, "axe"); 327 builder.put('e', 3, "tub"); 328 builder.put('r', 4, "foo"); 329 builder.put('x', 5, "bar"); 330 Table<Character, Integer, String> table = builder.build(); 331 ASSERT.that(table.columnKeySet()).has().exactly(0, 1, 2, 3, 4, 5, 7).inOrder(); 332 ASSERT.that(table.row('c').keySet()).has().exactly(0, 3).inOrder(); 333 } 334 335 public void testBuilder_orderColumnsBy_dense() { 336 ImmutableTable.Builder<Character, Integer, String> builder 337 = ImmutableTable.builder(); 338 builder.orderColumnsBy(Ordering.natural()); 339 builder.put('c', 3, "foo"); 340 builder.put('c', 2, "bar"); 341 builder.put('c', 1, "baz"); 342 builder.put('b', 3, "cat"); 343 builder.put('b', 1, "dog"); 344 builder.put('a', 3, "foo"); 345 builder.put('a', 2, "bar"); 346 builder.put('a', 1, "baz"); 347 Table<Character, Integer, String> table = builder.build(); 348 ASSERT.that(table.columnKeySet()).has().exactly(1, 2, 3).inOrder(); 349 ASSERT.that(table.row('c').keySet()).has().exactly(1, 2, 3).inOrder(); 350 } 351 352 @GwtIncompatible("Mind-bogglingly slow in GWT") 353 public void testOverflowCondition() { 354 // See https://code.google.com/p/guava-libraries/issues/detail?id=1322 for details. 355 ImmutableTable.Builder<Integer, Integer, String> builder = ImmutableTable.builder(); 356 for (int i = 1; i < 0x10000; i++) { 357 builder.put(i, 0, "foo"); 358 builder.put(0, i, "bar"); 359 } 360 assertTrue(builder.build() instanceof SparseImmutableTable); 361 } 362} 363