Home | History | Annotate | Download | only in internal
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package com.squareup.okhttp.internal;
     19 
     20 import org.junit.Test;
     21 
     22 import java.io.IOException;
     23 import java.lang.reflect.InvocationTargetException;
     24 
     25 import static org.junit.Assert.assertEquals;
     26 import static org.junit.Assert.assertFalse;
     27 import static org.junit.Assert.assertNull;
     28 import static org.junit.Assert.assertTrue;
     29 import static org.junit.Assert.fail;
     30 
     31 /**
     32  * Tests for {@link OptionalMethod}.
     33  */
     34 public class OptionalMethodTest {
     35   @SuppressWarnings("unused")
     36   private static class BaseClass {
     37     public String stringMethod() {
     38       return "string";
     39     }
     40 
     41     public void voidMethod() {}
     42   }
     43 
     44   @SuppressWarnings("unused")
     45   private static class SubClass1 extends BaseClass {
     46     public String subclassMethod() {
     47       return "subclassMethod1";
     48     }
     49 
     50     public String methodWithArgs(String arg) {
     51       return arg;
     52     }
     53   }
     54 
     55   @SuppressWarnings("unused")
     56   private static class SubClass2 extends BaseClass {
     57     public int subclassMethod() {
     58       return 1234;
     59     }
     60 
     61     public String methodWithArgs(String arg) {
     62       return arg;
     63     }
     64 
     65     public void throwsException() throws IOException {
     66       throw new IOException();
     67     }
     68 
     69     public void throwsRuntimeException() throws Exception {
     70       throw new NumberFormatException();
     71     }
     72 
     73     protected void nonPublic() {}
     74   }
     75 
     76   private final static OptionalMethod<BaseClass> STRING_METHOD_RETURNS_ANY =
     77       new OptionalMethod<BaseClass>(null, "stringMethod");
     78   private final static OptionalMethod<BaseClass> STRING_METHOD_RETURNS_STRING =
     79       new OptionalMethod<BaseClass>(String.class, "stringMethod");
     80   private final static OptionalMethod<BaseClass> STRING_METHOD_RETURNS_INT =
     81       new OptionalMethod<BaseClass>(Integer.TYPE, "stringMethod");
     82   private final static OptionalMethod<BaseClass> VOID_METHOD_RETURNS_ANY =
     83       new OptionalMethod<BaseClass>(null, "voidMethod");
     84   private final static OptionalMethod<BaseClass> VOID_METHOD_RETURNS_VOID =
     85       new OptionalMethod<BaseClass>(Void.TYPE, "voidMethod");
     86   private final static OptionalMethod<BaseClass> SUBCLASS_METHOD_RETURNS_ANY =
     87       new OptionalMethod<BaseClass>(null, "subclassMethod");
     88   private final static OptionalMethod<BaseClass> SUBCLASS_METHOD_RETURNS_STRING =
     89       new OptionalMethod<BaseClass>(String.class, "subclassMethod");
     90   private final static OptionalMethod<BaseClass> SUBCLASS_METHOD_RETURNS_INT =
     91       new OptionalMethod<BaseClass>(Integer.TYPE, "subclassMethod");
     92   private final static OptionalMethod<BaseClass> METHOD_WITH_ARGS_WRONG_PARAMS =
     93       new OptionalMethod<BaseClass>(null, "methodWithArgs", Integer.class);
     94   private final static OptionalMethod<BaseClass> METHOD_WITH_ARGS_CORRECT_PARAMS =
     95       new OptionalMethod<BaseClass>(null, "methodWithArgs", String.class);
     96 
     97   private final static OptionalMethod<BaseClass> THROWS_EXCEPTION =
     98       new OptionalMethod<BaseClass>(null, "throwsException");
     99   private final static OptionalMethod<BaseClass> THROWS_RUNTIME_EXCEPTION =
    100       new OptionalMethod<BaseClass>(null, "throwsRuntimeException");
    101   private final static OptionalMethod<BaseClass> NON_PUBLIC =
    102       new OptionalMethod<BaseClass>(null, "nonPublic");
    103 
    104   @Test
    105   public void isSupported() throws Exception {
    106     {
    107       BaseClass base = new BaseClass();
    108       assertTrue(STRING_METHOD_RETURNS_ANY.isSupported(base));
    109       assertTrue(STRING_METHOD_RETURNS_STRING.isSupported(base));
    110       assertFalse(STRING_METHOD_RETURNS_INT.isSupported(base));
    111       assertTrue(VOID_METHOD_RETURNS_ANY.isSupported(base));
    112       assertTrue(VOID_METHOD_RETURNS_VOID.isSupported(base));
    113       assertFalse(SUBCLASS_METHOD_RETURNS_ANY.isSupported(base));
    114       assertFalse(SUBCLASS_METHOD_RETURNS_STRING.isSupported(base));
    115       assertFalse(SUBCLASS_METHOD_RETURNS_INT.isSupported(base));
    116       assertFalse(METHOD_WITH_ARGS_WRONG_PARAMS.isSupported(base));
    117       assertFalse(METHOD_WITH_ARGS_CORRECT_PARAMS.isSupported(base));
    118     }
    119     {
    120       SubClass1 subClass1 = new SubClass1();
    121       assertTrue(STRING_METHOD_RETURNS_ANY.isSupported(subClass1));
    122       assertTrue(STRING_METHOD_RETURNS_STRING.isSupported(subClass1));
    123       assertFalse(STRING_METHOD_RETURNS_INT.isSupported(subClass1));
    124       assertTrue(VOID_METHOD_RETURNS_ANY.isSupported(subClass1));
    125       assertTrue(VOID_METHOD_RETURNS_VOID.isSupported(subClass1));
    126       assertTrue(SUBCLASS_METHOD_RETURNS_ANY.isSupported(subClass1));
    127       assertTrue(SUBCLASS_METHOD_RETURNS_STRING.isSupported(subClass1));
    128       assertFalse(SUBCLASS_METHOD_RETURNS_INT.isSupported(subClass1));
    129       assertFalse(METHOD_WITH_ARGS_WRONG_PARAMS.isSupported(subClass1));
    130       assertTrue(METHOD_WITH_ARGS_CORRECT_PARAMS.isSupported(subClass1));
    131     }
    132     {
    133       SubClass2 subClass2 = new SubClass2();
    134       assertTrue(STRING_METHOD_RETURNS_ANY.isSupported(subClass2));
    135       assertTrue(STRING_METHOD_RETURNS_STRING.isSupported(subClass2));
    136       assertFalse(STRING_METHOD_RETURNS_INT.isSupported(subClass2));
    137       assertTrue(VOID_METHOD_RETURNS_ANY.isSupported(subClass2));
    138       assertTrue(VOID_METHOD_RETURNS_VOID.isSupported(subClass2));
    139       assertTrue(SUBCLASS_METHOD_RETURNS_ANY.isSupported(subClass2));
    140       assertFalse(SUBCLASS_METHOD_RETURNS_STRING.isSupported(subClass2));
    141       assertTrue(SUBCLASS_METHOD_RETURNS_INT.isSupported(subClass2));
    142       assertFalse(METHOD_WITH_ARGS_WRONG_PARAMS.isSupported(subClass2));
    143       assertTrue(METHOD_WITH_ARGS_CORRECT_PARAMS.isSupported(subClass2));
    144     }
    145   }
    146 
    147   @Test
    148   public void invoke() throws Exception {
    149     {
    150       BaseClass base = new BaseClass();
    151       assertEquals("string", STRING_METHOD_RETURNS_STRING.invoke(base));
    152       assertEquals("string", STRING_METHOD_RETURNS_ANY.invoke(base));
    153       assertErrorOnInvoke(STRING_METHOD_RETURNS_INT, base);
    154       assertNull(VOID_METHOD_RETURNS_ANY.invoke(base));
    155       assertNull(VOID_METHOD_RETURNS_VOID.invoke(base));
    156       assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_ANY, base);
    157       assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_STRING, base);
    158       assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_INT, base);
    159       assertErrorOnInvoke(METHOD_WITH_ARGS_WRONG_PARAMS, base);
    160       assertErrorOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, base);
    161     }
    162     {
    163       SubClass1 subClass1 = new SubClass1();
    164       assertEquals("string", STRING_METHOD_RETURNS_STRING.invoke(subClass1));
    165       assertEquals("string", STRING_METHOD_RETURNS_ANY.invoke(subClass1));
    166       assertErrorOnInvoke(STRING_METHOD_RETURNS_INT, subClass1);
    167       assertNull(VOID_METHOD_RETURNS_ANY.invoke(subClass1));
    168       assertNull(VOID_METHOD_RETURNS_VOID.invoke(subClass1));
    169       assertEquals("subclassMethod1", SUBCLASS_METHOD_RETURNS_ANY.invoke(subClass1));
    170       assertEquals("subclassMethod1", SUBCLASS_METHOD_RETURNS_STRING.invoke(subClass1));
    171       assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_INT, subClass1);
    172       assertErrorOnInvoke(METHOD_WITH_ARGS_WRONG_PARAMS, subClass1);
    173       assertEquals("arg", METHOD_WITH_ARGS_CORRECT_PARAMS.invoke(subClass1, "arg"));
    174     }
    175 
    176     {
    177       SubClass2 subClass2 = new SubClass2();
    178       assertEquals("string", STRING_METHOD_RETURNS_STRING.invoke(subClass2));
    179       assertEquals("string", STRING_METHOD_RETURNS_ANY.invoke(subClass2));
    180       assertErrorOnInvoke(STRING_METHOD_RETURNS_INT, subClass2);
    181       assertNull(VOID_METHOD_RETURNS_ANY.invoke(subClass2));
    182       assertNull(VOID_METHOD_RETURNS_VOID.invoke(subClass2));
    183       assertEquals(1234, SUBCLASS_METHOD_RETURNS_ANY.invoke(subClass2));
    184       assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_STRING, subClass2);
    185       assertEquals(1234, SUBCLASS_METHOD_RETURNS_INT.invoke(subClass2));
    186       assertErrorOnInvoke(METHOD_WITH_ARGS_WRONG_PARAMS, subClass2);
    187       assertEquals("arg", METHOD_WITH_ARGS_CORRECT_PARAMS.invoke(subClass2, "arg"));
    188     }
    189   }
    190 
    191   @Test
    192   public void invokeBadArgs() throws Exception {
    193     SubClass1 subClass1 = new SubClass1();
    194     assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1); // no args
    195     assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, 123);
    196     assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, true);
    197     assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, new Object());
    198     assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, "one", "two");
    199   }
    200 
    201   @Test
    202   public void invokeWithException() throws Exception {
    203     SubClass2 subClass2 = new SubClass2();
    204     try {
    205       THROWS_EXCEPTION.invoke(subClass2);
    206     } catch (InvocationTargetException expected) {
    207       assertTrue(expected.getTargetException() instanceof IOException);
    208     }
    209 
    210     try {
    211       THROWS_RUNTIME_EXCEPTION.invoke(subClass2);
    212     } catch (InvocationTargetException expected) {
    213       assertTrue(expected.getTargetException() instanceof NumberFormatException);
    214     }
    215   }
    216 
    217   @Test
    218   public void invokeNonPublic() throws Exception {
    219     SubClass2 subClass2 = new SubClass2();
    220     assertFalse(NON_PUBLIC.isSupported(subClass2));
    221     assertErrorOnInvoke(NON_PUBLIC, subClass2);
    222   }
    223 
    224   @Test
    225   public void invokeOptional() throws Exception {
    226     {
    227       BaseClass base = new BaseClass();
    228       assertEquals("string", STRING_METHOD_RETURNS_STRING.invokeOptional(base));
    229       assertEquals("string", STRING_METHOD_RETURNS_ANY.invokeOptional(base));
    230       assertNull(STRING_METHOD_RETURNS_INT.invokeOptional(base));
    231       assertNull(VOID_METHOD_RETURNS_ANY.invokeOptional(base));
    232       assertNull(VOID_METHOD_RETURNS_VOID.invokeOptional(base));
    233       assertNull(SUBCLASS_METHOD_RETURNS_ANY.invokeOptional(base));
    234       assertNull(SUBCLASS_METHOD_RETURNS_STRING.invokeOptional(base));
    235       assertNull(SUBCLASS_METHOD_RETURNS_INT.invokeOptional(base));
    236       assertNull(METHOD_WITH_ARGS_WRONG_PARAMS.invokeOptional(base));
    237       assertNull(METHOD_WITH_ARGS_CORRECT_PARAMS.invokeOptional(base));
    238     }
    239     {
    240       SubClass1 subClass1 = new SubClass1();
    241       assertEquals("string", STRING_METHOD_RETURNS_STRING.invokeOptional(subClass1));
    242       assertEquals("string", STRING_METHOD_RETURNS_ANY.invokeOptional(subClass1));
    243       assertNull(STRING_METHOD_RETURNS_INT.invokeOptional(subClass1));
    244       assertNull(VOID_METHOD_RETURNS_ANY.invokeOptional(subClass1));
    245       assertNull(VOID_METHOD_RETURNS_VOID.invokeOptional(subClass1));
    246       assertEquals("subclassMethod1", SUBCLASS_METHOD_RETURNS_ANY.invokeOptional(subClass1));
    247       assertEquals("subclassMethod1", SUBCLASS_METHOD_RETURNS_STRING.invokeOptional(subClass1));
    248       assertNull(SUBCLASS_METHOD_RETURNS_INT.invokeOptional(subClass1));
    249       assertNull(METHOD_WITH_ARGS_WRONG_PARAMS.invokeOptional(subClass1));
    250       assertEquals("arg", METHOD_WITH_ARGS_CORRECT_PARAMS.invokeOptional(subClass1, "arg"));
    251     }
    252 
    253     {
    254       SubClass2 subClass2 = new SubClass2();
    255       assertEquals("string", STRING_METHOD_RETURNS_STRING.invokeOptional(subClass2));
    256       assertEquals("string", STRING_METHOD_RETURNS_ANY.invokeOptional(subClass2));
    257       assertNull(STRING_METHOD_RETURNS_INT.invokeOptional(subClass2));
    258       assertNull(VOID_METHOD_RETURNS_ANY.invokeOptional(subClass2));
    259       assertNull(VOID_METHOD_RETURNS_VOID.invokeOptional(subClass2));
    260       assertEquals(1234, SUBCLASS_METHOD_RETURNS_ANY.invokeOptional(subClass2));
    261       assertNull(SUBCLASS_METHOD_RETURNS_STRING.invokeOptional(subClass2));
    262       assertEquals(1234, SUBCLASS_METHOD_RETURNS_INT.invokeOptional(subClass2));
    263       assertNull(METHOD_WITH_ARGS_WRONG_PARAMS.invokeOptional(subClass2));
    264       assertEquals("arg", METHOD_WITH_ARGS_CORRECT_PARAMS.invokeOptional(subClass2, "arg"));
    265     }
    266   }
    267 
    268   @Test
    269   public void invokeOptionalBadArgs() throws Exception {
    270     SubClass1 subClass1 = new SubClass1();
    271     assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1); // no args
    272     assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, 123);
    273     assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, true);
    274     assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, new Object());
    275     assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, "one", "two");
    276   }
    277 
    278   @Test
    279   public void invokeOptionalWithException() throws Exception {
    280     SubClass2 subClass2 = new SubClass2();
    281     try {
    282       THROWS_EXCEPTION.invokeOptional(subClass2);
    283     } catch (InvocationTargetException expected) {
    284       assertTrue(expected.getTargetException() instanceof IOException);
    285     }
    286 
    287     try {
    288       THROWS_RUNTIME_EXCEPTION.invokeOptional(subClass2);
    289     } catch (InvocationTargetException expected) {
    290       assertTrue(expected.getTargetException() instanceof NumberFormatException);
    291     }
    292   }
    293 
    294   @Test
    295   public void invokeOptionalNonPublic() throws Exception {
    296     SubClass2 subClass2 = new SubClass2();
    297     assertFalse(NON_PUBLIC.isSupported(subClass2));
    298     assertErrorOnInvokeOptional(NON_PUBLIC, subClass2);
    299   }
    300 
    301   private static <T> void assertErrorOnInvoke(
    302       OptionalMethod<T> optionalMethod, T base, Object... args) throws Exception {
    303     try {
    304       optionalMethod.invoke(base, args);
    305       fail();
    306     } catch (Error expected) {
    307     }
    308   }
    309 
    310   private static <T> void assertIllegalArgumentExceptionOnInvoke(
    311       OptionalMethod<T> optionalMethod, T base, Object... args) throws Exception {
    312     try {
    313       optionalMethod.invoke(base, args);
    314       fail();
    315     } catch (IllegalArgumentException expected) {
    316     }
    317   }
    318 
    319   private static <T> void assertErrorOnInvokeOptional(
    320       OptionalMethod<T> optionalMethod, T base, Object... args) throws Exception {
    321     try {
    322       optionalMethod.invokeOptional(base, args);
    323       fail();
    324     } catch (Error expected) {
    325     }
    326   }
    327 
    328   private static <T> void assertIllegalArgumentExceptionOnInvokeOptional(
    329       OptionalMethod<T> optionalMethod, T base, Object... args) throws Exception {
    330     try {
    331       optionalMethod.invokeOptional(base, args);
    332       fail();
    333     } catch (IllegalArgumentException expected) {
    334     }
    335   }
    336 
    337 }
    338