All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nitorcreations.junit.runner.XmlJUnitFormatter Maven / Gradle / Ivy

There is a newer version: 1.3
Show newest version
/**
 * Copyright 2013 Nitor Creations Oy
 *
 * 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.nitorcreations.junit.runner;

import static com.nitorcreations.junit.runner.ThreadLocalStdOutErrCapturer.captureStdOutAndErrStreams;
import static com.nitorcreations.junit.runner.ThreadLocalStdOutErrCapturer.stderrCapture;
import static com.nitorcreations.junit.runner.ThreadLocalStdOutErrCapturer.stdoutCapture;
import static com.nitorcreations.junit.runner.XmlJUnitFormatter.Status.assumptionFailure;
import static com.nitorcreations.junit.runner.XmlJUnitFormatter.Status.error;
import static com.nitorcreations.junit.runner.XmlJUnitFormatter.Status.failed;
import static com.nitorcreations.junit.runner.XmlJUnitFormatter.Status.ignored;
import static com.nitorcreations.junit.runner.XmlJUnitFormatter.Status.success;
import static java.lang.System.currentTimeMillis;
import static java.lang.System.err;
import static java.lang.System.getProperty;
import static java.lang.System.out;

import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;

import com.nitorcreations.junit.runner.ThreadLocalStdOutErrCapturer.CaptureStreams;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

public class XmlJUnitFormatter extends RunListener {
  private final List results = new ArrayList();
  private final int threadNumber;
  private String testName;
  private PrintWriter xml;
  private Status status;
  private String failureTrace;
  private long testStartTime;
  private int errorCount;
  private int failureCount;
  private int skippedCount;

  private static final String outputDir;
  
  static {
    outputDir = getProperty("output.dir", ".") + File.separator;
    File dir = new File(outputDir);
    if (!dir.mkdirs() && !dir.exists()) {
      throw new RuntimeException("Failed to create output directory " + outputDir);
    }
    captureStdOutAndErrStreams();
  }
  
  enum Status {
    success(null),
    ignored("skipped"),
    error("error"),
    failed("failure"),
    assumptionFailure("skipped");
    
    public final String traceElement;

    Status(String traceElement) {
      this.traceElement = traceElement;
    }
  }

  public XmlJUnitFormatter(int threadNumber) {
    this.threadNumber = threadNumber;
  }

  static class TestStatus {
    public final String name;
    public final String classname;
    public final String stderr;
    public final String stdout;
    public final Status status;
    public final String trace;
    public final long runTime;

    public TestStatus(Description description, Status status, String trace, String stdout, String stderr, long runTime) {
      this.status = status;
      this.trace = trace;
      this.stdout = stdout;
      this.stderr = stderr;
      this.runTime = runTime;
      name = description.getMethodName();
      classname = description.getClassName();
    }
  }

  @Override
  public void testRunStarted(Description description) throws Exception {
    if ((description.getClassName() == null || description.getClassName().equals("null")) && !description.getChildren().isEmpty()) {
      testName = getProperty("test.name", "");
      if (!testName.isEmpty()) {
        testName += '-';
      }
      testName += description.getChildren().get(0).getClassName();
    } else {
      testName = getProperty("test.name", description.getClassName());
    }
    String name = "TEST-" + testName + "-" + threadNumber + ".xml";
    xml = new PrintWriter(outputDir + name, "UTF-8");
  }

  @Override
  @SuppressFBWarnings(value="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "JUnit runner calls testRunStarted before this method")
  public void testRunFinished(Result result) throws Exception {
    xml.printf("%n");
    xml.printf("%n", testName,
        result.getRunTime() / 1000.0, results.size(), errorCount, skippedCount, failureCount);
    for (TestStatus test : results) {
      String ignoreAttr = "";
      if (test.status == ignored) {
        ignoreAttr = " ignored=\"true\"";
      }
      xml.printf(" ", test.name, test.classname,
          test.runTime / 1000.0, ignoreAttr);
      printIfPresent("system-out", test.stdout);
      printIfPresent("system-err", test.stderr);
      printIfPresent(test.status.traceElement, test.trace);
      xml.printf("%n");
    }
    xml.print("");
    xml.close();
  }

  @SuppressFBWarnings(value="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "JUnit runner calls testRunStarted before this method")
  private void printIfPresent(String element, String text) {
    if (text == null || text.isEmpty()) {
      return;
    }
    xml.printf("%n  <%s>%s", element, xmlEscape(text), element);
  }

  private static String xmlEscape(String str) {
    return str.replace("&", "&").replace("<", "<").replace(">", ">");
  }

  @Override
  public void testStarted(Description description) throws Exception {
    status = success;
    failureTrace = null;
    testStartTime = currentTimeMillis();
  }

  @Override
  public void testFinished(Description description) throws Exception {
    addResult(description);
  }

  @Override
  public void testAssumptionFailure(Failure failure) {
    status = assumptionFailure;
    failureTrace = failure.getTrace();
    skippedCount++;
  }

  @Override
  public void testIgnored(Description description) throws Exception {
    failureTrace = "ignored";
    status = ignored;
    skippedCount++;
    addResult(description);
  }
  
  @Override
  public void testFailure(Failure failure) {
    if (status == success) {
      if (failure.getException() instanceof AssertionError) {
        status = failed;
        failureCount++;
      } else {
        status = error;
        errorCount++;
      }
      failureTrace = failure.getTrace();
    }
  }

  private void addResult(Description description) {
    long duration;
    if (testStartTime > 0) {
      duration = currentTimeMillis() - testStartTime;
      testStartTime = 0;
    } else {
      duration = 0;
    }
    out.flush();
    err.flush();
    CaptureStreams outCapture = stdoutCapture.get();
    CaptureStreams errCapture = stderrCapture.get();
    results.add(new TestStatus(description, status, failureTrace, outCapture.toString(), errCapture.toString(), duration));
    outCapture.bytes.reset();
    errCapture.bytes.reset();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy