• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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