• 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.collect.Tables.immutableCell;
20 
21 import com.google.common.annotations.GwtCompatible;
22 import com.google.common.annotations.J2ktIncompatible;
23 import com.google.common.base.Equivalence;
24 import com.google.common.base.Function;
25 import com.google.common.base.MoreObjects;
26 import com.google.common.collect.Table.Cell;
27 import com.google.common.testing.CollectorTester;
28 import java.util.function.BiPredicate;
29 import java.util.function.BinaryOperator;
30 import java.util.stream.Collector;
31 import java.util.stream.Stream;
32 import junit.framework.TestCase;
33 import org.checkerframework.checker.nullness.qual.Nullable;
34 
35 /** Unit tests for {@link TableCollectors}. */
36 @GwtCompatible(emulated = true)
37 @ElementTypesAreNonnullByDefault
38 public class TableCollectorsTest extends TestCase {
testToImmutableTable()39   public void testToImmutableTable() {
40     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
41         TableCollectors.toImmutableTable(Cell::getRowKey, Cell::getColumnKey, Cell::getValue);
42     BiPredicate<ImmutableTable<String, String, Integer>, ImmutableTable<String, String, Integer>>
43         equivalence = pairwiseOnResultOf(ImmutableTable::cellSet);
44     CollectorTester.of(collector, equivalence)
45         .expectCollects(
46             new ImmutableTable.Builder<String, String, Integer>()
47                 .put("one", "uno", 1)
48                 .put("two", "dos", 2)
49                 .put("three", "tres", 3)
50                 .build(),
51             immutableCell("one", "uno", 1),
52             immutableCell("two", "dos", 2),
53             immutableCell("three", "tres", 3));
54   }
55 
testToImmutableTableConflict()56   public void testToImmutableTableConflict() {
57     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
58         TableCollectors.toImmutableTable(Cell::getRowKey, Cell::getColumnKey, Cell::getValue);
59     try {
60       Stream.of(immutableCell("one", "uno", 1), immutableCell("one", "uno", 2)).collect(collector);
61       fail("Expected IllegalArgumentException");
62     } catch (IllegalArgumentException expected) {
63     }
64   }
65 
testToImmutableTableNullRowKey()66   public void testToImmutableTableNullRowKey() {
67     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
68         TableCollectors.toImmutableTable(t -> null, Cell::getColumnKey, Cell::getValue);
69     try {
70       Stream.of(immutableCell("one", "uno", 1)).collect(collector);
71       fail("Expected NullPointerException");
72     } catch (NullPointerException expected) {
73     }
74   }
75 
testToImmutableTableNullColumnKey()76   public void testToImmutableTableNullColumnKey() {
77     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
78         TableCollectors.toImmutableTable(Cell::getRowKey, t -> null, Cell::getValue);
79     try {
80       Stream.of(immutableCell("one", "uno", 1)).collect(collector);
81       fail("Expected NullPointerException");
82     } catch (NullPointerException expected) {
83     }
84   }
85 
testToImmutableTableNullValue()86   public void testToImmutableTableNullValue() {
87     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
88         TableCollectors.toImmutableTable(Cell::getRowKey, Cell::getColumnKey, t -> null);
89     try {
90       Stream.of(immutableCell("one", "uno", 1)).collect(collector);
91       fail("Expected NullPointerException");
92     } catch (NullPointerException expected) {
93     }
94     collector =
95         TableCollectors.toImmutableTable(Cell::getRowKey, Cell::getColumnKey, Cell::getValue);
96     try {
97       Stream.of(immutableCell("one", "uno", 1), immutableCell("one", "uno", (Integer) null))
98           .collect(collector);
99       fail("Expected NullPointerException");
100     } catch (NullPointerException expected) {
101     }
102   }
103 
testToImmutableTableMerging()104   public void testToImmutableTableMerging() {
105     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
106         TableCollectors.toImmutableTable(
107             Cell::getRowKey, Cell::getColumnKey, Cell::getValue, Integer::sum);
108     BiPredicate<ImmutableTable<String, String, Integer>, ImmutableTable<String, String, Integer>>
109         equivalence = pairwiseOnResultOf(ImmutableTable::cellSet);
110     CollectorTester.of(collector, equivalence)
111         .expectCollects(
112             new ImmutableTable.Builder<String, String, Integer>()
113                 .put("one", "uno", 1)
114                 .put("two", "dos", 6)
115                 .put("three", "tres", 3)
116                 .build(),
117             immutableCell("one", "uno", 1),
118             immutableCell("two", "dos", 2),
119             immutableCell("three", "tres", 3),
120             immutableCell("two", "dos", 4));
121   }
122 
testToImmutableTableMergingNullRowKey()123   public void testToImmutableTableMergingNullRowKey() {
124     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
125         TableCollectors.toImmutableTable(
126             t -> null, Cell::getColumnKey, Cell::getValue, Integer::sum);
127     try {
128       Stream.of(immutableCell("one", "uno", 1)).collect(collector);
129       fail("Expected NullPointerException");
130     } catch (NullPointerException expected) {
131     }
132   }
133 
testToImmutableTableMergingNullColumnKey()134   public void testToImmutableTableMergingNullColumnKey() {
135     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
136         TableCollectors.toImmutableTable(Cell::getRowKey, t -> null, Cell::getValue, Integer::sum);
137     try {
138       Stream.of(immutableCell("one", "uno", 1)).collect(collector);
139       fail("Expected NullPointerException");
140     } catch (NullPointerException expected) {
141     }
142   }
143 
testToImmutableTableMergingNullValue()144   public void testToImmutableTableMergingNullValue() {
145     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
146         TableCollectors.toImmutableTable(
147             Cell::getRowKey, Cell::getColumnKey, t -> null, Integer::sum);
148     try {
149       Stream.of(immutableCell("one", "uno", 1)).collect(collector);
150       fail("Expected NullPointerException");
151     } catch (NullPointerException expected) {
152     }
153     collector =
154         TableCollectors.toImmutableTable(
155             Cell::getRowKey,
156             Cell::getColumnKey,
157             Cell::getValue,
158             (i, j) -> MoreObjects.firstNonNull(i, 0) + MoreObjects.firstNonNull(j, 0));
159     try {
160       Stream.of(immutableCell("one", "uno", 1), immutableCell("one", "uno", (Integer) null))
161           .collect(collector);
162       fail("Expected NullPointerException");
163     } catch (NullPointerException expected) {
164     }
165   }
166 
testToImmutableTableMergingNullMerge()167   public void testToImmutableTableMergingNullMerge() {
168     Collector<Cell<String, String, Integer>, ?, ImmutableTable<String, String, Integer>> collector =
169         TableCollectors.toImmutableTable(
170             Cell::getRowKey, Cell::getColumnKey, Cell::getValue, (v1, v2) -> null);
171     try {
172       Stream.of(immutableCell("one", "uno", 1), immutableCell("one", "uno", 2)).collect(collector);
173       fail("Expected NullPointerException");
174     } catch (NullPointerException expected) {
175     }
176   }
177 
testToTable()178   public void testToTable() {
179     Collector<Cell<String, String, Integer>, ?, Table<String, String, Integer>> collector =
180         TableCollectors.toTable(
181             Cell::getRowKey, Cell::getColumnKey, Cell::getValue, HashBasedTable::create);
182     BiPredicate<Table<String, String, Integer>, Table<String, String, Integer>> equivalence =
183         pairwiseOnResultOf(Table::cellSet);
184     CollectorTester.of(collector, equivalence)
185         .expectCollects(
186             new ImmutableTable.Builder<String, String, Integer>()
187                 .put("one", "uno", 1)
188                 .put("two", "dos", 2)
189                 .put("three", "tres", 3)
190                 .build(),
191             immutableCell("one", "uno", 1),
192             immutableCell("two", "dos", 2),
193             immutableCell("three", "tres", 3));
194   }
195 
testToTableNullMerge()196   public void testToTableNullMerge() {
197     // TODO github.com/google/guava/issues/6824 - the null merge feature is not compatible with the
198     // current nullness annotation of the mergeFunction parameter. Work around with casts.
199     BinaryOperator<@Nullable Integer> mergeFunction = (v1, v2) -> null;
200     Collector<Cell<String, String, Integer>, ?, Table<String, String, Integer>> collector =
201         TableCollectors.toTable(
202             Cell::getRowKey,
203             Cell::getColumnKey,
204             Cell::getValue,
205             (BinaryOperator<Integer>) mergeFunction,
206             HashBasedTable::create);
207     BiPredicate<Table<String, String, Integer>, Table<String, String, Integer>> equivalence =
208         pairwiseOnResultOf(Table::cellSet);
209     CollectorTester.of(collector, equivalence)
210         .expectCollects(
211             ImmutableTable.of(), immutableCell("one", "uno", 1), immutableCell("one", "uno", 2));
212   }
213 
214   // https://youtrack.jetbrains.com/issue/KT-58242/. Crash when getValue result (null) is unboxed
215   @J2ktIncompatible
testToTableNullValues()216   public void testToTableNullValues() {
217     Collector<Cell<String, String, Integer>, ?, Table<String, String, Integer>> collector =
218         TableCollectors.toTable(
219             Cell::getRowKey,
220             Cell::getColumnKey,
221             Cell::getValue,
222             () -> {
223               Table<String, String, @Nullable Integer> table =
224                   ArrayTable.create(ImmutableList.of("one"), ImmutableList.of("uno"));
225               return (Table<String, String, Integer>) table;
226             });
227     try {
228       Cell<String, String, @Nullable Integer> cell = immutableCell("one", "uno", null);
229       Stream.of((Cell<String, String, Integer>) cell).collect(collector);
230       fail("Expected NullPointerException");
231     } catch (NullPointerException expected) {
232     }
233   }
234 
testToTableConflict()235   public void testToTableConflict() {
236     Collector<Cell<String, String, Integer>, ?, Table<String, String, Integer>> collector =
237         TableCollectors.toTable(
238             Cell::getRowKey, Cell::getColumnKey, Cell::getValue, HashBasedTable::create);
239     try {
240       Stream.of(immutableCell("one", "uno", 1), immutableCell("one", "uno", 2)).collect(collector);
241       fail("Expected IllegalStateException");
242     } catch (IllegalStateException expected) {
243     }
244   }
245 
testToTableMerging()246   public void testToTableMerging() {
247     Collector<Cell<String, String, Integer>, ?, Table<String, String, Integer>> collector =
248         TableCollectors.toTable(
249             Cell::getRowKey,
250             Cell::getColumnKey,
251             Cell::getValue,
252             Integer::sum,
253             HashBasedTable::create);
254     BiPredicate<Table<String, String, Integer>, Table<String, String, Integer>> equivalence =
255         pairwiseOnResultOf(Table::cellSet);
256     CollectorTester.of(collector, equivalence)
257         .expectCollects(
258             new ImmutableTable.Builder<String, String, Integer>()
259                 .put("one", "uno", 1)
260                 .put("two", "dos", 6)
261                 .put("three", "tres", 3)
262                 .build(),
263             immutableCell("one", "uno", 1),
264             immutableCell("two", "dos", 2),
265             immutableCell("three", "tres", 3),
266             immutableCell("two", "dos", 4));
267   }
268 
269   // This function specifically returns a BiPredicate, because Guava7’s Equivalence class does not
270   // actually implement BiPredicate, and CollectorTests expects a BiPredicate.
271   static <C, E extends @Nullable Object, R extends Iterable<E>>
pairwiseOnResultOf(Function<C, R> arg)272       BiPredicate<C, C> pairwiseOnResultOf(Function<C, R> arg) {
273     Equivalence<C> equivalence = Equivalence.equals().<E>pairwise().onResultOf(arg);
274     return equivalence::equivalent;
275   }
276 }
277