summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--luni/src/test/java/com/google/coretests/CoreTestRunner.java29
-rw-r--r--luni/src/test/java/com/google/coretests/CoreTestSuite.java18
-rw-r--r--luni/src/test/java/com/google/coretests/XmlReportPrinter.java249
3 files changed, 286 insertions, 10 deletions
diff --git a/luni/src/test/java/com/google/coretests/CoreTestRunner.java b/luni/src/test/java/com/google/coretests/CoreTestRunner.java
index d80fa4e..82e9f54 100644
--- a/luni/src/test/java/com/google/coretests/CoreTestRunner.java
+++ b/luni/src/test/java/com/google/coretests/CoreTestRunner.java
@@ -69,6 +69,11 @@ public class CoreTestRunner extends TestRunner {
private int fTimeout;
private int fStep = 1;
+
+ /**
+ * The path to write XML reports to, or {@code null} for no reports.
+ */
+ private String xmlReportsDirectory;
/**
* Creates a new instance of our CoreTestRunner.
@@ -127,11 +132,24 @@ public class CoreTestRunner extends TestRunner {
* Make sure the original suite is unreachable after we have
* created the new one, so GC can dispose terminated tests.
*/
- suite = new CoreTestSuite(suite, fFlags, fStep, null);
-
- return super.doRun(suite, wait);
+ CoreTestSuite coreTestSuite = new CoreTestSuite(suite, fFlags, fStep, null);
+
+ XmlReportPrinter xmlReportPrinter = xmlReportsDirectory != null
+ ? new XmlReportPrinter(coreTestSuite)
+ : null;
+
+ TestResult result = super.doRun(suite, wait);
+
+ if (xmlReportPrinter != null) {
+ System.out.print("Printing XML Reports... ");
+ xmlReportPrinter.setResults(result);
+ int numFiles = xmlReportPrinter.generateReports(xmlReportsDirectory);
+ System.out.println(numFiles + " files written.");
+ }
+
+ return result;
}
-
+
/**
* Prints a help screen on the console.
*/
@@ -162,6 +180,7 @@ public class CoreTestRunner extends TestRunner {
System.out.println(" --isolate-all");
System.out.println(" --isolate-none");
System.out.println(" --verbose");
+ System.out.println(" --xml-reports-directory <path>");
System.out.println(" --help");
System.out.println();
System.out.println("Default parameters are:");
@@ -270,6 +289,8 @@ public class CoreTestRunner extends TestRunner {
// victimName = args[++i];
} else if (args[i].equals("--dry-run")) {
fFlags = fFlags | CoreTestSuite.DRY_RUN;
+ } else if (args[i].equals("--xml-reports-directory")) {
+ xmlReportsDirectory = args[++i];
} else if (args[i].equals("--help")) {
showHelp();
System.exit(1);
diff --git a/luni/src/test/java/com/google/coretests/CoreTestSuite.java b/luni/src/test/java/com/google/coretests/CoreTestSuite.java
index 3c9e7fa..1828c57 100644
--- a/luni/src/test/java/com/google/coretests/CoreTestSuite.java
+++ b/luni/src/test/java/com/google/coretests/CoreTestSuite.java
@@ -98,6 +98,8 @@ public class CoreTestSuite implements Test {
public static final int REVERSE = 512;
public static final int DRY_RUN = 1024;
+
+ private final String name;
/**
* The total number of tests in the original suite.
@@ -154,7 +156,8 @@ public class CoreTestSuite implements Test {
*/
public CoreTestSuite(Test suite, int flags, int step, TestCase victim) {
super();
-
+
+ name = suite.toString();
fStep = step;
addAndFlatten(suite, flags);
fVictim = victim;
@@ -269,27 +272,27 @@ public class CoreTestSuite implements Test {
public void run(TestResult result) {
// Run tests
int i = 0;
-
+
while (fTests.size() != 0 && !result.shouldStop()) {
TestCase test = (TestCase)fTests.elementAt(i);
Thread.currentThread().setContextClassLoader(
test.getClass().getClassLoader());
-
+
test.run(result);
/*
if (fVictim != null) {
TestResult dummy = fVictim.run();
-
+
if (dummy.failureCount() != 0) {
result.addError(fTests.elementAt(i), new RuntimeException(
- "Probable side effect",
+ "Probable side effect",
((TestFailure)dummy.failures().nextElement()).
thrownException()));
} else if (dummy.errorCount() != 0) {
result.addError(fTests.elementAt(i), new RuntimeException(
- "Probable side effect",
+ "Probable side effect",
((TestFailure)dummy.errors().nextElement()).
thrownException()));
}
@@ -352,4 +355,7 @@ public class CoreTestSuite implements Test {
return fTests.size();
}
+ @Override public String toString() {
+ return name;
+ }
}
diff --git a/luni/src/test/java/com/google/coretests/XmlReportPrinter.java b/luni/src/test/java/com/google/coretests/XmlReportPrinter.java
new file mode 100644
index 0000000..315371f
--- /dev/null
+++ b/luni/src/test/java/com/google/coretests/XmlReportPrinter.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.google.coretests;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestResult;
+import junit.runner.BaseTestRunner;
+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.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+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.
+ */
+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;
+
+ /** the test suites, which each contain tests */
+ private final Map<String, Suite> suites = new LinkedHashMap<String, Suite>();
+
+ /**
+ * Create a report printer that prints the specified test suite. Since the
+ * CoreTestSuite nulls-out tests after they're run (to limit memory
+ * consumption), it is necessary to create the report printer prior to test
+ * execution.
+ */
+ public XmlReportPrinter(CoreTestSuite allTests) {
+ // partition the tests by suite to be consistent with Ant's printer
+ for (Enumeration<Test> e = allTests.tests(); e.hasMoreElements(); ) {
+ TestId test = new TestId(e.nextElement());
+
+ // create the suite's entry in the map if necessary
+ Suite suite = suites.get(test.className);
+ if (suite == null) {
+ suite = new Suite(test.className);
+ suites.put(test.className, suite);
+ }
+
+ suite.tests.add(test);
+ }
+ }
+
+ public void setResults(TestResult result) {
+ populateFailures(true, result.errors());
+ populateFailures(false, result.failures());
+ }
+
+ /**
+ * Populate the list of failures in each of the suites.
+ */
+ private void populateFailures(boolean errors, Enumeration<TestFailure> failures) {
+ while (failures.hasMoreElements()) {
+ TestFailure failure = failures.nextElement();
+ TestId test = new TestId(failure.failedTest());
+ Suite suite = suites.get(test.className);
+
+ if (suite == null) {
+ throw new IllegalStateException( "received a failure for a "
+ + "test that wasn't in the original test suite!");
+ }
+
+ if (errors) {
+ suite.errors.put(test, failure);
+ } else {
+ suite.failures.put(test, failure);
+ }
+ }
+ }
+
+ public int generateReports(String directory) {
+ File parent = new File(directory);
+ parent.mkdirs();
+
+ 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(parent, "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();
+ }
+
+ static class Suite {
+ private final String name;
+ private final List<TestId> tests = new ArrayList<TestId>();
+ private final Map<TestId, TestFailure> failures = new HashMap<TestId, TestFailure>();
+ private final Map<TestId, TestFailure> errors = new HashMap<TestId, TestFailure>();
+
+ 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(failures.size()));
+ serializer.attribute(ns, ATTR_ERRORS, Integer.toString(errors.size()));
+ 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 (TestId testId : tests) {
+ TestFailure error = errors.get(testId);
+ TestFailure failure = failures.get(testId);
+
+ if (error != null) {
+ testId.printFailure(serializer, ERROR, error.thrownException());
+ } else if (failure != null) {
+ testId.printFailure(serializer, FAILURE, failure.thrownException());
+ } else {
+ testId.printSuccess(serializer);
+ }
+ }
+
+ serializer.endTag(ns, TESTSUITE);
+ }
+ }
+
+ private static class TestId {
+ private final String name;
+ private final String className;
+
+ TestId(Test test) {
+ this.name = test instanceof TestCase
+ ? ((TestCase) test).getName()
+ : test.toString();
+ this.className = test.getClass().getName();
+ }
+
+ void printSuccess(KXmlSerializer serializer) throws IOException {
+ serializer.startTag(ns, TESTCASE);
+ printAttributes(serializer);
+ serializer.endTag(ns, TESTCASE);
+ }
+
+ void printFailure(KXmlSerializer serializer, String type, Throwable t)
+ throws IOException {
+ serializer.startTag(ns, TESTCASE);
+ printAttributes(serializer);
+
+ serializer.startTag(ns, type);
+ String message = t.getMessage();
+ if (message != null && message.length() > 0) {
+ serializer.attribute(ns, ATTR_MESSAGE, t.getMessage());
+ }
+ serializer.attribute(ns, ATTR_TYPE, t.getClass().getName());
+ serializer.text(BaseTestRunner.getFilteredTrace(t));
+ serializer.endTag(ns, type);
+
+ serializer.endTag(ns, TESTCASE);
+ }
+
+ void printAttributes(KXmlSerializer serializer) throws IOException {
+ serializer.attribute(ns, ATTR_NAME, name);
+ serializer.attribute(ns, ATTR_CLASSNAME, className);
+ serializer.attribute(ns, ATTR_TIME, "0");
+ }
+
+ @Override public boolean equals(Object o) {
+ return o instanceof TestId
+ && ((TestId) o).name.equals(name)
+ && ((TestId) o).className.equals(className);
+ }
+
+ @Override public int hashCode() {
+ return name.hashCode() ^ className.hashCode();
+ }
+ }
+} \ No newline at end of file