aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/junitparams/internal/InvokeParameterisedMethod.java
diff options
context:
space:
mode:
authorPaul Duffin <paulduffin@google.com>2016-07-12 11:23:47 +0100
committerPaul Duffin <paulduffin@google.com>2016-07-20 15:24:23 +0100
commitfd1f9491413fcdbfae3cbd43651db31fdabce41a (patch)
tree58f3125a8ac5aae2139281886fca5b80f53cf853 /src/main/java/junitparams/internal/InvokeParameterisedMethod.java
parent896c3e9298b039ead2b21a6377a01a63df7f20f7 (diff)
downloadplatform_external_junit-params-fd1f9491413fcdbfae3cbd43651db31fdabce41a.tar.gz
platform_external_junit-params-fd1f9491413fcdbfae3cbd43651db31fdabce41a.tar.bz2
platform_external_junit-params-fd1f9491413fcdbfae3cbd43651db31fdabce41a.zip
Initial checkin of JUnitParams-1.0.5
Adds README.version, README.google, MODULE_LICENSE_APACHE2 files as required by the process (see b/30087411). The code does not yet compile; it requires patching to work with Android API and JUnit 4.10. Those patches will be added in separate commits to make it easy to identify the Android specific changes. All the changes will be submitted together. Bug: 30244565 Change-Id: Icf556377478c3afdd644c5e4db0ff18898f496ae Test: Once it compiles the tests will be run.
Diffstat (limited to 'src/main/java/junitparams/internal/InvokeParameterisedMethod.java')
-rw-r--r--src/main/java/junitparams/internal/InvokeParameterisedMethod.java237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/main/java/junitparams/internal/InvokeParameterisedMethod.java b/src/main/java/junitparams/internal/InvokeParameterisedMethod.java
new file mode 100644
index 0000000..34024d5
--- /dev/null
+++ b/src/main/java/junitparams/internal/InvokeParameterisedMethod.java
@@ -0,0 +1,237 @@
+package junitparams.internal;
+
+import java.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+import junitparams.converters.ConversionFailedException;
+import junitparams.converters.ConvertParam;
+import junitparams.converters.ParamAnnotation;
+import junitparams.converters.ParamConverter;
+
+/**
+ * JUnit invoker for parameterised test methods
+ *
+ * @author Pawel Lipinski
+ */
+public class InvokeParameterisedMethod extends Statement {
+
+ private final Object[] params;
+ private final FrameworkMethod testMethod;
+ private final Object testClass;
+ private final String uniqueMethodId;
+
+ public InvokeParameterisedMethod(FrameworkMethod testMethod, Object testClass, Object params, int paramSetIdx) {
+ this.testMethod = testMethod;
+ this.testClass = testClass;
+ this.uniqueMethodId = Utils.uniqueMethodId(paramSetIdx - 1, params, testMethod.getName());
+ try {
+ if (params instanceof String)
+ this.params = castParamsFromString((String) params);
+ else {
+ this.params = castParamsFromObjects(params);
+ }
+ } catch (ConversionFailedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Object[] castParamsFromString(String params) throws ConversionFailedException {
+ Object[] columns = null;
+ try {
+ columns = Utils.splitAtCommaOrPipe(params);
+ columns = castParamsUsingConverters(columns);
+ } catch (RuntimeException e) {
+ new IllegalArgumentException("Cannot parse parameters. Did you use ',' or '|' as column separator? "
+ + params, e).printStackTrace();
+ }
+
+ return columns;
+ }
+
+ private Object[] castParamsFromObjects(Object params) throws ConversionFailedException {
+ Object[] paramset = Utils.safelyCastParamsToArray(params);
+
+ try {
+ return castParamsUsingConverters(paramset);
+ } catch (ConversionFailedException e) {
+ throw e;
+ } catch (Exception e) {
+ Class<?>[] typesOfParameters = createArrayOfTypesOf(paramset);
+ Object resultParam = createObjectOfExpectedTypeBasedOnParams(paramset, typesOfParameters);
+ return new Object[]{resultParam};
+ }
+ }
+
+ private Object createObjectOfExpectedTypeBasedOnParams(Object[] paramset, Class<?>[] typesOfParameters) {
+ Object resultParam;
+
+ try {
+ if (testMethod.getMethod().getParameterTypes()[0].isArray()) {
+ resultParam = Array.newInstance(typesOfParameters[0], paramset.length);
+ for (int i = 0; i < paramset.length; i++) {
+ ((Object[]) resultParam)[i] = paramset[i];
+ }
+ } else {
+ resultParam = testMethod.getMethod().getParameterTypes()[0].getConstructor(typesOfParameters).newInstance(paramset);
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("While trying to create object of class " + testMethod.getMethod().getParameterTypes()[0]
+ + " could not find constructor with arguments matching (type-wise) the ones given in parameters.", e);
+ }
+ return resultParam;
+ }
+
+ private Class<?>[] createArrayOfTypesOf(Object[] paramset) {
+ Class<?>[] parametersBasedOnValues = new Class<?>[paramset.length];
+ for (int i = 0; i < paramset.length; i++) {
+ parametersBasedOnValues[i] = paramset[i].getClass();
+ }
+ return parametersBasedOnValues;
+ }
+
+ private Object[] castParamsUsingConverters(Object[] columns) throws ConversionFailedException {
+ Class<?>[] expectedParameterTypes = testMethod.getMethod().getParameterTypes();
+
+ if (testMethodParamsHasVarargs(columns, expectedParameterTypes)) {
+ columns = columnsWithVarargs(columns, expectedParameterTypes);
+ }
+
+ Annotation[][] parameterAnnotations = testMethod.getMethod().getParameterAnnotations();
+ verifySameSizeOfArrays(columns, expectedParameterTypes);
+ columns = castAllParametersToProperTypes(columns, expectedParameterTypes, parameterAnnotations);
+ return columns;
+ }
+
+ private Object[] columnsWithVarargs(Object[] columns, Class<?>[] expectedParameterTypes) {
+ Object[] allParameters = standardParameters(columns, expectedParameterTypes);
+ allParameters[allParameters.length - 1] = varargsParameters(columns, expectedParameterTypes);
+ return allParameters;
+ }
+
+ private Object[] varargsParameters(Object[] columns, Class<?>[] expectedParameterTypes) {
+ Class<?> varArgType = expectedParameterTypes[expectedParameterTypes.length - 1].getComponentType();
+ Object[] varArgsParameters = (Object[]) Array.newInstance(varArgType, columns.length - expectedParameterTypes.length + 1);
+ for (int i = 0; i < varArgsParameters.length; i++) {
+ varArgsParameters[i] = columns[i + expectedParameterTypes.length - 1];
+ }
+ return varArgsParameters;
+ }
+
+ private Object[] standardParameters(Object[] columns, Class<?>[] expectedParameterTypes) {
+ Object[] standardParameters = new Object[expectedParameterTypes.length];
+ for (int i = 0; i < standardParameters.length - 1; i++) {
+ standardParameters[i] = columns[i];
+ }
+ return standardParameters;
+ }
+
+ private boolean testMethodParamsHasVarargs(Object[] columns, Class<?>[] expectedParameterTypes) {
+ int last = expectedParameterTypes.length - 1;
+ if (columns[last] == null) {
+ return false;
+ }
+ return expectedParameterTypes.length <= columns.length
+ && expectedParameterTypes[last].isArray()
+ && expectedParameterTypes[last].getComponentType().equals(columns[last].getClass());
+ }
+
+ private Object[] castAllParametersToProperTypes(Object[] columns, Class<?>[] expectedParameterTypes,
+ Annotation[][] parameterAnnotations) throws ConversionFailedException {
+ Object[] result = new Object[columns.length];
+
+ for (int i = 0; i < columns.length; i++) {
+ if (parameterAnnotations[i].length == 0)
+ result[i] = castParameterDirectly(columns[i], expectedParameterTypes[i]);
+ else
+ result[i] = castParameterUsingConverter(columns[i], parameterAnnotations[i]);
+ }
+
+ return result;
+ }
+
+ private Object castParameterUsingConverter(Object param, Annotation[] annotations) throws ConversionFailedException {
+ for (Annotation annotation : annotations) {
+ if (ParamAnnotation.matches(annotation)) {
+ return ParamAnnotation.convert(annotation, param);
+ }
+ if (annotation.annotationType().isAssignableFrom(ConvertParam.class)) {
+ Class<? extends ParamConverter<?>> converterClass = ((ConvertParam) annotation).value();
+ String options = ((ConvertParam) annotation).options();
+ try {
+ return converterClass.newInstance().convert(param, options);
+ } catch (ConversionFailedException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException("Your ParamConverter class must have a public no-arg constructor!", e);
+ }
+ }
+ }
+ return param;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object castParameterDirectly(Object object, Class clazz) {
+ if (object == null || clazz.isInstance(object) || (!(object instanceof String) && clazz.isPrimitive()))
+ return object;
+ if (clazz.isEnum())
+ return (Enum.valueOf(clazz, (String) object));
+ if (clazz.isAssignableFrom(String.class))
+ return object.toString();
+ if (clazz.isAssignableFrom(Class.class))
+ try {
+ return Class.forName((String) object);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Parameter class (" + object + ") not found", e);
+ }
+ if (clazz.isAssignableFrom(Integer.TYPE) || clazz.isAssignableFrom(Integer.class))
+ return Integer.parseInt((String) object);
+ if (clazz.isAssignableFrom(Short.TYPE) || clazz.isAssignableFrom(Short.class))
+ return Short.parseShort((String) object);
+ if (clazz.isAssignableFrom(Long.TYPE) || clazz.isAssignableFrom(Long.class))
+ return Long.parseLong((String) object);
+ if (clazz.isAssignableFrom(Float.TYPE) || clazz.isAssignableFrom(Float.class))
+ return Float.parseFloat((String) object);
+ if (clazz.isAssignableFrom(Double.TYPE) || clazz.isAssignableFrom(Double.class))
+ return Double.parseDouble((String) object);
+ if (clazz.isAssignableFrom(Boolean.TYPE) || clazz.isAssignableFrom(Boolean.class))
+ return Boolean.parseBoolean((String) object);
+ if (clazz.isAssignableFrom(Character.TYPE) || clazz.isAssignableFrom(Character.class))
+ return object.toString().charAt(0);
+ if (clazz.isAssignableFrom(Byte.TYPE) || clazz.isAssignableFrom(Byte.class))
+ return Byte.parseByte((String) object);
+ if (clazz.isAssignableFrom(BigDecimal.class))
+ return new BigDecimal((String) object);
+ PropertyEditor editor = PropertyEditorManager.findEditor(clazz);
+ if (editor != null) {
+ editor.setAsText((String) object);
+ return editor.getValue();
+ }
+ throw new IllegalArgumentException("Parameter type (" + clazz.getName() + ") cannot be handled!" +
+ " Only primitive types, BigDecimals and Strings can be used.");
+ }
+
+ private void verifySameSizeOfArrays(Object[] columns, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != columns.length)
+ throw new IllegalArgumentException(
+ "Number of parameters inside @Parameters annotation doesn't match the number of test method parameters.\nThere are "
+ + columns.length + " parameters in annotation, while there's " + parameterTypes.length + " parameters in the "
+ + testMethod.getName() + " method.");
+ }
+
+ boolean matchesDescription(Description description) {
+ return description.hashCode() == uniqueMethodId.hashCode();
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ testMethod.invokeExplosively(testClass, params == null ? new Object[]{params} : params);
+ }
+
+}