View Javadoc
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  
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  
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  
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  
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  
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  
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 
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 
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 
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 
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 
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 
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 
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 
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 
205   public void testNotInterfaceType() {
206     try {
207       new ForwardingWrapperTester().testForwarding(String.class, Functions.<String>identity());
208       fail();
209     } catch (IllegalArgumentException expected) {}
210   }
211 
212   public void testNulls() {
213     new NullPointerTester()
214         .setDefault(Class.class, Runnable.class)
215         .testAllPublicInstanceMethods(new ForwardingWrapperTester());
216   }
217 
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         assertThat(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 
236     ForwardingRunnable(Runnable runnable) {
237       this.runnable = runnable;
238     }
239 
240     @Override public void run() {
241       runnable.run();
242     }
243 
244     @Override public String toString() {
245       return runnable.toString();
246     }
247   }
248 
249   private interface Adder {
250     int add(int a, int b);
251   }
252 
253   private static class ForwardingArithmetic implements Arithmetic {
254     private final Arithmetic arithmetic;
255 
256     public ForwardingArithmetic(Arithmetic arithmetic) {
257       this.arithmetic = arithmetic;
258     }
259 
260     @Override public int add(int a, int b) {
261       return arithmetic.add(a, b);
262     }
263 
264     @Override public int minus(int a, int b) {
265       return arithmetic.minus(a, b);
266     }
267 
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 
276     FailsToForwardParameters(Adder adder) {
277       this.adder = adder;
278     }
279 
280     @Override public int add(int a, int b) {
281       return adder.add(b, a);
282     }
283 
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 
292     FailsToForwardReturnValue(Adder adder) {
293       this.adder = adder;
294     }
295 
296     @Override public int add(int a, int b) {
297       return adder.add(a, b) + 1;
298     }
299 
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 
308     FailsToPropagageException(Adder adder) {
309       this.adder = adder;
310     }
311 
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 
321     @Override public String toString() {
322       return adder.toString();
323     }
324   }
325 
326   public interface Arithmetic extends Adder {
327     int minus(int a, int b);
328   }
329 
330   private static class ForwardsToTheWrongMethod implements Arithmetic {
331     private final Arithmetic arithmetic;
332 
333     ForwardsToTheWrongMethod(Arithmetic arithmetic) {
334       this.arithmetic = arithmetic;
335     }
336 
337     @Override public int minus(int a, int b) { // bad!
338       return arithmetic.add(b, a);
339     }
340 
341     @Override public int add(int a, int b) {
342       return arithmetic.add(b, a);
343     }
344 
345     @Override public String toString() {
346       return arithmetic.toString();
347     }
348   }
349 
350   private interface ParameterTypesDifferent {
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 
361     public ParameterTypesDifferentForwarder(ParameterTypesDifferent delegate) {
362       this.delegate = delegate;
363     }
364 
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 
376     @Override public String toString() {
377       return delegate.toString();
378     }
379   }
380 
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 {
390     CharSequence getId();
391   }
392 
393   interface Sub extends Base {
394     @Override String getId();
395   }
396 
397   private static class ForwardingSub implements Sub {
398     private final Sub delegate;
399 
400     ForwardingSub(Sub delegate) {
401       this.delegate = delegate;
402     }
403 
404     @Override public String getId() {
405       return delegate.getId();
406     }
407 
408     @Override public String toString() {
409       return delegate.toString();
410     }
411   }
412 
413   private interface Equals {
414     @Override boolean equals(Object obj);
415     @Override int hashCode();
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 
429     NoDelegateToEquals(Equals delegate) {
430       this.delegate = delegate;
431     }
432 
433     @Override public String toString() {
434       return delegate.toString();
435     }
436   }
437 
438   public void testExplicitEqualsAndHashCodeNotDelegatedByDefault() {
439     new ForwardingWrapperTester()
440         .testForwarding(Equals.class, NoDelegateToEquals.WRAPPER);
441   }
442 
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'
459     ChainingCalls chainingCall();
460     // A method that just happens to return a ChainingCalls object
461     ChainingCalls nonChainingCall();
462   }
463 
464   private static class ForwardingChainingCalls implements ChainingCalls {
465     final ChainingCalls delegate;
466 
467     ForwardingChainingCalls(ChainingCalls delegate) {
468       this.delegate = delegate;
469     }
470 
471     @Override public ForwardingChainingCalls chainingCall() {
472       delegate.chainingCall();
473       return this;
474     }
475 
476     @Override public ChainingCalls nonChainingCall() {
477       return delegate.nonChainingCall();
478     }
479 
480     @Override public String toString() {
481       return delegate.toString();
482     }
483   }
484 
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 }