• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
stringMethod()37     public String stringMethod() {
38       return "string";
39     }
40 
voidMethod()41     public void voidMethod() {}
42   }
43 
44   @SuppressWarnings("unused")
45   private static class SubClass1 extends BaseClass {
subclassMethod()46     public String subclassMethod() {
47       return "subclassMethod1";
48     }
49 
methodWithArgs(String arg)50     public String methodWithArgs(String arg) {
51       return arg;
52     }
53   }
54 
55   @SuppressWarnings("unused")
56   private static class SubClass2 extends BaseClass {
subclassMethod()57     public int subclassMethod() {
58       return 1234;
59     }
60 
methodWithArgs(String arg)61     public String methodWithArgs(String arg) {
62       return arg;
63     }
64 
throwsException()65     public void throwsException() throws IOException {
66       throw new IOException();
67     }
68 
throwsRuntimeException()69     public void throwsRuntimeException() throws Exception {
70       throw new NumberFormatException();
71     }
72 
nonPublic()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
isSupported()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
invoke()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
invokeBadArgs()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
invokeWithException()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
invokeNonPublic()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
invokeOptional()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
invokeOptionalBadArgs()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
invokeOptionalWithException()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
invokeOptionalNonPublic()295   public void invokeOptionalNonPublic() throws Exception {
296     SubClass2 subClass2 = new SubClass2();
297     assertFalse(NON_PUBLIC.isSupported(subClass2));
298     assertErrorOnInvokeOptional(NON_PUBLIC, subClass2);
299   }
300 
assertErrorOnInvoke( OptionalMethod<T> optionalMethod, T base, Object... args)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 
assertIllegalArgumentExceptionOnInvoke( OptionalMethod<T> optionalMethod, T base, Object... args)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 
assertErrorOnInvokeOptional( OptionalMethod<T> optionalMethod, T base, Object... args)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 
assertIllegalArgumentExceptionOnInvokeOptional( OptionalMethod<T> optionalMethod, T base, Object... args)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