1/*
2 * Copyright 2001-2008 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
18import org.scalatest.Suite.checkForPublicNoArgConstructor
19
20import org.scalatest.events._
21import Suite.formatterForSuiteStarting
22import Suite.formatterForSuiteCompleted
23import Suite.formatterForSuiteAborted
24
25/**
26 * A Rerunner for Suites.
27 *
28 * @author Bill Venners
29 */
30private[scalatest] class SuiteRerunner(suiteClassName: String) extends Rerunner {
31
32  if (suiteClassName == null)
33    throw new NullPointerException
34
35  def apply(report: Reporter, stopRequested: Stopper, filter: Filter,
36            configMap: Map[String, Any], distributor: Option[Distributor], tracker: Tracker, loader: ClassLoader) {
37
38    val tagsToInclude =
39      filter.tagsToInclude match {
40        case None => Set[String]()
41        case Some(tti) => tti
42      }
43    val tagsToExclude = filter.tagsToExclude
44
45    val runStartTime = System.currentTimeMillis
46
47    try {
48      val suiteClass = loader.loadClass(suiteClassName)
49      val suite = suiteClass.newInstance().asInstanceOf[Suite]
50      val expectedTestCount = suite.expectedTestCount(filter)
51
52      // Create a Rerunner if the Suite has a public no-arg constructor
53      val rerunnable =
54        if (Suite.checkForPublicNoArgConstructor(suite.getClass))
55          Some(new SuiteRerunner(suite.getClass.getName))
56        else
57          None
58
59      report(RunStarting(tracker.nextOrdinal(), expectedTestCount, configMap))
60
61      val suiteStartTime = System.currentTimeMillis
62      try {
63
64        val rawString = Resources("suiteExecutionStarting")
65        val formatter = formatterForSuiteStarting(suite)
66
67        report(SuiteStarting(tracker.nextOrdinal(), suite.suiteName, Some(suite.getClass.getName), formatter, rerunnable))
68
69        suite.run(None, report, stopRequested, filter, configMap, distributor, tracker)
70
71        val rawString2 = Resources("suiteCompletedNormally")
72        val formatter2 = formatterForSuiteCompleted(suite)
73        val duration = System.currentTimeMillis - suiteStartTime
74
75        report(SuiteCompleted(tracker.nextOrdinal(), suite.suiteName, Some(suite.getClass.getName), Some(duration), formatter2, rerunnable))
76      }
77      catch {
78        case e: RuntimeException => {
79          val rawString3 = Resources("executeException")
80          val formatter3 = formatterForSuiteAborted(suite, rawString3)
81
82          val duration = System.currentTimeMillis - suiteStartTime
83          report(SuiteAborted(tracker.nextOrdinal(), rawString3, suite.suiteName, Some(suite.getClass.getName), Some(e), Some(duration), formatter3, rerunnable))
84        }
85      }
86
87      val duration = System.currentTimeMillis - runStartTime
88      if (stopRequested()) {
89        report(RunStopped(tracker.nextOrdinal(), Some(duration)))
90      }
91      else {
92        report(RunCompleted(tracker.nextOrdinal(), Some(duration)))
93      }
94    }
95    catch {
96      case e: ClassNotFoundException => {
97        val duration = System.currentTimeMillis - runStartTime
98        report(RunAborted(tracker.nextOrdinal(), Resources("cannotLoadSuite", e.getMessage), Some(e), Some(duration)))
99      }
100      case e: InstantiationException => {
101        val duration = System.currentTimeMillis - runStartTime
102        report(RunAborted(tracker.nextOrdinal(), Resources("cannotInstantiateSuite", e.getMessage), Some(e), Some(duration)))
103      }
104      case e: IllegalAccessException => {
105        val duration = System.currentTimeMillis - runStartTime
106        report(RunAborted(tracker.nextOrdinal(), Resources("cannotInstantiateSuite", e.getMessage), Some(e), Some(duration)))
107      }
108      case e: SecurityException => {
109        val duration = System.currentTimeMillis - runStartTime
110        report(RunAborted(tracker.nextOrdinal(), Resources("securityWhenRerruning", e.getMessage), Some(e), Some(duration)))
111      }
112      case e: NoClassDefFoundError => {
113        // Suggest the problem might be a bad runpath
114        // Maybe even print out the current runpath
115        val duration = System.currentTimeMillis - runStartTime
116        report(RunAborted(tracker.nextOrdinal(), Resources("cannotLoadClass", e.getMessage), Some(e), Some(duration)))
117      }
118      case e: Throwable => {
119        val duration = System.currentTimeMillis - runStartTime
120        report(RunAborted(tracker.nextOrdinal(), Resources.bigProblems(e), Some(e), Some(duration)))
121      }
122    }
123  }
124}
125