summaryrefslogtreecommitdiff
path: root/src/partest
diff options
context:
space:
mode:
authorPhilipp Haller <hallerp@gmail.com>2010-02-04 17:03:57 +0000
committerPhilipp Haller <hallerp@gmail.com>2010-02-04 17:03:57 +0000
commit429da0c3c7105510a29fcacd746916431e86d3e2 (patch)
tree112bb302851729a7b3ff2f8ce904deca0f0ef328 /src/partest
parentbf696d016ac6d07345659e099105e62ae8d298b5 (diff)
downloadscala-429da0c3c7105510a29fcacd746916431e86d3e2.tar.gz
scala-429da0c3c7105510a29fcacd746916431e86d3e2.tar.bz2
scala-429da0c3c7105510a29fcacd746916431e86d3e2.zip
Fixed issue in partest where result of tests th...
Fixed issue in partest where result of tests that timed out was not printed. Improved reporting. Added support for JUnit report files.
Diffstat (limited to 'src/partest')
-rw-r--r--src/partest/scala/tools/partest/PartestTask.scala58
-rw-r--r--src/partest/scala/tools/partest/nest/AntRunner.scala7
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleRunner.scala9
-rw-r--r--src/partest/scala/tools/partest/nest/DirectRunner.scala14
-rw-r--r--src/partest/scala/tools/partest/nest/Worker.scala106
5 files changed, 120 insertions, 74 deletions
diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala
index 905e52a491..4b023e7b73 100644
--- a/src/partest/scala/tools/partest/PartestTask.scala
+++ b/src/partest/scala/tools/partest/PartestTask.scala
@@ -104,6 +104,10 @@ class PartestTask extends Task {
debug = input
}
+ def setJUnitReportDir(input: File) {
+ jUnitReportDir = Some(input)
+ }
+
private var classpath: Option[Path] = None
private var javacmd: Option[File] = None
private var javaccmd: Option[File] = None
@@ -122,6 +126,7 @@ class PartestTask extends Task {
private var errorOnFailed: Boolean = false
private var scalacOpts: Option[String] = None
private var timeout: Option[String] = None
+ private var jUnitReportDir: Option[File] = None
private var debug = false
private def getFiles(fileSet: Option[FileSet]): Array[File] =
@@ -188,10 +193,8 @@ class PartestTask extends Task {
val runMethod =
antRunner.getClass.getMethod("reflectiveRunTestsForFiles", Array(classOf[Array[File]], classOf[String]): _*)
- def runTestsForFiles(kindFiles: Array[File], kind: String): (Int, Int) = {
- val result = runMethod.invoke(antRunner, Array(kindFiles, kind): _*).asInstanceOf[Int]
- (result >> 16, result & 0x00FF)
- }
+ def runTestsForFiles(kindFiles: Array[File], kind: String) =
+ runMethod.invoke(antRunner, kindFiles, kind).asInstanceOf[scala.collection.Map[String, Int]]
def setFileManagerBooleanProperty(name: String, value: Boolean) {
val setMethod =
@@ -232,26 +235,65 @@ class PartestTask extends Task {
(getScalapFiles, "scalap", "Running scalap tests")
)
- def runSet(set: TFSet): (Int, Int) = {
+ def runSet(set: TFSet): (Int, Int, Iterable[String]) = {
val (files, name, msg) = set
- if (files.isEmpty) (0, 0)
+ if (files.isEmpty) (0, 0, List())
else {
log(msg)
- runTestsForFiles(files, name)
+ val results: Iterable[(String, Int)] = runTestsForFiles(files, name)
+
+ val (succs, fails) =
+ results
+ .map { case (file, resultCode) => if (resultCode == 0) (1, 0) else (0, 1) }
+ .reduceLeft((res1, res2) => (res1._1 + res2._1, res1._2 + res2._2))
+
+ val failed: Iterable[String] = results flatMap { case (path, state) =>
+ if (state == 0) List()
+ else List(path+" ["+(if (state == 1) "FAILED" else "TIMOUT")+"]")
+ }
+
+ // create JUnit Report xml files if directory was specified
+ jUnitReportDir foreach { d =>
+ d.mkdir
+
+ val report = testReport(name, results, succs, fails)
+ scala.xml.XML.save(d.getAbsolutePath+"/"+name+".xml", report)
+ }
+
+ (succs, fails, failed)
}
}
val _results = testFileSets map runSet
val allSuccesses = _results map (_._1) sum
val allFailures = _results map (_._2) sum
+ val allFailedPaths = _results flatMap (_._3)
def f = if (errorOnFailed && allFailures > 0) error(_) else log(_: String)
def s = if (allFailures > 1) "s" else ""
val msg =
- if (allFailures > 0) "Test suite finished with %d case%s failing.".format(allFailures, s)
+ 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)
}
+ def oneResult(res: (String, Int)) =
+ <testcase name={res._1}>{
+ res._2 match {
+ case 0 => scala.xml.NodeSeq.Empty
+ case 1 => <failure message="Test failed"/>
+ case 2 => <failure message="Test timed out"/>
+ }
+ }</testcase>
+
+ def testReport(kind: String, results: Iterable[(String, Int)], succs: Int, fails: Int) =
+ <testsuite name={kind} tests={(succs + fails).toString} failures={fails.toString}>
+ <properties/>
+ {
+ results.map(oneResult(_))
+ }
+ </testsuite>
}
diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala
index cdc6961d3d..9219ed3305 100644
--- a/src/partest/scala/tools/partest/nest/AntRunner.scala
+++ b/src/partest/scala/tools/partest/nest/AntRunner.scala
@@ -24,9 +24,6 @@ class AntRunner extends DirectRunner {
val TESTROOT: String = ""
}
- def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String): Int = {
- val (succs, fails) = runTestsForFiles(kindFiles.toList, kind)
- succs << 16 | fails
- }
-
+ def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String) =
+ runTestsForFiles(kindFiles.toList, kind)
}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
index 94b1d6c684..12b4d0a038 100644
--- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
+++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
@@ -176,13 +176,18 @@ class ConsoleRunner extends DirectRunner with RunnerUtils {
}
}
+ def toStatistics[A](results: Iterable[(A, Int)]): (Int, Int) =
+ results
+ .map { case (file, resultCode) => if (resultCode == 0) (1, 0) else (0, 1) }
+ .reduceLeft((res1, res2) => (res1._1 + res2._1, res1._2 + res2._2))
+
def runTests(testSet: TestSet): (Int, Int) = {
val TestSet(loc, filter, kind, msg) = testSet
val files = fileManager.getFiles(loc, true, filter)
if (!files.isEmpty) {
NestUI.verbose("test files: "+files)
NestUI.outline("\n"+msg+"\n")
- runTestsForFiles(files, kind)
+ toStatistics(runTestsForFiles(files, kind))
} else {
NestUI.verbose("test dir empty\n")
(0, 0)
@@ -223,7 +228,7 @@ class ConsoleRunner extends DirectRunner with RunnerUtils {
Predef.exit(1)
} else {
NestUI.outline("\nTesting individual files\n")
- runTestsForFiles(testFiles, fstKind)
+ toStatistics(runTestsForFiles(testFiles, fstKind))
}
} else (0, 0)
diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala
index 7ea74424fc..43d2882628 100644
--- a/src/partest/scala/tools/partest/nest/DirectRunner.scala
+++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala
@@ -37,7 +37,7 @@ trait DirectRunner {
System.setProperty("actors.corePoolSize", "16")
}
- def runTestsForFiles(kindFiles: List[File], kind: String): (Int, Int) = {
+ def runTestsForFiles(kindFiles: List[File], kind: String): scala.collection.immutable.Map[String, Int] = {
val len = kindFiles.length
val (testsEach, lastFrag) = (len/numActors, len%numActors)
val last = numActors-1
@@ -51,20 +51,20 @@ trait DirectRunner {
worker ! RunTests(kind, toTest)
worker
}
- var succs = 0; var fails = 0
+
var logsToDelete: List[File] = List()
var outdirsToDelete: List[File] = List()
+ var results = new scala.collection.immutable.HashMap[String, Int]
workers foreach { w =>
receiveWithin(3600 * 1000) {
- case Results(s, f, logs, outdirs) =>
+ case Results(res, logs, outdirs) =>
logsToDelete = logsToDelete ::: logs.filter(_.toDelete)
outdirsToDelete = outdirsToDelete ::: outdirs
- succs += s
- fails += f
+ results = results ++ res
case TIMEOUT =>
// add at least one failure
NestUI.verbose("worker timed out; adding failed test")
- fails += 1
+ results = results + ("worker timed out; adding failed test" -> 2)
}
}
for (x <- logsToDelete ::: outdirsToDelete) {
@@ -72,7 +72,7 @@ trait DirectRunner {
Directory(x).deleteRecursively()
}
- (succs, fails)
+ results
}
}
diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala
index a894955e0f..1907c65932 100644
--- a/src/partest/scala/tools/partest/nest/Worker.scala
+++ b/src/partest/scala/tools/partest/nest/Worker.scala
@@ -20,12 +20,15 @@ import scala.actors.{Actor, Exit, TIMEOUT}
import scala.actors.Actor._
import scala.tools.scalap.scalax.rules.scalasig.{ByteCode, ClassFileParser, ScalaSigAttributeParsers}
-import scala.collection.mutable.HashMap
+import scala.collection.immutable.{Map => ImmMap}
+import scala.collection.Map
+import scala.collection.immutable.HashMap
import scala.tools.nsc.interactive.{BuildManager, RefinedBuildManager}
case class RunTests(kind: String, files: List[File])
-case class Results(succ: Int, fail: Int, logs: List[LogFile], outdirs: List[File])
+case class Results(results: ImmMap[String, Int], logs: List[LogFile], outdirs: List[File])
+
case class LogContext(file: LogFile, writers: Option[(StringWriter, PrintWriter)])
abstract class TestResult {
@@ -57,9 +60,9 @@ class Worker(val fileManager: FileManager) extends Actor {
case RunTests(kind, files) =>
NestUI.verbose("received "+files.length+" to test")
val master = sender
- runTests(kind, files, (succ: Int, fail: Int) => {
- master ! Results(succ, fail, createdLogFiles, createdOutputDirs)
- })
+ runTests(kind, files){ results =>
+ master ! Results(results, createdLogFiles, createdOutputDirs)
+ }
}
}
@@ -306,7 +309,7 @@ class Worker(val fileManager: FileManager) extends Actor {
* @param kind The test kind (pos, neg, run, etc.)
* @param files The list of test files
*/
- def runTests(kind: String, files: List[File], topcont: (Int, Int) => Unit) {
+ def runTests(kind: String, files: List[File])(topcont: ImmMap[String, Int] => Unit) {
val compileMgr = new CompileManager(fileManager)
var errors = 0
var succeeded = true
@@ -751,8 +754,7 @@ class Worker(val fileManager: FileManager) extends Actor {
}
def replaceSlashes(s: String): String = {
- val path = dir.getAbsolutePath/*.replace(File.separatorChar,'/')*/+
- File.separator
+ val path = dir.getAbsolutePath+File.separator
// find `path` in `line`
val index = s.indexOf(path)
val line =
@@ -970,37 +972,40 @@ class Worker(val fileManager: FileManager) extends Actor {
}
}
- def reportAll(cont: (Int, Int) => Unit) {
+ def reportAll(results: ImmMap[String, Int], cont: ImmMap[String, Int] => Unit) {
NestUI.verbose("finished testing "+kind+" with "+errors+" errors")
NestUI.verbose("created "+compileMgr.numSeparateCompilers+" separate compilers")
timer.cancel()
- cont(files.length-errors, errors)
+ cont(results)
}
- def reportResult(logs: Option[LogContext]) {
- if (!succeeded) {
+ def reportResult(state: Int, logFile: Option[LogFile], writers: Option[(StringWriter, PrintWriter)]) {
+ val good = (state == 0)
+ if (!good) {
errors += 1
NestUI.verbose("incremented errors: "+errors)
}
try {
// delete log file only if test was successful
- if (succeeded && !logs.isEmpty)
- logs.get.file.toDelete = true
-
- if (!logs.isEmpty)
- logs.get.writers match {
- case Some((swr, wr)) =>
- printInfoEnd(succeeded, wr)
- wr.flush()
- swr.flush()
- NestUI.normal(swr.toString)
- if (!succeeded && fileManager.showDiff && diff != "")
- NestUI.normal(diff)
- if (!succeeded && fileManager.showLog)
- showLog(logs.get.file)
- case None =>
- }
+ if (good && !logFile.isEmpty)
+ logFile.get.toDelete = true
+
+ writers match {
+ case Some((swr, wr)) =>
+ if (state == 2)
+ printInfoTimeout(wr)
+ else
+ printInfoEnd(good, wr)
+ wr.flush()
+ swr.flush()
+ NestUI.normal(swr.toString)
+ if (state == 1 && fileManager.showDiff && diff != "")
+ NestUI.normal(diff)
+ if (state == 1 && fileManager.showLog)
+ showLog(logFile.get)
+ case None =>
+ }
} catch {
case npe: NullPointerException =>
}
@@ -1008,10 +1013,10 @@ class Worker(val fileManager: FileManager) extends Actor {
val numFiles = files.size
if (numFiles == 0)
- reportAll(topcont)
+ reportAll(ImmMap(), topcont)
// maps canonical file names to the test result (0: OK, 1: FAILED, 2: TIMOUT)
- val status = new HashMap[String, Int]
+ var status = new HashMap[String, Int]
var fileCnt = 1
Actor.loopWhile(fileCnt <= numFiles) {
@@ -1044,28 +1049,25 @@ class Worker(val fileManager: FileManager) extends Actor {
val path = res.file.getCanonicalPath
status.get(path) match {
case Some(stat) => // ignore message
- case None => res match {
- case Timeout(_) =>
- status += (path -> 2)
- val swr = new StringWriter
- val wr = new PrintWriter(swr)
- printInfoStart(files(fileCnt-1), wr)
- printInfoTimeout(wr)
- wr.flush()
- swr.flush()
- NestUI.normal(swr.toString)
- succeeded = false
- reportResult(None)
- if (fileCnt == numFiles)
- reportAll(topcont)
- fileCnt += 1
- case Result(_, logs) =>
- status += (path -> (if (succeeded) 0 else 1))
- reportResult(if (logs != null) Some(logs) else None)
- if (fileCnt == numFiles)
- reportAll(topcont)
- fileCnt += 1
- }
+ case None =>
+ res match {
+ case Timeout(_) =>
+ status = status + (path -> 2)
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ printInfoStart(res.file, wr)
+ succeeded = false
+ reportResult(2, None, Some((swr, wr)))
+ case Result(_, logs) =>
+ status = status + (path -> (if (succeeded) 0 else 1))
+ reportResult(
+ if (succeeded) 0 else 1,
+ if (logs != null) Some(logs.file) else None,
+ if (logs != null) logs.writers else None)
+ }
+ if (fileCnt == numFiles)
+ reportAll(status, topcont)
+ fileCnt += 1
}
}
}