package org.testory.common;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
import static org.testory.common.Classes.canInvoke;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class TestClassesCanInvoke {
@Test
public void checks_argument_conversion() throws Exception {
List<Object> arguments = asList(
new Object(),
new Object[0],
"",
new String[0],
null,
Boolean.valueOf(false),
Character.valueOf('a'),
Byte.valueOf((byte) 0),
Short.valueOf((short) 0),
Integer.valueOf(0),
Long.valueOf(0),
Float.valueOf(0),
Double.valueOf(0),
new int[0],
new float[0],
new Integer[0],
new Float[0]);
for (Method method : Methods.withOneParameter()) {
for (Object argument : arguments) {
assertCorrectness(method, null, argument);
}
}
}
@Test
public void checks_number_of_parameters() {
for (Method method : Methods.withObjectParameters()) {
for (int i = 0; i <= 4; i++) {
assertCorrectness(method, null, new Object[i]);
}
}
}
@SuppressWarnings("unused")
@Test
public void checks_instance_assignability() throws Exception {
class SuperClass {
void superMethod() {}
}
class SubClass extends SuperClass {
void superMethod() {}
void method() {}
}
assertCorrectness(SubClass.class.getDeclaredMethod("method"), new SubClass());
assertCorrectness(SubClass.class.getDeclaredMethod("method"), new SuperClass());
assertCorrectness(SubClass.class.getDeclaredMethod("superMethod"), new SubClass());
assertCorrectness(SubClass.class.getDeclaredMethod("superMethod"), new SuperClass());
assertCorrectness(SuperClass.class.getDeclaredMethod("superMethod"), new SubClass());
assertCorrectness(SuperClass.class.getDeclaredMethod("superMethod"), new SuperClass());
}
@Test
public void ignores_instance_if_method_is_static() {
assertCorrectness(Methods.withParameters(), new Object());
assertCorrectness(Methods.withParameters(), null);
}
@Test
public void checks_instance_if_method_is_not_static() throws Exception {
Method method = Methods.getInstanceMethod();
try {
method.invoke(null);
fail();
} catch (NullPointerException e) {}
assertFalse(canInvoke(method, null));
}
@Test
public void method_cannot_be_null() {
try {
canInvoke(null, null);
fail();
} catch (NullPointerException e) {}
}
@Test
public void arguments_cannot_be_null_array() {
try {
canInvoke(Methods.withParameters(Object.class), null, (Object[]) null);
fail();
} catch (NullPointerException e) {}
}
private static void assertCorrectness(Method method, Object instance, Object... arguments) {
String message = "canInvoke(" + method + ", " + instance + ", " + asList(arguments) + ")";
boolean expected = canJavaInvoke(method, instance, arguments);
boolean actual = canInvoke(method, instance, arguments);
assertEquals(message, expected, actual);
}
private static boolean canJavaInvoke(Method method, Object instance, Object... arguments) {
try {
method.invoke(instance, arguments);
return true;
} catch (IllegalArgumentException e) {
return false;
} catch (ReflectiveOperationException e) {
throw new LinkageError(null, e);
}
}
@SuppressWarnings("unused")
private static class Methods {
public static void invoke() {}
public static void invoke(Object arg) {}
public static void invoke(Object[] arg) {}
public static void invoke(String arg) {}
public static void invoke(String[] arg) {}
public static void invoke(Object argA, Object argB) {}
public static void invoke(Object argA, Object argB, Object argC) {}
public static void invoke(Object arg, Object... varargs) {}
public static void invoke(boolean arg) {}
public static void invoke(char arg) {}
public static void invoke(byte arg) {}
public static void invoke(short arg) {}
public static void invoke(int arg) {}
public static void invoke(long arg) {}
public static void invoke(float arg) {}
public static void invoke(double arg) {}
public static void invoke(Void arg) {}
public static void invoke(Boolean arg) {}
public static void invoke(Character arg) {}
public static void invoke(Byte arg) {}
public static void invoke(Short arg) {}
public static void invoke(Integer arg) {}
public static void invoke(Long arg) {}
public static void invoke(Float arg) {}
public static void invoke(Double arg) {}
public static void invoke(int[] arg) {}
public static void invoke(float[] arg) {}
public static void invoke(Integer[] arg) {}
public static void invoke(Float[] arg) {}
public void nonStaticMethod() {}
public static List<Method> withOneParameter() {
List<Method> methods = new ArrayList<>();
for (Method method : Methods.class.getDeclaredMethods()) {
if (method.getName().equals("invoke") && hasOneParameter(method)) {
methods.add(method);
}
}
assume(methods.size() > 5);
return methods;
}
private static boolean hasOneParameter(Method method) {
return method.getParameterTypes().length == 1;
}
public static List<Method> withObjectParameters() {
List<Method> methods = new ArrayList<>();
for (Method method : Methods.class.getDeclaredMethods()) {
if (method.getName().equals("invoke") && hasObjectParameters(method)) {
methods.add(method);
}
}
assume(methods.size() > 2);
return methods;
}
private static boolean hasObjectParameters(Method method) {
for (Class<?> parameter : method.getParameterTypes()) {
if (parameter != Object.class) {
return false;
}
}
return true;
}
private static Method withParameters(Class<?>... parameters) {
try {
return Methods.class.getDeclaredMethod("invoke", parameters);
} catch (NoSuchMethodException e) {
throw new Error(e);
}
}
public static Method getInstanceMethod() {
try {
return Methods.class.getDeclaredMethod("nonStaticMethod");
} catch (NoSuchMethodException e) {
throw new Error(e);
}
}
private static void assume(boolean condition) {
if (!condition) {
throw new RuntimeException();
}
}
}
}