From 1ec2118219279344a135d64926091037d94b3872 Mon Sep 17 00:00:00 2001 From: cheeseng Date: Wed, 10 Apr 2013 15:28:50 +0800 Subject: [PATCH] -Moved code that count test results from TestLogger to SuiteResult. -Print the results in Tests.showResult. --- .../src/main/scala/sbt/ForkTests.scala | 16 +++--- main/actions/src/main/scala/sbt/Tests.scala | 23 ++++++-- main/src/main/scala/sbt/Defaults.scala | 8 +-- .../tests/t543/project/Ticket543Test.scala | 6 +-- .../src/main/scala/sbt/TestFramework.scala | 16 +++--- .../main/scala/sbt/TestReportListener.scala | 53 ++++++++----------- 6 files changed, 65 insertions(+), 57 deletions(-) diff --git a/main/actions/src/main/scala/sbt/ForkTests.scala b/main/actions/src/main/scala/sbt/ForkTests.scala index 0748797dc..54e3a0258 100755 --- a/main/actions/src/main/scala/sbt/ForkTests.scala +++ b/main/actions/src/main/scala/sbt/ForkTests.scala @@ -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() } } diff --git a/main/actions/src/main/scala/sbt/Tests.scala b/main/actions/src/main/scala/sbt/Tests.scala index a368876c6..86801fdd5 100644 --- a/main/actions/src/main/scala/sbt/Tests.scala +++ b/main/actions/src/main/scala/sbt/Tests.scala @@ -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 { diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 14f3cb5cf..e4d779518 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -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] = diff --git a/sbt/src/sbt-test/tests/t543/project/Ticket543Test.scala b/sbt/src/sbt-test/tests/t543/project/Ticket543Test.scala index 0ccfa8381..ba9881ba0 100755 --- a/sbt/src/sbt-test/tests/t543/project/Ticket543Test.scala +++ b/sbt/src/sbt-test/tests/t543/project/Ticket543Test.scala @@ -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() } diff --git a/testing/src/main/scala/sbt/TestFramework.scala b/testing/src/main/scala/sbt/TestFramework.scala index b59475983..f70ab09c9 100644 --- a/testing/src/main/scala/sbt/TestFramework.scala +++ b/testing/src/main/scala/sbt/TestFramework.scala @@ -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]]): diff --git a/testing/src/main/scala/sbt/TestReportListener.scala b/testing/src/main/scala/sbt/TestReportListener.scala index c1de312fd..9cb4e66c5 100644 --- a/testing/src/main/scala/sbt/TestReportListener.scala +++ b/testing/src/main/scala/sbt/TestReportListener.scala @@ -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)) }