com.google.testing.junit.runner.model.AntXmlResultWriter.java Source code

Java tutorial

Introduction

Here is the source code for com.google.testing.junit.runner.model.AntXmlResultWriter.java

Source

// Copyright 2015 The Bazel Authors. All Rights Reserved.
//
// 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.google.testing.junit.runner.model;

import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;

import org.joda.time.Interval;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map.Entry;

/**
 * Writes the JUnit test nodes and their results into Ant-JUnit XML. Ant-JUnit XML is not a
 * standardized format. For this implementation the
 * <a href="http://windyroad.com.au/dl/Open%20Source/JUnit.xsd">XML schema</a> that is generally
 * referred to as the best available source was used as a reference.
 */
public final class AntXmlResultWriter implements XmlResultWriter {
    private static final String JUNIT_ELEMENT_TESTSUITES = "testsuites";
    private static final String JUNIT_ELEMENT_TESTSUITE = "testsuite";
    private static final String JUNIT_ATTR_TESTSUITE_ERRORS = "errors";
    private static final String JUNIT_ATTR_TESTSUITE_FAILURES = "failures";
    private static final String JUNIT_ATTR_TESTSUITE_HOSTNAME = "hostname";
    private static final String JUNIT_ATTR_TESTSUITE_NAME = "name";
    private static final String JUNIT_ATTR_TESTSUITE_TESTS = "tests";
    private static final String JUNIT_ATTR_TESTSUITE_TIME = "time";
    private static final String JUNIT_ATTR_TESTSUITE_TIMESTAMP = "timestamp";
    private static final String JUNIT_ATTR_TESTSUITE_ID = "id";
    private static final String JUNIT_ATTR_TESTSUITE_PACKAGE = "package";
    private static final String JUNIT_ATTR_TESTSUITE_PROPERTIES = "properties";
    private static final String JUNIT_ATTR_TESTSUITE_SYSTEM_OUT = "system-out";
    private static final String JUNIT_ATTR_TESTSUITE_SYSTEM_ERR = "system-err";
    private static final String JUNIT_ELEMENT_PROPERTY = "property";
    private static final String JUNIT_ATTR_PROPERTY_NAME = "name";
    private static final String JUNIT_ATTR_PROPERTY_VALUE = "value";
    private static final String JUNIT_ELEMENT_TESTCASE = "testcase";
    private static final String JUNIT_ELEMENT_FAILURE = "failure";
    private static final String JUNIT_ATTR_FAILURE_MESSAGE = "message";
    private static final String JUNIT_ATTR_FAILURE_TYPE = "type";
    private static final String JUNIT_ATTR_TESTCASE_NAME = "name";
    private static final String JUNIT_ATTR_TESTCASE_CLASSNAME = "classname";
    private static final String JUNIT_ATTR_TESTCASE_TIME = "time";

    private int testSuiteId;

    @Override
    public void writeTestSuites(XmlWriter writer, TestResult result) throws IOException {
        testSuiteId = 0;
        writer.startDocument();
        writer.startElement(JUNIT_ELEMENT_TESTSUITES);
        for (TestResult child : result.getChildResults()) {
            writeTestSuite(writer, child, result.getFailures());
        }
        writer.endElement();
        writer.close();
    }

    private void writeTestSuite(XmlWriter writer, TestResult result, Iterable<Throwable> parentFailures)
            throws IOException {
        parentFailures = Iterables.concat(parentFailures, result.getFailures());

        writer.startElement(JUNIT_ELEMENT_TESTSUITE);

        writeTestSuiteAttributes(writer, result);
        writeTestSuiteProperties(writer, result);
        writeTestCases(writer, result, parentFailures);
        writeTestSuiteOutput(writer);

        writer.endElement();

        for (TestResult child : result.getChildResults()) {
            if (!child.getChildResults().isEmpty()) {
                writeTestSuite(writer, child, parentFailures);
            }
        }
    }

