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