/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2016 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://developer.catrobat.org/license_additional_term
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.catroid.test.utiltests;
import android.test.AndroidTestCase;
import org.catrobat.catroid.test.utils.Reflection;
import org.catrobat.catroid.test.utils.Reflection.Parameter;
import org.catrobat.catroid.test.utils.Reflection.ParameterList;
import java.util.Arrays;
public class ReflectionTest extends AndroidTestCase {
public void testPrivateFieldGettersAndSetters() {
char secretChar = (Character) Reflection.getPrivateField(SubClass.class, "SECRET_STATIC_CHAR");
assertEquals("Getting private static field failed!", SubClass.SECRET_STATIC_CHAR, secretChar);
String secretString = (String) Reflection.getPrivateField(new SubClass(), "secretString");
assertEquals("Getting private String failed!", new SubClass().secretString, secretString);
int secretInteger = (Integer) Reflection.getPrivateField(new SubClass(), "SECRET_INTEGER");
assertEquals("Getting private Integer failed!", new SubClass().SECRET_INTEGER, secretInteger);
float secretFloat = (Float) Reflection.getPrivateField(SuperClass.class, new SubClass(), "SECRET_FLOAT");
assertEquals("Getting private Float from super class failed!", new SuperClass().SECRET_FLOAT, secretFloat);
byte secretByte = (Byte) Reflection.getPrivateField(new SuperClass(), "secretByte");
assertEquals("Getting private Float from super class failed!", new SuperClass().secretByte, secretByte);
char newSecretChar = 'n';
Reflection.setPrivateField(SubClass.class, "SECRET_STATIC_CHAR", newSecretChar);
secretChar = (Character) Reflection.getPrivateField(SubClass.class, "SECRET_STATIC_CHAR");
assertEquals("Setting private static field failed!", newSecretChar, secretChar);
SubClass sub = new SubClass();
String newSecretString = "This is a new secret string!";
Reflection.setPrivateField(sub, "secretString", newSecretString);
secretString = (String) Reflection.getPrivateField(sub, "secretString");
assertEquals("Setting private String failed!", newSecretString, secretString);
int newSecretInteger = 128;
Reflection.setPrivateField(sub, "SECRET_INTEGER", newSecretInteger);
secretInteger = (Integer) Reflection.getPrivateField(sub, "SECRET_INTEGER");
assertEquals("Setting private Integer failed!", newSecretInteger, secretInteger);
float newSecretFloat = -5.4f;
Reflection.setPrivateField(SuperClass.class, sub, "SECRET_FLOAT", newSecretFloat);
secretFloat = (Float) Reflection.getPrivateField(SuperClass.class, sub, "SECRET_FLOAT");
assertEquals("Setting private Float from super class failed!", newSecretFloat, secretFloat);
}
public void testPrivateFieldWithNullObject() {
Object nullObject = null;
try {
Reflection.getPrivateField(nullObject, "nullObjectsDontHaveFields");
fail("Getting private field of null object didn't cause an IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
try {
Reflection.getPrivateField(SubClass.class, nullObject, "SECRET_INTEGER");
fail("Getting private field of null object didn't cause an IllegalArgumentException");
} catch (Exception exception) {
assertEquals("Wrong exception has been thrown", exception.getCause().getClass(), NullPointerException.class);
}
try {
Reflection.setPrivateField(nullObject, "nullObjectsDontHaveFields", null);
fail("Setting private field of null object didn't cause an IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
try {
Reflection.setPrivateField(SubClass.class, nullObject, "SECRET_INTEGER", 123);
fail("Setting private field of null object didn't cause an IllegalArgumentException");
} catch (Exception exception) {
assertEquals("Wrong exception has been thrown", exception.getCause().getClass(), NullPointerException.class);
}
}
public void testPrivateFieldWithWrongParameters() {
try {
Reflection.getPrivateField(SuperClass.class, new SubClass(), "secretString");
fail("Secret string is only located in SubClass but also found in SuperClass");
} catch (RuntimeException runtimeException) {
assertEquals("Wrong exception has been thrown", runtimeException.getCause().getClass(),
NoSuchFieldException.class);
}
try {
Reflection.getPrivateField(SubClass.class, new SuperClass(), "secretString");
fail("SuperClass object isn't a sub class of SubClass");
} catch (RuntimeException runtimeException) {
assertEquals("Wrong exception has been thrown", runtimeException.getCause().getClass(),
IllegalArgumentException.class);
}
try {
Reflection.getPrivateField(SubClass.class, null, "secretString");
fail("SubClass has a static member 'secretString'");
} catch (RuntimeException runtimeException) {
assertEquals("Wrong exception has been thrown", runtimeException.getCause().getClass(),
NullPointerException.class);
}
try {
Reflection.setPrivateField(SuperClass.class, new SubClass(), "secretString", "Secret string");
fail("Secret string is only located in SubClass but also found in SuperClass");
} catch (RuntimeException runtimeException) {
assertEquals("Wrong exception has been thrown", runtimeException.getCause().getClass(),
NoSuchFieldException.class);
}
try {
Reflection.setPrivateField(SubClass.class, new SuperClass(), "secretString", "Secret string");
fail("SuperClass object is a sub class of SubClass but shouldn't");
} catch (RuntimeException runtimeException) {
assertEquals("Wrong exception has been thrown", runtimeException.getCause().getClass(),
IllegalArgumentException.class);
}
try {
Reflection.setPrivateField(SubClass.class, null, "secretString", "Secret string");
fail("SubClass has a static member 'secretString'");
} catch (RuntimeException runtimeException) {
assertEquals("Wrong exception has been thrown", runtimeException.getCause().getClass(),
NullPointerException.class);
}
}
public void testInvokeMethodForObjects() {
InvokeMethodClass invokeMethodObject = new InvokeMethodClass();
String returnValue = (String) Reflection.invokeMethod(invokeMethodObject, "methodWithoutParameters");
assertEquals("Wrong return value", "Called methodWithoutParameters!", returnValue);
String parameter1 = "first parameter";
String parameter2 = "second parameter";
returnValue = (String) Reflection.invokeMethod(invokeMethodObject, "methodWithParameters", new ParameterList(
parameter1, parameter2));
assertEquals("Wrong return value", parameter1 + parameter2, returnValue);
returnValue = (String) Reflection.invokeMethod(invokeMethodObject, "methodWithParameters", new ParameterList(
new Parameter(String.class, null), parameter2));
assertEquals("Wrong return value", null + parameter2, returnValue);
InvokeMethodClass.calledVoidMethod = false;
Object voidReturnValue = Reflection.invokeMethod(invokeMethodObject, "voidMethod");
assertTrue("Void method hasn't been called", InvokeMethodClass.calledVoidMethod);
assertNull("Void method returned a non-null value", voidReturnValue);
String superClassMethodReturnValue = (String) Reflection.invokeMethod(Object.class, invokeMethodObject,
"toString");
assertNotNull("toString method returned null", superClassMethodReturnValue);
}
public void testInvokeMethodForClasses() {
String returnValue = (String) Reflection.invokeMethod(InvokeMethodClass.class, "staticMethodWithoutParameters");
assertEquals("Wrong return value", "Called staticMethodWithoutParameters!", returnValue);
String parameter1 = "first parameter";
String parameter2 = "second parameter";
returnValue = (String) Reflection.invokeMethod(InvokeMethodClass.class, "staticMethodWithParameters",
new ParameterList(parameter1, parameter2));
assertEquals("Wrong return value", parameter1 + parameter2, returnValue);
parameter1 = null;
returnValue = (String) Reflection.invokeMethod(InvokeMethodClass.class, "staticMethodWithParameters",
new ParameterList(new Parameter(String.class, parameter1), parameter2));
assertEquals("Wrong return value", parameter1 + parameter2, returnValue);
InvokeMethodClass.calledVoidMethod = false;
Object voidReturnValue = Reflection.invokeMethod(InvokeMethodClass.class, "staticVoidMethod");
assertTrue("Void method hasn't been called", InvokeMethodClass.calledVoidMethod);
assertNull("Void method returned a non-null value", voidReturnValue);
}
public void testInvokeMethodWithAutoBoxingParameter() {
InvokeMethodClass invokeMethodObject = new InvokeMethodClass();
float returnValue = (Float) Reflection.invokeMethod(invokeMethodObject, "methodWithPrimitiveParameter",
new ParameterList(3.14f));
assertEquals("Method with primitive float parameter hasn't been called", returnValue, 1.0f);
Float floatObject = Float.valueOf(1.234f);
returnValue = (Float) Reflection.invokeMethod(invokeMethodObject, "methodWithPrimitiveParameter",
new ParameterList(floatObject));
assertEquals("Method with float object parameter hasn't been converted into primitive", returnValue, 1.0f);
returnValue = (Float) Reflection.invokeMethod(invokeMethodObject, "methodWithWrappedPrimitiveParameter",
new ParameterList(new Parameter(Float.class, Float.valueOf(3.14f))));
assertEquals("Method with float object parameter hasn't been called", returnValue, -1.0f);
}
public void testConvertObjectsIntoPrimitives() {
ParameterList parameterList = new ParameterList(Boolean.TRUE, Byte.valueOf((byte) 1),
Character.valueOf('c'), Double.valueOf(1.0), Float.valueOf(1.0f), Integer.valueOf(1), Long.valueOf(1L),
Short.valueOf((short) 1));
Class<?>[] primitiveObjectsClass = (Class<?>[]) Reflection.getPrivateField(parameterList, "types");
Class<?>[] expectedPrimitiveObjectsClasses = new Class<?>[] { boolean.class, byte.class, char.class,
double.class, float.class, int.class, long.class, short.class };
assertTrue("Not all object classes are converted into primitve classes",
Arrays.deepEquals(expectedPrimitiveObjectsClasses, primitiveObjectsClass));
}
public void testInvokeMethodWithNullObject() {
Object nullObject = null;
try {
Reflection.invokeMethod(nullObject, "nullObjectsDontHaveMethods");
fail("Invoking method of a null object didn't cause an IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
try {
Reflection.invokeMethod(nullObject, "nullObjectsDontHaveMethods", new ParameterList("text"));
fail("Invoking method of a null object didn't cause an IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
try {
Reflection.invokeMethod(InvokeMethodClass.class, nullObject, "voidMethod");
fail("Invoking method of a null object didn't cause an IllegalArgumentException");
} catch (RuntimeException runtimeException) {
assertEquals("Wrong exception has been thrown", runtimeException.getCause().getClass(),
NullPointerException.class);
}
}
public void testInvokeMethodWithWrongParameters() {
InvokeMethodClass invokeMethodObject = new InvokeMethodClass();
try {
Reflection.invokeMethod(String.class, Integer.valueOf(1), "toString");
fail("Integer is a sub class of String");
} catch (RuntimeException runtimeException) {
assertEquals("Wrong exception has been thrown", runtimeException.getCause().getClass(),
IllegalArgumentException.class);
}
String parameter1 = "String";
String parameter2 = null;
try {
Reflection.invokeMethod(invokeMethodObject, "methodWithParameters", new ParameterList(parameter1,
parameter2));
fail("Found not existing method signature");
} catch (RuntimeException expected) {
}
}
private static class InvokeMethodClass {
private static boolean calledVoidMethod = false;
@SuppressWarnings("unused")
private static String staticMethodWithoutParameters() {
return "Called staticMethodWithoutParameters!";
}
@SuppressWarnings("unused")
private static String staticMethodWithParameters(String param1, String param2) {
return param1 + param2;
}
@SuppressWarnings("unused")
private static void staticVoidMethod() {
calledVoidMethod = true;
}
@SuppressWarnings("unused")
private String methodWithoutParameters() {
return "Called methodWithoutParameters!";
}
@SuppressWarnings("unused")
private String methodWithParameters(String param1, String param2) {
return param1 + param2;
}
@SuppressWarnings("unused")
private void voidMethod() {
calledVoidMethod = true;
}
@SuppressWarnings("unused")
private float methodWithPrimitiveParameter(float parameter) {
return 1.0f;
}
@SuppressWarnings("unused")
private float methodWithWrappedPrimitiveParameter(Float parameter) {
return -1.0f;
}
}
private class SuperClass {
// CHECKSTYLE DISABLE MemberNameCheck FOR 2 LINES
private final float SECRET_FLOAT = 3.1415f;
protected byte secretByte = 32;
}
private class SubClass extends SuperClass {
// CHECKSTYLE DISABLE MemberNameCheck FOR 3 LINES
private static final char SECRET_STATIC_CHAR = 'c';
private final int SECRET_INTEGER = 42;
private String secretString = "This is a secret string!";
}
}