    private void writeTestSuiteProperties(XmlWriter writer, TestResult result) throws IOException {
        writer.startElement(JUNIT_ATTR_TESTSUITE_PROPERTIES);
        for (Entry<String, String> entry : result.getProperties().entrySet()) {
            writer.startElement(JUNIT_ELEMENT_PROPERTY);
            writer.writeAttribute(JUNIT_ATTR_PROPERTY_NAME, entry.getKey());
            writer.writeAttribute(JUNIT_ATTR_PROPERTY_VALUE, entry.getValue());
            writer.endElement();
        }
        writer.endElement();
    }

    private void writeTestCases(XmlWriter writer, TestResult result, Iterable<Throwable> parentFailures)
            throws IOException {
        for (TestResult child : result.getChildResults()) {
            if (child.getChildResults().isEmpty()) {
                writeTestCase(writer, child, parentFailures);
            }
        }
    }

    private void writeTestSuiteOutput(XmlWriter writer) throws IOException {
        writer.startElement(JUNIT_ATTR_TESTSUITE_SYSTEM_OUT);
        // TODO(bazel-team) - where to get this from?
        writer.endElement();
        writer.startElement(JUNIT_ATTR_TESTSUITE_SYSTEM_ERR);
        // TODO(bazel-team) - where to get this from?
        writer.endElement();
    }

    private void writeTestSuiteAttributes(XmlWriter writer, TestResult result) throws IOException {
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_NAME, result.getName());
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_TIMESTAMP, getFormattedTimestamp(result.getRunTimeInterval()));
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_HOSTNAME, "localhost");
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_TESTS, result.getNumTests());
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_FAILURES, result.getNumFailures());
        // JUnit 4.x no longer distinguishes between errors and failures, so it should be safe to just
        // report errors as 0 and put everything into failures.
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_ERRORS, 0);
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_TIME, getFormattedRunTime(result.getRunTimeInterval()));
        // TODO(bazel-team) - do we want to report the package name here? Could we simply get it from
        // result.getClassName() by stripping the last element of the class name?
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_PACKAGE, "");
        writer.writeAttribute(JUNIT_ATTR_TESTSUITE_ID, this.testSuiteId++);
    }

    private static String getFormattedRunTime(Optional<Interval> runTimeInterval) {
        return !runTimeInterval.isPresent() ? "0.0"
                : String.valueOf(runTimeInterval.get().toDurationMillis() / 1000.0D);
    }

    private static String getFormattedTimestamp(Optional<Interval> runTimeInterval) {
        return !runTimeInterval.isPresent() ? "" : runTimeInterval.get().getStart().toString();
    }

    private void writeTestCase(XmlWriter writer, TestResult result, Iterable<Throwable> parentFailures)
            throws IOException {
        writer.startElement(JUNIT_ELEMENT_TESTCASE);
        writer.writeAttribute(JUNIT_ATTR_TESTCASE_NAME, result.getName());
        writer.writeAttribute(JUNIT_ATTR_TESTCASE_CLASSNAME, result.getClassName());
        writer.writeAttribute(JUNIT_ATTR_TESTCASE_TIME, getFormattedRunTime(result.getRunTimeInterval()));

        for (Throwable failure : Iterables.concat(parentFailures, result.getFailures())) {
            writer.startElement(JUNIT_ELEMENT_FAILURE);
            writer.writeAttribute(JUNIT_ATTR_FAILURE_MESSAGE, Strings.nullToEmpty(failure.getMessage()));
            writer.writeAttribute(JUNIT_ATTR_FAILURE_TYPE, failure.getClass().getName());
            writer.writeCharacters(formatStackTrace(failure));
            writer.endElement();
        }

        writer.endElement();
    }

    private static String formatStackTrace(Throwable throwable) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter writer = new PrintWriter(stringWriter);
        throwable.printStackTrace(writer);
        return stringWriter.getBuffer().toString();
    }
}