mirror of https://github.com/sbt/sbt.git
-Moved code that count test results from TestLogger to SuiteResult.
-Print the results in Tests.showResult.
This commit is contained in:
parent
a76523a5f6
commit
1ec2118219
|
|
@ -30,8 +30,8 @@ private[sbt] object ForkTests {
|
|||
if (!tests.isEmpty) {
|
||||
val server = new ServerSocket(0)
|
||||
object Acceptor extends Runnable {
|
||||
val resultsAcc = mutable.Map.empty[String, TestResult.Value]
|
||||
lazy val result = (overall(resultsAcc.values), resultsAcc.toMap)
|
||||
val resultsAcc = mutable.Map.empty[String, SuiteResult]
|
||||
lazy val result = (overall(resultsAcc.values.map(_.result)), resultsAcc.toMap)
|
||||
def run: Unit = {
|
||||
val socket =
|
||||
try {
|
||||
|
|
@ -76,7 +76,7 @@ private[sbt] object ForkTests {
|
|||
val ec = Fork.java(fork, options)
|
||||
val result =
|
||||
if (ec != 0)
|
||||
(TestResult.Error, Map("Running java with options " + options.mkString(" ") + " failed with exit code " + ec -> TestResult.Error))
|
||||
(TestResult.Error, Map("Running java with options " + options.mkString(" ") + " failed with exit code " + ec -> SuiteResult.Error))
|
||||
else {
|
||||
// Need to wait acceptor thread to finish its business
|
||||
acceptorThread.join()
|
||||
|
|
@ -89,11 +89,11 @@ private[sbt] object ForkTests {
|
|||
server.close()
|
||||
}
|
||||
} else
|
||||
(TestResult.Passed, Map.empty[String, TestResult.Value])
|
||||
(TestResult.Passed, Map.empty[String, SuiteResult])
|
||||
} tagw (config.tags: _*)
|
||||
}
|
||||
}
|
||||
private final class React(is: ObjectInputStream, os: ObjectOutputStream, log: Logger, listeners: Seq[TestReportListener], results: mutable.Map[String, TestResult.Value])
|
||||
private final class React(is: ObjectInputStream, os: ObjectOutputStream, log: Logger, listeners: Seq[TestReportListener], results: mutable.Map[String, SuiteResult])
|
||||
{
|
||||
import ForkTags._
|
||||
@annotation.tailrec def react(): Unit = is.readObject match {
|
||||
|
|
@ -107,9 +107,9 @@ private final class React(is: ObjectInputStream, os: ObjectOutputStream, log: Lo
|
|||
listeners.foreach(_ startGroup group)
|
||||
val event = TestEvent(tEvents)
|
||||
listeners.foreach(_ testEvent event)
|
||||
val result = event.result getOrElse TestResult.Passed
|
||||
results += group -> result
|
||||
listeners.foreach(_ endGroup (group, result))
|
||||
val suiteResult = SuiteResult(tEvents)
|
||||
results += group -> suiteResult
|
||||
listeners.foreach(_ endGroup (group, suiteResult.result))
|
||||
react()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ sealed trait TestOption
|
|||
object Tests
|
||||
{
|
||||
// (overall result, individual results)
|
||||
type Output = (TestResult.Value, Map[String,TestResult.Value])
|
||||
type Output = (TestResult.Value, Map[String,SuiteResult])
|
||||
|
||||
final case class Setup(setup: ClassLoader => Unit) extends TestOption
|
||||
def Setup(setup: () => Unit) = new Setup(_ => setup())
|
||||
|
|
@ -119,14 +119,14 @@ object Tests
|
|||
cleanupTasks map { _ => results }
|
||||
}
|
||||
}
|
||||
type TestRunnable = (String, () => TestResult.Value)
|
||||
type TestRunnable = (String, () => SuiteResult)
|
||||
def makeParallel(runnables: Iterable[TestRunnable], setupTasks: Task[Unit], tags: Seq[(Tag,Int)]) =
|
||||
runnables map { case (name, test) => task { (name, test()) } tagw(tags : _*) dependsOn setupTasks named name }
|
||||
def makeSerial(runnables: Seq[TestRunnable], setupTasks: Task[Unit], tags: Seq[(Tag,Int)]) =
|
||||
task { runnables map { case (name, test) => (name, test()) } } dependsOn(setupTasks)
|
||||
|
||||
def processResults(results: Iterable[(String, TestResult.Value)]): (TestResult.Value, Map[String, TestResult.Value]) =
|
||||
(overall(results.map(_._2)), results.toMap)
|
||||
def processResults(results: Iterable[(String, SuiteResult)]): (TestResult.Value, Map[String, SuiteResult]) =
|
||||
(overall(results.map(_._2.result)), results.toMap)
|
||||
def foldTasks(results: Seq[Task[Output]], parallel: Boolean): Task[Output] =
|
||||
if (parallel)
|
||||
reduced(results.toIndexedSeq, {
|
||||
|
|
@ -169,8 +169,21 @@ object Tests
|
|||
(tests, mains.toSet)
|
||||
}
|
||||
|
||||
def showResults(log: Logger, results: (TestResult.Value, Map[String, TestResult.Value]), noTestsMessage: =>String): Unit =
|
||||
def showResults(log: Logger, results: (TestResult.Value, Map[String, SuiteResult]), noTestsMessage: =>String): Unit =
|
||||
{
|
||||
val (skipped, errors, passed, failures) =
|
||||
results._2.foldLeft((0, 0, 0, 0)) { case (acc, entry) =>
|
||||
val suiteResult = entry._2
|
||||
(acc._1 + suiteResult.skippedCount, acc._2 + suiteResult.errorCount, acc._3 + suiteResult.passedCount, acc._4 + suiteResult.failureCount)
|
||||
}
|
||||
val totalCount = failures + errors + skipped + passed
|
||||
val postfix = "Total " + totalCount + ", Failed " + failures + ", Errors " + errors + ", Passed " + passed + ", Skipped " + skipped
|
||||
results._1 match {
|
||||
case TestResult.Error => log.error("Error: " + postfix)
|
||||
case TestResult.Passed => log.info("Passed: " + postfix)
|
||||
case TestResult.Failed => log.error("Failed: " + postfix)
|
||||
}
|
||||
|
||||
if (results._2.isEmpty)
|
||||
log.info(noTestsMessage)
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -479,10 +479,12 @@ object Defaults extends BuildCommon
|
|||
}
|
||||
}
|
||||
val output = Tests.foldTasks(groupTasks, config.parallel)
|
||||
runners foreach { case (tf, r) =>
|
||||
r.done()
|
||||
output map { out =>
|
||||
runners foreach { case (tf, r) =>
|
||||
r.done()
|
||||
}
|
||||
out
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
def selectedFilter(args: Seq[String]): Seq[String => Boolean] =
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ object Ticket543Test extends Build {
|
|||
fork := true,
|
||||
testListeners += new TestReportListener {
|
||||
def testEvent(event: TestEvent) {
|
||||
for (e <- event.detail.filter(_.result == org.scalatools.testing.Result.Failure)) {
|
||||
if (e.error ne null) {
|
||||
for (e <- event.detail.filter(_.status == sbt.testing.Status.Failure)) {
|
||||
if (e.throwable ne null) {
|
||||
val caw = new CharArrayWriter
|
||||
e.error.printStackTrace(new PrintWriter(caw))
|
||||
e.throwable.printStackTrace(new PrintWriter(caw))
|
||||
if (caw.toString.contains("Test.scala:"))
|
||||
marker.createNewFile()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ final class TestDefinition(val name: String, val fingerprint: Fingerprint)
|
|||
|
||||
final class TestRunner(delegate: Runner, listeners: Seq[TestReportListener], log: Logger) {
|
||||
|
||||
final def run(testDefinition: TestDefinition): TestResult.Value =
|
||||
final def run(testDefinition: TestDefinition): SuiteResult =
|
||||
{
|
||||
log.debug("Running " + testDefinition)
|
||||
val name = testDefinition.name
|
||||
|
|
@ -82,21 +82,21 @@ final class TestRunner(delegate: Runner, listeners: Seq[TestReportListener], log
|
|||
finally loggers.foreach( _.flush() )
|
||||
val event = TestEvent(results)
|
||||
safeListenersCall(_.testEvent( event ))
|
||||
event.result
|
||||
SuiteResult(results)
|
||||
}
|
||||
|
||||
safeListenersCall(_.startGroup(name))
|
||||
try
|
||||
{
|
||||
val result = runTest().getOrElse(TestResult.Passed)
|
||||
safeListenersCall(_.endGroup(name, result))
|
||||
result
|
||||
val suiteResult = runTest()
|
||||
safeListenersCall(_.endGroup(name, suiteResult.result))
|
||||
suiteResult
|
||||
}
|
||||
catch
|
||||
{
|
||||
case e: Throwable =>
|
||||
safeListenersCall(_.endGroup(name, e))
|
||||
TestResult.Error
|
||||
SuiteResult.Error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ object TestFramework
|
|||
log: Logger,
|
||||
listeners: Seq[TestReportListener],
|
||||
testArgsByFramework: Map[Framework, Seq[String]]):
|
||||
(() => Unit, Seq[(String, () => TestResult.Value)], TestResult.Value => () => Unit) =
|
||||
(() => Unit, Seq[(String, () => SuiteResult)], TestResult.Value => () => Unit) =
|
||||
{
|
||||
val arguments = testArgsByFramework withDefaultValue Nil
|
||||
val mappedTests = testMap(frameworks.values.toSeq, tests, arguments)
|
||||
|
|
@ -158,7 +158,7 @@ object TestFramework
|
|||
createTestTasks(testLoader, runners.map { case (tf, r) => (frameworks(tf), new TestRunner(r, listeners, log))}, mappedTests, tests, log, listeners)
|
||||
}
|
||||
|
||||
private[this] def order(mapped: Map[String, () => TestResult.Value], inputs: Seq[TestDefinition]): Seq[(String, () => TestResult.Value)] =
|
||||
private[this] def order(mapped: Map[String, () => SuiteResult], inputs: Seq[TestDefinition]): Seq[(String, () => SuiteResult)] =
|
||||
for( d <- inputs; act <- mapped.get(d.name) ) yield (d.name, act)
|
||||
|
||||
private[this] def testMap(frameworks: Seq[Framework], tests: Seq[TestDefinition], args: Map[Framework, Seq[String]]):
|
||||
|
|
|
|||
|
|
@ -28,6 +28,24 @@ trait TestsListener extends TestReportListener
|
|||
def doComplete(finalResult: TestResult.Value)
|
||||
}
|
||||
|
||||
final class SuiteResult(val result: TestResult.Value, val passedCount: Int, val failureCount: Int, val errorCount: Int, val skippedCount: Int)
|
||||
object SuiteResult
|
||||
{
|
||||
def apply(events: Seq[TEvent]): SuiteResult =
|
||||
{
|
||||
def count(status: TStatus) = events.count(_.status == status)
|
||||
val overallResult = (TestResult.Passed /: events) { (sum, event) =>
|
||||
val status = event.status
|
||||
if(sum == TestResult.Error || status == TStatus.Error) TestResult.Error
|
||||
else if(sum == TestResult.Failed || status == TStatus.Failure) TestResult.Failed
|
||||
else TestResult.Passed
|
||||
}
|
||||
new SuiteResult (overallResult, count(TStatus.Success), count(TStatus.Failure), count(TStatus.Error), count(TStatus.Skipped))
|
||||
}
|
||||
val Error: SuiteResult = new SuiteResult(TestResult.Error, 0, 0, 0, 0)
|
||||
val Empty: SuiteResult = new SuiteResult(TestResult.Passed, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
abstract class TestEvent extends NotNull
|
||||
{
|
||||
def result: Option[TestResult.Value]
|
||||
|
|
@ -77,43 +95,18 @@ final class TestLogging(val global: TLogger, val logTest: TestDefinition => Cont
|
|||
final class ContentLogger(val log: TLogger, val flush: () => Unit)
|
||||
class TestLogger(val logging: TestLogging) extends TestsListener
|
||||
{
|
||||
import logging.{global => log, logTest}
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
protected val skippedCount, errorsCount, passedCount, failuresCount = new AtomicInteger
|
||||
import logging.{global => log, logTest}
|
||||
|
||||
def startGroup(name: String) {}
|
||||
def testEvent(event: TestEvent): Unit = event.detail.foreach(count)
|
||||
def testEvent(event: TestEvent): Unit = {}
|
||||
def endGroup(name: String, t: Throwable)
|
||||
{
|
||||
log.trace(t)
|
||||
log.error("Could not run test " + name + ": " + t.toString)
|
||||
}
|
||||
def endGroup(name: String, result: TestResult.Value) {}
|
||||
protected def count(event: TEvent): Unit =
|
||||
{
|
||||
val count = event.status match {
|
||||
case TStatus.Error => errorsCount
|
||||
case TStatus.Success => passedCount
|
||||
case TStatus.Failure => failuresCount
|
||||
case TStatus.Skipped => skippedCount
|
||||
}
|
||||
count.incrementAndGet()
|
||||
}
|
||||
def doInit
|
||||
{
|
||||
for (count <- List(skippedCount, errorsCount, passedCount, failuresCount)) count.set(0)
|
||||
}
|
||||
/** called once, at end. */
|
||||
def doComplete(finalResult: TestResult.Value): Unit =
|
||||
{
|
||||
val (skipped, errors, passed, failures) = (skippedCount.get, errorsCount.get, passedCount.get, failuresCount.get)
|
||||
val totalCount = failures + errors + skipped + passed
|
||||
val postfix = ": Total " + totalCount + ", Failed " + failures + ", Errors " + errors + ", Passed " + passed + ", Skipped " + skipped
|
||||
finalResult match {
|
||||
case TestResult.Error => log.error("Error" + postfix)
|
||||
case TestResult.Passed => log.info("Passed: " + postfix)
|
||||
case TestResult.Failed => log.error("Failed: " + postfix)
|
||||
}
|
||||
}
|
||||
def doInit {}
|
||||
/** called once, at end of test group. */
|
||||
def doComplete(finalResult: TestResult.Value): Unit = {}
|
||||
override def contentLogger(test: TestDefinition): Option[ContentLogger] = Some(logTest(test))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue