package org.xtest.results; import java.util.Collection; import java.util.List; import org.eclipse.emf.ecore.EObject; import org.xtest.XTestEvaluationException; import org.xtest.validation.XTestJavaValidator; import org.xtest.xTest.Body; import org.xtest.xTest.XTestExpression; import com.google.common.base.Objects; import com.google.common.collect.Lists; /** * Xtest result * * @author Michael Barry */ public class XTestResult { /** * Key to use as index to store {@link XTestResult}s in {@link XTestJavaValidator} context map */ public static final String KEY = "XtestResult"; private final EObject eObject; private final Collection<XTestEvaluationException> expressions = Lists.newArrayList(); private final String name; private final XTestResult parent; private boolean pending = false; private Object resultObject; private XTestState state = XTestState.NOT_RUN; private final List<XTestResult> subTests = Lists.newArrayList(); private final List<String> syntaxErrors = Lists.newArrayList(); private boolean uniqueFailure = false; /** * Construct a top-level xtest result * * @param main * The xtest expression model */ public XTestResult(Body main) { this(null, null, main); } // Private constructor so that users are forced to call subTest to // instantiate a non-top-level test private XTestResult(XTestResult parent, String name, EObject eObject) { this.parent = parent; this.name = name != null ? name.replaceAll("[\n\r]", "") : null; this.eObject = eObject; } /** * Fails the test and all of its parents and stores the evaluation exception * * @param exception * The evaluation exception */ public void addEvaluationException(XTestEvaluationException exception) { fail(); expressions.add(exception); } /** * Fails this test and all of its parents and adds a syntax error for this test. * * @param string * The syntax error. */ public void addSyntaxError(String string) { fail(); syntaxErrors.add(string); } /** * Counts the number of failures * * @return The number of failures including this and sub tests */ public int countFailures() { int result = uniqueFailure ? 1 : 0; for (XTestResult sub : subTests) { result += sub.countFailures(); } return result; } /** * Counts the number of pending tests * * @return The number of pending tests including this and sub tests */ public int countPendings() { int result = pending ? 1 : 0; for (XTestResult sub : subTests) { result += sub.countPendings(); } return result; } /** * Counts the total number of tests * * @return The total number of tests including this and sub tests */ public int countTests() { int result = 1; for (XTestResult sub : subTests) { result += sub.countTests(); } return result; } /** * Fails the test and all of its parents */ public void fail() { uniqueFailure = true; internalFail(); } /** * Returns the {@link EObject} associated with this result * * @return The {@link EObject} assocated with this result */ public EObject getEObject() { return eObject; } /** * Returns the syntax errors in this test * * @return The syntax errors in this test */ public List<String> getErrorMessages() { return syntaxErrors; } /** * Returns the evaluation exception for this result, or null if there was none * * @return the evaluation exception for this result, or null if there was none */ public Collection<XTestEvaluationException> getEvaluationException() { return expressions; } /** * Returns the name of this test * * @return The name of this test (can be null) */ public String getName() { return name; } /** * Returns the name of this test, prepended with all of the tests it is contained within. * * @return The name of this test, prepended with all of the tests it is contained within (can't * be null, can be empty) */ public String getQualifiedName() { StringBuilder builder = new StringBuilder(name == null ? "" : name); for (XTestResult cursor = parent; cursor != null; cursor = cursor.parent) { if (cursor.getName() != null) { builder.insert(0, '.'); builder.insert(0, cursor.getName()); } } return builder.toString(); } /** * Gets the return value of the test * * @return The return value of the test */ public Object getResultObject() { return resultObject; } /** * Returns the state of this test result * * @return The state of this test result */ public XTestState getState() { return state; } /** * Returns the tests contained within this test * * @return The tests contained within this test */ public List<XTestResult> getSubTests() { return subTests; } /** * Returns true if this test is pending, false if not * * @return True if this test is pending, false if not */ public boolean isPending() { return pending; } /** * Passes this result. Only passes its parent if the parent has not been run yet. */ public void pass() { if (state == XTestState.NOT_RUN) { state = XTestState.PASS; if (parent != null && parent.getState() == XTestState.NOT_RUN) { parent.pass(); } } } /** * Sets this test as pending */ public void setPending() { this.pending = true; } /** * Sets the return value of the test * * @param resultObject * The return vale of the test */ public void setResultObject(Object resultObject) { this.resultObject = resultObject; } /** * Constructs a new test result that is contained in this test. * * @param name * The name of the test * @param eObject * The test test expression that the result corresponds to * @return The new test result */ public XTestResult subTest(String name, XTestExpression eObject) { XTestResult result = new XTestResult(this, name, eObject); subTests.add(result); return result; } @Override public String toString() { return Objects.toStringHelper(XTestResult.class).add("name", name).add("state", state) .toString(); } private void internalFail() { state = XTestState.FAIL; if (parent != null) { parent.internalFail(); } } }