blob: 0d122d20b2d863e2731b4aed58df1f125be2de72 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.base.test.util.parameter;
import junit.framework.TestCase;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* The annotation for an individual parameter in a {@link ParameterizedTest}.
*
* Contains all annotations required to run tests ParameterizedTests.
*/
public @interface Parameter {
String tag();
Argument[] arguments() default {};
/**
* The annotation for an individual argument in a {@link Parameter}.
*/
@interface Argument {
String name();
String stringVar() default Parameter.ArgumentDefault.STRING;
String[] stringArray() default {};
int intVar() default Parameter.ArgumentDefault.INT;
int[] intArray() default {};
}
/**
* Default values for {@link Parameter.Argument}s.
*
* TODO (crbug.com/520232): Move to within {@link Parameter.Argument} and rename to Default
* when fixed.
*/
final class ArgumentDefault {
public static final String STRING = "";
public static final int INT = 0;
}
/**
* The tool to read Parameter related annotations.
*/
class Reader {
private Class mAnnotatedTestClass;
private AnnotatedElement mAnnotatedTestMethod;
private ParameterizedTest mParameterizedTest;
public Reader(TestCase testCase) {
try {
mAnnotatedTestClass = testCase.getClass();
mAnnotatedTestMethod = testCase.getClass().getMethod(testCase.getName());
} catch (NoSuchMethodException e) {
// ignore
}
}
/**
* Gets the {@link ParameterizedTest}s for the current test.
*
* @return a list of all the {@link ParameterizedTest}s for the current test.
*/
public List<ParameterizedTest> getParameterizedTests() {
return new ArrayList<ParameterizedTest>(getParameterizedTestsImpl());
}
/**
* Gets the {@link ParameterizedTest}s for the current test as immutable list.
*
* @return a list of all the {@link ParameterizedTest}s for the current test.
*/
private List<ParameterizedTest> getParameterizedTestsImpl() {
// Note: this must be aligned with Python code in
// instrumentation_test_instance.ParseCommandLineFlagParameters (regarding priority of
// ParameterizedTest.Set vs. ParameterizedTest) and in test_jar._GetProguardData
// (regarding composition of method annotations with class and superclasses
// annotations). Composition precedes selecting the annotation to process.
if (mAnnotatedTestMethod.isAnnotationPresent(ParameterizedTest.Set.class)) {
return Arrays.asList(getParameterizedTestSet(mAnnotatedTestMethod).tests());
}
AnnotatedElement classWithAnnotation = findClassWithAnnotation(
mAnnotatedTestClass, ParameterizedTest.Set.class);
if (classWithAnnotation != null) {
return Arrays.asList(getParameterizedTestSet(classWithAnnotation).tests());
}
if (mAnnotatedTestMethod.isAnnotationPresent(ParameterizedTest.class)) {
return Collections.singletonList(getParameterizedTest(mAnnotatedTestMethod));
}
classWithAnnotation = findClassWithAnnotation(
mAnnotatedTestClass, ParameterizedTest.class);
if (classWithAnnotation != null) {
return Collections.singletonList(getParameterizedTest(classWithAnnotation));
}
return Collections.emptyList();
}
/**
* Finds a class with the given annotation class starting from the given clazz.
*
* @return the class as {@link AnnotatedElement} or null if the class is not found.
*/
private AnnotatedElement findClassWithAnnotation(
Class<?> clazz, Class<? extends Annotation> annotationClass) {
if (clazz == null || clazz.isAnnotationPresent(annotationClass)) {
return clazz;
} else {
return findClassWithAnnotation(clazz.getSuperclass(), annotationClass);
}
}
/**
* Gets the {@link ParameterizedTest} annotation of the current test.
*
* @return a {@link ParameterizedTest} of the current test's parameters.
*/
private ParameterizedTest getParameterizedTest(AnnotatedElement element) {
return element.getAnnotation(ParameterizedTest.class);
}
/**
* Gets the {@link ParameterizedTest.Set} annotation of the current test.
*
* @return a {@link ParameterizedTest.Set} of the current test's parameters.
*/
private ParameterizedTest.Set getParameterizedTestSet(AnnotatedElement element) {
return element.getAnnotation(ParameterizedTest.Set.class);
}
public boolean isParameterizedTest() {
return mAnnotatedTestMethod.isAnnotationPresent(ParameterizedTest.Set.class)
|| mAnnotatedTestMethod.isAnnotationPresent(ParameterizedTest.class)
|| findClassWithAnnotation(
mAnnotatedTestClass, ParameterizedTest.Set.class) != null
|| findClassWithAnnotation(
mAnnotatedTestClass, ParameterizedTest.class) != null;
}
public void setCurrentParameterizedTest(ParameterizedTest parameterizedTest) {
mParameterizedTest = parameterizedTest;
}
/**
* Gets a {@link Parameter} object for a given target parameter.
*
* @param targetParameter the name of the {@link Parameter} to get in the current
* parameterized test.
* @return the {@link Parameter} for a given {@link ParameterizedTest} with the
* targetParameter as its tag if it exists, otherwise returns null.
*/
public Parameter getParameter(String targetParameter) {
if (mParameterizedTest == null || targetParameter == null) {
return null;
}
for (Parameter parameter : mParameterizedTest.parameters()) {
if (targetParameter.equals(parameter.tag())) {
return parameter;
}
}
return null;
}
/**
* Gets the {@link Parameter.Argument} for a given {@link Parameter}.
*
* @param targetParameter the name of the {@link Parameter} to search for when looking for
* a {@link Parameter.Argument}.
* @param targetArgument the name of the {@link Parameter.Argument} to look for in the
* target {@link Parameter}.
* @return the {@link Parameter.Argument} for a given {@link ParameterizedTest} for the
* {@link Parameter} with the tag matching targetParameter and the argument name being
* targetArgument if it exists, otherwise returns null.
*/
public Parameter.Argument getParameterArgument(String targetParameter,
String targetArgument) {
Parameter parameter = getParameter(targetParameter);
return (parameter == null) ? null : getParameterArgument(parameter, targetArgument);
}
public static Parameter.Argument getParameterArgument(Parameter parameter,
String targetArgument) {
if (targetArgument == null) {
return null;
}
for (Parameter.Argument argument : parameter.arguments()) {
if (targetArgument.equals(argument.name())) {
return argument;
}
}
return null;
}
}
}