summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorskirmani <skirmani@google.com>2015-08-12 17:02:41 -0700
committerCommit bot <commit-bot@chromium.org>2015-08-13 00:03:24 +0000
commit01780b3cebecf652aa7d7cf41c781ba77d73aff8 (patch)
tree5b5c2ef7ba3dbf128ee14f14f99acabf452c9e18 /base
parent849f612a16c1a47fd037ee6ebcb31026032c1cbf (diff)
downloadchromium_src-01780b3cebecf652aa7d7cf41c781ba77d73aff8.zip
chromium_src-01780b3cebecf652aa7d7cf41c781ba77d73aff8.tar.gz
chromium_src-01780b3cebecf652aa7d7cf41c781ba77d73aff8.tar.bz2
Added Generic Parametrized Testing
Usage and Info in this doc: https://docs.google.com/a/google.com/document/d/1ItTezv49Idns-r_ZcIJNCLsc3xy0h1uwUMQjCJ9vcCM/edit?usp=sharing Added a ParameterizedTest annotion with ability to have extra setup and teardown functionality specific to parameters. Has an array of valid Parameter objects to run. Each Parameter object can have an array of ParameterArgument objects. ParameterArgument objects can be set to have a default, otherwise they are required. CQ-DEPEND=CL:1259253007 Review URL: https://codereview.chromium.org/1219683014 Cr-Commit-Position: refs/heads/master@{#343131}
Diffstat (limited to 'base')
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java46
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java108
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java360
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/parameter/BaseParameter.java80
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameter.java154
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameterizable.java15
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/parameter/ParameterizedTest.java32
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/parameter/parameters/MethodParameter.java21
8 files changed, 710 insertions, 106 deletions
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
index 7c7cdc9..9ce432b 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
@@ -7,6 +7,14 @@ package org.chromium.base.test;
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
+import org.chromium.base.test.util.parameter.BaseParameter;
+import org.chromium.base.test.util.parameter.Parameter;
+import org.chromium.base.test.util.parameter.Parameterizable;
+import org.chromium.base.test.util.parameter.parameters.MethodParameter;
+
+import java.util.HashMap;
+import java.util.Map;
+
/**
* Base class for all Activity-based Instrumentation tests.
*
@@ -15,10 +23,46 @@ import android.test.ActivityInstrumentationTestCase2;
* @param <T> The Activity type.
*/
public class BaseActivityInstrumentationTestCase<T extends Activity>
- extends ActivityInstrumentationTestCase2<T> {
+ extends ActivityInstrumentationTestCase2<T> implements Parameterizable {
+ private Parameter.Reader mParameterReader;
+ /**
+ * Creates a instance for running tests against an Activity of the given class.
+ *
+ * @param activityClass The type of activity that will be tested.
+ */
public BaseActivityInstrumentationTestCase(Class<T> activityClass) {
super(activityClass);
}
+ /**
+ * Creates the list of available parameters that inherited classes can use.
+ *
+ * @return a list of {@link BaseParameter} objects to set as the available parameters.
+ */
+ public Map<String, BaseParameter> getAvailableParameters() {
+ Map<String, BaseParameter> parameters = new HashMap<>();
+ parameters.put(MethodParameter.PARAMETER_TAG, new MethodParameter(getParameterReader()));
+ return parameters;
+ }
+
+ /**
+ * Setter method for {@link Parameter.Reader}.
+ *
+ * @param parameterReader the {@link Parameter.Reader} to set.
+ */
+ public void setParameterReader(Parameter.Reader parameterReader) {
+ mParameterReader = parameterReader;
+ }
+
+ /**
+ * Getter method for {@link Parameter.Reader} object to be used by test cases reading the
+ * parameter.
+ *
+ * @return the {@link Parameter.Reader} for the current {@link
+ * org.chromium.base.test.util.parameter.ParameterizedTest} being run.
+ */
+ protected Parameter.Reader getParameterReader() {
+ return mParameterReader;
+ }
}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
index cd202cc..35fe9b9 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -8,8 +8,6 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemClock;
import android.test.AndroidTestRunner;
import android.test.InstrumentationTestRunner;
import android.text.TextUtils;
@@ -17,17 +15,14 @@ import android.text.TextUtils;
import junit.framework.TestCase;
import junit.framework.TestResult;
-import org.chromium.base.CommandLine;
import org.chromium.base.Log;
import org.chromium.base.SysUtils;
-import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.BaseTestResult.SkipCheck;
import org.chromium.base.test.util.MinAndroidSdkLevel;
import org.chromium.base.test.util.Restriction;
import org.chromium.test.reporter.TestStatusListener;
import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
// TODO(jbudorick): Add support for on-device handling of timeouts.
/**
@@ -36,84 +31,12 @@ import java.util.List;
public class BaseInstrumentationTestRunner extends InstrumentationTestRunner {
private static final String TAG = "cr.base.test";
- private static final int SLEEP_INTERVAL = 50; // milliseconds
- private static final int WAIT_DURATION = 5000; // milliseconds
-
- /**
- * An interface for classes that check whether a test case should be skipped.
- */
- public interface SkipCheck {
- /**
- * Checks whether the given test case should be skipped.
- *
- * @param testCase The test case to check.
- * @return Whether the test case should be skipped.
- */
- public boolean shouldSkip(TestCase testCase);
- }
-
- /**
- * A test result that can skip tests.
- */
- public class BaseTestResult extends TestResult {
-
- private final List<SkipCheck> mSkipChecks;
-
- /**
- * Creates an instance of BaseTestResult.
- */
- public BaseTestResult() {
- mSkipChecks = new ArrayList<SkipCheck>();
- }
-
- /**
- * Adds a check for whether a test should run.
- *
- * @param skipCheck The check to add.
- */
- public void addSkipCheck(SkipCheck skipCheck) {
- mSkipChecks.add(skipCheck);
- }
-
- private boolean shouldSkip(final TestCase test) {
- for (SkipCheck s : mSkipChecks) {
- if (s.shouldSkip(test)) return true;
- }
- return false;
- }
-
- @Override
- protected void run(final TestCase test) {
- if (shouldSkip(test)) {
- startTest(test);
-
- Bundle skipResult = new Bundle();
- skipResult.putString("class", test.getClass().getName());
- skipResult.putString("test", test.getName());
- skipResult.putBoolean("test_skipped", true);
- sendStatus(0, skipResult);
-
- endTest(test);
- } else {
- try {
- CommandLine.reset();
- CommandLineFlags.setUp(
- BaseInstrumentationTestRunner.this.getTargetContext(),
- test.getClass().getMethod(test.getName()));
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "Unable to set up CommandLineFlags", e);
- }
- super.run(test);
- }
- }
- }
-
@Override
protected AndroidTestRunner getAndroidTestRunner() {
AndroidTestRunner runner = new AndroidTestRunner() {
@Override
protected TestResult createTestResult() {
- BaseTestResult r = new BaseTestResult();
+ BaseTestResult r = new BaseTestResult(BaseInstrumentationTestRunner.this);
addSkipChecks(r);
return r;
}
@@ -184,7 +107,7 @@ public class BaseInstrumentationTestRunner extends InstrumentationTestRunner {
public static class MinAndroidSdkLevelSkipCheck implements SkipCheck {
/**
- * If {@link org.chromium.base.test.util.MinAndroidSdkLevel} is present, checks its value
+ * If {@link MinAndroidSdkLevel} is present, checks its value
* against the device's SDK level.
*
* @param testCase The test to check.
@@ -205,29 +128,4 @@ public class BaseInstrumentationTestRunner extends InstrumentationTestRunner {
return false;
}
}
-
- /**
- * Gets the target context.
- *
- * On older versions of Android, getTargetContext() may initially return null, so we have to
- * wait for it to become available.
- *
- * @return The target {@link android.content.Context} if available; null otherwise.
- */
- @Override
- public Context getTargetContext() {
- Context targetContext = super.getTargetContext();
- try {
- long startTime = SystemClock.uptimeMillis();
- // TODO(jbudorick): Convert this to CriteriaHelper once that moves to base/.
- while (targetContext == null
- && SystemClock.uptimeMillis() - startTime < WAIT_DURATION) {
- Thread.sleep(SLEEP_INTERVAL);
- targetContext = super.getTargetContext();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while attempting to initialize the command line.");
- }
- return targetContext;
- }
}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java b/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java
new file mode 100644
index 0000000..5802f40
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java
@@ -0,0 +1,360 @@
+// 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;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.SystemClock;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+import org.chromium.base.Log;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.parameter.BaseParameter;
+import org.chromium.base.test.util.parameter.Parameter;
+import org.chromium.base.test.util.parameter.Parameterizable;
+import org.chromium.base.test.util.parameter.ParameterizedTest;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * A test result that can skip tests.
+ */
+public class BaseTestResult extends TestResult {
+ private static final String TAG = "cr.base.test";
+
+ private static final int SLEEP_INTERVAL_MS = 50;
+ private static final int WAIT_DURATION_MS = 5000;
+
+ private final Instrumentation mInstrumentation;
+ private final List<SkipCheck> mSkipChecks;
+
+ /**
+ * Creates an instance of BaseTestResult.
+ */
+ public BaseTestResult(Instrumentation instrumentation) {
+ mSkipChecks = new ArrayList<>();
+ mInstrumentation = instrumentation;
+ }
+
+ /**
+ * An interface for classes that check whether a test case should be skipped.
+ */
+ public interface SkipCheck {
+ /**
+ *
+ * Checks whether the given test case should be skipped.
+ *
+ * @param testCase The test case to check.
+ * @return Whether the test case should be skipped.
+ */
+ boolean shouldSkip(TestCase testCase);
+ }
+
+ /**
+ * Adds a check for whether a test should run.
+ *
+ * @param skipCheck The check to add.
+ */
+ public void addSkipCheck(SkipCheck skipCheck) {
+ mSkipChecks.add(skipCheck);
+ }
+
+ protected boolean shouldSkip(TestCase test) {
+ for (SkipCheck s : mSkipChecks) {
+ if (s.shouldSkip(test)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void run(TestCase test) {
+ if (shouldSkip(test)) {
+ startTest(test);
+
+ Bundle skipResult = new Bundle();
+ skipResult.putString("class", test.getClass().getName());
+ skipResult.putString("test", test.getName());
+ skipResult.putBoolean("test_skipped", true);
+ mInstrumentation.sendStatus(0, skipResult);
+
+ endTest(test);
+ } else {
+ try {
+ CommandLineFlags.setUp(
+ getTargetContext(),
+ test.getClass().getMethod(test.getName()));
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Unable to set up CommandLineFlags", e);
+ }
+
+ if (test instanceof Parameterizable) {
+ try {
+ runParameterized(test);
+ } catch (ThreadDeath e) {
+ Log.e(TAG, "Parameterized test run failed: %s", e);
+ }
+ } else {
+ super.run(test);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T extends TestCase & Parameterizable> void runParameterized(TestCase test)
+ throws ThreadDeath {
+ T testCase = (T) test;
+
+ // Prepare test.
+ Parameter.Reader parameterReader = new Parameter.Reader(test);
+ testCase.setParameterReader(parameterReader);
+ List<ParameterizedTest> parameterizedTests = parameterReader.getParameterizedTests();
+ List<ParameterError> errors = new ArrayList<>();
+ List<ParameterError> failures = new ArrayList<>();
+ Map<String, BaseParameter> availableParameters = testCase.getAvailableParameters();
+
+ if (parameterizedTests.isEmpty()) {
+ super.run(test);
+ } else {
+ // Start test.
+ startTest(testCase);
+ for (ParameterizedTest parameterizedTest : parameterizedTests) {
+ parameterReader.setCurrentParameterizedTest(parameterizedTest);
+ try {
+ setUpParameters(availableParameters, parameterReader);
+ testCase.runBare();
+ tearDownParameters(availableParameters, parameterReader);
+ } catch (AssertionFailedError e) {
+ failures.add(new ParameterError(e, parameterizedTest));
+ } catch (ThreadDeath e) {
+ throw e;
+ } catch (Throwable e) {
+ errors.add(new ParameterError(e, parameterizedTest));
+ }
+ }
+
+ // Generate failures and errors.
+ if (!failures.isEmpty()) {
+ addFailure(test, new ParameterizedTestFailure(failures));
+ }
+ if (!errors.isEmpty()) {
+ addError(test, new ParameterizedTestError(errors));
+ }
+
+ // End test.
+ endTest(testCase);
+ }
+ }
+
+ private static <T extends TestCase & Parameterizable> void setUpParameters(
+ Map<String, BaseParameter> availableParameters, Parameter.Reader reader)
+ throws Exception {
+ for (Entry<String, BaseParameter> entry : availableParameters.entrySet()) {
+ if (reader.getParameter(entry.getValue().getTag()) != null) {
+ entry.getValue().setUp();
+ }
+ }
+ }
+
+ private static <T extends TestCase & Parameterizable> void tearDownParameters(
+ Map<String, BaseParameter> availableParameters, Parameter.Reader reader)
+ throws Exception {
+ for (Entry<String, BaseParameter> entry : availableParameters.entrySet()) {
+ if (reader.getParameter(entry.getValue().getTag()) != null) {
+ entry.getValue().tearDown();
+ }
+ }
+ }
+
+ private static class ParameterError {
+ private final Throwable mThrowable;
+ private final ParameterizedTest mParameterizedTest;
+
+ public ParameterError(Throwable throwable, ParameterizedTest parameterizedTest) {
+ mThrowable = throwable;
+ mParameterizedTest = parameterizedTest;
+ }
+
+ private Throwable getThrowable() {
+ return mThrowable;
+ }
+
+ private ParameterizedTest getParameterizedTest() {
+ return mParameterizedTest;
+ }
+ }
+
+ private static class ParameterizedTestFailure extends AssertionFailedError {
+ public ParameterizedTestFailure(List<ParameterError> failures) {
+ super(new ParameterizedTestError(failures).toString());
+ }
+ }
+
+ private static class ParameterizedTestError extends Exception {
+ private final List<ParameterError> mErrors;
+
+ public ParameterizedTestError(List<ParameterError> errors) {
+ mErrors = errors;
+ }
+
+ /**
+ * Error output is as follows.
+ *
+ * DEFINITIONS:
+ * {{ERROR}} is the standard error output from
+ * {@link ParameterError#getThrowable().toString()}.
+ * {{PARAMETER_TAG}} is the {@link Parameter#tag()} value associated with the parameter.
+ * {{ARGUMENT_NAME}} is the {@link Parameter.Argument#name()} associated with the argument.
+ * {{ARGUMENT_VALUE}} is the value associated with the {@link Parameter.Argument}. This can
+ * be a String, int, String[], or int[].
+ *
+ * With no {@link Parameter}:
+ * {{ERROR}} (with no parameters)
+ *
+ * With Single {@link Parameter} and no {@link Parameter.Argument}:
+ * {{ERROR}} (with parameters: {{PARAMETER_TAG}} with no arguments)
+ *
+ * With Single {@link Parameter} and one {@link Parameter.Argument}:
+ * {{ERROR}} (with parameters: {{PARAMETER_TAG}} with arguments:
+ * {{ARGUMENT_NAME}}={{ARGUMENT_VALUE}})
+ *
+ * With Single {@link Parameter} and multiple {@link Parameter.Argument}s:
+ * {{ERROR}} (with parameters: {{PARAMETER_TAG}} with arguments:
+ * {{ARGUMENT_NAME}}={{ARGUMENT_VALUE}}, {{ARGUMENT_NAME}}={{ARGUMENT_VALUE}}, ...)
+ *
+ * DEFINITION:
+ * {{PARAMETER_ERROR}} is the output of a single {@link Parameter}'s error. Format:
+ * {{PARAMETER_TAG}} with arguments: {{ARGUMENT_NAME}}={{ARGUMENT_NAME}}, ...
+ *
+ * With Multiple {@link Parameter}s:
+ * {{ERROR}} (with parameters: {{PARAMETER_ERROR}}; {{PARAMETER_ERROR}}; ...)
+ *
+ * There will be a trace after this. And this is shown for every possible {@link
+ * ParameterizedTest} that is failed in the {@link ParameterizedTest.Set} if there is one.
+ *
+ * @return the error message and trace of the test failures.
+ */
+ @Override
+ public String toString() {
+ if (mErrors.isEmpty()) return "\n";
+ StringBuilder builder = new StringBuilder();
+ Iterator<ParameterError> iter = mErrors.iterator();
+ if (iter.hasNext()) {
+ builder.append(createErrorBuilder(iter.next()));
+ }
+ while (iter.hasNext()) {
+ builder.append("\n").append(createErrorBuilder(iter.next()));
+ }
+ return builder.toString();
+ }
+
+ private static StringBuilder createErrorBuilder(ParameterError error) {
+ StringBuilder builder = new StringBuilder("\n").append(error.getThrowable().toString());
+ List<Parameter> parameters =
+ Arrays.asList(error.getParameterizedTest().parameters());
+ if (parameters.isEmpty()) {
+ builder.append(" (with no parameters)");
+ } else {
+ Iterator<Parameter> iter = parameters.iterator();
+ builder.append(" (with parameters: ").append(createParameterBuilder(iter.next()));
+ while (iter.hasNext()) {
+ builder.append("; ").append(createParameterBuilder(iter.next()));
+ }
+ builder.append(")");
+ }
+ return builder.append("\n").append(trace(error));
+ }
+
+ private static StringBuilder createParameterBuilder(Parameter parameter) {
+ StringBuilder builder = new StringBuilder(parameter.tag());
+ List<Parameter.Argument> arguments = Arrays.asList(parameter.arguments());
+ if (arguments.isEmpty()) {
+ builder.append(" with no arguments");
+ } else {
+ Iterator<Parameter.Argument> iter = arguments.iterator();
+ builder.append(" with arguments: ").append(createArgumentBuilder(iter.next()));
+ while (iter.hasNext()) {
+ builder.append(", ").append(createArgumentBuilder(iter.next()));
+ }
+ }
+ return builder;
+ }
+
+ private static StringBuilder createArgumentBuilder(Parameter.Argument argument) {
+ StringBuilder builder = new StringBuilder(argument.name()).append("=");
+ if (!Parameter.ArgumentDefault.STRING.equals(argument.stringVar())) {
+ builder.append(argument.stringVar());
+ } else if (Parameter.ArgumentDefault.INT != argument.intVar()) {
+ builder.append(argument.intVar());
+ } else if (argument.stringArray().length > 0) {
+ builder.append(Arrays.toString(argument.stringArray()));
+ } else if (argument.intArray().length > 0) {
+ builder.append(Arrays.toString(argument.intArray()));
+ }
+ return builder;
+ }
+
+ /**
+ * @return the trace without the error message
+ */
+ private static StringBuilder trace(ParameterError error) {
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter writer = new PrintWriter(stringWriter);
+ error.getThrowable().printStackTrace(writer);
+ StringBuilder builder = new StringBuilder(stringWriter.getBuffer());
+ return trim(deleteFirstLine(builder));
+ }
+
+ private static StringBuilder deleteFirstLine(StringBuilder builder) {
+ return builder.delete(0, builder.indexOf("\n") + 1);
+ }
+
+ private static StringBuilder trim(StringBuilder sb) {
+ if (sb == null || sb.length() == 0) return sb;
+ for (int i = sb.length() - 1; i >= 0; i--) {
+ if (Character.isWhitespace(sb.charAt(i))) {
+ sb.deleteCharAt(i);
+ } else {
+ return sb;
+ }
+ }
+ return sb;
+ }
+ }
+
+ /**
+ * Gets the target context.
+ *
+ * On older versions of Android, getTargetContext() may initially return null, so we have to
+ * wait for it to become available.
+ *
+ * @return The target {@link Context} if available; null otherwise.
+ */
+ public Context getTargetContext() {
+ Context targetContext = mInstrumentation.getTargetContext();
+ try {
+ long startTime = SystemClock.uptimeMillis();
+ // TODO(jbudorick): Convert this to CriteriaHelper once that moves to base/.
+ while (targetContext == null
+ && SystemClock.uptimeMillis() - startTime < WAIT_DURATION_MS) {
+ Thread.sleep(SLEEP_INTERVAL_MS);
+ targetContext = mInstrumentation.getTargetContext();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while attempting to initialize the command line.");
+ }
+ return targetContext;
+ }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/BaseParameter.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/BaseParameter.java
new file mode 100644
index 0000000..bc4c8e4
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/BaseParameter.java
@@ -0,0 +1,80 @@
+// 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;
+
+/**
+ * The attributes of a single parameter.
+ */
+public class BaseParameter {
+ private final String mTag;
+ private final Parameter.Reader mParameterReader;
+
+ public BaseParameter(String tag, Parameter.Reader parameterReader) {
+ mTag = tag;
+ mParameterReader = parameterReader;
+ }
+
+ public String getTag() {
+ return mTag;
+ }
+
+ public String getStringArgument(String argumentName, String defaultString) {
+ Parameter.Argument parameterArgument = getArgument(argumentName);
+ return parameterArgument != null ? parameterArgument.stringVar() : defaultString;
+ }
+
+ public String getStringArgument(String argumentName) {
+ Parameter.Argument parameterArgument = getArgument(argumentName);
+ checkArgumentExists(parameterArgument);
+ return parameterArgument.stringVar();
+ }
+
+ public int getIntArgument(String argumentName, int defaultInt) {
+ Parameter.Argument parameterArgument = getArgument(argumentName);
+ return parameterArgument != null ? parameterArgument.intVar() : defaultInt;
+ }
+
+ public int getIntArgument(String argumentName) {
+ Parameter.Argument parameterArgument = getArgument(argumentName);
+ checkArgumentExists(parameterArgument);
+ return parameterArgument.intVar();
+ }
+
+ public String[] getStringArrayArgument(String argumentName, String[] defaultStringArray) {
+ Parameter.Argument parameterArgument = getArgument(argumentName);
+ return parameterArgument != null ? parameterArgument.stringArray() : defaultStringArray;
+ }
+
+ public String[] getStringArrayArgument(String argumentName) {
+ Parameter.Argument parameterArgument = getArgument(argumentName);
+ checkArgumentExists(parameterArgument);
+ return parameterArgument.stringArray();
+ }
+
+ public int[] getIntArrayArgument(String argumentName, int[] defaultIntArray) {
+ Parameter.Argument parameterArgument = getArgument(argumentName);
+ return parameterArgument != null ? parameterArgument.intArray() : defaultIntArray;
+ }
+
+ public int[] getIntArrayArgument(String argumentName) {
+ Parameter.Argument parameterArgument = getArgument(argumentName);
+ checkArgumentExists(parameterArgument);
+ return parameterArgument.intArray();
+ }
+
+ private Parameter.Argument getArgument(String argumentName) {
+ return mParameterReader.getParameterArgument(getTag(), argumentName);
+ }
+
+ private static void checkArgumentExists(Parameter.Argument parameterArgument) {
+ if (parameterArgument == null) {
+ throw new IllegalArgumentException("Argument must be specified");
+ }
+ }
+
+ public void setUp() throws Exception {}
+
+ public void tearDown() throws Exception {}
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameter.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameter.java
new file mode 100644
index 0000000..5559a56
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameter.java
@@ -0,0 +1,154 @@
+// 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.reflect.AnnotatedElement;
+import java.util.ArrayList;
+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 AnnotatedElement mAnnotatedElement;
+ private ParameterizedTest mParameterizedTest;
+
+ public Reader(TestCase testCase) {
+ try {
+ mAnnotatedElement = 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() {
+ List<ParameterizedTest> parameterizedTests = new ArrayList<>();
+ if (mAnnotatedElement.isAnnotationPresent(ParameterizedTest.Set.class)) {
+ Collections.addAll(parameterizedTests, getParameterizedTestSet().tests());
+ } else if (mAnnotatedElement.isAnnotationPresent(ParameterizedTest.class)) {
+ parameterizedTests.add(getParameterizedTest());
+ }
+ return parameterizedTests;
+ }
+
+
+ /**
+ * Gets the {@link ParameterizedTest} annotation of the current test.
+ *
+ * @return a {@link ParameterizedTest} of the current test's parameters.
+ */
+ private ParameterizedTest getParameterizedTest() {
+ return mAnnotatedElement.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() {
+ return mAnnotatedElement.getAnnotation(ParameterizedTest.Set.class);
+ }
+
+ public boolean isParameterizedTest() {
+ return mAnnotatedElement.isAnnotationPresent(ParameterizedTest.class)
+ || mAnnotatedElement.isAnnotationPresent(ParameterizedTest.Set.class);
+ }
+
+ 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;
+ }
+ }
+}
+
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameterizable.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameterizable.java
new file mode 100644
index 0000000..b271430
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/Parameterizable.java
@@ -0,0 +1,15 @@
+// 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 java.util.Map;
+
+/**
+ * An interface to implement on test cases to run {@link ParameterizedTest}s.
+ */
+public interface Parameterizable {
+ Map<String, BaseParameter> getAvailableParameters();
+ void setParameterReader(Parameter.Reader parameterReader);
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/ParameterizedTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/ParameterizedTest.java
new file mode 100644
index 0000000..65e929f
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/ParameterizedTest.java
@@ -0,0 +1,32 @@
+// 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 java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The annotation for an individual set of {@link Parameter}s to run on a single test.
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface ParameterizedTest {
+ Parameter[] parameters() default {};
+
+ /**
+ * The annotation that contains a set of {@link ParameterizedTest}s to run. A test method
+ * is attempted for every set of {@link Parameter}s in each {@link ParameterizedTest}.
+ */
+ @Inherited
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD, ElementType.TYPE})
+ @interface Set {
+ ParameterizedTest[] tests() default {};
+ }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/parameter/parameters/MethodParameter.java b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/parameters/MethodParameter.java
new file mode 100644
index 0000000..c314540
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/parameter/parameters/MethodParameter.java
@@ -0,0 +1,21 @@
+// 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.parameters;
+
+import org.chromium.base.test.util.parameter.BaseParameter;
+import org.chromium.base.test.util.parameter.Parameter;
+
+/**
+ * Allows for passing of certain parameters arguments to function when this parameter is used.
+ */
+public class MethodParameter extends BaseParameter {
+ public static final String PARAMETER_TAG = "method-parameter";
+
+ public MethodParameter(Parameter.Reader parameterReader) {
+ super(PARAMETER_TAG, parameterReader);
+ }
+}
+
+