org.scalatest.path.FreeSpec.scala Maven / Gradle / Ivy
Show all versions of scalatest_2.9.0 Show documentation
package org.scalatest.path import org.scalatest.verb.BehaveWord import scala.collection.immutable.ListSet import org.scalatest._ import org.scalatest.Suite.autoTagClassAnnotations /** * A sister trait to
, see the * Shared tests section in the main documentation for sister * traitorg.scalatest.FreeSpec
that isolates tests by running each test in its own * instance of the test class, and for each test, only executing the path leading to that test. * ** Trait
* *path.FreeSpec
behaves similarly to traitorg.scalatest.FreeSpec
, except that tests * are isolated based on their path. The purpose ofpath.FreeSpec
is to facilitate writing * specification-style tests for mutable objects in a clear, boilerpate-free way. To test mutable objects, you need to * mutate them. Using a path trait, you can make a statement in text, then implement that statement in code (including * mutating state), and nest and combine these test/code pairs in any way you wish. Each test will only see * the side effects of code that is in blocks that enclose the test. Here's an example: ** import org.scalatest.path * import org.scalatest.matchers.ShouldMatchers * import scala.collection.mutable.ListBuffer * * class ExampleSpec extends path.FreeSpec with ShouldMatchers { * * "A ListBuffer" - { * * val buf = ListBuffer.empty[Int] // This implements "A ListBuffer" * * "should be empty when created" in { * * // This test sees: * // val buf = ListBuffer.empty[Int] * // So buf is: ListBuffer() * * buf should be ('empty) * } * * "when 1 is appended" - { * * buf += 1 // This implements "when 1 is appended", etc... * * "should contain 1" in { * * // This test sees: * // val buf = ListBuffer.empty[Int] * // buf += 1 * // So buf is: ListBuffer(1) * * buf.remove(0) should equal (1) * buf should be ('empty) * } * * "when 2 is appended" - { * * buf += 2 * * "should contain 1 and 2" in { * * // This test sees: * // val buf = ListBuffer.empty[Int] * // buf += 1 * // buf += 2 * // So buf is: ListBuffer(1, 2) * * buf.remove(0) should equal (1) * buf.remove(0) should equal (2) * buf should be ('empty) * } * * "when 2 is removed" - { * * buf -= 2 * * "should contain only 1 again" in { * * // This test sees: * // val buf = ListBuffer.empty[Int] * // buf += 1 * // buf += 2 * // buf -= 2 * // So buf is: ListBuffer(1) * * buf.remove(0) should equal (1) * buf should be ('empty) * } * } * * "when 3 is appended" - { * * buf += 3 * * "should contain 1, 2, and 3" in { * * // This test sees: * // val buf = ListBuffer.empty[Int] * // buf += 1 * // buf += 2 * // buf += 3 * // So buf is: ListBuffer(1, 2, 3) * * buf.remove(0) should equal (1) * buf.remove(0) should equal (2) * buf.remove(0) should equal (3) * buf should be ('empty) * } * } * } * * "when 88 is appended" - { * * buf += 88 * * "should contain 1 and 88" in { * * // This test sees: * // val buf = ListBuffer.empty[Int] * // buf += 1 * // buf += 88 * // So buf is: ListBuffer(1, 88) * * buf.remove(0) should equal (1) * buf.remove(0) should equal (88) * buf should be ('empty) * } * } * } * * "should have size 0 when created" in { * * // This test sees: * // val buf = ListBuffer.empty[Int] * // So buf is: ListBuffer() * * buf should have size 0 * } * } * } ** ** Note that the above class is organized by writing a bit of specification text that opens a new block followed * by, at the top of the new block, some code that "implements" or "performs" what is described in the text. This is repeated as * the mutable object (here, a
ListBuffer
), is prepared for the enclosed tests. For example: ** *
* "A ListBuffer" - { * val buf = ListBuffer.empty[Int] ** ** Or: *
* ** "when 2 is appended" - { * buf += 2 ** ** Note also that although each test mutates the
ListBuffer
, none of the other tests observe those * side effects: ** *
* "should contain 1" in { * * buf.remove(0) should equal (1) * // ... * } * * "when 2 is appended" - { * * buf += 2 * * "should contain 1 and 2" in { * * // This test does not see the buf.remove(0) from the previous test, * // so the first element in the ListBuffer is again 1 * buf.remove(0) should equal (1) * buf.remove(0) should equal (2) ** ** This kind of isolation of tests from each other is a consequence of running each test in its own instance of the test * class, and can also be achieved by simply mixing
* *OneInstancePerTest
into a regular *org.scalatest.FreeSpec
. However,path.FreeSpec
takes isolation one step further: a test * in apath.FreeSpec
does not observe side effects performed outside tests in earlier blocks that do not * enclose it. Here's an example: ** "when 2 is removed" - { * * buf -= 2 * * // ... * } * * "when 3 is appended" - { * * buf += 3 * * "should contain 1, 2, and 3" in { * * // This test does not see the buf -= 2 from the earlier "when 2 is removed" block, * // because that block does not enclose this test, so the second element in the * // ListBuffer is still 2 * buf.remove(0) should equal (1) * buf.remove(0) should equal (2) * buf.remove(0) should equal (3) ** ** Running the full
* *ExampleSpec
, shown above, in the Scala interpeter would give you: ** scala> import org.scalatest._ * import org.scalatest._ * * scala> run(new ExampleSpec) * ExampleSpec: * A ListBuffer * - should be empty when created * when 1 is appended * - should contain 1 * when 2 is appended * - should contain 1 and 2 * when 2 is removed * - should contain only 1 again * when 3 is appended * - should contain 1, 2, and 3 * when 88 is appended * - should contain 1 and 88 * - should have size 0 when created *
* ** Note: trait
* *path.FreeSpec
's approach to isolation was inspired in part by the * specsy framework, written by Esko Luontola. *Shared fixtures
* ** A test fixture is objects or other artifacts (such as files, sockets, database * connections, etc.) used by tests to do their work. * If a fixture is used by only one test, then the definitions of the fixture objects can * be local to the method. If multiple tests need to share an immutable fixture, you can simply * assign them to instance variables. If multiple tests need to share mutable fixture objects or
* *var
s, * there's one and only one way to do it in apath.FreeSpec
: place the mutable objects lexically before * the test. Any mutations needed by the test must be placed lexically before and/or after the test. * As used here, "Lexically before" means that the code needs to be executed during construction of that test's * instance of the test class to reach the test (or put another way, the * code is along the "path to the test.") "Lexically after" means that the code needs to be executed to exit the * constructor after the test has been executed. ** The reason lexical placement is the one and only one way to share fixtures in a
* *path.FreeSpec
is because * all of its lifecycle methods are overridden and declaredfinal
. Thus you can't override *withFixture
, because it isfinal
, or mix inBeforeAndAfter
or *BeforeAndAfterEach
, because both overriderunTest
, which isfinal
in * apath.FreeSpec
. In short: **
*
* * ** ** In a *path.FreeSpec
, if you need some code to execute before a test, place that code lexically before * the test. If you need some code to execute after a test, place that code lexically after the test. ** The reason the life cycle methods are final, by the way, is to prevent users from attempting to combine * a
* *path.FreeSpec
's approach to isolation with other ways ScalaTest provides to share fixtures or * execute tests, because doing so could make the resulting test code hard to reason about. A *path.FreeSpec
's execution model is a bit magical, but because it executes in one and only one * way, users should be able to reason about the code. * To help you visualize how apath.FreeSpec
is executed, consider the following variant of *ExampleSpec
that includes print statements: ** import org.scalatest.path * import org.scalatest.matchers.ShouldMatchers * import scala.collection.mutable.ListBuffer * * class ExampleSpec extends path.FreeSpec with ShouldMatchers { * * println("Start of: ExampleSpec") * "A ListBuffer" - { * * println("Start of: A ListBuffer") * val buf = ListBuffer.empty[Int] * * "should be empty when created" in { * * println("In test: should be empty when created; buf is: " + buf) * buf should be ('empty) * } * * "when 1 is appended" - { * * println("Start of: when 1 is appended") * buf += 1 * * "should contain 1" in { * * println("In test: should contain 1; buf is: " + buf) * buf.remove(0) should equal (1) * buf should be ('empty) * } * * "when 2 is appended" - { * * println("Start of: when 2 is appended") * buf += 2 * * "should contain 1 and 2" in { * * println("In test: should contain 1 and 2; buf is: " + buf) * buf.remove(0) should equal (1) * buf.remove(0) should equal (2) * buf should be ('empty) * } * * "when 2 is removed" - { * * println("Start of: when 2 is removed") * buf -= 2 * * "should contain only 1 again" in { * * println("In test: should contain only 1 again; buf is: " + buf) * buf.remove(0) should equal (1) * buf should be ('empty) * } * * println("End of: when 2 is removed") * } * * "when 3 is appended" - { * * println("Start of: when 3 is appended") * buf += 3 * * "should contain 1, 2, and 3" in { * * println("In test: should contain 1, 2, and 3; buf is: " + buf) * buf.remove(0) should equal (1) * buf.remove(0) should equal (2) * buf.remove(0) should equal (3) * buf should be ('empty) * } * println("End of: when 3 is appended") * } * * println("End of: when 2 is appended") * } * * "when 88 is appended" - { * * println("Start of: when 88 is appended") * buf += 88 * * "should contain 1 and 88" in { * * println("In test: should contain 1 and 88; buf is: " + buf) * buf.remove(0) should equal (1) * buf.remove(0) should equal (88) * buf should be ('empty) * } * * println("End of: when 88 is appended") * } * * println("End of: when 1 is appended") * } * * "should have size 0 when created" in { * * println("In test: should have size 0 when created; buf is: " + buf) * buf should have size 0 * } * * println("End of: A ListBuffer") * } * println("End of: ExampleSpec") * println() * } ** ** Running the above version of
* *ExampleSpec
in the Scala interpreter will give you output similar to: ** scala> import org.scalatest._ * import org.scalatest._ * * scala> run(new ExampleSpec) * ExampleSpec: * Start of: ExampleSpec * Start of: A ListBuffer * In test: should be empty when created; buf is: ListBuffer() * End of: A ListBuffer * End of: ExampleSpec * * Start of: ExampleSpec * Start of: A ListBuffer * Start of: when 1 is appended * In test: should contain 1; buf is: ListBuffer(1) * ExampleSpec: * End of: when 1 is appended * End of: A ListBuffer * End of: ExampleSpec * * Start of: ExampleSpec * Start of: A ListBuffer * Start of: when 1 is appended * Start of: when 2 is appended * In test: should contain 1 and 2; buf is: ListBuffer(1, 2) * End of: when 2 is appended * End of: when 1 is appended * End of: A ListBuffer * End of: ExampleSpec * * Start of: ExampleSpec * Start of: A ListBuffer * Start of: when 1 is appended * Start of: when 2 is appended * Start of: when 2 is removed * In test: should contain only 1 again; buf is: ListBuffer(1) * End of: when 2 is removed * End of: when 2 is appended * End of: when 1 is appended * End of: A ListBuffer * End of: ExampleSpec * * Start of: ExampleSpec * Start of: A ListBuffer * Start of: when 1 is appended * Start of: when 2 is appended * Start of: when 3 is appended * In test: should contain 1, 2, and 3; buf is: ListBuffer(1, 2, 3) * End of: when 3 is appended * End of: when 2 is appended * End of: when 1 is appended * End of: A ListBuffer * End of: ExampleSpec * * Start of: ExampleSpec * Start of: A ListBuffer * Start of: when 1 is appended * Start of: when 88 is appended * In test: should contain 1 and 88; buf is: ListBuffer(1, 88) * End of: when 88 is appended * End of: when 1 is appended * End of: A ListBuffer * End of: ExampleSpec * * Start of: ExampleSpec * Start of: A ListBuffer * In test: should have size 0 when created; buf is: ListBuffer() * End of: A ListBuffer * End of: ExampleSpec * * A ListBuffer * - should be empty when created * when 1 is appended * - should contain 1 * when 2 is appended * - should contain 1 and 2 * when 2 is removed * - should contain only 1 again * when 3 is appended * - should contain 1, 2, and 3 * when 88 is appended * - should contain 1 and 88 * - should have size 0 when created ** ** Note that each test is executed in order of appearance in the
* * *path.FreeSpec
, and that only * thoseprintln
statements residing in blocks that enclose the test being run are executed. Any *println
statements in blocks that do not form the "path" to a test are not executed in the * instance of the class that executes that test. *How it executes
* ** To provide its special brand of test isolation,
path.FreeSpec
executes quite differently from its * sister trait inorg.scalatest
. Anorg.scalatest.FreeSpec
* registers tests during construction and executes them whenrun
is invoked. An *org.scalatest.path.FreeSpec
, by contrast, runs each test in its own instance while that * instance is being constructed. During construction, it registers not the tests to run, but the results of * running those tests. Whenrun
is invoked on apath.FreeSpec
, it reports the registered * results and does not run the tests again. Ifrun
is invoked a second or third time, in fact, * apath.FreeSpec
will each time report the same results registered during construction. If you want * to run the tests of apath.FreeSpec
anew, you'll need to create a new instance and invoke *run
on that. ** *
* A
* *path.FreeSpec
will create one instance for each "leaf" node it contains. The main kind of leaf node is * a test, such as: ** // One instance will be created for each test * "should be empty when created" in { * buf should be ('empty) * } ** ** However, an empty scope (a scope that contains no tests or nested scopes) is also a leaf node: *
* ** // One instance will be created for each empty scope * "when 99 is added" - { * // A scope is "empty" and therefore a leaf node if it has no * // tests or nested scopes, though it may have other code (which * // will be executed in the instance created for that leaf node) * buf += 99 * } ** ** The tests will be executed sequentially, in the order of appearance. The first test (or empty scope, * if that is first) will be executed when a class that mixes in
* *path.FreeSpec
is * instantiated. Only the first test will be executed during this initial instance, and of course, only * the path to that test. Then, the first time the client uses the initial instance (by invoking one ofrun
, *expectedTestsCount
,tags
, ortestNames
on the instance), the initial instance will, * before doing anything else, ensure that any remaining tests are executed, each in its own instance. ** To ensure that the correct path is taken in each instance, and to register its test results, the initial *
* * *path.FreeSpec
instance must communicate with the other instances it creates for running any subsequent * leaf nodes. It does so by setting a thread-local variable prior to creating each instance (a technique * suggested by Esko Luontola). Each instance * ofpath.FreeSpec
checks the thread-local variable. If the thread-local is not set, it knows it * is an initial instance and therefore executes every block it encounters until it discovers, and executes the * first test (or empty scope, if that's the first leaf node). It then discovers, but does not execute the next * leaf node, or discovers there are no other leaf nodes remaining to execute. It communicates the path to the next * leaf node, if any, and the result of running the test it did execute, if any, back to the initial instance. The * initial instance repeats this process until all leaf nodes have been executed and all test results registered. *Ignored tests
* ** You mark a test as ignored in an
* *org.scalatest.path.FreeSpec
in the same manner as in * anorg.scalatest.FreeSpec
. Please see the Ignored tests section * in its documentation for more information. ** Note that a separate instance will be created for an ignored test, * and the path to the ignored test will be executed in that instance, but the test function itself will not * be executed. Instead, a
* * *TestIgnored
event will be fired. *Informers
* ** You output information using
* * *Informer
s in anorg.scalatest.path.FreeSpec
in the same manner * as in anorg.scalatest.FreeSpec
. Please see the Informers * section in its documentation for more information. *Pending tests
* ** You mark a test as pending in an
* *org.scalatest.path.FreeSpec
in the same manner as in * anorg.scalatest.FreeSpec
. Please see the Pending tests * section in its documentation for more information. ** Note that a separate instance will be created for a pending test, * and the path to the ignored test will be executed in that instance, as well as the test function (up until it * completes abruptly with a
* * *TestPendingException
). *Tagging tests
* ** You can place tests into groups by tagging them in an
* *org.scalatest.path.FreeSpec
in the same manner * as in anorg.scalatest.FreeSpec
. Please see the Tagging tests * section in its documentation for more information. ** Note that one difference between this trait and its sister trait *
* *org.scalatest.FreeSpec
is that because tests are executed at construction time, rather than each * time run is invoked, anorg.scalatest.path.FreeSpec
will always execute all non-ignored tests. When *run
is invoked on apath.FreeSpec
, if some tests are excluded based on tags, the registered * results of running those tests will not be reported. (But those tests will have already run and the results * registered.) By contrast, because anorg.scalatest.FreeSpec
only executes tests afterrun
* has been called, and at that time the tags to include and exclude are known, only tests selected by the tags * will be executed. ** In short, in an
* *org.scalatest.FreeSpec
, tests not selected by the tags to include * and exclude specified for the run (via theFilter
passed torun
) will not be executed. * In anorg.scalatest.path.FreeSpec
, by contrast, all non-ignored tests will be executed, each * during the construction of its own instance, and tests not selected by the tags to include and exclude specified * for a run will not be reported. (One upshot of this is that if you have tests that you want to tag as being slow so * you can sometimes exclude them during a run, you probably don't want to put them in apath.FreeSpec
. Because * in apath.Freespec
the slow tests will be run regardless, with only their registered results not being reported * if you exclude slow tests during a run.) *Shared tests
** You can factor out shared tests in an
* *org.scalatest.path.FreeSpec
in the same manner as in * anorg.scalatest.FreeSpec
. Please see the Shared tests * section in its documentation for more information. *Nested suites
* ** Nested suites are not allowed in a
* * *path.FreeSpec
. Because * apath.FreeSpec
executes tests eagerly at construction time, registering the results of those test runs * and reporting them later whenrun
is invoked, the order of nested suites versus test runs would be * different in aorg.scalatest.path.FreeSpec
than in anorg.scalatest.FreeSpec
. In *org.scalatest.FreeSpec
's implementation ofrun
, nested suites are executed then tests * are executed. Aorg.scalatest.path.FreeSpec
with nested suites would execute these in the opposite * order: first tests then nested suites. To help makepath.FreeSpec
code easier to * reason about by giving readers of one less difference to think about, nested suites are not allowed. If you want * to add nested suites to apath.FreeSpec
, you can instead wrap them all in a *Suites
orSpecs
object. They will * be executed in the order of appearance (unless a Distributor is passed, in which case * they will execute in parallel). *Durations
** Many ScalaTest events include a duration that indicates how long the event being reported took to execute. For * example, a
* *TestSucceeded
event provides a duration indicating how long it took for that test * to execute. ASuiteCompleted
event provides a duration indicating how long it took for that entire * suite of tests to execute. ** In the test completion events fired by a
* * @author Bill Venners * @author Chua Chee Seng */ @Finders(Array("org.scalatest.finders.FreeSpecFinder")) trait FreeSpec extends org.scalatest.Suite with OneInstancePerTest { thisSuite => private final val engine = PathEngine.getEngine() import engine._ override def newInstance: FreeSpec = this.getClass.newInstance.asInstanceOf[FreeSpec] /** * Returns anpath.FreeSpec
(TestSucceeded
, *TestFailed
, orTestPending
), the durations reported refer * to the time it took for the tests to run. This time is registered with the test results and reported along * with the test results each timerun
is invoked. * By contrast, the suite completion events fired for apath.FreeSpec
represent the amount of time * it took to report the registered results. (These events are not fired bypath.FreeSpec
, but instead * by the entity that invokesrun
on thepath.FreeSpec
.) As a result, the total time * for running the tests of apath.FreeSpec
, calculated by summing the durations of all the individual * test completion events, may be greater than the duration reported for executing the entire suite. *Informer
that during test execution will forward strings (and other objects) passed to its *apply
method to the current reporter. If invoked in a constructor (including within a test, since * those are invoked during construction in apath.FreeSpec
, it * will register the passed string for forwarding later whenrun
is invoked. If invoked at any other * time, it will throw an exception. This method can be called safely by any thread. */ implicit protected def info: Informer = atomicInformer.get /** * Register a test with the given spec text, optional tags, and test function value that takes no arguments. * An invocation of this method is called an “example.” * * This method will register the test for later execution via an invocation of one of theexecute
* methods. The name of the test will be a concatenation of the text of all surrounding describers, * from outside in, and the passed spec text, with one space placed between each item. (See the documenation * fortestNames
for an example.) The resulting test name must not have been registered previously on * thisFreeSpec
instance. * * @param specText the specification text, which will be combined with the descText of any surrounding describers * to form the test name * @param testTags the optional list of tags for this test * @param methodName caller's method name * @param testFun the test function * @throws DuplicateTestNameException if a test with the same name has been registered previously * @throws TestRegistrationClosedException if invoked afterrun
has been invoked on this suite * @throws NullPointerException ifspecText
or any passed test tag isnull
*/ private def registerTestToRun(specText: String, testTags: List[Tag], methodName: String, testFun: () => Unit) { handleTest(thisSuite, specText, testFun, "itCannotAppearInsideAnotherIt", "FreeSpec.scala", methodName, 4, -3, None, testTags: _*) } /** * Register a test to ignore, which has the given spec text, optional tags, and test function value that takes no arguments. * This method will register the test for later ignoring via an invocation of one of theexecute
* methods. This method exists to make it easy to ignore an existing test by changing the call toit
* toignore
without deleting or commenting out the actual test code. The test will not be executed, but a * report will be sent that indicates the test was ignored. The name of the test will be a concatenation of the text of all surrounding describers, * from outside in, and the passed spec text, with one space placed between each item. (See the documentation * fortestNames
for an example.) The resulting test name must not have been registered previously on * thisFreeSpec
instance. * * @param specText the specification text, which will be combined with the descText of any surrounding describers * to form the test name * @param testTags the optional list of tags for this test * @param methodName caller's method name * @param testFun the test function * @throws DuplicateTestNameException if a test with the same name has been registered previously * @throws TestRegistrationClosedException if invoked afterrun
has been invoked on this suite * @throws NullPointerException ifspecText
or any passed test tag isnull
*/ private def registerTestToIgnore(specText: String, testTags: List[Tag], methodName: String, testFun: () => Unit) { handleIgnoredTest(specText, testFun, "ignoreCannotAppearInsideAnIt", "FreeSpec.scala", methodName, 4, -3, None, testTags: _*) } /** * Class that supports the registration of tagged tests. * ** Instances of this class are returned by the
* * @author Bill Venners */ protected final class ResultOfTaggedAsInvocationOnString(specText: String, tags: List[Tag]) { /** * Supports tagged test registration. * *taggedAs
method of * classFreeSpecStringWrapper
. ** For example, this method supports syntax such as the following: *
* ** "complain on peek" taggedAs(SlowTest) in { ... } * ^ ** ** This trait's implementation of this method will decide whether to register the text (passed to the constructor * of
*/ def in(testFun: => Unit) { registerTestToRun(specText, tags, "in", testFun _) } /** * Supports registration of tagged, pending tests. * *ResultOfTaggedAsInvocationOnString
) and invoke the passed function * based on whether or not this is part of the current "test path." For the details on this process, see * the How it executes section of the main documentation for * traitorg.scalatest.path.FreeSpec
. ** For example, this method supports syntax such as the following: *
* ** "complain on peek" taggedAs(SlowTest) is (pending) * ^ ** ** For more information and examples of this method's use, see the * Pending tests section in the main documentation for * sister trait
*/ def is(testFun: => PendingNothing) { registerTestToRun(specText, tags, "is", testFun _) } /** * Supports registration of tagged, ignored tests. * *org.scalatest.FreeSpec
. * Note that this trait's implementation of this method will decide whether to register the text (passed to the constructor * ofResultOfTaggedAsInvocationOnString
) and invoke the passed function * based on whether or not this is part of the current "test path." For the details on this process, see * the How it executes section of the main documentation for * traitorg.scalatest.path.FreeSpec
. ** For example, this method supports syntax such as the following: *
* ** "complain on peek" taggedAs(SlowTest) ignore { ... } * ^ ** ** For more information and examples of this method's use, see the * Ignored tests section in the main documentation for sister * trait
*/ def ignore(testFun: => Unit) { registerTestToIgnore(specText, tags, "ignore", testFun _) } } /** * A class that via an implicit conversion (namedorg.scalatest.FreeSpec
. Note that a separate instance will be created for an ignored test, * and the path to the ignored test will be executed in that instance, but the test function itself will not * be executed. Instead, aTestIgnored
event will be fired. *convertToFreeSpecStringWrapper
) enables * methodsin
,is
,taggedAs
andignore
, * as well as the dash operator (-
), to be invoked onString
s. * * @author Bill Venners */ protected final class FreeSpecStringWrapper(string: String) { /** * Register some text that may surround one or more tests. The passed * passed function value may contain surrounding text registrations (defined with dash (-
)) and/or tests * (defined within
). This class's implementation of this method will decide whether to * register the text (passed to the constructor ofFreeSpecStringWrapper
) and invoke the passed function * based on whether or not this is part of the current "test path." For the details on this process, see * the How it executes section of the main documentation for trait *org.scalatest.path.FreeSpec
. */ def - (fun: => Unit) { // TODO: Fix the resource name handleNestedBranch(string, None, fun, "describeCannotAppearInsideAnIt", "FreeSpec.scala", "-", 3, -2, None) } /** * Supports test registration. * ** For example, this method supports syntax such as the following: *
* ** "complain on peek" in { ... } * ^ ** ** This trait's implementation of this method will decide whether to register the text (passed to the constructor * of
*/ def in(f: => Unit) { registerTestToRun(string, List(), "in", f _) } /** * Supports ignored test registration. * *FreeSpecStringWrapper
) and invoke the passed function * based on whether or not this is part of the current "test path." For the details on this process, see * the How it executes section of the main documentation for * traitorg.scalatest.path.FreeSpec
. ** For example, this method supports syntax such as the following: *
* ** "complain on peek" ignore { ... } * ^ ** ** For more information and examples of this method's use, see the * Ignored tests section in the main documentation for sister * trait
*/ def ignore(f: => Unit) { registerTestToIgnore(string, List(), "ignore", f _) } /** * Supports pending test registration. * *org.scalatest.FreeSpec
. Note that a separate instance will be created for an ignored test, * and the path to the ignored test will be executed in that instance, but the test function itself will not * be executed. Instead, aTestIgnored
event will be fired. ** For example, this method supports syntax such as the following: *
* ** "complain on peek" is (pending) * ^ ** ** For more information and examples of this method's use, see the * Pending tests section in the main documentation for * sister trait
*/ def is(f: => PendingNothing) { registerTestToRun(string, List(), "is", f _) } /** * Supports tagged test registration. * *org.scalatest.FreeSpec
. * Note that this trait's implementation of this method will decide whether to register the text (passed to the constructor * ofFreeSpecStringWrapper
) and invoke the passed function * based on whether or not this is part of the current "test path." For the details on this process, see * the How it executes section of the main documentation for * traitorg.scalatest.path.FreeSpec
. ** For example, this method supports syntax such as the following: *
* ** "complain on peek" taggedAs(SlowTest) in { ... } * ^ ** ** For more information and examples of this method's use, see the * Tagging tests section in the main documentation for sister * trait
*/ def taggedAs(firstTestTag: Tag, otherTestTags: Tag*) = { val tagList = firstTestTag :: otherTestTags.toList new ResultOfTaggedAsInvocationOnString(string, tagList) } } /** * Implicitly convertsorg.scalatest.FreeSpec
. *String
s toFreeSpecStringWrapper
, which enables * methodsin
,is
,taggedAs
andignore
, * as well as the dash operator (-
), to be invoked onString
s. */ protected implicit def convertToFreeSpecStringWrapper(s: String) = new FreeSpecStringWrapper(s) /** * Supports shared test registration inpath.FreeSpec
s. * ** This field enables syntax such as the following: *
* ** behave like nonFullStack(stackWithOneItem) * ^ ** ** For more information and examples of the use of
behave org.scalatest.FreeSpec
. * */ protected val behave = new BehaveWord /** * This lifecycle method is unused by this trait, and will complete abruptly with *UnsupportedOperationException
if invoked. * ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
* * @param test unused */ final override def withFixture(test: NoArgTest) { throw new UnsupportedOperationException } /** * An immutableSet
of test names. If thisFreeSpec
contains no tests, this method returns an * emptySet
. * ** This trait's implementation of this method will first ensure that the results of all tests, each run its its * own instance executing only the path to the test, are registered. For details on this process see the * How it executes section in the main documentation for this trait. *
* ** This trait's implementation of this method will return a set that contains the names of all registered tests. The set's * iterator will return those names in the order in which the tests were registered. Each test's name is composed * of the concatenation of the text of each surrounding describer, in order from outside in, and the text of the * example itself, with all components separated by a space. For example, consider this
* *FreeSpec
: ** import org.scalatest.path * * class StackSpec extends path.FreeSpec { * "A Stack" - { * "when not empty" - { * "must allow me to pop" in {} * } * "when not full" - { * "must allow me to push" in {} * } * } * } ** ** Invoking
* *testNames
on thisFreeSpec
will yield a set that contains the following * two test name strings: ** "A Stack when not empty must allow me to pop" * "A Stack when not full must allow me to push" ** ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
*/ final override def testNames: Set[String] = { ensureTestResultsRegistered(thisSuite) // I'm returning a ListSet here so that they tests will be run in registration order ListSet(atomic.get.testNamesList.toArray: _*) } /** * The total number of tests that are expected to run when thispath.FreeSpec
'srun
method * is invoked. * ** This trait's implementation of this method will first ensure that the results of all tests, each run its its * own instance executing only the path to the test, are registered. For details on this process see the * How it executes section in the main documentation for this trait. *
* ** This trait's implementation of this method returns the size of the
* *testNames
List
, minus * the number of tests marked as ignored as well as any tests excluded by the passedFilter
. ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
* * @param filter aFilter
with which to filter tests to count based on their tags */ final override def expectedTestCount(filter: Filter): Int = { ensureTestResultsRegistered(thisSuite) super.expectedTestCount(filter) } /** * Runs a test. * ** This trait's implementation of this method will first ensure that the results of all tests, each run its its * own instance executing only the path to the test, are registered. For details on this process see the * How it executes section in the main documentation for this trait. *
* ** This trait's implementation reports the test results registered with the name specified by *
testName
. Each test's name is a concatenation of the text of all describers surrounding a test, * from outside in, and the test's spec text, with one space placed between each item. (See the documentation * fortestNames
for an example.) * ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
* * @param testName the name of one test to execute. * @param args theArgs
for this run * * @throws NullPointerException if any oftestName
,reporter
,stopper
, orconfigMap
* isnull
. */ final protected override def runTest(testName: String, args: Args): Status = { ensureTestResultsRegistered(thisSuite) def dontInvokeWithFixture(theTest: TestLeaf) { theTest.testFun() } runTestImpl(thisSuite, testName, args, true, dontInvokeWithFixture) } /** * AMap
whose keys areString
tag names to which tests in thispath.FreeSpec
* belong, and values theSet
of test names that belong to each tag. If thispath.FreeSpec
* contains no tags, this method returns an emptyMap
. * ** This trait's implementation of this method will first ensure that the results of all tests, each run its its * own instance executing only the path to the test, are registered. For details on this process see the * How it executes section in the main documentation for this trait. *
* ** This trait's implementation returns tags that were passed as strings contained in
* *Tag
objects passed * to methodstest
andignore
. ** In addition, this trait's implementation will also auto-tag tests with class level annotations. * For example, if you annotate @Ignore at the class level, all test methods in the class will be auto-annotated with @Ignore. *
* ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
*/ final override def tags: Map[String, Set[String]] = { ensureTestResultsRegistered(thisSuite) autoTagClassAnnotations(atomic.get.tagsMap, this) } /** * Runs thispath.FreeSpec
, reporting test results that were registered when the tests * were run, each during the construction of its own instance. * ** This trait's implementation of this method will first ensure that the results of all tests, each run its its * own instance executing only the path to the test, are registered. For details on this process see the * How it executes section in the main documentation for this trait. *
* *If
* *testName
isNone
, this trait's implementation of this method * will report the registered results for all tests except any excluded by the passedFilter
. * IftestName
is defined, it will report the results of only that named test. Because a *path.FreeSpec
is not allowed to contain nested suites, this trait's implementation of * this method does not callrunNestedSuites
. ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
* * @param testName an optional name of one test to run. IfNone
, all relevant tests should be run. * I.e.,None
acts like a wildcard that means run all relevant tests in thisSuite
. * @param args theArgs
for this run * * @throws NullPointerException if any passed parameter isnull
. * @throws IllegalArgumentException iftestName
is defined, but no test with the specified test name * exists in thisSuite
*/ final override def run(testName: Option[String], args: Args): Status = { // TODO enforce those throws specs ensureTestResultsRegistered(thisSuite) runPathTestsImpl(thisSuite, testName, args, info, true, runTest) } /** * This lifecycle method is unused by this trait, and will complete abruptly with *UnsupportedOperationException
if invoked. * ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
*/ final protected override def runTests(testName: Option[String], args: Args): Status = { throw new UnsupportedOperationException } /** * This lifecycle method is unused by this trait, and is implemented to do nothing. If invoked, it will * just return immediately. * ** Nested suites are not allowed in a
* *path.FreeSpec
. Because * apath.FreeSpec
executes tests eagerly at construction time, registering the results of * those test runs and reporting them later, the order of nested suites versus test runs would be different * in aorg.scalatest.path.FreeSpec
than in anorg.scalatest.FreeSpec
. In an *org.scalatest.FreeSpec
, nested suites are executed then tests are executed. In an *org.scalatest.path.FreeSpec
it would be the opposite. To make the code easy to reason about, * therefore, this is just not allowed. If you want to add nested suites to apath.FreeSpec
, you can * instead wrap them all in aSuites
or *Specs
object and put them in whatever order * you wish. ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
*/ final protected override def runNestedSuites(args: Args): Status = SucceededStatus /** * Returns an empty list. * ** This lifecycle method is unused by this trait. If invoked, it will return an empty list, because * nested suites are not allowed in a
* *path.FreeSpec
. Because * apath.FreeSpec
executes tests eagerly at construction time, registering the results of * those test runs and reporting them later, the order of nested suites versus test runs would be different * in aorg.scalatest.path.FreeSpec
than in anorg.scalatest.FreeSpec
. In an *org.scalatest.FreeSpec
, nested suites are executed then tests are executed. In an *org.scalatest.path.FreeSpec
it would be the opposite. To make the code easy to reason about, * therefore, this is just not allowed. If you want to add nested suites to apath.FreeSpec
, you can * instead wrap them all in aSuites
or *Specs
object and put them in whatever order * you wish. ** This trait's implementation of this method is marked as final. For insight onto why, see the * Shared fixtures section in the main documentation for this trait. *
*/ final override def nestedSuites: collection.immutable.IndexedSeq[Suite] = Vector.empty /** * Suite style name. */ final override val styleName: String = "org.scalatest.path.FreeSpec" override def testDataFor(testName: String, theConfigMap: Map[String, Any] = Map.empty): TestData = { ensureTestResultsRegistered(thisSuite) createTestDataFor(testName, theConfigMap, this) } }