blob: 819f9904850f44e1b2f3ca4d10bad5ea53759883 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.dltk.internal.testing.model;
import org.eclipse.core.runtime.Assert;
import org.eclipse.dltk.testing.ITestingClient;
import org.eclipse.dltk.testing.model.ITestElement;
import org.eclipse.dltk.testing.model.ITestElementContainer;
import org.eclipse.dltk.testing.model.ITestRunSession;
public abstract class TestElement implements ITestElement {
public final static class Status {
public static final Status RUNNING_ERROR = new Status(
"RUNNING_ERROR", 5); //$NON-NLS-1$
public static final Status RUNNING_FAILURE = new Status(
"RUNNING_FAILURE", 6); //$NON-NLS-1$
public static final Status RUNNING = new Status("RUNNING", 3); //$NON-NLS-1$
public static final Status ERROR = new Status(
"ERROR", /* 1 */ITestRunListener2.STATUS_ERROR); //$NON-NLS-1$
public static final Status FAILURE = new Status(
"FAILURE", /* 2 */ITestRunListener2.STATUS_FAILURE); //$NON-NLS-1$
public static final Status FAILURE_BLOCKED = new Status(
"BLOCKED", /* 2 */ITestRunListener2.STATUS_FAILURE, ITestingClient.BLOCKED); //$NON-NLS-1$
public static final Status FAILURE_SKIPPED = new Status(
"SKIPPED", /* 2 */ITestRunListener2.STATUS_FAILURE, ITestingClient.SKIPPED); //$NON-NLS-1$
public static final Status FAILURE_UNKNOWN = new Status(
"UNKNOWN", /* 2 */ITestRunListener2.STATUS_FAILURE, ITestingClient.UNKNOWN); //$NON-NLS-1$
public static final Status FAILURE_ABORTED = new Status(
"ABORTED", /* 2 */ITestRunListener2.STATUS_FAILURE, ITestingClient.ABORTED); //$NON-NLS-1$
public static final Status OK = new Status(
"OK", /* 0 */ITestRunListener2.STATUS_OK); //$NON-NLS-1$
public static final Status NOT_RUN = new Status("NOT_RUN", 4); //$NON-NLS-1$
private static final Status[] OLD_CODE = { OK, ERROR, FAILURE };
private String fName;
private final int fOldCode;
private int failedCode;
private Status(String name, int oldCode) {
fName = name;
fOldCode = oldCode;
failedCode = ITestingClient.PASSED;
}
private Status(String name, int oldCode, int failedCode) {
fName = name;
fOldCode = oldCode;
this.failedCode = failedCode;
}
public int getOldCode() {
return fOldCode;
}
@Override
public String toString() {
return fName;
}
/* error state predicates */
public boolean isOK() {
return this == OK || this == RUNNING || this == NOT_RUN;
}
public boolean isFailure() {
return this.fOldCode == FAILURE.fOldCode || this == RUNNING_FAILURE;
}
public int getFailedCode() {
return this.failedCode;
}
public boolean isError() {
return this == ERROR || this == RUNNING_ERROR;
}
public boolean isErrorOrFailure() {
return isError() || isFailure();
}
/* progress state predicates */
public boolean isNotRun() {
return this == NOT_RUN;
}
public boolean isRunning() {
return this == RUNNING || this == RUNNING_FAILURE
|| this == RUNNING_ERROR;
}
public boolean isDone() {
return this == OK || this == FAILURE || this == ERROR;
}
public static Status combineStatus(Status one, Status two) {
Status progress = combineProgress(one, two);
Status error = combineError(one, two);
return combineProgressAndErrorStatus(progress, error);
}
private static Status combineProgress(Status one, Status two) {
if (one.isNotRun() && two.isNotRun())
return NOT_RUN;
else if (one.isDone() && two.isDone())
return OK;
else if (!one.isRunning() && !two.isRunning())
return OK; // one done, one not-run -> a parent failed and its
// children are not run
else
return RUNNING;
}
private static Status combineError(Status one, Status two) {
if (one.isError() || two.isError())
return ERROR;
else if (one.isFailure() || two.isFailure())
return FAILURE;
else
return OK;
}
private static Status combineProgressAndErrorStatus(Status progress,
Status error) {
if (progress.isDone()) {
if (error.isError())
return ERROR;
if (error.isFailure())
return FAILURE;
return OK;
}
if (progress.isNotRun()) {
// Assert.isTrue(!error.isErrorOrFailure());
return NOT_RUN;
}
// Assert.isTrue(progress.isRunning());
if (error.isError())
return RUNNING_ERROR;
if (error.isFailure())
return RUNNING_FAILURE;
// Assert.isTrue(error.isOK());
return RUNNING;
}
/**
* @param oldStatus
* one of {@link ITestRunListener2}'s STATUS_* constants
* @return the Status
*/
public static Status convert(int oldStatus, int failedCode) {
if (oldStatus < 3) {
// This is Failed/ special case
if (oldStatus == 2) {
switch (failedCode) {
case ITestingClient.ABORTED:
return FAILURE_ABORTED;
case ITestingClient.BLOCKED:
return FAILURE_BLOCKED;
case ITestingClient.SKIPPED:
return FAILURE_SKIPPED;
case ITestingClient.UNKNOWN:
return FAILURE_UNKNOWN;
default:
return FAILURE;
}
}
return OLD_CODE[oldStatus];
}
return null;
}
public Result convertToResult() {
if (isNotRun())
return Result.UNDEFINED;
if (isError())
return Result.ERROR;
if (isFailure())
return Result.FAILURE;
if (isRunning()) {
return Result.UNDEFINED;
}
return Result.OK;
}
public ProgressState convertToProgressState() {
if (isRunning()) {
return ProgressState.RUNNING;
}
if (isDone()) {
return ProgressState.COMPLETED;
}
return ProgressState.NOT_STARTED;
}
}
private final TestContainerElement fParent;
private final String fId;
private String fTestName;
private Status fStatus;
private String fTrace;
private String fExpected;
private String fActual;
/**
* Running time in seconds. Contents depend on the current {@link #getProgressState()}:
* <ul>
* <li>{@link org.eclipse.dltk.testing.model.ITestElement.ProgressState#NOT_STARTED}: {@link Double#NaN}</li>
* <li>{@link org.eclipse.dltk.testing.model.ITestElement.ProgressState#RUNNING}: negated start time</li>
* <li>{@link org.eclipse.dltk.testing.model.ITestElement.ProgressState#STOPPED}: elapsed time</li>
* <li>{@link org.eclipse.dltk.testing.model.ITestElement.ProgressState#COMPLETED}: elapsed time</li>
* </ul>
*//* default */ double fTime= Double.NaN;
/**
* @param parent
* the parent, can be <code>null</code>
* @param id
* the test id
* @param testName
* the test name
*/
public TestElement(TestContainerElement parent, String id, String testName) {
Assert.isNotNull(id);
Assert.isNotNull(testName);
fParent = parent;
fId = id;
fTestName = testName;
fStatus = Status.NOT_RUN;
if (parent != null)
parent.addChild(this);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.junit.ITestElement#getProgressState()
*/
@Override
public ProgressState getProgressState() {
return getStatus().convertToProgressState();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.junit.ITestElement#getTestResult()
*/
@Override
public Result getTestResult(boolean includeChildren) {
return getStatus().convertToResult();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.junit.ITestElement#getTestRunSession()
*/
@Override
public ITestRunSession getTestRunSession() {
return getRoot().getTestRunSession();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.junit.ITestElement#getParentContainer()
*/
@Override
public ITestElementContainer getParentContainer() {
if (fParent instanceof TestRoot) {
return getTestRunSession();
}
return fParent;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.junit.model.ITestElement#getFailureTrace()
*/
@Override
public FailureTrace getFailureTrace() {
Result testResult = getTestResult(false);
if (testResult == Result.ERROR || testResult == Result.FAILURE) {
return new FailureTrace(fTrace, fExpected, fActual);
}
return null;
}
/**
* @return the parent suite, or <code>null</code> for the root
*/
public TestContainerElement getParent() {
return fParent;
}
@Override
public String getId() {
return fId;
}
public String getTestName() {
return fTestName;
}
public void setStatus(Status status) {
// TODO: notify about change?
// TODO: multiple errors/failures per test
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=125296
if (status == Status.RUNNING) {
fTime= - System.currentTimeMillis() / 1000d ;
} else if (status.convertToProgressState() == ProgressState.COMPLETED) {
if (fTime < 0) { // assert ! Double.isNaN(fTime)
double endTime= System.currentTimeMillis() / 1000.0d;
fTime= endTime + fTime;
}
}
fStatus = status;
TestContainerElement parent = getParent();
if (parent != null)
parent.childChangedStatus(this, status);
}
public void setStatus(Status status, String trace, String expected,
String actual) {
// TODO: notify about change?
// TODO: multiple errors/failures per test
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=125296
fTrace = trace;
fExpected = expected;
fActual = actual;
setStatus(status);
}
public void setElapsedTimeInSeconds(double time) {
fTime= time;
}
@Override
public double getElapsedTimeInSeconds() {
if (Double.isNaN(fTime) || fTime < 0.0d) {
return Double.NaN;
}
return fTime;
}
public Status getStatus() {
return fStatus;
}
public String getTrace() {
return fTrace;
}
public String getExpected() {
return fExpected;
}
public String getActual() {
return fActual;
}
public boolean isComparisonFailure() {
return fExpected != null && fActual != null;
}
public TestRoot getRoot() {
return getParent().getRoot();
}
@Override
public String toString() {
return getProgressState() + " - " + getTestResult(true); //$NON-NLS-1$
}
protected void setTestName(String value) {
this.fTestName = value;
}
}