1 /* 2 * Copyright (C) 2012 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.testing.anotherpackage; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.common.base.Equivalence; 23 import com.google.common.base.Function; 24 import com.google.common.base.Functions; 25 import com.google.common.base.Joiner; 26 import com.google.common.base.Predicate; 27 import com.google.common.collect.Ordering; 28 import com.google.common.primitives.UnsignedInteger; 29 import com.google.common.primitives.UnsignedLong; 30 import com.google.common.testing.ForwardingWrapperTester; 31 import com.google.common.testing.NullPointerTester; 32 import com.google.errorprone.annotations.CanIgnoreReturnValue; 33 import java.io.InputStream; 34 import java.nio.charset.Charset; 35 import java.util.concurrent.TimeUnit; 36 import java.util.regex.Pattern; 37 import junit.framework.AssertionFailedError; 38 import junit.framework.TestCase; 39 import org.checkerframework.checker.nullness.qual.Nullable; 40 41 /** 42 * Tests for {@link ForwardingWrapperTester}. Live in a different package to detect reflection 43 * access issues, if any. 44 * 45 * @author Ben Yu 46 */ 47 public class ForwardingWrapperTesterTest extends TestCase { 48 49 private final ForwardingWrapperTester tester = new ForwardingWrapperTester(); 50 testGoodForwarder()51 public void testGoodForwarder() { 52 tester.testForwarding( 53 Arithmetic.class, 54 new Function<Arithmetic, Arithmetic>() { 55 @Override 56 public Arithmetic apply(Arithmetic arithmetic) { 57 return new ForwardingArithmetic(arithmetic); 58 } 59 }); 60 tester.testForwarding( 61 ParameterTypesDifferent.class, 62 new Function<ParameterTypesDifferent, ParameterTypesDifferent>() { 63 @Override 64 public ParameterTypesDifferent apply(ParameterTypesDifferent delegate) { 65 return new ParameterTypesDifferentForwarder(delegate); 66 } 67 }); 68 } 69 testVoidMethodForwarding()70 public void testVoidMethodForwarding() { 71 tester.testForwarding( 72 Runnable.class, 73 new Function<Runnable, Runnable>() { 74 @Override 75 public Runnable apply(final Runnable runnable) { 76 return new ForwardingRunnable(runnable); 77 } 78 }); 79 } 80 testToStringForwarding()81 public void testToStringForwarding() { 82 tester.testForwarding( 83 Runnable.class, 84 new Function<Runnable, Runnable>() { 85 @Override 86 public Runnable apply(final Runnable runnable) { 87 return new ForwardingRunnable(runnable) { 88 @Override 89 public String toString() { 90 return runnable.toString(); 91 } 92 }; 93 } 94 }); 95 } 96 testFailsToForwardToString()97 public void testFailsToForwardToString() { 98 assertFailure( 99 Runnable.class, 100 new Function<Runnable, Runnable>() { 101 @Override 102 public Runnable apply(final Runnable runnable) { 103 return new ForwardingRunnable(runnable) { 104 @Override 105 public String toString() { 106 return ""; 107 } 108 }; 109 } 110 }, 111 "toString()"); 112 } 113 testFailsToForwardHashCode()114 public void testFailsToForwardHashCode() { 115 tester.includingEquals(); 116 assertFailure( 117 Runnable.class, 118 new Function<Runnable, Runnable>() { 119 @Override 120 public Runnable apply(final Runnable runnable) { 121 return new ForwardingRunnable(runnable) { 122 123 @SuppressWarnings("EqualsHashCode") 124 @Override 125 public boolean equals(@Nullable Object o) { 126 if (o instanceof ForwardingRunnable) { 127 ForwardingRunnable that = (ForwardingRunnable) o; 128 return runnable.equals(that.runnable); 129 } 130 return false; 131 } 132 }; 133 } 134 }, 135 "Runnable"); 136 } 137 testEqualsAndHashCodeForwarded()138 public void testEqualsAndHashCodeForwarded() { 139 tester.includingEquals(); 140 tester.testForwarding( 141 Runnable.class, 142 new Function<Runnable, Runnable>() { 143 @Override 144 public Runnable apply(final Runnable runnable) { 145 return new ForwardingRunnable(runnable) { 146 @Override 147 public boolean equals(@Nullable Object o) { 148 if (o instanceof ForwardingRunnable) { 149 ForwardingRunnable that = (ForwardingRunnable) o; 150 return runnable.equals(that.runnable); 151 } 152 return false; 153 } 154 155 @Override 156 public int hashCode() { 157 return runnable.hashCode(); 158 } 159 }; 160 } 161 }); 162 } 163 testFailsToForwardEquals()164 public void testFailsToForwardEquals() { 165 tester.includingEquals(); 166 assertFailure( 167 Runnable.class, 168 new Function<Runnable, Runnable>() { 169 @Override 170 public Runnable apply(final Runnable runnable) { 171 return new ForwardingRunnable(runnable) { 172 @Override 173 public int hashCode() { 174 return runnable.hashCode(); 175 } 176 }; 177 } 178 }, 179 "Runnable"); 180 } 181 testFailsToForward()182 public void testFailsToForward() { 183 assertFailure( 184 Runnable.class, 185 new Function<Runnable, Runnable>() { 186 @Override 187 public Runnable apply(Runnable runnable) { 188 return new ForwardingRunnable(runnable) { 189 @Override 190 public void run() {} 191 }; 192 } 193 }, 194 "run()", 195 "Failed to forward"); 196 } 197 testRedundantForwarding()198 public void testRedundantForwarding() { 199 assertFailure( 200 Runnable.class, 201 new Function<Runnable, Runnable>() { 202 @Override 203 public Runnable apply(final Runnable runnable) { 204 return new Runnable() { 205 @Override 206 public void run() { 207 runnable.run(); 208 runnable.run(); 209 } 210 }; 211 } 212 }, 213 "run()", 214 "invoked more than once"); 215 } 216 testFailsToForwardParameters()217 public void testFailsToForwardParameters() { 218 assertFailure( 219 Adder.class, 220 new Function<Adder, Adder>() { 221 @Override 222 public Adder apply(Adder adder) { 223 return new FailsToForwardParameters(adder); 224 } 225 }, 226 "add(", 227 "Parameter #0"); 228 } 229 testForwardsToTheWrongMethod()230 public void testForwardsToTheWrongMethod() { 231 assertFailure( 232 Arithmetic.class, 233 new Function<Arithmetic, Arithmetic>() { 234 @Override 235 public Arithmetic apply(Arithmetic adder) { 236 return new ForwardsToTheWrongMethod(adder); 237 } 238 }, 239 "minus"); 240 } 241 testFailsToForwardReturnValue()242 public void testFailsToForwardReturnValue() { 243 assertFailure( 244 Adder.class, 245 new Function<Adder, Adder>() { 246 @Override 247 public Adder apply(Adder adder) { 248 return new FailsToForwardReturnValue(adder); 249 } 250 }, 251 "add(", 252 "Return value"); 253 } 254 testFailsToPropagateException()255 public void testFailsToPropagateException() { 256 assertFailure( 257 Adder.class, 258 new Function<Adder, Adder>() { 259 @Override 260 public Adder apply(Adder adder) { 261 return new FailsToPropagateException(adder); 262 } 263 }, 264 "add(", 265 "exception"); 266 } 267 testNotInterfaceType()268 public void testNotInterfaceType() { 269 assertThrows( 270 IllegalArgumentException.class, 271 () -> 272 new ForwardingWrapperTester() 273 .testForwarding(String.class, Functions.<String>identity())); 274 } 275 testNulls()276 public void testNulls() { 277 new NullPointerTester() 278 .setDefault(Class.class, Runnable.class) 279 .testAllPublicInstanceMethods(new ForwardingWrapperTester()); 280 } 281 assertFailure( Class<T> interfaceType, Function<T, ? extends T> wrapperFunction, String... expectedMessages)282 private <T> void assertFailure( 283 Class<T> interfaceType, 284 Function<T, ? extends T> wrapperFunction, 285 String... expectedMessages) { 286 try { 287 tester.testForwarding(interfaceType, wrapperFunction); 288 } catch (AssertionFailedError expected) { 289 for (String message : expectedMessages) { 290 assertThat(expected.getMessage()).contains(message); 291 } 292 return; 293 } 294 fail("expected failure not reported"); 295 } 296 297 private class ForwardingRunnable implements Runnable { 298 299 private final Runnable runnable; 300 ForwardingRunnable(Runnable runnable)301 ForwardingRunnable(Runnable runnable) { 302 this.runnable = runnable; 303 } 304 305 @Override run()306 public void run() { 307 runnable.run(); 308 } 309 310 @Override toString()311 public String toString() { 312 return runnable.toString(); 313 } 314 } 315 316 private interface Adder { add(int a, int b)317 int add(int a, int b); 318 } 319 320 private static class ForwardingArithmetic implements Arithmetic { 321 private final Arithmetic arithmetic; 322 ForwardingArithmetic(Arithmetic arithmetic)323 public ForwardingArithmetic(Arithmetic arithmetic) { 324 this.arithmetic = arithmetic; 325 } 326 327 @Override add(int a, int b)328 public int add(int a, int b) { 329 return arithmetic.add(a, b); 330 } 331 332 @Override minus(int a, int b)333 public int minus(int a, int b) { 334 return arithmetic.minus(a, b); 335 } 336 337 @Override toString()338 public String toString() { 339 return arithmetic.toString(); 340 } 341 } 342 343 private static class FailsToForwardParameters implements Adder { 344 private final Adder adder; 345 FailsToForwardParameters(Adder adder)346 FailsToForwardParameters(Adder adder) { 347 this.adder = adder; 348 } 349 350 @Override add(int a, int b)351 public int add(int a, int b) { 352 return adder.add(b, a); 353 } 354 355 @Override toString()356 public String toString() { 357 return adder.toString(); 358 } 359 } 360 361 private static class FailsToForwardReturnValue implements Adder { 362 private final Adder adder; 363 FailsToForwardReturnValue(Adder adder)364 FailsToForwardReturnValue(Adder adder) { 365 this.adder = adder; 366 } 367 368 @Override add(int a, int b)369 public int add(int a, int b) { 370 return adder.add(a, b) + 1; 371 } 372 373 @Override toString()374 public String toString() { 375 return adder.toString(); 376 } 377 } 378 379 private static class FailsToPropagateException implements Adder { 380 private final Adder adder; 381 FailsToPropagateException(Adder adder)382 FailsToPropagateException(Adder adder) { 383 this.adder = adder; 384 } 385 386 @Override add(int a, int b)387 public int add(int a, int b) { 388 try { 389 return adder.add(a, b); 390 } catch (Exception e) { 391 // swallow! 392 return 0; 393 } 394 } 395 396 @Override toString()397 public String toString() { 398 return adder.toString(); 399 } 400 } 401 402 public interface Arithmetic extends Adder { minus(int a, int b)403 int minus(int a, int b); 404 } 405 406 private static class ForwardsToTheWrongMethod implements Arithmetic { 407 private final Arithmetic arithmetic; 408 ForwardsToTheWrongMethod(Arithmetic arithmetic)409 ForwardsToTheWrongMethod(Arithmetic arithmetic) { 410 this.arithmetic = arithmetic; 411 } 412 413 @Override minus(int a, int b)414 public int minus(int a, int b) { // bad! 415 return arithmetic.add(a, b); 416 } 417 418 @Override add(int a, int b)419 public int add(int a, int b) { 420 return arithmetic.add(a, b); 421 } 422 423 @Override toString()424 public String toString() { 425 return arithmetic.toString(); 426 } 427 } 428 429 private interface ParameterTypesDifferent { foo( String s, Runnable r, Number n, Iterable<?> it, boolean b, Equivalence<String> eq, Exception e, InputStream in, Comparable<?> c, Ordering<Integer> ord, Charset charset, TimeUnit unit, Class<?> cls, Joiner joiner, Pattern pattern, UnsignedInteger ui, UnsignedLong ul, StringBuilder sb, Predicate<?> pred, Function<?, ?> func, Object obj)430 void foo( 431 String s, 432 Runnable r, 433 Number n, 434 Iterable<?> it, 435 boolean b, 436 Equivalence<String> eq, 437 Exception e, 438 InputStream in, 439 Comparable<?> c, 440 Ordering<Integer> ord, 441 Charset charset, 442 TimeUnit unit, 443 Class<?> cls, 444 Joiner joiner, 445 Pattern pattern, 446 UnsignedInteger ui, 447 UnsignedLong ul, 448 StringBuilder sb, 449 Predicate<?> pred, 450 Function<?, ?> func, 451 Object obj); 452 } 453 454 private static class ParameterTypesDifferentForwarder implements ParameterTypesDifferent { 455 private final ParameterTypesDifferent delegate; 456 ParameterTypesDifferentForwarder(ParameterTypesDifferent delegate)457 public ParameterTypesDifferentForwarder(ParameterTypesDifferent delegate) { 458 this.delegate = delegate; 459 } 460 461 @Override foo( String s, Runnable r, Number n, Iterable<?> it, boolean b, Equivalence<String> eq, Exception e, InputStream in, Comparable<?> c, Ordering<Integer> ord, Charset charset, TimeUnit unit, Class<?> cls, Joiner joiner, Pattern pattern, UnsignedInteger ui, UnsignedLong ul, StringBuilder sb, Predicate<?> pred, Function<?, ?> func, Object obj)462 public void foo( 463 String s, 464 Runnable r, 465 Number n, 466 Iterable<?> it, 467 boolean b, 468 Equivalence<String> eq, 469 Exception e, 470 InputStream in, 471 Comparable<?> c, 472 Ordering<Integer> ord, 473 Charset charset, 474 TimeUnit unit, 475 Class<?> cls, 476 Joiner joiner, 477 Pattern pattern, 478 UnsignedInteger ui, 479 UnsignedLong ul, 480 StringBuilder sb, 481 Predicate<?> pred, 482 Function<?, ?> func, 483 Object obj) { 484 delegate.foo( 485 s, r, n, it, b, eq, e, in, c, ord, charset, unit, cls, joiner, pattern, ui, ul, sb, pred, 486 func, obj); 487 } 488 489 @Override toString()490 public String toString() { 491 return delegate.toString(); 492 } 493 } 494 testCovariantReturn()495 public void testCovariantReturn() { 496 new ForwardingWrapperTester() 497 .testForwarding( 498 Sub.class, 499 new Function<Sub, Sub>() { 500 @Override 501 public Sub apply(Sub sub) { 502 return new ForwardingSub(sub); 503 } 504 }); 505 } 506 507 interface Base { getId()508 CharSequence getId(); 509 } 510 511 interface Sub extends Base { 512 @Override getId()513 String getId(); 514 } 515 516 private static class ForwardingSub implements Sub { 517 private final Sub delegate; 518 ForwardingSub(Sub delegate)519 ForwardingSub(Sub delegate) { 520 this.delegate = delegate; 521 } 522 523 @Override getId()524 public String getId() { 525 return delegate.getId(); 526 } 527 528 @Override toString()529 public String toString() { 530 return delegate.toString(); 531 } 532 } 533 534 private interface Equals { 535 @Override equals(@ullable Object obj)536 boolean equals(@Nullable Object obj); 537 538 @Override hashCode()539 int hashCode(); 540 541 @Override toString()542 String toString(); 543 } 544 545 private static class NoDelegateToEquals implements Equals { 546 547 private static Function<Equals, Equals> WRAPPER = 548 new Function<Equals, Equals>() { 549 @Override 550 public NoDelegateToEquals apply(Equals delegate) { 551 return new NoDelegateToEquals(delegate); 552 } 553 }; 554 555 private final Equals delegate; 556 NoDelegateToEquals(Equals delegate)557 NoDelegateToEquals(Equals delegate) { 558 this.delegate = delegate; 559 } 560 561 @Override toString()562 public String toString() { 563 return delegate.toString(); 564 } 565 } 566 testExplicitEqualsAndHashCodeNotDelegatedByDefault()567 public void testExplicitEqualsAndHashCodeNotDelegatedByDefault() { 568 new ForwardingWrapperTester().testForwarding(Equals.class, NoDelegateToEquals.WRAPPER); 569 } 570 testExplicitEqualsAndHashCodeDelegatedWhenExplicitlyAsked()571 public void testExplicitEqualsAndHashCodeDelegatedWhenExplicitlyAsked() { 572 try { 573 new ForwardingWrapperTester() 574 .includingEquals() 575 .testForwarding(Equals.class, NoDelegateToEquals.WRAPPER); 576 } catch (AssertionFailedError expected) { 577 return; 578 } 579 fail("Should have failed"); 580 } 581 582 /** An interface for the 2 ways that a chaining call might be defined. */ 583 private interface ChainingCalls { 584 // A method that is defined to 'return this' 585 @CanIgnoreReturnValue chainingCall()586 ChainingCalls chainingCall(); 587 588 // A method that just happens to return a ChainingCalls object nonChainingCall()589 ChainingCalls nonChainingCall(); 590 } 591 592 private static class ForwardingChainingCalls implements ChainingCalls { 593 final ChainingCalls delegate; 594 ForwardingChainingCalls(ChainingCalls delegate)595 ForwardingChainingCalls(ChainingCalls delegate) { 596 this.delegate = delegate; 597 } 598 599 @CanIgnoreReturnValue 600 @Override chainingCall()601 public ForwardingChainingCalls chainingCall() { 602 delegate.chainingCall(); 603 return this; 604 } 605 606 @Override nonChainingCall()607 public ChainingCalls nonChainingCall() { 608 return delegate.nonChainingCall(); 609 } 610 611 @Override toString()612 public String toString() { 613 return delegate.toString(); 614 } 615 } 616 testChainingCalls()617 public void testChainingCalls() { 618 tester.testForwarding( 619 ChainingCalls.class, 620 new Function<ChainingCalls, ChainingCalls>() { 621 @Override 622 public ChainingCalls apply(ChainingCalls delegate) { 623 return new ForwardingChainingCalls(delegate); 624 } 625 }); 626 } 627 } 628