1 /* 2 * Copyright (C) 2005 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.base; 18 19 import static com.google.common.base.ReflectionFreeAssertThrows.assertThrows; 20 21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.annotations.GwtIncompatible; 23 import com.google.common.annotations.J2ktIncompatible; 24 import com.google.common.collect.ImmutableMap; 25 import com.google.common.collect.Maps; 26 import com.google.common.testing.ClassSanityTester; 27 import com.google.common.testing.EqualsTester; 28 import com.google.common.testing.NullPointerTester; 29 import com.google.common.testing.SerializableTester; 30 import java.io.Serializable; 31 import java.util.Map; 32 import junit.framework.TestCase; 33 import org.checkerframework.checker.nullness.qual.Nullable; 34 35 /** 36 * Tests for {@link Functions}. 37 * 38 * @author Mike Bostock 39 * @author Vlad Patryshev 40 */ 41 @GwtCompatible(emulated = true) 42 @ElementTypesAreNonnullByDefault 43 public class FunctionsTest extends TestCase { 44 testIdentity_same()45 public void testIdentity_same() { 46 Function<@Nullable String, @Nullable String> identity = Functions.identity(); 47 assertNull(identity.apply(null)); 48 assertSame("foo", identity.apply("foo")); 49 } 50 testIdentity_notSame()51 public void testIdentity_notSame() { 52 Function<Long, Long> identity = Functions.identity(); 53 assertNotSame(new Long(135135L), identity.apply(new Long(135135L))); 54 } 55 56 @J2ktIncompatible 57 @GwtIncompatible // SerializableTester testIdentitySerializable()58 public void testIdentitySerializable() { 59 checkCanReserializeSingleton(Functions.identity()); 60 } 61 testToStringFunction_apply()62 public void testToStringFunction_apply() { 63 assertEquals("3", Functions.toStringFunction().apply(3)); 64 assertEquals("hiya", Functions.toStringFunction().apply("hiya")); 65 assertEquals( 66 "I'm a string", 67 Functions.toStringFunction() 68 .apply( 69 new Object() { 70 @Override 71 public String toString() { 72 return "I'm a string"; 73 } 74 })); 75 assertThrows(NullPointerException.class, () -> Functions.toStringFunction().apply(null)); 76 } 77 78 @J2ktIncompatible 79 @GwtIncompatible // SerializableTester testToStringFunctionSerializable()80 public void testToStringFunctionSerializable() { 81 checkCanReserializeSingleton(Functions.toStringFunction()); 82 } 83 84 @J2ktIncompatible 85 @GwtIncompatible // NullPointerTester testNullPointerExceptions()86 public void testNullPointerExceptions() { 87 NullPointerTester tester = new NullPointerTester(); 88 tester.testAllPublicStaticMethods(Functions.class); 89 } 90 testForMapWithoutDefault()91 public void testForMapWithoutDefault() { 92 Map<String, @Nullable Integer> map = Maps.newHashMap(); 93 map.put("One", 1); 94 map.put("Three", 3); 95 map.put("Null", null); 96 Function<String, @Nullable Integer> function = Functions.forMap(map); 97 98 assertEquals(1, function.apply("One").intValue()); 99 assertEquals(3, function.apply("Three").intValue()); 100 assertNull(function.apply("Null")); 101 102 assertThrows(IllegalArgumentException.class, () -> function.apply("Two")); 103 104 new EqualsTester() 105 .addEqualityGroup(function, Functions.forMap(map)) 106 .addEqualityGroup(Functions.forMap(map, 42)) 107 .testEquals(); 108 } 109 110 @J2ktIncompatible 111 @GwtIncompatible // SerializableTester testForMapWithoutDefaultSerializable()112 public void testForMapWithoutDefaultSerializable() { 113 checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2))); 114 } 115 testForMapWithDefault()116 public void testForMapWithDefault() { 117 Map<String, @Nullable Integer> map = Maps.newHashMap(); 118 map.put("One", 1); 119 map.put("Three", 3); 120 map.put("Null", null); 121 Function<String, @Nullable Integer> function = Functions.forMap(map, 42); 122 123 assertEquals(1, function.apply("One").intValue()); 124 assertEquals(42, function.apply("Two").intValue()); 125 assertEquals(3, function.apply("Three").intValue()); 126 assertNull(function.apply("Null")); 127 128 new EqualsTester() 129 .addEqualityGroup(function, Functions.forMap(map, 42)) 130 .addEqualityGroup(Functions.forMap(map)) 131 .addEqualityGroup(Functions.forMap(map, null)) 132 .addEqualityGroup(Functions.forMap(map, 43)) 133 .testEquals(); 134 } 135 136 @J2ktIncompatible 137 @GwtIncompatible // SerializableTester testForMapWithDefault_includeSerializable()138 public void testForMapWithDefault_includeSerializable() { 139 Map<String, Integer> map = Maps.newHashMap(); 140 map.put("One", 1); 141 map.put("Three", 3); 142 Function<String, Integer> function = Functions.forMap(map, 42); 143 144 assertEquals(1, function.apply("One").intValue()); 145 assertEquals(42, function.apply("Two").intValue()); 146 assertEquals(3, function.apply("Three").intValue()); 147 148 new EqualsTester() 149 .addEqualityGroup( 150 function, Functions.forMap(map, 42), SerializableTester.reserialize(function)) 151 .addEqualityGroup(Functions.forMap(map)) 152 .addEqualityGroup(Functions.forMap(map, null)) 153 .addEqualityGroup(Functions.forMap(map, 43)) 154 .testEquals(); 155 } 156 157 @J2ktIncompatible 158 @GwtIncompatible // SerializableTester testForMapWithDefaultSerializable()159 public void testForMapWithDefaultSerializable() { 160 checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2), 3)); 161 } 162 testForMapWithDefault_null()163 public void testForMapWithDefault_null() { 164 ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1); 165 Function<String, @Nullable Integer> function = Functions.forMap(map, null); 166 167 assertEquals((Integer) 1, function.apply("One")); 168 assertNull(function.apply("Two")); 169 170 // check basic sanity of equals and hashCode 171 new EqualsTester() 172 .addEqualityGroup(function) 173 .addEqualityGroup(Functions.forMap(map, 1)) 174 .testEquals(); 175 } 176 177 @J2ktIncompatible 178 @GwtIncompatible // SerializableTester testForMapWithDefault_null_compareWithSerializable()179 public void testForMapWithDefault_null_compareWithSerializable() { 180 ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1); 181 Function<String, Integer> function = Functions.forMap(map, null); 182 183 assertEquals((Integer) 1, function.apply("One")); 184 assertNull(function.apply("Two")); 185 186 // check basic sanity of equals and hashCode 187 new EqualsTester() 188 .addEqualityGroup(function, SerializableTester.reserialize(function)) 189 .addEqualityGroup(Functions.forMap(map, 1)) 190 .testEquals(); 191 } 192 testForMapWildCardWithDefault()193 public void testForMapWildCardWithDefault() { 194 Map<String, Integer> map = Maps.newHashMap(); 195 map.put("One", 1); 196 map.put("Three", 3); 197 Number number = Double.valueOf(42); 198 Function<String, Number> function = Functions.forMap(map, number); 199 200 assertEquals(1, function.apply("One").intValue()); 201 assertEquals(number, function.apply("Two")); 202 assertEquals(3L, function.apply("Three").longValue()); 203 } 204 testComposition()205 public void testComposition() { 206 Map<String, Integer> mJapaneseToInteger = Maps.newHashMap(); 207 mJapaneseToInteger.put("Ichi", 1); 208 mJapaneseToInteger.put("Ni", 2); 209 mJapaneseToInteger.put("San", 3); 210 Function<String, Integer> japaneseToInteger = Functions.forMap(mJapaneseToInteger); 211 212 Map<Integer, String> mIntegerToSpanish = Maps.newHashMap(); 213 mIntegerToSpanish.put(1, "Uno"); 214 mIntegerToSpanish.put(3, "Tres"); 215 mIntegerToSpanish.put(4, "Cuatro"); 216 Function<Integer, String> integerToSpanish = Functions.forMap(mIntegerToSpanish); 217 218 Function<String, String> japaneseToSpanish = 219 Functions.compose(integerToSpanish, japaneseToInteger); 220 221 assertEquals("Uno", japaneseToSpanish.apply("Ichi")); 222 assertThrows(IllegalArgumentException.class, () -> japaneseToSpanish.apply("Ni")); 223 assertEquals("Tres", japaneseToSpanish.apply("San")); 224 assertThrows(IllegalArgumentException.class, () -> japaneseToSpanish.apply("Shi")); 225 226 new EqualsTester() 227 .addEqualityGroup(japaneseToSpanish, Functions.compose(integerToSpanish, japaneseToInteger)) 228 .addEqualityGroup(japaneseToInteger) 229 .addEqualityGroup(integerToSpanish) 230 .addEqualityGroup(Functions.compose(japaneseToInteger, integerToSpanish)) 231 .testEquals(); 232 } 233 234 @J2ktIncompatible 235 @GwtIncompatible // SerializableTester testComposition_includeReserializabled()236 public void testComposition_includeReserializabled() { 237 Map<String, Integer> mJapaneseToInteger = Maps.newHashMap(); 238 mJapaneseToInteger.put("Ichi", 1); 239 mJapaneseToInteger.put("Ni", 2); 240 mJapaneseToInteger.put("San", 3); 241 Function<String, Integer> japaneseToInteger = Functions.forMap(mJapaneseToInteger); 242 243 Map<Integer, String> mIntegerToSpanish = Maps.newHashMap(); 244 mIntegerToSpanish.put(1, "Uno"); 245 mIntegerToSpanish.put(3, "Tres"); 246 mIntegerToSpanish.put(4, "Cuatro"); 247 Function<Integer, String> integerToSpanish = Functions.forMap(mIntegerToSpanish); 248 249 Function<String, String> japaneseToSpanish = 250 Functions.compose(integerToSpanish, japaneseToInteger); 251 252 new EqualsTester() 253 .addEqualityGroup( 254 japaneseToSpanish, 255 Functions.compose(integerToSpanish, japaneseToInteger), 256 SerializableTester.reserialize(japaneseToSpanish)) 257 .addEqualityGroup(japaneseToInteger) 258 .addEqualityGroup(integerToSpanish) 259 .addEqualityGroup(Functions.compose(japaneseToInteger, integerToSpanish)) 260 .testEquals(); 261 } 262 testCompositionWildcard()263 public void testCompositionWildcard() { 264 Map<String, Integer> mapJapaneseToInteger = Maps.newHashMap(); 265 Function<String, Integer> japaneseToInteger = Functions.forMap(mapJapaneseToInteger); 266 267 Function<Object, String> numberToSpanish = Functions.constant("Yo no se"); 268 269 Function<String, String> unusedJapaneseToSpanish = 270 Functions.compose(numberToSpanish, japaneseToInteger); 271 } 272 273 private static class HashCodeFunction implements Function<@Nullable Object, Integer> { 274 @Override apply(@ullable Object o)275 public Integer apply(@Nullable Object o) { 276 return (o == null) ? 0 : o.hashCode(); 277 } 278 } 279 testComposeOfFunctionsIsAssociative()280 public void testComposeOfFunctionsIsAssociative() { 281 Map<Float, String> m = ImmutableMap.of(4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D"); 282 Function<? super Integer, Boolean> h = Functions.constant(Boolean.TRUE); 283 Function<? super String, Integer> g = new HashCodeFunction(); 284 Function<Float, String> f = Functions.forMap(m, "F"); 285 286 Function<Float, Boolean> c1 = Functions.compose(Functions.compose(h, g), f); 287 Function<Float, Boolean> c2 = Functions.compose(h, Functions.compose(g, f)); 288 289 // Might be nice (eventually) to have: 290 // assertEquals(c1, c2); 291 292 // But for now, settle for this: 293 assertEquals(c1.hashCode(), c2.hashCode()); 294 295 assertEquals(c1.apply(1.0f), c2.apply(1.0f)); 296 assertEquals(c1.apply(5.0f), c2.apply(5.0f)); 297 } 298 testComposeOfPredicateAndFunctionIsAssociative()299 public void testComposeOfPredicateAndFunctionIsAssociative() { 300 Map<Float, String> m = ImmutableMap.of(4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D"); 301 Predicate<? super Integer> h = Predicates.equalTo(42); 302 Function<? super String, Integer> g = new HashCodeFunction(); 303 Function<Float, String> f = Functions.forMap(m, "F"); 304 305 Predicate<Float> p1 = Predicates.compose(Predicates.compose(h, g), f); 306 Predicate<Float> p2 = Predicates.compose(h, Functions.compose(g, f)); 307 308 // Might be nice (eventually) to have: 309 // assertEquals(p1, p2); 310 311 // But for now, settle for this: 312 assertEquals(p1.hashCode(), p2.hashCode()); 313 314 assertEquals(p1.apply(1.0f), p2.apply(1.0f)); 315 assertEquals(p1.apply(5.0f), p2.apply(5.0f)); 316 } 317 testForPredicate()318 public void testForPredicate() { 319 Function<Object, Boolean> alwaysTrue = Functions.forPredicate(Predicates.alwaysTrue()); 320 Function<Object, Boolean> alwaysFalse = Functions.forPredicate(Predicates.alwaysFalse()); 321 322 assertTrue(alwaysTrue.apply(0)); 323 assertFalse(alwaysFalse.apply(0)); 324 325 new EqualsTester() 326 .addEqualityGroup(alwaysTrue, Functions.forPredicate(Predicates.alwaysTrue())) 327 .addEqualityGroup(alwaysFalse) 328 .addEqualityGroup(Functions.identity()) 329 .testEquals(); 330 } 331 332 @J2ktIncompatible 333 @GwtIncompatible // SerializableTester testForPredicateSerializable()334 public void testForPredicateSerializable() { 335 checkCanReserialize(Functions.forPredicate(Predicates.equalTo(5))); 336 } 337 testConstant()338 public void testConstant() { 339 Function<@Nullable Object, Object> f = Functions.<Object>constant("correct"); 340 assertEquals("correct", f.apply(new Object())); 341 assertEquals("correct", f.apply(null)); 342 343 Function<@Nullable Object, @Nullable String> g = Functions.constant(null); 344 assertEquals(null, g.apply(2)); 345 assertEquals(null, g.apply(null)); 346 347 new EqualsTester() 348 .addEqualityGroup(f, Functions.constant("correct")) 349 .addEqualityGroup(Functions.constant("incorrect")) 350 .addEqualityGroup(Functions.toStringFunction()) 351 .addEqualityGroup(g) 352 .testEquals(); 353 354 new EqualsTester() 355 .addEqualityGroup(g, Functions.<@Nullable Object>constant(null)) 356 .addEqualityGroup(Functions.constant("incorrect")) 357 .addEqualityGroup(Functions.toStringFunction()) 358 .addEqualityGroup(f) 359 .testEquals(); 360 } 361 362 @J2ktIncompatible 363 @GwtIncompatible // SerializableTester testConstantSerializable()364 public void testConstantSerializable() { 365 checkCanReserialize(Functions.constant(5)); 366 } 367 368 private static class CountingSupplier implements Supplier<Integer>, Serializable { 369 370 private static final long serialVersionUID = 0; 371 372 private int value; 373 374 @Override get()375 public Integer get() { 376 return ++value; 377 } 378 379 @Override equals(@ullable Object obj)380 public boolean equals(@Nullable Object obj) { 381 if (obj instanceof CountingSupplier) { 382 return this.value == ((CountingSupplier) obj).value; 383 } 384 return false; 385 } 386 387 @Override hashCode()388 public int hashCode() { 389 return value; 390 } 391 } 392 testForSupplier()393 public void testForSupplier() { 394 Supplier<Integer> supplier = new CountingSupplier(); 395 Function<@Nullable Object, Integer> function = Functions.forSupplier(supplier); 396 397 assertEquals(1, (int) function.apply(null)); 398 assertEquals(2, (int) function.apply("foo")); 399 400 new EqualsTester() 401 .addEqualityGroup(function, Functions.forSupplier(supplier)) 402 .addEqualityGroup(Functions.forSupplier(new CountingSupplier())) 403 .addEqualityGroup(Functions.forSupplier(Suppliers.ofInstance(12))) 404 .addEqualityGroup(Functions.toStringFunction()) 405 .testEquals(); 406 } 407 408 @J2ktIncompatible 409 @GwtIncompatible // SerializableTester testForSupplierSerializable()410 public void testForSupplierSerializable() { 411 checkCanReserialize(Functions.forSupplier(new CountingSupplier())); 412 } 413 414 @J2ktIncompatible 415 @GwtIncompatible // reflection testNulls()416 public void testNulls() throws Exception { 417 new ClassSanityTester().forAllPublicStaticMethods(Functions.class).testNulls(); 418 } 419 420 @J2ktIncompatible 421 @GwtIncompatible // reflection 422 @AndroidIncompatible // TODO(cpovirk): ClassNotFoundException: com.google.common.base.Function 423 // (I suspect that this and the other similar failures happen with ArbitraryInstances proxies.) testEqualsAndSerializable()424 public void testEqualsAndSerializable() throws Exception { 425 new ClassSanityTester().forAllPublicStaticMethods(Functions.class).testEqualsAndSerializable(); 426 } 427 428 @J2ktIncompatible 429 @GwtIncompatible // SerializableTester checkCanReserialize(Function<? super Integer, Y> f)430 private static <Y> void checkCanReserialize(Function<? super Integer, Y> f) { 431 Function<? super Integer, Y> g = SerializableTester.reserializeAndAssert(f); 432 for (int i = 1; i < 5; i++) { 433 // convoluted way to check that the same result happens from each 434 Y expected = null; 435 try { 436 expected = f.apply(i); 437 } catch (IllegalArgumentException e) { 438 try { 439 g.apply(i); 440 fail(); 441 } catch (IllegalArgumentException ok) { 442 continue; 443 } 444 } 445 assertEquals(expected, g.apply(i)); 446 } 447 } 448 449 @J2ktIncompatible 450 @GwtIncompatible // SerializableTester checkCanReserializeSingleton(Function<? super String, Y> f)451 private static <Y> void checkCanReserializeSingleton(Function<? super String, Y> f) { 452 Function<? super String, Y> g = SerializableTester.reserializeAndAssert(f); 453 assertSame(f, g); 454 for (Integer i = 1; i < 5; i++) { 455 assertEquals(f.apply(i.toString()), g.apply(i.toString())); 456 } 457 } 458 } 459