/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.test.runner.listener; import android.app.Instrumentation; import android.os.Bundle; import org.junit.runner.Description; import org.junit.runner.Result; import org.junit.runner.notification.Failure; /** * A {@link RunListener} that sends detailed pass/fail results back as instrumentation status * bundles. This output appears when running the instrumentation in '-r' or raw mode. */ public class InstrumentationResultPrinter extends InstrumentationRunListener { /** * This value, if stored with key {@link android.app.Instrumentation#REPORT_KEY_IDENTIFIER}, * identifies AndroidJUnitRunner as the source of the report. This is sent with all * status messages. */ public static final String REPORT_VALUE_ID = "AndroidJUnitRunner"; /** * If included in the status or final bundle sent to an IInstrumentationWatcher, this key * identifies the total number of tests that are being run. This is sent with all status * messages. */ public static final String REPORT_KEY_NUM_TOTAL = "numtests"; /** * If included in the status or final bundle sent to an IInstrumentationWatcher, this key * identifies the sequence number of the current test. This is sent with any status message * describing a specific test being started or completed. */ public static final String REPORT_KEY_NUM_CURRENT = "current"; /** * If included in the status or final bundle sent to an IInstrumentationWatcher, this key * identifies the name of the current test class. This is sent with any status message * describing a specific test being started or completed. */ public static final String REPORT_KEY_NAME_CLASS = "class"; /** * If included in the status or final bundle sent to an IInstrumentationWatcher, this key * identifies the name of the current test. This is sent with any status message * describing a specific test being started or completed. */ public static final String REPORT_KEY_NAME_TEST = "test"; /** * The test is starting. */ public static final int REPORT_VALUE_RESULT_START = 1; /** * The test completed successfully. */ public static final int REPORT_VALUE_RESULT_OK = 0; /** * The test completed with an error. */ public static final int REPORT_VALUE_RESULT_ERROR = -1; /** * The test completed with a failure. */ public static final int REPORT_VALUE_RESULT_FAILURE = -2; /** * The test was ignored. */ public static final int REPORT_VALUE_RESULT_IGNORED = -3; /** * If included in the status bundle sent to an IInstrumentationWatcher, this key * identifies a stack trace describing an error or failure. This is sent with any status * message describing a specific test being completed. */ public static final String REPORT_KEY_STACK = "stack"; private final Bundle mResultTemplate; Bundle mTestResult; int mTestNum = 0; int mTestResultCode = 0; String mTestClass = null; public InstrumentationResultPrinter(Instrumentation i) { super(i); mResultTemplate = new Bundle(); } @Override public void testRunStarted(Description description) throws Exception { mResultTemplate.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID); mResultTemplate.putInt(REPORT_KEY_NUM_TOTAL, description.testCount()); } @Override public void testRunFinished(Result result) throws Exception { } /** * send a status for the start of a each test, so long tests can be seen * as "running" */ @Override public void testStarted(Description description) throws Exception { String testClass = description.getClassName(); String testName = description.getMethodName(); mTestResult = new Bundle(mResultTemplate); mTestResult.putString(REPORT_KEY_NAME_CLASS, testClass); mTestResult.putString(REPORT_KEY_NAME_TEST, testName); mTestResult.putInt(REPORT_KEY_NUM_CURRENT, ++mTestNum); // pretty printing if (testClass != null && !testClass.equals(mTestClass)) { mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, String.format("\n%s:", testClass)); mTestClass = testClass; } else { mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, ""); } sendStatus(REPORT_VALUE_RESULT_START, mTestResult); mTestResultCode = 0; } @Override public void testFinished(Description description) throws Exception { if (mTestResultCode == 0) { mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "."); } sendStatus(mTestResultCode, mTestResult); } @Override public void testFailure(Failure failure) throws Exception { mTestResultCode = REPORT_VALUE_RESULT_ERROR; reportFailure(failure); } @Override public void testAssumptionFailure(Failure failure) { mTestResultCode = REPORT_VALUE_RESULT_FAILURE; reportFailure(failure); } private void reportFailure(Failure failure) { mTestResult.putString(REPORT_KEY_STACK, failure.getTrace()); // pretty printing mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, String.format("\nError in %s:\n%s", failure.getDescription().getDisplayName(), failure.getTrace())); } @Override public void testIgnored(Description description) throws Exception { testStarted(description); mTestResultCode = REPORT_VALUE_RESULT_IGNORED; testFinished(description); } }