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