-
-
Notifications
You must be signed in to change notification settings - Fork 224
/
ClassRunner.scala
128 lines (106 loc) · 4.83 KB
/
ClassRunner.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package org.specs2
package runner
import control.*
import io.StringOutput
import specification.process.*
import specification.core.*
import reporter.*
import main.Arguments
import fp.syntax.*
import Runner.*
import scala.concurrent.*
trait ClassRunner:
def run(className: String): Action[Stats]
def run(spec: SpecificationStructure): Action[Stats]
def run(spec: SpecStructure): Action[Stats]
/** A runner for Specification classes based on their names
*/
case class DefaultClassRunner(env: Env, reporter: Reporter, specFactory: SpecFactory) extends ClassRunner:
val arguments: Arguments =
env.arguments
/** instantiate a Specification from its class name and use arguments to determine how to execute it and report
* results
*/
def run(className: String): Action[Stats] =
specFactory.createSpecification(className).toAction.flatMap(spec => run(spec.structure)) |||
Action
.pure(println("cannot instantiate the specification: " + className + ". Please check your classpath"))
.as(Stats.empty)
def run(spec: SpecificationStructure): Action[Stats] =
run(spec.structure)
def run(specStructure: SpecStructure): Action[Stats] =
val allSpecs = arguments.isSet("all")
if allSpecs then
for
ss <- specFactory.createLinkedSpecs(specStructure).toAction
sorted <- Action.pure(SpecStructure.topologicalSort(ss)(env.specs2ExecutionEnv).getOrElse(ss))
stats <- reporter.report(sorted.toList)
yield stats
else reporter.report(specStructure)
trait ClassRunnerMain:
/** run a specification but don't exit with System.exit
*/
def run(args: Array[String]): Unit =
run(args, exit = false)
/** run the specification, the first argument is expected to be the specification name The class runner expects the
* first command-line argument to be the class name of a specification to execute
*/
def run(args: Array[String], exit: Boolean): Unit =
val arguments = Arguments(args.drop(1)*)
val env = EnvDefault.create(arguments)
val actions: Action[Stats] = args.toList match
case List() =>
Action.fail("there must be at least one argument, the fully qualified class name") >>
Action.pure(Stats.empty)
case className :: rest =>
for
classRunner <- createClassRunner(env).toAction
stats <- classRunner.run(className)
yield stats
try execute(actions, env, exit)
finally env.shutdown()
/** Create a ClassRunner from the default environment containing the command line arguments
*/
def createClassRunner(env: Env): Operation[ClassRunner] =
val arguments = env.arguments
val loader = Thread.currentThread.getContextClassLoader
val customInstances = CustomInstances(arguments, loader, env.systemLogger)
val printerFactory = PrinterFactory(arguments, customInstances, env.systemLogger)
val specFactory = DefaultSpecFactory(env, loader)
for
printers <- printerFactory.createPrinters
reporter <- Reporter.createCustomInstance(customInstances).map(_.getOrElse(Reporter.create(printers, env)))
yield DefaultClassRunner(env, reporter, specFactory)
object ClassRunner extends ClassRunnerMain
object consoleRunner extends ClassRunnerMain:
def main(args: Array[String]) =
run(args, exit = true)
/** Test runner to simulate a console run
*/
object TextRunner extends ClassRunnerMain:
def run(spec: SpecificationStructure, arguments: Arguments = Arguments())(env: Env): PrinterLogger & StringOutput =
val logger = PrinterLogger.stringPrinterLogger
val env1 = env.setPrinterLogger(logger).setArguments(env.arguments.overrideWith(arguments))
val loader = Thread.currentThread.getContextClassLoader
val customInstances = CustomInstances(arguments, loader, StringOutputLogger(logger))
val action =
for
reporter <- customInstances
.createCustomInstance[Reporter](
"reporter",
(m: String) => "a custom reporter can not be instantiated " + m,
"no custom reporter defined, using the default one"
)
.map(_.getOrElse(Reporter.create(List(TextPrinter(env1)), env1)))
.toAction
stats <- reporter.report(spec.structure)
yield stats
action.runAction(env1.specs2ExecutionEnv)
logger
/** this method returns a Future and does not try to instantiate any class so it is suitable for ScalaJS */
def runFuture(spec: SpecificationStructure, arguments: Arguments = Arguments())(env: Env): Future[PrinterLogger & StringOutput] =
val logger = PrinterLogger.stringPrinterLogger
val env1 = env.setPrinterLogger(logger).setArguments(env.arguments.overrideWith(arguments))
given ExecutionContext = env1.executionContext
val reporter = Reporter.create(List(TextPrinter(env1)), env1)
reporter.report(spec.structure).runFuture(env1.specs2ExecutionEnv).map(_ => logger)