Skip to content

Commit

Permalink
Merge pull request scala#40 from szeiger/wip/sbt-partest
Browse files Browse the repository at this point in the history
Updated SBTRunner improvements for passing arguments to partest
  • Loading branch information
SethTisue committed Nov 2, 2015
2 parents 3271e7d + 98ad0e9 commit 5f1d8d3
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 206 deletions.
180 changes: 180 additions & 0 deletions src/partest/scala/tools/partest/nest/AbstractRunner.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/* NEST (New Scala Test)
* Copyright 2007-2013 LAMP/EPFL
* @author Philipp Haller
*/

package scala.tools
package partest
package nest

import utils.Properties._
import scala.tools.nsc.Properties.{ versionMsg, propOrFalse, setProp }
import scala.collection.{ mutable, immutable }
import TestKinds._
import scala.reflect.internal.util.Collections.distinctBy
import scala.tools.cmd.{ CommandLine, CommandLineParser, Instance }

abstract class AbstractRunner(argstr: String) extends {
val parsed = RunnerSpec.creator(CommandLineParser tokenize argstr)
} with RunnerSpec with Instance {

val suiteRunner: SuiteRunner

import suiteRunner._
import NestUI._
import NestUI.color._

private var totalTests = 0
private val passedTests = mutable.ListBuffer[TestState]()
private val failedTests = mutable.ListBuffer[TestState]()

def comment(s: String) = echo(magenta("# " + s))
def levyJudgment() = {
if (totalTests == 0) echoMixed("No tests to run.")
else if (elapsedMillis == 0) echoMixed("Test Run ABORTED")
else if (isSuccess) echoPassed("Test Run PASSED")
else echoFailed("Test Run FAILED")
}

def passFailString(passed: Int, failed: Int, skipped: Int): String = {
val total = passed + failed + skipped
val isSuccess = failed == 0
def p0 = s"$passed/$total"
def p = ( if (isSuccess) bold(green(p0)) else p0 ) + " passed"
def f = if (failed == 0) "" else bold(red("" + failed)) + " failed"
def s = if (skipped == 0) "" else bold(yellow("" + skipped)) + " skipped"

oempty(p, f, s) mkString ", "
}

protected var summarizing = false
private var elapsedMillis = 0L
private var expectedFailures = 0
protected def isSuccess = failedTests.size == expectedFailures

def issueSummaryReport() {
// Don't run twice
if (!summarizing) {
summarizing = true

val passed0 = passedTests.toList
val failed0 = failedTests.toList
val passed = passed0.size
val failed = failed0.size
val skipped = totalTests - (passed + failed)
val passFail = passFailString(passed, failed, skipped)
val elapsed = if (elapsedMillis > 0) " (elapsed time: " + elapsedString(elapsedMillis) + ")" else ""
val message = passFail + elapsed

if (failed0.nonEmpty) {
if (isPartestVerbose) {
echo(bold(cyan("##### Transcripts from failed tests #####\n")))
failed0 foreach { state =>
comment("partest " + state.testFile)
echo(state.transcriptString + "\n")
}
}

def files_s = failed0.map(_.testFile).mkString(""" \""" + "\n ")
echo("# Failed test paths (this command will update checkfiles)")
echo("test/partest --update-check \\\n " + files_s + "\n")
}

echo(message)
levyJudgment()
}
}

def run(): Unit = {
if (optDebug || propOrFalse("partest.debug")) NestUI.setDebug()
if (optVerbose) NestUI.setVerbose()
if (optTerse) NestUI.setTerse()
if (optShowDiff) NestUI.setDiffOnFail()

// Early return on no args, version, or invalid args
if (optVersion) return echo(versionMsg)
if (optHelp) return NestUI.usage()

val (individualTests, invalid) = parsed.residualArgs map (p => Path(p)) partition denotesTestPath
if (invalid.nonEmpty) {
if (isPartestVerbose)
invalid foreach (p => echoWarning(s"Discarding invalid test path " + p))
else if (!isPartestTerse)
echoWarning(s"Discarding ${invalid.size} invalid test paths")
}

optTimeout foreach (x => setProp("partest.timeout", x))

if (!isPartestTerse)
NestUI echo banner

val partestTests = (
if (optSelfTest) TestKinds.testsForPartest
else Nil
)

val grepExpr = optGrep getOrElse ""

// If --grep is given we suck in every file it matches.
// TODO: intersect results of grep with specified kinds, if any
val greppedTests = if (grepExpr == "") Nil else {
val paths = grepFor(grepExpr)
if (paths.isEmpty)
echoWarning(s"grep string '$grepExpr' matched no tests.\n")

paths.sortBy(_.toString)
}

val isRerun = optFailed
val rerunTests = if (isRerun) TestKinds.failedTests else Nil
def miscTests = partestTests ++ individualTests ++ greppedTests ++ rerunTests

val givenKinds = standardKinds filter parsed.isSet
val kinds = (
if (givenKinds.nonEmpty) givenKinds
else if (miscTests.isEmpty) standardKinds // If no kinds, --grep, or individual tests were given, assume --all
else Nil
)
val kindsTests = kinds flatMap testsFor

def testContributors = {
List(
if (partestTests.isEmpty) "" else "partest self-tests",
if (rerunTests.isEmpty) "" else "previously failed tests",
if (kindsTests.isEmpty) "" else s"${kinds.size} named test categories",
if (greppedTests.isEmpty) "" else s"${greppedTests.size} tests matching '$grepExpr'",
if (individualTests.isEmpty) "" else "specified tests"
) filterNot (_ == "") mkString ", "
}

val allTests: Array[Path] = distinctBy(miscTests ++ kindsTests)(_.toCanonical) sortBy (_.toString) toArray
val grouped = (allTests groupBy kindOf).toArray sortBy (x => standardKinds indexOf x._1)

totalTests = allTests.size
expectedFailures = propOrNone("partest.errors") match {
case Some(num) => num.toInt
case _ => 0
}
val expectedFailureMessage = if (expectedFailures == 0) "" else s" (expecting $expectedFailures to fail)"
echo(s"Selected $totalTests tests drawn from $testContributors$expectedFailureMessage\n")

val (_, millis) = timed {
for ((kind, paths) <- grouped) {
val num = paths.size
val ss = if (num == 1) "" else "s"
comment(s"starting $num test$ss in $kind")
val results = runTestsForFiles(paths map (_.jfile.getAbsoluteFile), kind)
val (passed, failed) = results partition (_.isOk)

passedTests ++= passed
failedTests ++= failed
if (failed.nonEmpty) {
comment(passFailString(passed.size, failed.size, 0) + " in " + kind)
}
echo("")
}
}
this.elapsedMillis = millis
issueSummaryReport()
}
}
5 changes: 2 additions & 3 deletions src/partest/scala/tools/partest/nest/AntRunner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ abstract class AntRunner(srcDir: String, testClassLoader: URLClassLoader, javaCm
failed = false,
javaCmdPath = Option(javaCmd).map(_.getAbsolutePath) getOrElse PartestDefaults.javaCmd,
javacCmdPath = Option(javacCmd).map(_.getAbsolutePath) getOrElse PartestDefaults.javacCmd,
scalacExtraArgs = scalacArgs) {

for (jOpts <- javaOpts) System.setProperty("partest.java_opts", jOpts mkString " ")
scalacExtraArgs = scalacArgs,
javaOpts = javaOpts.map(_.mkString(" ")).getOrElse(PartestDefaults.javaOpts)) {

def error(msg: String): Nothing = sys.error(msg)
def echo(msg: String): Unit
Expand Down
172 changes: 5 additions & 167 deletions src/partest/scala/tools/partest/nest/ConsoleRunner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,185 +7,23 @@ package scala.tools
package partest
package nest

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

class ConsoleRunner(argstr: String) extends {
val parsed = ConsoleRunnerSpec.creator(CommandLineParser tokenize argstr)
} with ConsoleRunnerSpec with Instance {

val suiteRunner = new SuiteRunner (
override val suiteRunner = new SuiteRunner (
testSourcePath = optSourcePath getOrElse PartestDefaults.sourcePath,
fileManager = new FileManager(ClassPath split PathResolver.Environment.javaUserClassPath map (Path(_))), // the script sets up our classpath for us via ant
updateCheck = optUpdateCheck,
failed = optFailed)
import suiteRunner._
import NestUI._
import NestUI.color._

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

private var totalTests = 0
private val passedTests = mutable.ListBuffer[TestState]()
private val failedTests = mutable.ListBuffer[TestState]()

def comment(s: String) = echo(magenta("# " + s))
def levyJudgment() = {
if (totalTests == 0) echoMixed("No tests to run.")
else if (elapsedMillis == 0) echoMixed("Test Run ABORTED")
else if (isSuccess) echoPassed("Test Run PASSED")
else echoFailed("Test Run FAILED")
}

def passFailString(passed: Int, failed: Int, skipped: Int): String = {
val total = passed + failed + skipped
val isSuccess = failed == 0
def p0 = s"$passed/$total"
def p = ( if (isSuccess) bold(green(p0)) else p0 ) + " passed"
def f = if (failed == 0) "" else bold(red("" + failed)) + " failed"
def s = if (skipped == 0) "" else bold(yellow("" + skipped)) + " skipped"

oempty(p, f, s) mkString ", "
}

private var summarizing = false
private var elapsedMillis = 0L
private var expectedFailures = 0
private def isSuccess = failedTests.size == expectedFailures

def issueSummaryReport() {
// Don't run twice
if (!summarizing) {
summarizing = true

val passed0 = passedTests.toList
val failed0 = failedTests.toList
val passed = passed0.size
val failed = failed0.size
val skipped = totalTests - (passed + failed)
val passFail = passFailString(passed, failed, skipped)
val elapsed = if (elapsedMillis > 0) " (elapsed time: " + elapsedString(elapsedMillis) + ")" else ""
val message = passFail + elapsed

if (failed0.nonEmpty) {
if (isPartestVerbose) {
echo(bold(cyan("##### Transcripts from failed tests #####\n")))
failed0 foreach { state =>
comment("partest " + state.testFile)
echo(state.transcriptString + "\n")
}
}

def files_s = failed0.map(_.testFile).mkString(""" \""" + "\n ")
echo("# Failed test paths (this command will update checkfiles)")
echo("test/partest --update-check \\\n " + files_s + "\n")
}

echo(message)
levyJudgment()
}
}

def run(): Unit = {
if (optDebug || propOrFalse("partest.debug")) NestUI.setDebug()
if (optVerbose) NestUI.setVerbose()
if (optTerse) NestUI.setTerse()
if (optShowDiff) NestUI.setDiffOnFail()

// Early return on no args, version, or invalid args
if (optVersion) return echo(versionMsg)
if (optHelp) return NestUI.usage()

val (individualTests, invalid) = parsed.residualArgs map (p => Path(p)) partition denotesTestPath
if (invalid.nonEmpty) {
if (isPartestVerbose)
invalid foreach (p => echoWarning(s"Discarding invalid test path " + p))
else if (!isPartestTerse)
echoWarning(s"Discarding ${invalid.size} invalid test paths")
}

optTimeout foreach (x => setProp("partest.timeout", x))

if (!isPartestTerse)
NestUI echo banner

val partestTests = (
if (optSelfTest) TestKinds.testsForPartest
else Nil
)

val grepExpr = optGrep getOrElse ""

// If --grep is given we suck in every file it matches.
// TODO: intersect results of grep with specified kinds, if any
val greppedTests = if (grepExpr == "") Nil else {
val paths = grepFor(grepExpr)
if (paths.isEmpty)
echoWarning(s"grep string '$grepExpr' matched no tests.\n")

paths.sortBy(_.toString)
}

val isRerun = optFailed
val rerunTests = if (isRerun) TestKinds.failedTests else Nil
def miscTests = partestTests ++ individualTests ++ greppedTests ++ rerunTests

val givenKinds = standardKinds filter parsed.isSet
val kinds = (
if (givenKinds.nonEmpty) givenKinds
else if (miscTests.isEmpty) standardKinds // If no kinds, --grep, or individual tests were given, assume --all
else Nil
)
val kindsTests = kinds flatMap testsFor

def testContributors = {
List(
if (partestTests.isEmpty) "" else "partest self-tests",
if (rerunTests.isEmpty) "" else "previously failed tests",
if (kindsTests.isEmpty) "" else s"${kinds.size} named test categories",
if (greppedTests.isEmpty) "" else s"${greppedTests.size} tests matching '$grepExpr'",
if (individualTests.isEmpty) "" else "specified tests"
) filterNot (_ == "") mkString ", "
}

val allTests: Array[Path] = distinctBy(miscTests ++ kindsTests)(_.toCanonical) sortBy (_.toString) toArray
val grouped = (allTests groupBy kindOf).toArray sortBy (x => standardKinds indexOf x._1)

totalTests = allTests.size
expectedFailures = propOrNone("partest.errors") match {
case Some(num) => num.toInt
case _ => 0
}
val expectedFailureMessage = if (expectedFailures == 0) "" else s" (expecting $expectedFailures to fail)"
echo(s"Selected $totalTests tests drawn from $testContributors$expectedFailureMessage\n")

val (_, millis) = timed {
for ((kind, paths) <- grouped) {
val num = paths.size
val ss = if (num == 1) "" else "s"
comment(s"starting $num test$ss in $kind")
val results = runTestsForFiles(paths map (_.jfile.getAbsoluteFile), kind)
val (passed, failed) = results partition (_.isOk)

passedTests ++= passed
failedTests ++= failed
if (failed.nonEmpty) {
comment(passFailString(passed.size, failed.size, 0) + " in " + kind)
}
echo("")
}
}
this.elapsedMillis = millis
issueSummaryReport()
override def run(): Unit = {
super.run()
System exit ( if (isSuccess) 0 else 1 )
}

run()
}

Expand Down
4 changes: 2 additions & 2 deletions src/partest/scala/tools/partest/nest/NestUI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ object NestUI {
}

def usage() {
println(ConsoleRunnerSpec.programInfo.usage)
println(ConsoleRunnerSpec.helpMsg)
println(RunnerSpec.programInfo.usage)
println(RunnerSpec.helpMsg)
sys.exit(1)
}

Expand Down
Loading

0 comments on commit 5f1d8d3

Please sign in to comment.