Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.base.test; | |
| 6 | |
| 7 import android.app.Instrumentation; | |
| 8 import android.content.Context; | |
| 9 import android.os.Bundle; | |
| 10 import android.os.SystemClock; | |
| 11 | |
| 12 import junit.framework.AssertionFailedError; | |
| 13 import junit.framework.TestCase; | |
| 14 import junit.framework.TestResult; | |
| 15 | |
| 16 import org.chromium.base.Log; | |
| 17 import org.chromium.base.test.util.CommandLineFlags; | |
| 18 import org.chromium.base.test.util.parameters.BaseParameter; | |
| 19 import org.chromium.base.test.util.parameters.Parameter; | |
| 20 import org.chromium.base.test.util.parameters.Parameterizable; | |
| 21 import org.chromium.base.test.util.parameters.ParameterizedTest; | |
| 22 | |
| 23 import java.io.PrintWriter; | |
| 24 import java.io.StringWriter; | |
| 25 import java.util.ArrayList; | |
| 26 import java.util.Arrays; | |
| 27 import java.util.List; | |
| 28 | |
| 29 /** | |
| 30 * A test result that can skip tests. | |
| 31 */ | |
| 32 public class BaseTestResult extends TestResult { | |
| 33 private static final String TAG = "cr.base.test"; | |
| 34 | |
| 35 private static final int SLEEP_INTERVAL = 50; // milliseconds | |
| 36 private static final int WAIT_DURATION = 5000; // milliseconds | |
| 37 | |
| 38 | |
| 39 private List<BaseParameter> mAvailableParameters; | |
| 40 private Instrumentation mInstrumentation; | |
| 41 private final List<SkipCheck> mSkipChecks; | |
| 42 | |
| 43 /** | |
| 44 * Creates an instance of BaseTestResult. | |
| 45 */ | |
| 46 public BaseTestResult(Instrumentation instrumentation) { | |
| 47 mSkipChecks = new ArrayList<SkipCheck>(); | |
| 48 mInstrumentation = instrumentation; | |
| 49 mAvailableParameters = new ArrayList<>(); | |
| 50 } | |
| 51 | |
| 52 /** | |
| 53 * An interface for classes that check whether a test case should be skipped . | |
| 54 */ | |
| 55 public interface SkipCheck { | |
| 56 /** | |
| 57 * | |
| 58 * Checks whether the given test case should be skipped. | |
| 59 * | |
| 60 * @param testCase The test case to check. | |
| 61 * @return Whether the test case should be skipped. | |
| 62 */ | |
| 63 public boolean shouldSkip(TestCase testCase); | |
| 64 } | |
| 65 | |
| 66 /** | |
| 67 * Adds a check for whether a test should run. | |
| 68 * | |
| 69 * @param skipCheck The check to add. | |
| 70 */ | |
| 71 public void addSkipCheck(SkipCheck skipCheck) { | |
| 72 mSkipChecks.add(skipCheck); | |
| 73 } | |
| 74 | |
| 75 protected boolean shouldSkip(final TestCase test) { | |
| 76 for (SkipCheck s : mSkipChecks) { | |
| 77 if (s.shouldSkip(test)) return true; | |
| 78 } | |
| 79 return false; | |
| 80 } | |
| 81 | |
| 82 @Override | |
| 83 protected void run(final TestCase test) { | |
| 84 if (shouldSkip(test)) { | |
| 85 startTest(test); | |
| 86 | |
| 87 Bundle skipResult = new Bundle(); | |
| 88 skipResult.putString("class", test.getClass().getName()); | |
| 89 skipResult.putString("test", test.getName()); | |
| 90 skipResult.putBoolean("test_skipped", true); | |
| 91 mInstrumentation.sendStatus(0, skipResult); | |
| 92 | |
| 93 endTest(test); | |
| 94 } else { | |
| 95 try { | |
| 96 CommandLineFlags.setUp( | |
| 97 getTargetContext(), | |
| 98 test.getClass().getMethod(test.getName())); | |
| 99 } catch (NoSuchMethodException e) { | |
| 100 Log.e(TAG, "Unable to set up CommandLineFlags", e); | |
| 101 } | |
| 102 | |
| 103 if (test instanceof Parameterizable) { | |
| 104 try { | |
| 105 runParameterized(test); | |
| 106 } catch (ThreadDeath e) { | |
| 107 Log.e(TAG, "Parameterized test run failed: %s", e); | |
| 108 } | |
| 109 } else { | |
| 110 super.run(test); | |
| 111 } | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 @SuppressWarnings("unchecked") | |
| 116 private <T extends TestCase & Parameterizable> void runParameterized(final T estCase test) | |
| 117 throws ThreadDeath { | |
| 118 final T testCase = (T) test; | |
| 119 | |
| 120 Parameter.Reader parameterReader = new Parameter.Reader(test); | |
| 121 testCase.setParameterReader(parameterReader); | |
| 122 List<ParameterizedTest> parameterizedTests = parameterReader.getParamete rizedTests(); | |
| 123 if (!parameterizedTests.isEmpty()) { | |
| 124 | |
| 125 // Start and prepare test. | |
| 126 startTest(testCase); | |
| 127 List<ParameterError> errors = new ArrayList<>(); | |
| 128 List<ParameterError> failures = new ArrayList<>(); | |
| 129 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.
| |
| 130 | |
| 131 // Run the actual tests. | |
| 132 for (final ParameterizedTest parameterizedTest : parameterizedTests) { | |
| 133 parameterReader.setCurrentParameterizedTest(parameterizedTest); | |
| 134 try { | |
| 135 setUpParameters(testCase); | |
| 136 testCase.runBare(); | |
| 137 tearDownParameters(testCase); | |
| 138 } catch (AssertionFailedError e) { | |
| 139 failures.add(new ParameterError(e, parameterizedTest)); | |
| 140 } catch (ThreadDeath e) { | |
| 141 throw e; | |
| 142 } catch (Throwable e) { | |
| 143 errors.add(new ParameterError(e, parameterizedTest)); | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 // Generate failures and errors. | |
| 148 if (!failures.isEmpty()) { | |
| 149 addFailure(test, new ParameterizedTestFailure(failures)); | |
| 150 } | |
| 151 if (!errors.isEmpty()) { | |
| 152 addError(test, new ParameterizedTestError(errors)); | |
| 153 } | |
| 154 | |
| 155 // End test. | |
| 156 mAvailableParameters = new ArrayList<>(); | |
| 157 endTest(testCase); | |
| 158 } else { | |
| 159 super.run(test); | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 private <T extends TestCase & Parameterizable> void setUpParameters(final T test) | |
| 164 throws Exception { | |
| 165 Parameter.Reader parameterReader = new Parameter.Reader(test); | |
| 166 for (BaseParameter parameter : mAvailableParameters) { | |
| 167 if (parameterReader.getParameter(parameter.getTag()) != null) { | |
| 168 parameter.setUp(); | |
| 169 } | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 private <T extends TestCase & Parameterizable> void tearDownParameters(final T test) | |
| 174 throws Exception { | |
| 175 Parameter.Reader parameterReader = new Parameter.Reader(test); | |
| 176 for (BaseParameter parameter : mAvailableParameters) { | |
| 177 if (parameterReader.getParameter(parameter.getTag()) != null) { | |
| 178 parameter.tearDown(); | |
| 179 } | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 private static class ParameterError { | |
| 184 private Throwable mThrowable; | |
| 185 private ParameterizedTest mParameterizedTest; | |
| 186 | |
| 187 public ParameterError(Throwable throwable, ParameterizedTest parameteriz edTest) { | |
| 188 mThrowable = throwable; | |
| 189 mParameterizedTest = parameterizedTest; | |
| 190 } | |
| 191 | |
| 192 private Throwable getThrowable() { | |
| 193 return mThrowable; | |
| 194 } | |
| 195 | |
| 196 private ParameterizedTest getParameterizedTest() { | |
| 197 return mParameterizedTest; | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 private static class ParameterizedTestFailure extends AssertionFailedError { | |
| 202 public ParameterizedTestFailure(List<ParameterError> failures) { | |
| 203 super(new ParameterizedTestError(failures).toString()); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 private static class ParameterizedTestError extends Exception { | |
| 208 public List<ParameterError> mErrors; | |
| 209 | |
| 210 public ParameterizedTestError(List<ParameterError> errors) { | |
| 211 mErrors = errors; | |
| 212 } | |
| 213 | |
| 214 @Override | |
| 215 public String toString() { | |
| 216 StringBuffer buffer = new StringBuffer(); | |
| 217 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.
| |
| 218 for (ParameterError error : mErrors) { | |
| 219 List<Parameter> parameters = | |
| 220 Arrays.asList(error.getParameterizedTest().parameters()) ; | |
| 221 if (!parameters.isEmpty()) { | |
| 222 StringBuffer parametersString = new StringBuffer(); | |
| 223 for (int i = 0; i < parameters.size(); i++) { | |
| 224 parametersString.append(parameters.get(i).tag()); | |
| 225 if (i != parameters.size() - 1) { | |
| 226 parametersString.append(','); | |
| 227 } | |
| 228 } | |
| 229 buffer.append(String.format("%s (with parameters %s)%n", | |
| 230 error.getThrowable().toString(), parametersString.to String())); | |
| 231 } else { | |
| 232 buffer.append(String.format("%s (with no parameters)%n", | |
| 233 error.getThrowable().toString())); | |
| 234 } | |
| 235 buffer.append(trace(error) + '\n'); | |
| 236 } | |
| 237 return buffer.toString(); | |
| 238 } | |
| 239 | |
| 240 /** | |
| 241 * @return the trace without the error message | |
| 242 */ | |
| 243 private String trace(ParameterError error) { | |
| 244 StringWriter stringWriter = new StringWriter(); | |
| 245 PrintWriter writer = new PrintWriter(stringWriter); | |
| 246 error.getThrowable().printStackTrace(writer); | |
| 247 StringBuffer buffer = stringWriter.getBuffer(); | |
| 248 return buffer.toString().substring(buffer.toString().indexOf('\n') + 1); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 /** | |
| 253 * Gets the target context. | |
| 254 * | |
| 255 * On older versions of Android, getTargetContext() may initially return nul l, so we have to | |
| 256 * wait for it to become available. | |
| 257 * | |
| 258 * @return The target {@link android.content.Context} if available; null oth erwise. | |
| 259 */ | |
| 260 public Context getTargetContext() { | |
| 261 Context targetContext = mInstrumentation.getTargetContext(); | |
| 262 try { | |
| 263 long startTime = SystemClock.uptimeMillis(); | |
| 264 // TODO(jbudorick): Convert this to CriteriaHelper once that moves t o base/. | |
| 265 while (targetContext == null | |
| 266 && SystemClock.uptimeMillis() - startTime < WAIT_DURATION) { | |
| 267 Thread.sleep(SLEEP_INTERVAL); | |
| 268 targetContext = mInstrumentation.getTargetContext(); | |
| 269 } | |
| 270 } catch (InterruptedException e) { | |
| 271 Log.e(TAG, "Interrupted while attempting to initialize the command l ine."); | |
| 272 } | |
| 273 return targetContext; | |
| 274 } | |
| 275 } | |
| OLD | NEW |