• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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