Chromium Code Reviews| Index: base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java |
| 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 0000000000000000000000000000000000000000..d91ccc470bb744f018d4e808686abef68873c91e |
| --- /dev/null |
| +++ b/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java |
| @@ -0,0 +1,275 @@ |
| +// 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.parameters.BaseParameter; |
| +import org.chromium.base.test.util.parameters.Parameter; |
| +import org.chromium.base.test.util.parameters.Parameterizable; |
| +import org.chromium.base.test.util.parameters.ParameterizedTest; |
| + |
| +import java.io.PrintWriter; |
| +import java.io.StringWriter; |
| +import java.util.ArrayList; |
| +import java.util.Arrays; |
| +import java.util.List; |
| + |
| +/** |
| + * 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 = 50; // milliseconds |
| + private static final int WAIT_DURATION = 5000; // milliseconds |
| + |
| + |
| + private List<BaseParameter> mAvailableParameters; |
| + private Instrumentation mInstrumentation; |
| + private final List<SkipCheck> mSkipChecks; |
| + |
| + /** |
| + * Creates an instance of BaseTestResult. |
| + */ |
| + public BaseTestResult(Instrumentation instrumentation) { |
| + mSkipChecks = new ArrayList<SkipCheck>(); |
| + mInstrumentation = instrumentation; |
| + mAvailableParameters = new ArrayList<>(); |
| + } |
| + |
| + /** |
| + * 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); |
| + } |
| + |
| + /** |
| + * 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(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); |
| + 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(final TestCase test) |
| + throws ThreadDeath { |
| + final T testCase = (T) test; |
| + |
| + Parameter.Reader parameterReader = new Parameter.Reader(test); |
| + testCase.setParameterReader(parameterReader); |
| + List<ParameterizedTest> parameterizedTests = parameterReader.getParameterizedTests(); |
| + if (!parameterizedTests.isEmpty()) { |
| + |
| + // Start and prepare test. |
| + startTest(testCase); |
| + List<ParameterError> errors = new ArrayList<>(); |
| + List<ParameterError> failures = new ArrayList<>(); |
| + mAvailableParameters.addAll(testCase.getAvailableParameters()); |
|
jbudorick
2015/08/06 16:48:17
Make mAvailableParameters local to this function &
Sean Kirmani
2015/08/06 17:16:58
Done.
|
| + |
| + // Run the actual tests. |
| + for (final ParameterizedTest parameterizedTest : parameterizedTests) { |
| + parameterReader.setCurrentParameterizedTest(parameterizedTest); |
| + try { |
| + setUpParameters(testCase); |
| + testCase.runBare(); |
| + tearDownParameters(testCase); |
| + } 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. |
| + mAvailableParameters = new ArrayList<>(); |
| + endTest(testCase); |
| + } else { |
| + super.run(test); |
| + } |
| + } |
| + |
| + private <T extends TestCase & Parameterizable> void setUpParameters(final T test) |
| + throws Exception { |
| + Parameter.Reader parameterReader = new Parameter.Reader(test); |
| + for (BaseParameter parameter : mAvailableParameters) { |
| + if (parameterReader.getParameter(parameter.getTag()) != null) { |
| + parameter.setUp(); |
| + } |
| + } |
| + } |
| + |
| + private <T extends TestCase & Parameterizable> void tearDownParameters(final T test) |
| + throws Exception { |
| + Parameter.Reader parameterReader = new Parameter.Reader(test); |
| + for (BaseParameter parameter : mAvailableParameters) { |
| + if (parameterReader.getParameter(parameter.getTag()) != null) { |
| + parameter.tearDown(); |
| + } |
| + } |
| + } |
| + |
| + private static class ParameterError { |
| + private Throwable mThrowable; |
| + private 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 { |
| + public List<ParameterError> mErrors; |
| + |
| + public ParameterizedTestError(List<ParameterError> errors) { |
| + mErrors = errors; |
| + } |
| + |
| + @Override |
| + public String toString() { |
| + StringBuffer buffer = new StringBuffer(); |
| + buffer.append('\n'); |
|
jbudorick
2015/08/06 16:48:17
nit: collapse this line into the ctor above
Sean Kirmani
2015/08/06 17:16:58
Done.
|
| + for (ParameterError error : mErrors) { |
| + List<Parameter> parameters = |
| + Arrays.asList(error.getParameterizedTest().parameters()); |
| + if (!parameters.isEmpty()) { |
| + StringBuffer parametersString = new StringBuffer(); |
| + for (int i = 0; i < parameters.size(); i++) { |
| + parametersString.append(parameters.get(i).tag()); |
| + if (i != parameters.size() - 1) { |
| + parametersString.append(','); |
| + } |
| + } |
| + buffer.append(String.format("%s (with parameters %s)%n", |
| + error.getThrowable().toString(), parametersString.toString())); |
| + } else { |
| + buffer.append(String.format("%s (with no parameters)%n", |
| + error.getThrowable().toString())); |
| + } |
| + buffer.append(trace(error) + '\n'); |
| + } |
| + return buffer.toString(); |
| + } |
| + |
| + /** |
| + * @return the trace without the error message |
| + */ |
| + private String trace(ParameterError error) { |
| + StringWriter stringWriter = new StringWriter(); |
| + PrintWriter writer = new PrintWriter(stringWriter); |
| + error.getThrowable().printStackTrace(writer); |
| + StringBuffer buffer = stringWriter.getBuffer(); |
| + return buffer.toString().substring(buffer.toString().indexOf('\n') + 1); |
| + } |
| + } |
| + |
| + /** |
| + * 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. |
| + */ |
| + 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) { |
| + Thread.sleep(SLEEP_INTERVAL); |
| + targetContext = mInstrumentation.getTargetContext(); |
| + } |
| + } catch (InterruptedException e) { |
| + Log.e(TAG, "Interrupted while attempting to initialize the command line."); |
| + } |
| + return targetContext; |
| + } |
| +} |