org.scalatest.Status.scala Maven / Gradle / Ivy
Show all versions of scalatest_2.9.0 Show documentation
package org.scalatest
import org.scalatest.tools.SuiteRunner
import java.util.concurrent.CountDownLatch
import scala.collection.GenSet
/**
* The result status of running a test or a suite.
*
*
* This trait is the return type of the "run" lifecycle methods of trait Suite
: run
, runNestedSuites
,
* runTests
, and runTest
. It can be used to determine whether a test or suite has completed, and if completed,
* whether it succeeded or failed. The main use case for this trait in ScalaTest is to enable BeforeAndAfterAll
's afterAll
* method to wait until all relevant tests and nested suites have completed before performing the "after all" code, even if those tests are
* nested suites are run in parallel.
*
*
* @author cheeseng
*/
trait Status {
/**
* Blocking call that waits until completion, then returns returns true
if no tests failed and no suites aborted, else returns false
.
*
*
* This only reports false
if there was a failed test or aborted suite in the context of the "run" lifecycle method it was returned from. For example,
* if you call succeeds
on the return Status
of runTest
, it returns (after that test has completed) true
if the
* test whose name was passed to runTest
succeeded, false
if that test failed (or the suite aborts). If you call
* succeeds
on the return value of runTests
, by contrast, it returns (after the suite's tests have completed) true
only
* if all tests in the suite succeeded. If any test in the suite fails (or the whole suite aborts), the succeeds
call will return false
.
* The Status
returned from runNestedSuites
will return true only if all tests in all nested suites (and their nested suites, etc.) fired
* off by that runNestedSuites
call succeed and no suites abort.
* Simlarly, the Status
returned from run
will return true only if all tests in all nested suites (and their nested suites, etc.) fired
* off by that run
call succeed and no suites abort.
*
*
* @return true
if no tests failed and no suites aborted, false
otherwise
*/
def succeeds(): Boolean
/**
* Non-blocking call that indicates whether the all the tests or nested suites fired off by the run method that returned the Status
have completed.
* Because this is non-blocking, you can use this to poll the completion status.
*
* @return true
if the test or suite run is already completed, false
otherwise.
*/
def isCompleted: Boolean
/**
* Blocking call that returns only after the underlying test or suite is completed.
*/
def waitUntilCompleted()
}
/**
* Singleton status that represents an already completed run with no tests failed and no suites aborted.
*/
@serializable
object SucceededStatus extends Status {
/**
* Always returns true
.
*
* @return true
*/
def succeeds() = true
/**
* Always returns true
.
*
* @return true
*/
def isCompleted = true
/**
* Always returns immediately.
*/
def waitUntilCompleted() {}
}
/**
* Singleton status that represents an already completed run with at least one failed test or aborted suite.
*/
@serializable
object FailedStatus extends Status {
/**
* Always returns false
.
*
* @return true
*/
def succeeds() = false
/**
* Always returns true
.
*
* @return true
*/
def isCompleted = true
/**
* Always returns immediately.
*/
def waitUntilCompleted() {}
}
// Used internally in ScalaTest
@serializable
private[scalatest] final class ScalaTestStatefulStatus extends Status {
private val latch = new CountDownLatch(1)
@volatile private var succeeded = true
def succeeds() = {
waitUntilCompleted()
succeeded
}
def isCompleted = latch.getCount() == 0L
def waitUntilCompleted() {
latch.await()
}
def setFailed() {
if (isCompleted)
throw new IllegalStateException("status is already completed")
succeeded = false
}
def setCompleted() {
latch.countDown()
}
}
/**
* Status implementation that can change its state over time.
*
*
* A StatefulStatus
begins its life in a successful state, and will remain successful unless setFailed
is called.
* Once setFailed
is called, the status will remain at failed. The setFailed
method can be called multiple times (even
* though invoking it once is sufficient to permanently set the status to failed), but only up until setCompleted
has been called.
* After setCompleted
has been called, any invocation of setFailed
will be greeted with an IllegalStateException
.
*
*
*
* Instances of this class are thread safe.
*
*/
@serializable
final class StatefulStatus extends Status {
private val latch = new CountDownLatch(1)
@volatile private var succeeded = true
/**
* Blocking call that waits until completion, as indicated by an invocation of setCompleted
on this instance, then returns returns false
* if setFailed
was called on this instance, else returns true
.
*
* @return true
if no tests failed and no suites aborted, false
otherwise
*/
def succeeds() = {
waitUntilCompleted()
succeeded
}
/**
* Non-blocking call that returns true
if setCompleted
has been invoked on this instance, false
otherwise.
*
* @return true
if the test or suite run is already completed, false
otherwise.
*/
def isCompleted = latch.getCount() == 0L
/**
* Blocking call that returns only after setCompleted
has been invoked on this StatefulStatus
instance.
*/
def waitUntilCompleted() {
latch.await()
}
/**
* Sets the status to failed without changing the completion status.
*
*
* This method may be invoked repeatedly, even though invoking it once is sufficient to set the state of the Status
to failed, but only
* up until setCompleted
has been called. Once setCompleted
has been called, invoking this method will result in a
* thrown IllegalStateException
.
*
*
* @throws IllegalStateException if this method is invoked on this instance after setCompleted
has been invoked on this instance.
*/
def setFailed() {
if (isCompleted)
throw new IllegalStateException("status is already completed")
succeeded = false
}
/**
* Sets the status to completed.
*
*
* This method may be invoked repeatedly, even though invoking it once is sufficient to set the state of the Status
to completed.
*
*/
def setCompleted() {
latch.countDown()
}
}
/**
* Composite Status
that aggregates its completion and failed states of set of other Status
es passed to its constructor.
*
* @param status the Status
es out of which this status is composed.
*/
@serializable
final class CompositeStatus(statuses: Set[Status]) extends Status {
/**
* Blocking call that waits until all composite Status
es have completed, then returns
* true
only if all of the composite Status
es succeeded. If any Status
passed in the statuses
set fails, this method
* will return false
.
*
* @return true
if all composite Status
es succeed, false
otherwise.
*/
def succeeds() = statuses.forall(_.succeeds())
/**
* Non-blocking call to check if the test or suite run is completed, returns true
if all compositite Status
es have completed,
* false
otherwise. You can use this to poll the run status.
*
* @return true
if all compositite Status
es have completed, false
otherwise.
*/
def isCompleted = statuses.forall(_.isCompleted)
/**
* Blocking call that returns only after all compositite Status
s have completed.
*/
def waitUntilCompleted() {
statuses.foreach(_.waitUntilCompleted())
}
}