Skip to content
This repository was archived by the owner on Sep 8, 2022. It is now read-only.

Commit 7c9a535

Browse files
gourlaysamaszeiger
authored andcommitted
extract internal partest behavior from ConsoleRunner
This splits ConsoleRunner in two: AbstractRunner contains most of the behavior but doesn't assume (or at least less that before...) that we are running from the command line. ConsoleRunner extends it to do the same as before. Now SBTRunner also extends AbstractRunner (instead of AntRunner), to get support for --grep, --update-check, and all other options, for testing an explicit file, and for pretty output. This requires changes on the scala-partest-interface side too (SBTRunner's public API has changed).
1 parent ee3ae8a commit 7c9a535

File tree

5 files changed

+217
-198
lines changed

5 files changed

+217
-198
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/* NEST (New Scala Test)
2+
* Copyright 2007-2013 LAMP/EPFL
3+
* @author Philipp Haller
4+
*/
5+
6+
package scala.tools
7+
package partest
8+
package nest
9+
10+
import utils.Properties._
11+
import scala.tools.nsc.Properties.{ versionMsg, propOrFalse, setProp }
12+
import scala.collection.{ mutable, immutable }
13+
import TestKinds._
14+
import scala.reflect.internal.util.Collections.distinctBy
15+
import scala.tools.cmd.{ CommandLine, CommandLineParser, Instance }
16+
17+
abstract class AbstractRunner(argstr: String) extends {
18+
val parsed = RunnerSpec.creator(CommandLineParser tokenize argstr)
19+
} with RunnerSpec with Instance {
20+
21+
val suiteRunner: SuiteRunner
22+
23+
import suiteRunner._
24+
import NestUI._
25+
import NestUI.color._
26+
27+
private var totalTests = 0
28+
private val passedTests = mutable.ListBuffer[TestState]()
29+
private val failedTests = mutable.ListBuffer[TestState]()
30+
31+
def comment(s: String) = echo(magenta("# " + s))
32+
def levyJudgment() = {
33+
if (totalTests == 0) echoMixed("No tests to run.")
34+
else if (elapsedMillis == 0) echoMixed("Test Run ABORTED")
35+
else if (isSuccess) echoPassed("Test Run PASSED")
36+
else echoFailed("Test Run FAILED")
37+
}
38+
39+
def passFailString(passed: Int, failed: Int, skipped: Int): String = {
40+
val total = passed + failed + skipped
41+
val isSuccess = failed == 0
42+
def p0 = s"$passed/$total"
43+
def p = ( if (isSuccess) bold(green(p0)) else p0 ) + " passed"
44+
def f = if (failed == 0) "" else bold(red("" + failed)) + " failed"
45+
def s = if (skipped == 0) "" else bold(yellow("" + skipped)) + " skipped"
46+
47+
oempty(p, f, s) mkString ", "
48+
}
49+
50+
protected var summarizing = false
51+
private var elapsedMillis = 0L
52+
private var expectedFailures = 0
53+
protected def isSuccess = failedTests.size == expectedFailures
54+
55+
def issueSummaryReport() {
56+
// Don't run twice
57+
if (!summarizing) {
58+
summarizing = true
59+
60+
val passed0 = passedTests.toList
61+
val failed0 = failedTests.toList
62+
val passed = passed0.size
63+
val failed = failed0.size
64+
val skipped = totalTests - (passed + failed)
65+
val passFail = passFailString(passed, failed, skipped)
66+
val elapsed = if (elapsedMillis > 0) " (elapsed time: " + elapsedString(elapsedMillis) + ")" else ""
67+
val message = passFail + elapsed
68+
69+
if (failed0.nonEmpty) {
70+
if (isPartestVerbose) {
71+
echo(bold(cyan("##### Transcripts from failed tests #####\n")))
72+
failed0 foreach { state =>
73+
comment("partest " + state.testFile)
74+
echo(state.transcriptString + "\n")
75+
}
76+
}
77+
78+
def files_s = failed0.map(_.testFile).mkString(""" \""" + "\n ")
79+
echo("# Failed test paths (this command will update checkfiles)")
80+
echo("test/partest --update-check \\\n " + files_s + "\n")
81+
}
82+
83+
echo(message)
84+
levyJudgment()
85+
}
86+
}
87+
88+
def run(): Unit = {
89+
if (optDebug || propOrFalse("partest.debug")) NestUI.setDebug()
90+
if (optVerbose) NestUI.setVerbose()
91+
if (optTerse) NestUI.setTerse()
92+
if (optShowDiff) NestUI.setDiffOnFail()
93+
94+
// Early return on no args, version, or invalid args
95+
if (optVersion) return echo(versionMsg)
96+
if (optHelp) return NestUI.usage()
97+
98+
val (individualTests, invalid) = parsed.residualArgs map (p => Path(p)) partition denotesTestPath
99+
if (invalid.nonEmpty) {
100+
if (isPartestVerbose)
101+
invalid foreach (p => echoWarning(s"Discarding invalid test path " + p))
102+
else if (!isPartestTerse)
103+
echoWarning(s"Discarding ${invalid.size} invalid test paths")
104+
}
105+
106+
optTimeout foreach (x => setProp("partest.timeout", x))
107+
108+
if (!isPartestTerse)
109+
NestUI echo banner
110+
111+
val partestTests = (
112+
if (optSelfTest) TestKinds.testsForPartest
113+
else Nil
114+
)
115+
116+
val grepExpr = optGrep getOrElse ""
117+
118+
// If --grep is given we suck in every file it matches.
119+
// TODO: intersect results of grep with specified kinds, if any
120+
val greppedTests = if (grepExpr == "") Nil else {
121+
val paths = grepFor(grepExpr)
122+
if (paths.isEmpty)
123+
echoWarning(s"grep string '$grepExpr' matched no tests.\n")
124+
125+
paths.sortBy(_.toString)
126+
}
127+
128+
val isRerun = optFailed
129+
val rerunTests = if (isRerun) TestKinds.failedTests else Nil
130+
def miscTests = partestTests ++ individualTests ++ greppedTests ++ rerunTests
131+
132+
val givenKinds = standardKinds filter parsed.isSet
133+
val kinds = (
134+
if (givenKinds.nonEmpty) givenKinds
135+
else if (miscTests.isEmpty) standardKinds // If no kinds, --grep, or individual tests were given, assume --all
136+
else Nil
137+
)
138+
val kindsTests = kinds flatMap testsFor
139+
140+
def testContributors = {
141+
List(
142+
if (partestTests.isEmpty) "" else "partest self-tests",
143+
if (rerunTests.isEmpty) "" else "previously failed tests",
144+
if (kindsTests.isEmpty) "" else s"${kinds.size} named test categories",
145+
if (greppedTests.isEmpty) "" else s"${greppedTests.size} tests matching '$grepExpr'",
146+
if (individualTests.isEmpty) "" else "specified tests"
147+
) filterNot (_ == "") mkString ", "
148+
}
149+
150+
val allTests: Array[Path] = distinctBy(miscTests ++ kindsTests)(_.toCanonical) sortBy (_.toString) toArray
151+
val grouped = (allTests groupBy kindOf).toArray sortBy (x => standardKinds indexOf x._1)
152+
153+
totalTests = allTests.size
154+
expectedFailures = propOrNone("partest.errors") match {
155+
case Some(num) => num.toInt
156+
case _ => 0
157+
}
158+
val expectedFailureMessage = if (expectedFailures == 0) "" else s" (expecting $expectedFailures to fail)"
159+
echo(s"Selected $totalTests tests drawn from $testContributors$expectedFailureMessage\n")
160+
161+
val (_, millis) = timed {
162+
for ((kind, paths) <- grouped) {
163+
val num = paths.size
164+
val ss = if (num == 1) "" else "s"
165+
comment(s"starting $num test$ss in $kind")
166+
val results = runTestsForFiles(paths map (_.jfile.getAbsoluteFile), kind)
167+
val (passed, failed) = results partition (_.isOk)
168+
169+
passedTests ++= passed
170+
failedTests ++= failed
171+
if (failed.nonEmpty) {
172+
comment(passFailString(passed.size, failed.size, 0) + " in " + kind)
173+
}
174+
echo("")
175+
}
176+
}
177+
this.elapsedMillis = millis
178+
issueSummaryReport()
179+
}
180+
}

src/main/scala/scala/tools/partest/nest/ConsoleRunner.scala

Lines changed: 5 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -7,185 +7,23 @@ package scala.tools
77
package partest
88
package nest
99

10-
import utils.Properties._
11-
import scala.tools.nsc.Properties.{ versionMsg, propOrFalse, setProp }
12-
import scala.collection.{ mutable, immutable }
13-
import TestKinds._
14-
import scala.reflect.internal.util.Collections.distinctBy
15-
import scala.tools.cmd.{ CommandLine, CommandLineParser, Instance }
10+
class ConsoleRunner(argstr: String) extends AbstractRunner(argstr) {
1611

17-
class ConsoleRunner(argstr: String) extends {
18-
val parsed = ConsoleRunnerSpec.creator(CommandLineParser tokenize argstr)
19-
} with ConsoleRunnerSpec with Instance {
20-
21-
val suiteRunner = new SuiteRunner (
12+
override val suiteRunner = new SuiteRunner (
2213
testSourcePath = optSourcePath getOrElse PartestDefaults.sourcePath,
2314
fileManager = new FileManager(ClassPath split PathResolver.Environment.javaUserClassPath map (Path(_))), // the script sets up our classpath for us via ant
2415
updateCheck = optUpdateCheck,
2516
failed = optFailed)
26-
import suiteRunner._
27-
import NestUI._
28-
import NestUI.color._
2917

3018
// So we can ctrl-C a test run and still hear all
3119
// the buffered failure info.
3220
scala.sys addShutdownHook issueSummaryReport()
3321

34-
private var totalTests = 0
35-
private val passedTests = mutable.ListBuffer[TestState]()
36-
private val failedTests = mutable.ListBuffer[TestState]()
37-
38-
def comment(s: String) = echo(magenta("# " + s))
39-
def levyJudgment() = {
40-
if (totalTests == 0) echoMixed("No tests to run.")
41-
else if (elapsedMillis == 0) echoMixed("Test Run ABORTED")
42-
else if (isSuccess) echoPassed("Test Run PASSED")
43-
else echoFailed("Test Run FAILED")
44-
}
45-
46-
def passFailString(passed: Int, failed: Int, skipped: Int): String = {
47-
val total = passed + failed + skipped
48-
val isSuccess = failed == 0
49-
def p0 = s"$passed/$total"
50-
def p = ( if (isSuccess) bold(green(p0)) else p0 ) + " passed"
51-
def f = if (failed == 0) "" else bold(red("" + failed)) + " failed"
52-
def s = if (skipped == 0) "" else bold(yellow("" + skipped)) + " skipped"
53-
54-
oempty(p, f, s) mkString ", "
55-
}
56-
57-
private var summarizing = false
58-
private var elapsedMillis = 0L
59-
private var expectedFailures = 0
60-
private def isSuccess = failedTests.size == expectedFailures
61-
62-
def issueSummaryReport() {
63-
// Don't run twice
64-
if (!summarizing) {
65-
summarizing = true
66-
67-
val passed0 = passedTests.toList
68-
val failed0 = failedTests.toList
69-
val passed = passed0.size
70-
val failed = failed0.size
71-
val skipped = totalTests - (passed + failed)
72-
val passFail = passFailString(passed, failed, skipped)
73-
val elapsed = if (elapsedMillis > 0) " (elapsed time: " + elapsedString(elapsedMillis) + ")" else ""
74-
val message = passFail + elapsed
75-
76-
if (failed0.nonEmpty) {
77-
if (isPartestVerbose) {
78-
echo(bold(cyan("##### Transcripts from failed tests #####\n")))
79-
failed0 foreach { state =>
80-
comment("partest " + state.testFile)
81-
echo(state.transcriptString + "\n")
82-
}
83-
}
84-
85-
def files_s = failed0.map(_.testFile).mkString(""" \""" + "\n ")
86-
echo("# Failed test paths (this command will update checkfiles)")
87-
echo("test/partest --update-check \\\n " + files_s + "\n")
88-
}
89-
90-
echo(message)
91-
levyJudgment()
92-
}
93-
}
94-
95-
def run(): Unit = {
96-
if (optDebug || propOrFalse("partest.debug")) NestUI.setDebug()
97-
if (optVerbose) NestUI.setVerbose()
98-
if (optTerse) NestUI.setTerse()
99-
if (optShowDiff) NestUI.setDiffOnFail()
100-
101-
// Early return on no args, version, or invalid args
102-
if (optVersion) return echo(versionMsg)
103-
if (optHelp) return NestUI.usage()
104-
105-
val (individualTests, invalid) = parsed.residualArgs map (p => Path(p)) partition denotesTestPath
106-
if (invalid.nonEmpty) {
107-
if (isPartestVerbose)
108-
invalid foreach (p => echoWarning(s"Discarding invalid test path " + p))
109-
else if (!isPartestTerse)
110-
echoWarning(s"Discarding ${invalid.size} invalid test paths")
111-
}
112-
113-
optTimeout foreach (x => setProp("partest.timeout", x))
114-
115-
if (!isPartestTerse)
116-
NestUI echo banner
117-
118-
val partestTests = (
119-
if (optSelfTest) TestKinds.testsForPartest
120-
else Nil
121-
)
122-
123-
val grepExpr = optGrep getOrElse ""
124-
125-
// If --grep is given we suck in every file it matches.
126-
// TODO: intersect results of grep with specified kinds, if any
127-
val greppedTests = if (grepExpr == "") Nil else {
128-
val paths = grepFor(grepExpr)
129-
if (paths.isEmpty)
130-
echoWarning(s"grep string '$grepExpr' matched no tests.\n")
131-
132-
paths.sortBy(_.toString)
133-
}
134-
135-
val isRerun = optFailed
136-
val rerunTests = if (isRerun) TestKinds.failedTests else Nil
137-
def miscTests = partestTests ++ individualTests ++ greppedTests ++ rerunTests
138-
139-
val givenKinds = standardKinds filter parsed.isSet
140-
val kinds = (
141-
if (givenKinds.nonEmpty) givenKinds
142-
else if (miscTests.isEmpty) standardKinds // If no kinds, --grep, or individual tests were given, assume --all
143-
else Nil
144-
)
145-
val kindsTests = kinds flatMap testsFor
146-
147-
def testContributors = {
148-
List(
149-
if (partestTests.isEmpty) "" else "partest self-tests",
150-
if (rerunTests.isEmpty) "" else "previously failed tests",
151-
if (kindsTests.isEmpty) "" else s"${kinds.size} named test categories",
152-
if (greppedTests.isEmpty) "" else s"${greppedTests.size} tests matching '$grepExpr'",
153-
if (individualTests.isEmpty) "" else "specified tests"
154-
) filterNot (_ == "") mkString ", "
155-
}
156-
157-
val allTests: Array[Path] = distinctBy(miscTests ++ kindsTests)(_.toCanonical) sortBy (_.toString) toArray
158-
val grouped = (allTests groupBy kindOf).toArray sortBy (x => standardKinds indexOf x._1)
159-
160-
totalTests = allTests.size
161-
expectedFailures = propOrNone("partest.errors") match {
162-
case Some(num) => num.toInt
163-
case _ => 0
164-
}
165-
val expectedFailureMessage = if (expectedFailures == 0) "" else s" (expecting $expectedFailures to fail)"
166-
echo(s"Selected $totalTests tests drawn from $testContributors$expectedFailureMessage\n")
167-
168-
val (_, millis) = timed {
169-
for ((kind, paths) <- grouped) {
170-
val num = paths.size
171-
val ss = if (num == 1) "" else "s"
172-
comment(s"starting $num test$ss in $kind")
173-
val results = runTestsForFiles(paths map (_.jfile.getAbsoluteFile), kind)
174-
val (passed, failed) = results partition (_.isOk)
175-
176-
passedTests ++= passed
177-
failedTests ++= failed
178-
if (failed.nonEmpty) {
179-
comment(passFailString(passed.size, failed.size, 0) + " in " + kind)
180-
}
181-
echo("")
182-
}
183-
}
184-
this.elapsedMillis = millis
185-
issueSummaryReport()
22+
override def run(): Unit = {
23+
super.run()
18624
System exit ( if (isSuccess) 0 else 1 )
18725
}
188-
26+
18927
run()
19028
}
19129

src/main/scala/scala/tools/partest/nest/NestUI.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ object NestUI {
144144
}
145145

146146
def usage() {
147-
println(ConsoleRunnerSpec.programInfo.usage)
148-
println(ConsoleRunnerSpec.helpMsg)
147+
println(RunnerSpec.programInfo.usage)
148+
println(RunnerSpec.helpMsg)
149149
sys.exit(1)
150150
}
151151

0 commit comments

Comments
 (0)