1/*
2 * Copyright 2001-2009 Artima, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.scalatest
17
18/**
19 * Trait that can be mixed into suites that need methods invoked before and after executing the
20 * suite. This trait allows code to be executed before and/or after all the tests and nested suites of a
21 * suite are run. This trait overrides <code>run</code> (the main <code>run</code> method that
22 * takes seven parameters, an optional test name, reporter, stopper, filter, configMap, optional distributor,
23 * and tracker) and calls the
24 * <code>beforeAll</code> method, then calls <code>super.run</code>. After the <code>super.run</code>
25 * invocation completes, whether it returns normally or completes abruptly with an exception,
26 * this trait's <code>run</code> method will invoke <code>afterAll</code>.
27 *
28 * <p>
29 * Trait <code>BeforeAndAfterAll</code> defines two overloaded variants  each of <code>beforeAll</code>
30 * and <code>afterAll</code>, one that takes a <code>configMap</code> and another that takes no
31 * arguments. This traits implemention of the variant that takes the <code>configMap</code>
32 * simply invokes the variant that takes no parameters, which does nothing. Thus you can override
33 * whichever variant you want. If you need something from the <code>configMap</code> before
34 * all tests and nested suites are run, override <code>beforeAll(Map[String, Any])</code>. Otherwise,
35 * override <code>beforeAll()</code>.
36 * </p>
37 *
38 * <p>
39 * For example, the following <code>MasterSuite</code> mixes in <code>BeforeAndAfterAll</code> and
40 * in <code>beforeAll</code>, creates and writes to a temp file, taking the name of the temp file
41 * from the <code>configMap</code>. This same <code>configMap</code> is then passed to the <code>run</code>
42 * methods of the nested suites, <code>OneSuite</code>, <code>TwoSuite</code>, <code>RedSuite</code>,
43 * and <code>BlueSuite</code>, so those suites can access the filename and, therefore, the file's
44 * contents. After all of the nested suites have executed, <code>afterAll</code> is invoked, which
45 * again grabs the file name from the <code>configMap</code> and deletes the file:
46 * </p>
47 *
48 * <pre class="stHighlight">
49 * import org.scalatest.SuperSuite
50 * import org.scalatest.BeforeAndAfterAll
51 * import java.io.FileReader
52 * import java.io.FileWriter
53 * import java.io.File
54 *
55 * class MasterSuite extends Suite with BeforeAndAfterAll {
56 *
57 *   private val FileNameKeyInGoodies = "tempFileName"
58 *
59 *   // Set up the temp file needed by the test, taking
60 *   // a file name from the configMap
61 *   override def beforeAll(configMap: Map[String, Any]) {
62 *
63 *     require(
64 *       configMap.isDefinedAt(FileNameKeyInGoodies),
65 *       "must place a temp file name in the configMap under the key: " + FileNameKeyInGoodies
66 *     )
67 *
68 *     val fileName = configMap(tempFileName)
69 *
70 *     val writer = new FileWriter(fileName)
71 *     try {
72 *       writer.write("Hello, suite of tests!")
73 *     }
74 *     finally {
75 *       writer.close()
76 *     }
77 *   }
78 *
79 *   override def nestedSuites =
80 *     List(new OneSuite, new TwoSuite, new RedSuite, new BlueSuite)
81 *
82 *   // Delete the temp file
83 *   override def afterAll(configMap: Map[String, Any]) {
84 *     // No need to require that configMap contains the key again because it won't get
85 *     // here if it didn't contain the key in beforeAll
86 *     val fileName = configMap(tempFileName))
87 *     val file = new File(fileName)
88 *     file.delete()
89 *   }
90 * }
91 * </pre>
92 *
93 * <p>
94 * Because the <code>BeforeAndAfterAll</code> trait invokes <code>super.run</code> to run the suite, you may need to
95 * mix this trait in last to get the desired behavior. For example, this won't
96 * work, because <code>BeforeAndAfterAll</code> is "super" to </code>FunSuite</code>:
97 * </p>
98 * <pre class="stHighlight">
99 * class MySuite extends BeforeAndAfterAll with FunSuite
100 * </pre>
101 * <p>
102 * You'd need to turn it around, so that <code>FunSuite</code> is "super" to <code>BeforeAndAfterAll</code>, like this:
103 * </p>
104 * <pre class="stHighlight">
105 * class MySuite extends FunSuite with BeforeAndAfterAll
106 * </pre>
107 *
108 * <strong>Note: This trait does not currently ensure that the code in <code>afterAll</code> is executed after
109 * all the tests and nested suites are executed if a <code>Distributor</code> is passed. The
110 * plan is to do that eventually, but in the meantime, be aware that <code>afterAll</code> is
111 * guaranteed to be run after all the tests and nested suites only when they are run
112 * sequentially.</strong>
113 *
114 * @author Bill Venners
115 */
116trait BeforeAndAfterAll  extends AbstractSuite {
117
118  this: Suite =>
119
120  /**
121   * Defines a method to be run before any of this suite's tests or nested suites are run.
122   *
123   * <p>
124   * This trait's implementation
125   * of <code>run</code> invokes the overloaded form of this method that
126   * takes a <code>configMap</code> before executing
127   * any tests or nested suites. This trait's implementation of that <code>beforeAll(Map[String, Any])</code>
128   * method simply invokes this <code>beforeAll()</code>
129   * method. Thus this method can be used to set up a test fixture
130   * needed by the entire suite, when you don't need anything from the <code>configMap</code>.
131   * This trait's implementation of this method does nothing.
132   * </p>
133   */
134  protected def beforeAll() = ()
135
136  /**
137   * Defines a method (that takes a <code>configMap</code>) to be run before any
138   * of this suite's tests or nested suites are run.
139   *
140   * <p>
141   * This trait's implementation
142   * of <code>run</code> invokes this method before executing
143   * any tests or nested suites (passing in the <code>configMap</code> passed to it), thus this
144   * method can be used to set up a test fixture
145   * needed by the entire suite. This trait's implementation of this method invokes the
146   * overloaded form of <code>beforeAll</code> that takes no <code>configMap</code>.
147   * </p>
148   */
149  protected def beforeAll(configMap: Map[String, Any]) {
150    beforeAll()
151  }
152
153  /**
154   * Defines a method to be run after all of this suite's tests and nested suites have
155   * been run.
156   *
157   * <p>
158   * This trait's implementation
159   * of <code>run</code> invokes the overloaded form of this method that
160   * takes a <code>configMap</code> after executing
161   * all tests and nested suites. This trait's implementation of that <code>afterAll(Map[String, Any])</code> method simply invokes this
162   * <code>afterAll()</code> method. Thus this method can be used to tear down a test fixture
163   * needed by the entire suite, when you don't need anything from the <code>configMap</code>.
164   * This trait's implementation of this method does nothing.
165   * </p>
166   */
167  protected def afterAll() = ()
168
169  /**
170   * Defines a method (that takes a <code>configMap</code>) to be run after
171   * all of this suite's tests and nested suites have been run.
172   *
173   * <p>
174   * This trait's implementation
175   * of <code>run</code> invokes this method after executing all tests
176   * and nested suites (passing in the <code>configMap</code> passed to it), thus this
177   * method can be used to tear down a test fixture
178   * needed by the entire suite. This trait's implementation of this method invokes the
179   * overloaded form of <code>afterAll</code> that takes no <code>configMap</code>.
180   * </p>
181   */
182  protected def afterAll(configMap: Map[String, Any]) {
183    afterAll()
184  }
185
186  /**
187   * Execute a suite surrounded by calls to <code>beforeAll</code> and <code>afterAll</code>.
188   *
189   * <p>
190   * This trait's implementation of this method ("this method") invokes <code>beforeAll(Map[String, Any])</code>
191   * before executing any tests or nested suites and <code>afterAll(Map[String, Any])</code>
192   * after executing all tests and nested suites. It runs the suite by invoking <code>super.run</code>, passing along
193   * the seven parameters passed to it.
194   * </p>
195   *
196   * <p>
197   * If any invocation of <code>beforeAll</code> completes abruptly with an exception, this
198   * method will complete abruptly with the same exception. If any call to
199   * <code>super.run</code> completes abruptly with an exception, this method
200   * will complete abruptly with the same exception, however, before doing so, it will
201   * invoke <code>afterAll</code>. If <cod>afterAll</code> <em>also</em> completes abruptly with an exception, this
202   * method will nevertheless complete abruptly with the exception previously thrown by <code>super.run</code>.
203   * If <code>super.run</code> returns normally, but <code>afterAll</code> completes abruptly with an
204   * exception, this method will complete abruptly with the same exception.
205   * </p>
206  */
207  abstract override def run(testName: Option[String], reporter: Reporter, stopper: Stopper, filter: Filter,
208                       configMap: Map[String, Any], distributor: Option[Distributor], tracker: Tracker) {
209    var thrownException: Option[Throwable] = None
210
211    beforeAll(configMap)
212    try {
213      super.run(testName, reporter, stopper, filter, configMap, distributor, tracker)
214    }
215    catch {
216      case e: Exception => thrownException = Some(e)
217    }
218    finally {
219      try {
220        afterAll(configMap) // Make sure that afterAll is called even if run completes abruptly.
221        thrownException match {
222          case Some(e) => throw e
223          case None =>
224        }
225      }
226      catch {
227        case laterException: Exception =>
228          thrownException match { // If both run and afterAll throw an exception, report the test exception
229            case Some(earlierException) => throw earlierException
230            case None => throw laterException
231          }
232      }
233    }
234  }
235}
236