blob: 3e129a2353e9189b3a4a3951974224c2f211f648 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.okhttp.internal;
import org.junit.Test;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Tests for {@link OptionalMethod}.
*/
public class OptionalMethodTest {
@SuppressWarnings("unused")
private static class BaseClass {
public String stringMethod() {
return "string";
}
public void voidMethod() {}
}
@SuppressWarnings("unused")
private static class SubClass1 extends BaseClass {
public String subclassMethod() {
return "subclassMethod1";
}
public String methodWithArgs(String arg) {
return arg;
}
}
@SuppressWarnings("unused")
private static class SubClass2 extends BaseClass {
public int subclassMethod() {
return 1234;
}
public String methodWithArgs(String arg) {
return arg;
}
public void throwsException() throws IOException {
throw new IOException();
}
public void throwsRuntimeException() throws Exception {
throw new NumberFormatException();
}
protected void nonPublic() {}
}
private final static OptionalMethod<BaseClass> STRING_METHOD_RETURNS_ANY =
new OptionalMethod<BaseClass>(null, "stringMethod");
private final static OptionalMethod<BaseClass> STRING_METHOD_RETURNS_STRING =
new OptionalMethod<BaseClass>(String.class, "stringMethod");
private final static OptionalMethod<BaseClass> STRING_METHOD_RETURNS_INT =
new OptionalMethod<BaseClass>(Integer.TYPE, "stringMethod");
private final static OptionalMethod<BaseClass> VOID_METHOD_RETURNS_ANY =
new OptionalMethod<BaseClass>(null, "voidMethod");
private final static OptionalMethod<BaseClass> VOID_METHOD_RETURNS_VOID =
new OptionalMethod<BaseClass>(Void.TYPE, "voidMethod");
private final static OptionalMethod<BaseClass> SUBCLASS_METHOD_RETURNS_ANY =
new OptionalMethod<BaseClass>(null, "subclassMethod");
private final static OptionalMethod<BaseClass> SUBCLASS_METHOD_RETURNS_STRING =
new OptionalMethod<BaseClass>(String.class, "subclassMethod");
private final static OptionalMethod<BaseClass> SUBCLASS_METHOD_RETURNS_INT =
new OptionalMethod<BaseClass>(Integer.TYPE, "subclassMethod");
private final static OptionalMethod<BaseClass> METHOD_WITH_ARGS_WRONG_PARAMS =
new OptionalMethod<BaseClass>(null, "methodWithArgs", Integer.class);
private final static OptionalMethod<BaseClass> METHOD_WITH_ARGS_CORRECT_PARAMS =
new OptionalMethod<BaseClass>(null, "methodWithArgs", String.class);
private final static OptionalMethod<BaseClass> THROWS_EXCEPTION =
new OptionalMethod<BaseClass>(null, "throwsException");
private final static OptionalMethod<BaseClass> THROWS_RUNTIME_EXCEPTION =
new OptionalMethod<BaseClass>(null, "throwsRuntimeException");
private final static OptionalMethod<BaseClass> NON_PUBLIC =
new OptionalMethod<BaseClass>(null, "nonPublic");
@Test
public void isSupported() throws Exception {
{
BaseClass base = new BaseClass();
assertTrue(STRING_METHOD_RETURNS_ANY.isSupported(base));
assertTrue(STRING_METHOD_RETURNS_STRING.isSupported(base));
assertFalse(STRING_METHOD_RETURNS_INT.isSupported(base));
assertTrue(VOID_METHOD_RETURNS_ANY.isSupported(base));
assertTrue(VOID_METHOD_RETURNS_VOID.isSupported(base));
assertFalse(SUBCLASS_METHOD_RETURNS_ANY.isSupported(base));
assertFalse(SUBCLASS_METHOD_RETURNS_STRING.isSupported(base));
assertFalse(SUBCLASS_METHOD_RETURNS_INT.isSupported(base));
assertFalse(METHOD_WITH_ARGS_WRONG_PARAMS.isSupported(base));
assertFalse(METHOD_WITH_ARGS_CORRECT_PARAMS.isSupported(base));
}
{
SubClass1 subClass1 = new SubClass1();
assertTrue(STRING_METHOD_RETURNS_ANY.isSupported(subClass1));
assertTrue(STRING_METHOD_RETURNS_STRING.isSupported(subClass1));
assertFalse(STRING_METHOD_RETURNS_INT.isSupported(subClass1));
assertTrue(VOID_METHOD_RETURNS_ANY.isSupported(subClass1));
assertTrue(VOID_METHOD_RETURNS_VOID.isSupported(subClass1));
assertTrue(SUBCLASS_METHOD_RETURNS_ANY.isSupported(subClass1));
assertTrue(SUBCLASS_METHOD_RETURNS_STRING.isSupported(subClass1));
assertFalse(SUBCLASS_METHOD_RETURNS_INT.isSupported(subClass1));
assertFalse(METHOD_WITH_ARGS_WRONG_PARAMS.isSupported(subClass1));
assertTrue(METHOD_WITH_ARGS_CORRECT_PARAMS.isSupported(subClass1));
}
{
SubClass2 subClass2 = new SubClass2();
assertTrue(STRING_METHOD_RETURNS_ANY.isSupported(subClass2));
assertTrue(STRING_METHOD_RETURNS_STRING.isSupported(subClass2));
assertFalse(STRING_METHOD_RETURNS_INT.isSupported(subClass2));
assertTrue(VOID_METHOD_RETURNS_ANY.isSupported(subClass2));
assertTrue(VOID_METHOD_RETURNS_VOID.isSupported(subClass2));
assertTrue(SUBCLASS_METHOD_RETURNS_ANY.isSupported(subClass2));
assertFalse(SUBCLASS_METHOD_RETURNS_STRING.isSupported(subClass2));
assertTrue(SUBCLASS_METHOD_RETURNS_INT.isSupported(subClass2));
assertFalse(METHOD_WITH_ARGS_WRONG_PARAMS.isSupported(subClass2));
assertTrue(METHOD_WITH_ARGS_CORRECT_PARAMS.isSupported(subClass2));
}
}
@Test
public void invoke() throws Exception {
{
BaseClass base = new BaseClass();
assertEquals("string", STRING_METHOD_RETURNS_STRING.invoke(base));
assertEquals("string", STRING_METHOD_RETURNS_ANY.invoke(base));
assertErrorOnInvoke(STRING_METHOD_RETURNS_INT, base);
assertNull(VOID_METHOD_RETURNS_ANY.invoke(base));
assertNull(VOID_METHOD_RETURNS_VOID.invoke(base));
assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_ANY, base);
assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_STRING, base);
assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_INT, base);
assertErrorOnInvoke(METHOD_WITH_ARGS_WRONG_PARAMS, base);
assertErrorOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, base);
}
{
SubClass1 subClass1 = new SubClass1();
assertEquals("string", STRING_METHOD_RETURNS_STRING.invoke(subClass1));
assertEquals("string", STRING_METHOD_RETURNS_ANY.invoke(subClass1));
assertErrorOnInvoke(STRING_METHOD_RETURNS_INT, subClass1);
assertNull(VOID_METHOD_RETURNS_ANY.invoke(subClass1));
assertNull(VOID_METHOD_RETURNS_VOID.invoke(subClass1));
assertEquals("subclassMethod1", SUBCLASS_METHOD_RETURNS_ANY.invoke(subClass1));
assertEquals("subclassMethod1", SUBCLASS_METHOD_RETURNS_STRING.invoke(subClass1));
assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_INT, subClass1);
assertErrorOnInvoke(METHOD_WITH_ARGS_WRONG_PARAMS, subClass1);
assertEquals("arg", METHOD_WITH_ARGS_CORRECT_PARAMS.invoke(subClass1, "arg"));
}
{
SubClass2 subClass2 = new SubClass2();
assertEquals("string", STRING_METHOD_RETURNS_STRING.invoke(subClass2));
assertEquals("string", STRING_METHOD_RETURNS_ANY.invoke(subClass2));
assertErrorOnInvoke(STRING_METHOD_RETURNS_INT, subClass2);
assertNull(VOID_METHOD_RETURNS_ANY.invoke(subClass2));
assertNull(VOID_METHOD_RETURNS_VOID.invoke(subClass2));
assertEquals(1234, SUBCLASS_METHOD_RETURNS_ANY.invoke(subClass2));
assertErrorOnInvoke(SUBCLASS_METHOD_RETURNS_STRING, subClass2);
assertEquals(1234, SUBCLASS_METHOD_RETURNS_INT.invoke(subClass2));
assertErrorOnInvoke(METHOD_WITH_ARGS_WRONG_PARAMS, subClass2);
assertEquals("arg", METHOD_WITH_ARGS_CORRECT_PARAMS.invoke(subClass2, "arg"));
}
}
@Test
public void invokeBadArgs() throws Exception {
SubClass1 subClass1 = new SubClass1();
assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1); // no args
assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, 123);
assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, true);
assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, new Object());
assertIllegalArgumentExceptionOnInvoke(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, "one", "two");
}
@Test
public void invokeWithException() throws Exception {
SubClass2 subClass2 = new SubClass2();
try {
THROWS_EXCEPTION.invoke(subClass2);
} catch (InvocationTargetException expected) {
assertTrue(expected.getTargetException() instanceof IOException);
}
try {
THROWS_RUNTIME_EXCEPTION.invoke(subClass2);
} catch (InvocationTargetException expected) {
assertTrue(expected.getTargetException() instanceof NumberFormatException);
}
}
@Test
public void invokeNonPublic() throws Exception {
SubClass2 subClass2 = new SubClass2();
assertFalse(NON_PUBLIC.isSupported(subClass2));
assertErrorOnInvoke(NON_PUBLIC, subClass2);
}
@Test
public void invokeOptional() throws Exception {
{
BaseClass base = new BaseClass();
assertEquals("string", STRING_METHOD_RETURNS_STRING.invokeOptional(base));
assertEquals("string", STRING_METHOD_RETURNS_ANY.invokeOptional(base));
assertNull(STRING_METHOD_RETURNS_INT.invokeOptional(base));
assertNull(VOID_METHOD_RETURNS_ANY.invokeOptional(base));
assertNull(VOID_METHOD_RETURNS_VOID.invokeOptional(base));
assertNull(SUBCLASS_METHOD_RETURNS_ANY.invokeOptional(base));
assertNull(SUBCLASS_METHOD_RETURNS_STRING.invokeOptional(base));
assertNull(SUBCLASS_METHOD_RETURNS_INT.invokeOptional(base));
assertNull(METHOD_WITH_ARGS_WRONG_PARAMS.invokeOptional(base));
assertNull(METHOD_WITH_ARGS_CORRECT_PARAMS.invokeOptional(base));
}
{
SubClass1 subClass1 = new SubClass1();
assertEquals("string", STRING_METHOD_RETURNS_STRING.invokeOptional(subClass1));
assertEquals("string", STRING_METHOD_RETURNS_ANY.invokeOptional(subClass1));
assertNull(STRING_METHOD_RETURNS_INT.invokeOptional(subClass1));
assertNull(VOID_METHOD_RETURNS_ANY.invokeOptional(subClass1));
assertNull(VOID_METHOD_RETURNS_VOID.invokeOptional(subClass1));
assertEquals("subclassMethod1", SUBCLASS_METHOD_RETURNS_ANY.invokeOptional(subClass1));
assertEquals("subclassMethod1", SUBCLASS_METHOD_RETURNS_STRING.invokeOptional(subClass1));
assertNull(SUBCLASS_METHOD_RETURNS_INT.invokeOptional(subClass1));
assertNull(METHOD_WITH_ARGS_WRONG_PARAMS.invokeOptional(subClass1));
assertEquals("arg", METHOD_WITH_ARGS_CORRECT_PARAMS.invokeOptional(subClass1, "arg"));
}
{
SubClass2 subClass2 = new SubClass2();
assertEquals("string", STRING_METHOD_RETURNS_STRING.invokeOptional(subClass2));
assertEquals("string", STRING_METHOD_RETURNS_ANY.invokeOptional(subClass2));
assertNull(STRING_METHOD_RETURNS_INT.invokeOptional(subClass2));
assertNull(VOID_METHOD_RETURNS_ANY.invokeOptional(subClass2));
assertNull(VOID_METHOD_RETURNS_VOID.invokeOptional(subClass2));
assertEquals(1234, SUBCLASS_METHOD_RETURNS_ANY.invokeOptional(subClass2));
assertNull(SUBCLASS_METHOD_RETURNS_STRING.invokeOptional(subClass2));
assertEquals(1234, SUBCLASS_METHOD_RETURNS_INT.invokeOptional(subClass2));
assertNull(METHOD_WITH_ARGS_WRONG_PARAMS.invokeOptional(subClass2));
assertEquals("arg", METHOD_WITH_ARGS_CORRECT_PARAMS.invokeOptional(subClass2, "arg"));
}
}
@Test
public void invokeOptionalBadArgs() throws Exception {
SubClass1 subClass1 = new SubClass1();
assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1); // no args
assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, 123);
assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, true);
assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, new Object());
assertIllegalArgumentExceptionOnInvokeOptional(METHOD_WITH_ARGS_CORRECT_PARAMS, subClass1, "one", "two");
}
@Test
public void invokeOptionalWithException() throws Exception {
SubClass2 subClass2 = new SubClass2();
try {
THROWS_EXCEPTION.invokeOptional(subClass2);
} catch (InvocationTargetException expected) {
assertTrue(expected.getTargetException() instanceof IOException);
}
try {
THROWS_RUNTIME_EXCEPTION.invokeOptional(subClass2);
} catch (InvocationTargetException expected) {
assertTrue(expected.getTargetException() instanceof NumberFormatException);
}
}
@Test
public void invokeOptionalNonPublic() throws Exception {
SubClass2 subClass2 = new SubClass2();
assertFalse(NON_PUBLIC.isSupported(subClass2));
assertErrorOnInvokeOptional(NON_PUBLIC, subClass2);
}
private static <T> void assertErrorOnInvoke(
OptionalMethod<T> optionalMethod, T base, Object... args) throws Exception {
try {
optionalMethod.invoke(base, args);
fail();
} catch (Error expected) {
}
}
private static <T> void assertIllegalArgumentExceptionOnInvoke(
OptionalMethod<T> optionalMethod, T base, Object... args) throws Exception {
try {
optionalMethod.invoke(base, args);
fail();
} catch (IllegalArgumentException expected) {
}
}
private static <T> void assertErrorOnInvokeOptional(
OptionalMethod<T> optionalMethod, T base, Object... args) throws Exception {
try {
optionalMethod.invokeOptional(base, args);
fail();
} catch (Error expected) {
}
}
private static <T> void assertIllegalArgumentExceptionOnInvokeOptional(
OptionalMethod<T> optionalMethod, T base, Object... args) throws Exception {
try {
optionalMethod.invokeOptional(base, args);
fail();
} catch (IllegalArgumentException expected) {
}
}
}