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

hudson.tasks.junit.CaseResult Maven / Gradle / Ivy

package hudson.tasks.junit;

import hudson.model.AbstractBuild;
import org.dom4j.Element;
import org.kohsuke.stapler.export.Exported;

import java.util.Comparator;
import java.text.DecimalFormat;
import java.text.ParseException;

/**
 * One test result.
 *
 * @author Kohsuke Kawaguchi
 */
public final class CaseResult extends TestObject implements Comparable {
    private final float duration;
    private final String className;
    private final String testName;
    private final boolean skipped;
    private final String errorStackTrace;
    private final String errorDetails;
    private transient SuiteResult parent;

    private transient ClassResult classResult;

    /**
     * This test has been failing since this build number (not id.)
     *
     * If {@link #isPassed() passing}, this field is left unused to 0.
     */
    private /*final*/ int failedSince;

    CaseResult(SuiteResult parent, String testClassName, Element testCase) {
        this(parent,testClassName,testCase.attributeValue("name"), getError(testCase), getErrorMessage(testCase), parseTime(testCase), isMarkedAsSkipped(testCase));
    }

    private static float parseTime(Element testCase) {
        String time = testCase.attributeValue("time");
        if(time!=null) {
            time = time.replace(",","");
            try {
                return Float.parseFloat(time);
            } catch (NumberFormatException e) {
                try {
                    return new DecimalFormat().parse(time).floatValue();
                } catch (ParseException x) {
                    // hmm, don't know what this format is.
                }
            }
        }
        return 0.0f;
    }

    CaseResult(SuiteResult parent, Element testCase, String testCaseName) {
        // schema for JUnit report XML format is not available in Ant,
        // so I don't know for sure what means what.
        // reports in http://www.nabble.com/difference-in-junit-publisher-and-ant-junitreport-tf4308604.html#a12265700
        // indicates that maybe I shouldn't use @classname altogether.

        //String cn = testCase.attributeValue("classname");
        //if(cn==null)
        //    // Maven seems to skip classname, and that shows up in testSuite/@name
        //    cn = parent.getName();

        String cn = parent.getName();
        className = safe(cn);
        testName = safe(testCaseName);
        duration = parseTime(testCase);
        errorStackTrace = getError(testCase);
        errorDetails = getErrorMessage(testCase);
        skipped = isMarkedAsSkipped(testCase);
    }

    /**
     * Used to create a fake failure, when Hudson fails to load data from XML files.
     */
    CaseResult(SuiteResult parent, String testName, String errorStackTrace) {
        this( parent, parent.getName(), testName, errorStackTrace, "", 0.0f, false );
    }

    CaseResult(SuiteResult parent, String testClassName, String testName, String errorStackTrace, String errorDetails, float duration, boolean skipped) {
        this.className = testClassName;
        this.testName = testName;
        this.errorStackTrace = errorStackTrace;
        this.errorDetails = errorDetails;
        this.parent = parent;
        this.duration = duration;
        this.skipped = skipped;
    }

    private static String getError(Element testCase) {
        String msg = testCase.elementText("error");
        if(msg!=null)
            return msg;
        return testCase.elementText("failure");
    }

    private static String getErrorMessage(Element testCase) {

        Element msg = testCase.element("error");
        if (msg == null) {
            msg = testCase.element("failure");
        }
        if (msg == null) {
            return null; // no error or failure elements! damn!
        }

        return msg.attributeValue("message");
    }

    /**
     * If the testCase element includes the skipped element (as output by TestNG), then
     * the test has neither passed nor failed, it was never run.
     */
    private static boolean isMarkedAsSkipped(Element testCase) {
        return testCase.element("skipped") != null;
    }

    public String getDisplayName() {
        return testName;
    }

    /**
     * Gets the name of the test, which is returned from {@code TestCase.getName()}
     *
     * 

* Note that this may contain any URL-unfriendly character. */ @Exported public String getName() { return testName; } /** * Gets the duration of the test, in seconds */ @Exported public float getDuration() { return duration; } /** * Gets the version of {@link #getName()} that's URL-safe. */ public String getSafeName() { StringBuffer buf = new StringBuffer(testName); for( int i=0; i getOwner() { return parent.getParent().getOwner(); } /** * Gets the relative path to this test case from the given object. */ public String getRelativePathFrom(TestObject it) { if(it==this) return "."; // package, then class StringBuffer buf = new StringBuffer(); buf.append(getSafeName()); if(it!=classResult) { buf.insert(0,'/'); buf.insert(0,classResult.getName()); PackageResult pkg = classResult.getParent(); if(it!=pkg) { buf.insert(0,'/'); buf.insert(0,pkg.getName()); } } return buf.toString(); } public void freeze(SuiteResult parent) { this.parent = parent; // some old test data doesn't have failedSince value set, so for those compute them. if(!isPassed() && failedSince==0) { CaseResult prev = getPreviousResult(); if(prev!=null && !prev.isPassed()) this.failedSince = prev.failedSince; else this.failedSince = getOwner().getNumber(); } } public int compareTo(CaseResult that) { return this.getFullName().compareTo(that.getFullName()); } @Exported(name="status") // because stapler notices suffix 's' and remove it public Status getStatus() { if (skipped) { return Status.SKIPPED; } CaseResult pr = getPreviousResult(); if(pr==null) { return isPassed() ? Status.PASSED : Status.FAILED; } if(pr.isPassed()) { return isPassed() ? Status.PASSED : Status.REGRESSION; } else { return isPassed() ? Status.FIXED : Status.FAILED; } } /*package*/ void setClass(ClassResult classResult) { this.classResult = classResult; } /** * Constants that represent the status of this test. */ public enum Status { /** * This test runs OK, just like its previous run. */ PASSED("result-passed",Messages.CaseResult_Status_Passed(),true), /** * This test was skipped due to configuration or the * failure or skipping of a method that it depends on. */ SKIPPED("result-skipped",Messages.CaseResult_Status_Skipped(),false), /** * This test failed, just like its previous run. */ FAILED("result-failed",Messages.CaseResult_Status_Failed(),false), /** * This test has been failing, but now it runs OK. */ FIXED("result-fixed",Messages.CaseResult_Status_Fixed(),true), /** * This test has been running OK, but now it failed. */ REGRESSION("result-regression",Messages.CaseResult_Status_Regression(),false); private final String cssClass; private final String message; public final boolean isOK; Status(String cssClass, String message, boolean OK) { this.cssClass = cssClass; this.message = message; isOK = OK; } public String getCssClass() { return cssClass; } public String getMessage() { return message; } public boolean isRegression() { return this==REGRESSION; } } /** * For sorting errors by age. */ /*package*/ static final Comparator BY_AGE = new Comparator() { public int compare(CaseResult lhs, CaseResult rhs) { return lhs.getAge()-rhs.getAge(); } }; private static final long serialVersionUID = 1L; }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy