blob: 669a26c22112a814b26f674be5631fe501e3b523 [file] [log] [blame]
/*
* Copyright (C) 2009 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 dalvik.runner;
import org.kxml2.io.KXmlSerializer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
/**
* Writes JUnit results to a series of XML files in a format consistent with
* Ant's XMLJUnitResultFormatter.
*
* <p>Unlike Ant's formatter, this class does not report the execution time of
* tests.
*
* TODO: unify this and com.google.coretests.XmlReportPrinter
*/
public class XmlReportPrinter {
private static final String TESTSUITE = "testsuite";
private static final String TESTCASE = "testcase";
private static final String ERROR = "error";
private static final String FAILURE = "failure";
private static final String ATTR_NAME = "name";
private static final String ATTR_TIME = "time";
private static final String ATTR_ERRORS = "errors";
private static final String ATTR_FAILURES = "failures";
private static final String ATTR_TESTS = "tests";
private static final String ATTR_TYPE = "type";
private static final String ATTR_MESSAGE = "message";
private static final String PROPERTIES = "properties";
private static final String ATTR_CLASSNAME = "classname";
private static final String TIMESTAMP = "timestamp";
private static final String HOSTNAME = "hostname";
/** the XML namespace */
private static final String ns = null;
/**
* Populates the directory with the report data from the completed tests.
*/
public int generateReports(File directory, Collection<TestRun> results) {
Map<String, Suite> suites = testsToSuites(results);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
TimeZone gmt = TimeZone.getTimeZone("GMT");
dateFormat.setTimeZone(gmt);
dateFormat.setLenient(true);
String timestamp = dateFormat.format(new Date());
for (Suite suite : suites.values()) {
FileOutputStream stream = null;
try {
stream = new FileOutputStream(new File(directory, "TEST-" + suite.name + ".xml"));
KXmlSerializer serializer = new KXmlSerializer();
serializer.setOutput(stream, "UTF-8");
serializer.startDocument("UTF-8", null);
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
suite.print(serializer, timestamp);
serializer.endDocument();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException ignored) {
}
}
}
}
return suites.size();
}
private Map<String, Suite> testsToSuites(Collection<TestRun> testRuns) {
Map<String, Suite> result = new LinkedHashMap<String, Suite>();
for (TestRun testRun : testRuns) {
if (testRun.getResult() == Result.UNSUPPORTED) {
continue;
}
String suiteName = testRun.getSuiteName();
Suite suite = result.get(suiteName);
if (suite == null) {
suite = new Suite(suiteName);
result.put(suiteName, suite);
}
suite.tests.add(testRun);
if (!testRun.isExpectedResult()) {
if (testRun.getResult() == Result.EXEC_FAILED) {
suite.failuresCount++;
} else {
suite.errorsCount++;
}
}
}
return result;
}
static class Suite {
private final String name;
private final List<TestRun> tests = new ArrayList<TestRun>();
private int failuresCount;
private int errorsCount;
Suite(String name) {
this.name = name;
}
void print(KXmlSerializer serializer, String timestamp) throws IOException {
serializer.startTag(ns, TESTSUITE);
serializer.attribute(ns, ATTR_NAME, name);
serializer.attribute(ns, ATTR_TESTS, Integer.toString(tests.size()));
serializer.attribute(ns, ATTR_FAILURES, Integer.toString(failuresCount));
serializer.attribute(ns, ATTR_ERRORS, Integer.toString(errorsCount));
serializer.attribute(ns, ATTR_TIME, "0");
serializer.attribute(ns, TIMESTAMP, timestamp);
serializer.attribute(ns, HOSTNAME, "localhost");
serializer.startTag(ns, PROPERTIES);
serializer.endTag(ns, PROPERTIES);
for (TestRun testRun : tests) {
print(serializer, testRun);
}
serializer.endTag(ns, TESTSUITE);
}
void print(KXmlSerializer serializer, TestRun testRun) throws IOException {
serializer.startTag(ns, TESTCASE);
serializer.attribute(ns, ATTR_NAME, testRun.getTestName());
serializer.attribute(ns, ATTR_CLASSNAME, testRun.getSuiteName());
serializer.attribute(ns, ATTR_TIME, "0");
if (!testRun.isExpectedResult()) {
String result = testRun.getResult() == Result.EXEC_FAILED ? FAILURE : ERROR;
serializer.startTag(ns, result);
String title = testRun.getDescription();
if (title != null && title.length() > 0) {
serializer.attribute(ns, ATTR_MESSAGE, title);
}
serializer.attribute(ns, ATTR_TYPE, testRun.getResult().toString());
String text = sanitize(Strings.join(testRun.getOutputLines(), "\n"));
serializer.text(text);
serializer.endTag(ns, result);
}
serializer.endTag(ns, TESTCASE);
}
/**
* Returns the text in a format that is safe for use in an XML document.
*/
private String sanitize(String text) {
return text.replace("\0", "<\\0>");
}
}
}