OptionalMethodTest.java revision 8cdfc1007818eec034fd6f547425cfda7369ed49
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
18package com.squareup.okhttp.internal;
19
20import org.junit.Test;
21
22import java.io.IOException;
23import java.lang.reflect.InvocationTargetException;
24
25import static org.junit.Assert.assertEquals;
26import static org.junit.Assert.assertFalse;
27import static org.junit.Assert.assertNull;
28import static org.junit.Assert.assertTrue;
29import static org.junit.Assert.fail;
30
31/**
32 * Tests for {@link OptionalMethod}.
33 */
34public 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