blob: edecc766d654672c0781d5f314dacfebad0456d1 [file] [log] [blame]
/*
* Copyright (C) 2013 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.tradefed.util;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.util.xml.AbstractXmlParser;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.Collections;
/**
* Parser that extracts test result data from JUnit results stored in ant's XMLJUnitResultFormatter
* and forwards it to a ITestInvocationListener.
* <p/>
* @see ddmlib's XmlTestRunListener
*/
public class JUnitXmlParser extends AbstractXmlParser {
private final ITestInvocationListener mTestListener;
/**
* Parses the xml format. Expected tags/attributes are
*
* testsuite name="runname" tests="X"
* testcase classname="FooTest" name="testMethodName"
* failure type="blah" message="exception message"
* stack
*/
private class JUnitXmlHandler extends DefaultHandler {
private static final String FAILURE_TAG = "failure";
private static final String TESTSUITE_TAG = "testsuite";
private static final String TESTCASE_TAG = "testcase";
private TestIdentifier mCurrentTest = null;
private StringBuffer mFailureContent = null;
/**
* {@inheritDoc}
*/
@Override
public void startElement(String uri, String localName, String name, Attributes attributes)
throws SAXException {
mFailureContent = null;
if (TESTSUITE_TAG.equalsIgnoreCase(name)) {
// top level tag - maps to a test run in TF terminology
String testSuiteName = getMandatoryAttribute(name, "name", attributes);
String testCountString = getMandatoryAttribute(name, "tests", attributes);
int testCount = Integer.parseInt(testCountString);
mTestListener.testRunStarted(testSuiteName, testCount);
}
if (TESTCASE_TAG.equalsIgnoreCase(name)) {
// start of description of an individual test method - extract out test name and
// store it
String testClassName = getMandatoryAttribute(name, "classname", attributes);
String methodName = getMandatoryAttribute(name, "name", attributes);
mCurrentTest = new TestIdentifier(testClassName, methodName);
mTestListener.testStarted(mCurrentTest);
}
if (FAILURE_TAG.equalsIgnoreCase(name)) {
// current testcase has a failure - extract out message and type and store it
// detailed stack is CDATA, will be extracted in characters() callback
mFailureContent = new StringBuffer();
String message = attributes.getValue("message");
String type = attributes.getValue("type");
if (message != null) {
mFailureContent.append(message);
mFailureContent.append("\n");
}
if (type != null) {
mFailureContent.append(type);
mFailureContent.append("\n");
}
}
}
/**
* Called when parsing CDATA content of a tag
*/
@Override
public void characters(char[] data, int offset, int len) {
// if currently parsing a failure, add stack data to content
if (mFailureContent != null) {
mFailureContent.append(data, offset, len);
}
}
/**
* {@inheritDoc}
*/
@Override
public void endElement(String uri, String localName, String name) {
if (TESTSUITE_TAG.equalsIgnoreCase(name)) {
mTestListener.testRunEnded(0, Collections.<String, String> emptyMap());
}
if (TESTCASE_TAG.equalsIgnoreCase(name)) {
mTestListener.testEnded(mCurrentTest, Collections.<String, String> emptyMap());
}
if (FAILURE_TAG.equalsIgnoreCase(name)) {
mTestListener.testFailed(mCurrentTest,
mFailureContent.toString());
}
mFailureContent = null;
}
/**
* Retrieves an attributes value.
*
* @throws SAXException if attribute is not present
*/
String getMandatoryAttribute(String tagName, String attrName, Attributes attributes)
throws SAXException {
String value = attributes.getValue(attrName);
if (value == null) {
throw new SAXException(String.format(
"Malformed XML, could not find '%s' attribute in '%s'", attrName, tagName));
}
return value;
}
}
/**
* Create a JUnitXmlParser
*
* @param listener the {@link ITestInvocationListener} to forward results to
*/
public JUnitXmlParser(ITestInvocationListener listener) {
mTestListener = listener;
}
/**
* {@inheritDoc}
*/
@Override
protected DefaultHandler createXmlHandler() {
return new JUnitXmlHandler();
}
}