Home | History | Annotate | Download | only in anotherpackage
      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 
     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         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 
    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 }
    494