/* __ *\
** ________ ___ / / ___ Scala Parallel Testing **
** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
package scala.tools
package partest
import scala.util.Properties.setProp
import scala.tools.ant.sabbus.CompilationPathProperty
import java.lang.reflect.Method
import org.apache.tools.ant.Task
import org.apache.tools.ant.types.{ Reference, FileSet}
import org.apache.tools.ant.types.Commandline.Argument
import scala.tools.ant.ScalaTask
/** An Ant task to execute the Scala test suite (NSC).
*
* This task can take the following parameters as attributes:
* - `srcdir`,
* - `classpath`,
* - `classpathref`,
* - `erroronfailed`,
* - `javacmd`,
* - `javaccmd`,
* - `scalacopts`,
* - `debug`,
* - `junitreportdir`.
*
* It also takes the following parameters as nested elements:
* - `compilationpath`.
*
* @author Philippe Haller
*/
class PartestTask extends Task with CompilationPathProperty with ScalaTask {
type Path = org.apache.tools.ant.types.Path
private var kinds: List[String] = Nil
private var classpath: Option[Path] = None
private var debug = false
private var errorOnFailed: Boolean = true
private var jUnitReportDir: Option[File] = None
private var javaccmd: Option[File] = None
private var javacmd: Option[File] = Option(sys.props("java.home")) map (x => new File(x, "bin/java"))
private var scalacArgs: Option[Seq[Argument]] = None
private var srcDir: Option[String] = None
private var colors: Int = 0
def setSrcDir(input: String) {
srcDir = Some(input)
}
def setColors(input: String) {
try colors = input.toInt catch { case _: NumberFormatException => () }
if (colors > 0)
sys.props("partest.colors") = colors.toString
}
def setClasspath(input: Path) {
if (classpath.isEmpty)
classpath = Some(input)
else
classpath.get.append(input)
}
def createClasspath(): Path = {
if (classpath.isEmpty) classpath = Some(new Path(getProject()))
classpath.get.createPath()
}
def setClasspathref(input: Reference) {
createClasspath().setRefid(input)
}
def setErrorOnFailed(input: Boolean) {
errorOnFailed = input
}
def setJavaCmd(input: File) {
javacmd = Some(input)
}
def setKinds(input: String) {
kinds = words(input)
}
def setJavacCmd(input: File) {
javaccmd = Some(input)
}
def setScalacOpts(input: String) {
val s = input.split(' ').map { s => val a = new Argument; a.setValue(s); a }
scalacArgs = Some(scalacArgs.getOrElse(Seq()) ++ s)
}
def createCompilerArg(): Argument = {
val a = new Argument
scalacArgs = Some(scalacArgs.getOrElse(Seq()) :+ a)
a
}
def setDebug(input: Boolean) {
debug = input
}
def setJUnitReportDir(input: File) {
jUnitReportDir = Some(input)
}
override def execute() {
if (debug || sys.props.contains("partest.debug")) {
nest.NestUI.setDebug()
}
srcDir foreach (x => setProp("partest.srcdir", x))
val classpath = this.compilationPath getOrElse sys.error("Mandatory attribute 'compilationPath' is not set.")
val cpfiles = classpath.list map { fs => new File(fs) } toList
def findCp(name: String) = cpfiles find (f =>
(f.getName == s"scala-$name.jar")
|| (f.absolutePathSegments endsWith Seq("classes", name))
) getOrElse sys.error(s"Provided classpath does not contain a Scala $name element.")
val scalaLibrary = findCp("library")
val scalaReflect = findCp("reflect")
val scalaCompiler = findCp("compiler")
val scalaPartest = findCp("partest")
val scalaActors = findCp("actors")
def scalacArgsFlat: Option[Seq[String]] = scalacArgs map (_ flatMap { a =>
val parts = a.getParts
if (parts eq null) Nil else parts.toSeq
})
val antRunner = new scala.tools.partest.nest.AntRunner
val antFileManager = antRunner.fileManager
// antFileManager.failed = runFailed
antFileManager.CLASSPATH = ClassPath.join(classpath.list: _*)
antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath
antFileManager.LATEST_REFLECT = scalaReflect.getAbsolutePath
antFileManager.LATEST_COMP = scalaCompiler.getAbsolutePath
antFileManager.LATEST_PARTEST = scalaPartest.getAbsolutePath
antFileManager.LATEST_ACTORS = scalaActors.getAbsolutePath
javacmd foreach (x => antFileManager.JAVACMD = x.getAbsolutePath)
javaccmd foreach (x => antFileManager.JAVAC_CMD = x.getAbsolutePath)
scalacArgsFlat foreach (antFileManager.SCALAC_OPTS ++= _)
def runSet(kind: String, files: Array[File]): (Int, Int, List[String]) = {
if (files.isEmpty) (0, 0, List())
else {
log(s"Running ${files.length} tests in '$kind' at $now")
// log(s"Tests: ${files.toList}")
val results = antRunner.reflectiveRunTestsForFiles(files, kind)
val (passed, failed) = results partition (_.isOk)
val numPassed = passed.size
val numFailed = failed.size
def failedMessages = failed map (_.longStatus)
log(s"Completed '$kind' at $now")
// create JUnit Report xml files if directory was specified
jUnitReportDir foreach { d =>
d.mkdir
val report = testReport(kind, results, numPassed, numFailed)
scala.xml.XML.save(d.getAbsolutePath+"/"+kind+".xml", report)
}
(numPassed, numFailed, failedMessages)
}
}
val _results = kinds map (k => runSet(k, TestKinds testsFor k map (_.jfile) toArray))
val allSuccesses = _results map (_._1) sum
val allFailures = _results map (_._2) sum
val allFailedPaths = _results flatMap (_._3)
def f = if (errorOnFailed && allFailures > 0) buildError(_: String) else log(_: String)
def s = if (allFailures > 1) "s" else ""
val msg =
if (allFailures > 0)
"Test suite finished with %d case%s failing:\n".format(allFailures, s)+
allFailedPaths.mkString("\n")
else if (allSuccesses == 0) "There were no tests to run."
else "Test suite finished with no failures."
f(msg)
}
private def oneResult(res: TestState) =
{
if (res.isOk) scala.xml.NodeSeq.Empty
else
}
private def testReport(kind: String, results: Iterable[TestState], succs: Int, fails: Int) =
{
results map oneResult
}
}