View Javadoc
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  import static java.util.Arrays.asList;
21  
22  import com.google.common.annotations.GwtCompatible;
23  import com.google.common.annotations.GwtIncompatible;
24  import com.google.common.base.Objects;
25  import com.google.common.collect.Table.Cell;
26  import com.google.common.testing.EqualsTester;
27  import com.google.common.testing.NullPointerTester;
28  import com.google.common.testing.SerializableTester;
29  
30  import java.util.Arrays;
31  import java.util.Map;
32  
33  /**
34   * Test cases for {@link ArrayTable}.
35   *
36   * @author Jared Levy
37   */
38  @GwtCompatible(emulated = true)
39  public class ArrayTableTest extends AbstractTableTest {
40  
41    @Override protected ArrayTable<String, Integer, Character> create(
42        Object... data) {
43      // TODO: Specify different numbers of rows and columns, to detect problems
44      // that arise when the wrong size is used.
45      ArrayTable<String, Integer, Character> table =
46          ArrayTable.create(asList("foo", "bar", "cat"), asList(1, 2, 3));
47      populate(table, data);
48      return table;
49    }
50  
51    @Override protected void assertSize(int expectedSize) {
52      assertEquals(9, table.size());
53    }
54  
55    @Override protected boolean supportsRemove() {
56      return false;
57    }
58  
59    @Override protected boolean supportsNullValues() {
60      return true;
61    }
62  
63    // Overriding tests of behavior that differs for ArrayTable.
64  
65    @Override public void testContains() {
66      table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
67      assertTrue(table.contains("foo", 1));
68      assertTrue(table.contains("bar", 1));
69      assertTrue(table.contains("foo", 3));
70      assertTrue(table.contains("foo", 2));
71      assertTrue(table.contains("bar", 3));
72      assertTrue(table.contains("cat", 1));
73      assertFalse(table.contains("foo", -1));
74      assertFalse(table.contains("bad", 1));
75      assertFalse(table.contains("bad", -1));
76      assertFalse(table.contains("foo", null));
77      assertFalse(table.contains(null, 1));
78      assertFalse(table.contains(null, null));
79    }
80  
81    @Override public void testContainsRow() {
82      table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
83      assertTrue(table.containsRow("foo"));
84      assertTrue(table.containsRow("bar"));
85      assertTrue(table.containsRow("cat"));
86      assertFalse(table.containsRow("bad"));
87      assertFalse(table.containsRow(null));
88    }
89  
90    @Override public void testContainsColumn() {
91      table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
92      assertTrue(table.containsColumn(1));
93      assertTrue(table.containsColumn(3));
94      assertTrue(table.containsColumn(2));
95      assertFalse(table.containsColumn(-1));
96      assertFalse(table.containsColumn(null));
97    }
98  
99    @Override public void testContainsValue() {
100     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
101     assertTrue(table.containsValue('a'));
102     assertTrue(table.containsValue('b'));
103     assertTrue(table.containsValue('c'));
104     assertFalse(table.containsValue('x'));
105     assertTrue(table.containsValue(null));
106   }
107 
108   @Override public void testIsEmpty() {
109     assertFalse(table.isEmpty());
110     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
111     assertFalse(table.isEmpty());
112   }
113 
114   @Override public void testEquals() {
115     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
116     Table<String, Integer, Character> hashCopy = HashBasedTable.create();
117     hashCopy.put("foo", 1, 'a');
118     hashCopy.put("bar", 1, 'b');
119     hashCopy.put("foo", 3, 'c');
120     Table<String, Integer, Character> reordered
121         = create("foo", 3, 'c', "foo", 1, 'a', "bar", 1, 'b');
122     Table<String, Integer, Character> smaller
123         = create("foo", 1, 'a', "bar", 1, 'b');
124     Table<String, Integer, Character> swapOuter
125         = create("bar", 1, 'a', "foo", 1, 'b', "bar", 3, 'c');
126     Table<String, Integer, Character> swapValues
127         = create("foo", 1, 'c', "bar", 1, 'b', "foo", 3, 'a');
128 
129     new EqualsTester()
130         .addEqualityGroup(table, reordered)
131         .addEqualityGroup(hashCopy)
132         .addEqualityGroup(smaller)
133         .addEqualityGroup(swapOuter)
134         .addEqualityGroup(swapValues)
135         .testEquals();
136   }
137 
138   @Override public void testHashCode() {
139     table = ArrayTable.create(asList("foo", "bar"), asList(1, 3));
140     table.put("foo", 1, 'a');
141     table.put("bar", 1, 'b');
142     table.put("foo", 3, 'c');
143     int expected = Objects.hashCode("foo", 1, 'a')
144         + Objects.hashCode("bar", 1, 'b')
145         + Objects.hashCode("foo", 3, 'c')
146         + Objects.hashCode("bar", 3, 0);
147     assertEquals(expected, table.hashCode());
148   }
149 
150   @Override public void testRow() {
151     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
152     Map<Integer, Character> expected = Maps.newHashMap();
153     expected.put(1, 'a');
154     expected.put(3, 'c');
155     expected.put(2, null);
156     assertEquals(expected, table.row("foo"));
157   }
158 
159   @Override public void testColumn() {
160     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
161     Map<String, Character> expected = Maps.newHashMap();
162     expected.put("foo", 'a');
163     expected.put("bar", 'b');
164     expected.put("cat", null);
165     assertEquals(expected, table.column(1));
166   }
167 
168   @Override public void testToStringSize1() {
169     table = ArrayTable.create(ImmutableList.of("foo"), ImmutableList.of(1));
170     table.put("foo", 1, 'a');
171     assertEquals("{foo={1=a}}", table.toString());
172   }
173 
174   public void testCreateDuplicateRows() {
175     try {
176       ArrayTable.create(asList("foo", "bar", "foo"), asList(1, 2, 3));
177       fail();
178     } catch (IllegalArgumentException expected) {}
179   }
180 
181   public void testCreateDuplicateColumns() {
182     try {
183       ArrayTable.create(asList("foo", "bar"), asList(1, 2, 3, 2));
184       fail();
185     } catch (IllegalArgumentException expected) {}
186   }
187 
188   public void testCreateEmptyRows() {
189     try {
190       ArrayTable.create(Arrays.<String>asList(), asList(1, 2, 3));
191       fail();
192     } catch (IllegalArgumentException expected) {}
193   }
194 
195   public void testCreateEmptyColumns() {
196     try {
197       ArrayTable.create(asList("foo", "bar"), Arrays.<Integer>asList());
198       fail();
199     } catch (IllegalArgumentException expected) {}
200   }
201 
202   public void testCreateCopyArrayTable() {
203     Table<String, Integer, Character> original
204         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
205     Table<String, Integer, Character> copy = ArrayTable.create(original);
206     assertEquals(original, copy);
207     original.put("foo", 1, 'd');
208     assertEquals((Character) 'd', original.get("foo", 1));
209     assertEquals((Character) 'a', copy.get("foo", 1));
210     assertEquals(copy.rowKeySet(), original.rowKeySet());
211     assertEquals(copy.columnKeySet(), original.columnKeySet());
212   }
213 
214   public void testCreateCopyHashBasedTable() {
215     Table<String, Integer, Character> original = HashBasedTable.create();
216     original.put("foo", 1, 'a');
217     original.put("bar", 1, 'b');
218     original.put("foo", 3, 'c');
219     Table<String, Integer, Character> copy = ArrayTable.create(original);
220     assertEquals(4, copy.size());
221     assertEquals((Character) 'a', copy.get("foo", 1));
222     assertEquals((Character) 'b', copy.get("bar", 1));
223     assertEquals((Character) 'c', copy.get("foo", 3));
224     assertNull(copy.get("bar", 3));
225     original.put("foo", 1, 'd');
226     assertEquals((Character) 'd', original.get("foo", 1));
227     assertEquals((Character) 'a', copy.get("foo", 1));
228     assertEquals(copy.rowKeySet(), ImmutableSet.of("foo", "bar"));
229     assertEquals(copy.columnKeySet(), ImmutableSet.of(1, 3));
230   }
231 
232   public void testCreateCopyEmptyTable() {
233     Table<String, Integer, Character> original = HashBasedTable.create();
234     try {
235       ArrayTable.create(original);
236       fail();
237     } catch (IllegalArgumentException expected) {}
238   }
239 
240   public void testSerialization() {
241     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
242     SerializableTester.reserializeAndAssert(table);
243   }
244 
245   @GwtIncompatible("reflection")
246   public void testNullPointerStatic() {
247     new NullPointerTester().testAllPublicStaticMethods(ArrayTable.class);
248   }
249 
250   public void testToString_ordered() {
251     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
252     assertEquals("{foo={1=a, 2=null, 3=c}, " +
253         "bar={1=b, 2=null, 3=null}, " +
254         "cat={1=null, 2=null, 3=null}}",
255         table.toString());
256     assertEquals("{foo={1=a, 2=null, 3=c}, " +
257         "bar={1=b, 2=null, 3=null}, " +
258         "cat={1=null, 2=null, 3=null}}",
259         table.rowMap().toString());
260   }
261 
262   public void testCellSetToString_ordered() {
263     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
264     assertEquals("[(foo,1)=a, (foo,2)=null, (foo,3)=c, " +
265         "(bar,1)=b, (bar,2)=null, (bar,3)=null, " +
266         "(cat,1)=null, (cat,2)=null, (cat,3)=null]",
267         table.cellSet().toString());
268   }
269 
270   public void testRowKeySetToString_ordered() {
271     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
272     assertEquals("[foo, bar, cat]", table.rowKeySet().toString());
273   }
274 
275   public void testColumnKeySetToString_ordered() {
276     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
277     assertEquals("[1, 2, 3]", table.columnKeySet().toString());
278   }
279 
280   public void testValuesToString_ordered() {
281     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
282     assertEquals("[a, null, c, b, null, null, null, null, null]",
283         table.values().toString());
284   }
285 
286   public void testRowKeyList() {
287     ArrayTable<String, Integer, Character> table
288         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
289     assertThat(table.rowKeyList()).has().exactly("foo", "bar", "cat").inOrder();
290   }
291 
292   public void testColumnKeyList() {
293     ArrayTable<String, Integer, Character> table
294         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
295     assertThat(table.columnKeyList()).has().exactly(1, 2, 3).inOrder();
296   }
297 
298   public void testGetMissingKeys() {
299     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
300     assertNull(table.get("dog", 1));
301     assertNull(table.get("foo", 4));
302   }
303 
304   public void testAt() {
305     ArrayTable<String, Integer, Character> table
306         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
307     assertEquals((Character) 'b', table.at(1, 0));
308     assertEquals((Character) 'c', table.at(0, 2));
309     assertNull(table.at(1, 2));
310     try {
311       table.at(1, 3);
312       fail();
313     } catch (IndexOutOfBoundsException expected) {}
314     try {
315       table.at(1, -1);
316       fail();
317     } catch (IndexOutOfBoundsException expected) {}
318     try {
319       table.at(3, 2);
320       fail();
321     } catch (IndexOutOfBoundsException expected) {}
322     try {
323       table.at(-1, 2);
324       fail();
325     } catch (IndexOutOfBoundsException expected) {}
326   }
327 
328   public void testSet() {
329     ArrayTable<String, Integer, Character> table
330         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
331     assertEquals((Character) 'b', table.set(1, 0, 'd'));
332     assertEquals((Character) 'd', table.get("bar", 1));
333     assertNull(table.set(2, 0, 'e'));
334     assertEquals((Character) 'e', table.get("cat", 1));
335     assertEquals((Character) 'a', table.set(0, 0, null));
336     assertNull(table.get("foo", 1));
337     try {
338       table.set(1, 3, 'z');
339       fail();
340     } catch (IndexOutOfBoundsException expected) {}
341     try {
342       table.set(1, -1, 'z');
343       fail();
344     } catch (IndexOutOfBoundsException expected) {}
345     try {
346       table.set(3, 2, 'z');
347       fail();
348     } catch (IndexOutOfBoundsException expected) {}
349     try {
350       table.set(-1, 2, 'z');
351       fail();
352     } catch (IndexOutOfBoundsException expected) {}
353     assertFalse(table.containsValue('z'));
354   }
355 
356   public void testEraseAll() {
357     ArrayTable<String, Integer, Character> table
358         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
359     table.eraseAll();
360     assertEquals(9, table.size());
361     assertNull(table.get("bar", 1));
362     assertTrue(table.containsRow("foo"));
363     assertFalse(table.containsValue('a'));
364   }
365 
366   public void testPutIllegal() {
367     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
368     try {
369       table.put("dog", 1, 'd');
370       fail();
371     } catch (IllegalArgumentException expected) {
372       assertEquals("Row dog not in [foo, bar, cat]", expected.getMessage());
373     }
374     try {
375       table.put("foo", 4, 'd');
376       fail();
377     } catch (IllegalArgumentException expected) {
378       assertEquals("Column 4 not in [1, 2, 3]", expected.getMessage());
379     }
380     assertFalse(table.containsValue('d'));
381   }
382 
383   public void testErase() {
384     ArrayTable<String, Integer, Character> table
385         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
386     assertEquals((Character) 'b', table.erase("bar", 1));
387     assertNull(table.get("bar", 1));
388     assertEquals(9, table.size());
389     assertNull(table.erase("bar", 1));
390     assertNull(table.erase("foo", 2));
391     assertNull(table.erase("dog", 1));
392     assertNull(table.erase("bar", 5));
393     assertNull(table.erase(null, 1));
394     assertNull(table.erase("bar", null));
395   }
396 
397   @GwtIncompatible("ArrayTable.toArray(Class)")
398   public void testToArray() {
399     ArrayTable<String, Integer, Character> table
400         = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
401     Character[][] array = table.toArray(Character.class);
402     assertEquals(3, array.length);
403     assertThat(array[0]).asList().has().exactly('a', null, 'c').inOrder();
404     assertThat(array[1]).asList().has().exactly('b', null, null).inOrder();
405     assertThat(array[2]).asList().has().exactly(null, null, null).inOrder();
406     table.set(0, 2, 'd');
407     assertEquals((Character) 'c', array[0][2]);
408     array[0][2] = 'e';
409     assertEquals((Character) 'd', table.at(0, 2));
410   }
411 
412   public void testCellReflectsChanges() {
413     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
414     Cell<String, Integer, Character> cell = table.cellSet().iterator().next();
415     assertEquals(Tables.immutableCell("foo", 1, 'a'), cell);
416     assertEquals((Character) 'a', table.put("foo", 1, 'd'));
417     assertEquals(Tables.immutableCell("foo", 1, 'd'), cell);
418   }
419 
420   public void testRowMissing() {
421     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
422     Map<Integer, Character> row = table.row("dog");
423     assertTrue(row.isEmpty());
424     try {
425       row.put(1, 'd');
426       fail();
427     } catch (UnsupportedOperationException expected) {}
428   }
429 
430   public void testColumnMissing() {
431     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
432     Map<String, Character> column = table.column(4);
433     assertTrue(column.isEmpty());
434     try {
435       column.put("foo", 'd');
436       fail();
437     } catch (UnsupportedOperationException expected) {}
438   }
439 
440   public void testRowPutIllegal() {
441     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
442     Map<Integer, Character> map = table.row("foo");
443     try {
444       map.put(4, 'd');
445       fail();
446     } catch (IllegalArgumentException expected) {
447       assertEquals("Column 4 not in [1, 2, 3]", expected.getMessage());
448     }
449   }
450 
451   public void testColumnPutIllegal() {
452     table = create("foo", 1, 'a', "bar", 1, 'b', "foo", 3, 'c');
453     Map<String, Character> map = table.column(3);
454     try {
455       map.put("dog", 'd');
456       fail();
457     } catch (IllegalArgumentException expected) {
458       assertEquals("Row dog not in [foo, bar, cat]", expected.getMessage());
459     }
460   }
461 
462   @GwtIncompatible("reflection")
463   public void testNulls() {
464     new NullPointerTester().testAllPublicInstanceMethods(create());
465   }
466 
467   @GwtIncompatible("serialize")
468   public void testSerializable() {
469     SerializableTester.reserializeAndAssert(create());
470   }
471 }