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