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