From 4d5effcb28c5094150c9148754f002ae74bb920e Mon Sep 17 00:00:00 2001 From: Eugene Vigdorchik Date: Mon, 2 Apr 2012 12:08:18 +0400 Subject: [PATCH] Fixes after review, take 2. --- main/Defaults.scala | 29 ++++++----- main/Keys.scala | 2 +- main/actions/ForkTests.scala | 11 +++-- main/actions/Tests.scala | 48 ++++++++++--------- testing/TestFramework.scala | 3 +- testing/agent/src/main/java/sbt/ForkMain.java | 22 ++++----- 6 files changed, 60 insertions(+), 55 deletions(-) diff --git a/main/Defaults.scala b/main/Defaults.scala index 7061ba19a..74340121b 100755 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -286,26 +286,29 @@ object Defaults extends BuildCommon testOptions in GlobalScope :== Nil, testFilter in testOnly :== (selectedFilter _), testFilter in testQuick <<= testQuickFilter, - executeTests <<= (streams in test, loadedTestFrameworks, testLoader, testGrouping in test, fullClasspath in test, javaOptions in test, javaHome in test, resolvedScoped, state) flatMap { - (s, frameworkMap, loader, groups, cp, javaOpts, javaHome, scoped, st) => - implicit val display = Project.showContextKey(st) + executeTests <<= (streams in test, loadedTestFrameworks, testLoader, testGrouping in test, fullClasspath in test, javaOptions in test, javaHome in test) flatMap { + (s, frameworkMap, loader, groups, cp, javaOpts, javaHome) => val results = groups map { - case Tests.TestGroup(name, tests, config) => + case Tests.Group(name, tests, config) => config.subproc match { case Tests.Fork(extraJvm) => ForkTests(frameworkMap.keys.toSeq, tests.toList, config, cp.files, javaHome, javaOpts, s.log) case Tests.InProcess => - Tests(frameworkMap, loader, tests, config, noTestsMessage(scoped, name), s.log) + Tests(frameworkMap, loader, tests, config, s.log) } } - Tests.reduce(results) + Tests.flatten(results) + }, + test <<= (executeTests, streams, resolvedScoped, state) map { + (results, s, scoped, st) => + implicit val display = Project.showContextKey(st) + Tests.showResults(s.log, results, noTestsMessage(scoped)) }, - test <<= (executeTests, streams) map { (results, s) => Tests.showResults(s.log, results) }, testOnly <<= inputTests(testOnly), testQuick <<= inputTests(testQuick) ) - private[this] def noTestsMessage(scoped: ScopedKey[_], group: String)(implicit display: Show[ScopedKey[_]]): String = - "No tests to run for group " + group + " in " + display(scoped) + private[this] def noTestsMessage(scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String = + "No tests to run for " + display(scoped) lazy val TaskGlobal: Scope = ThisScope.copy(task = Global) lazy val ConfigGlobal: Scope = ThisScope.copy(config = Global) @@ -316,7 +319,7 @@ object Defaults extends BuildCommon testOptions <<= (testOptions in TaskGlobal, testListeners) map { (options, ls) => Tests.Listeners(ls) +: options }, testExecution <<= testExecutionTask(key), testGrouping <<= ((definedTests, testExecution) map { - (tests, exec) => Seq(new Tests.TestGroup("", tests, exec)) + (tests, exec) => Seq(new Tests.Group("", tests, exec)) }) ) ) def testLogger(manager: Streams, baseKey: Scoped)(tdef: TestDefinition): Logger = @@ -372,17 +375,17 @@ object Defaults extends BuildCommon case (s, frameworks, filter, groups, loader, scoped, (selected, frameworkOptions), cp, javaOpts, javaHome, st) => implicit val display = Project.showContextKey(st) val results = groups map { - case Tests.TestGroup(name, tests, config) => + case Tests.Group(name, tests, config) => val modifiedOpts = Tests.Filter(filter(selected)) +: Tests.Argument(frameworkOptions : _*) +: config.options val newConfig = config.copy(options = modifiedOpts) newConfig.subproc match { case Tests.Fork(extraJvm) => ForkTests(frameworks.keys.toSeq, tests.toList, newConfig, cp.files, javaHome, javaOpts, s.log) case Tests.InProcess => - Tests(frameworks, loader, tests, newConfig, noTestsMessage(scoped, name), s.log) + Tests(frameworks, loader, tests, newConfig, s.log) } } - Tests.reduce(results) map (Tests.showResults(s.log, _)) + Tests.flatten(results) map (Tests.showResults(s.log, _, noTestsMessage(scoped))) } } diff --git a/main/Keys.scala b/main/Keys.scala index 0a9ce289f..8c41696dd 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -198,7 +198,7 @@ object Keys val testListeners = TaskKey[Seq[TestReportListener]]("test-listeners", "Defines test listeners.") val testExecution = TaskKey[Tests.Execution]("test-execution", "Settings controlling test execution") val testFilter = TaskKey[Seq[String] => String => Boolean]("test-filter", "Filter controlling whether the test is executed") - val testGrouping = TaskKey[Seq[Tests.TestGroup]]("test-grouping", "Groups discovered tests into groups. Groups are run sequentially.") + val testGrouping = TaskKey[Seq[Tests.Group]]("test-grouping", "Groups discovered tests into groups. Groups are run sequentially.") val isModule = AttributeKey[Boolean]("is-module", "True if the target is a module.") // Classpath/Dependency Management Keys diff --git a/main/actions/ForkTests.scala b/main/actions/ForkTests.scala index 09bf8117e..64371b815 100755 --- a/main/actions/ForkTests.scala +++ b/main/actions/ForkTests.scala @@ -58,12 +58,13 @@ private[sbt] object ForkTests { os.writeObject(args.toArray) } + import Tags._ @annotation.tailrec def react: Unit = is.readObject match { - case `TestsDone` => os.writeObject(TestsDone); - case Array(`ErrorTag`, s: String) => log.error(s); react - case Array(`WarnTag`, s: String) => log.warn(s); react - case Array(`InfoTag`, s: String) => log.info(s); react - case Array(`DebugTag`, s: String) => log.debug(s); react + case `Done` => os.writeObject(Done); + case Array(`Error`, s: String) => log.error(s); react + case Array(`Warn`, s: String) => log.warn(s); react + case Array(`Info`, s: String) => log.info(s); react + case Array(`Debug`, s: String) => log.debug(s); react case t: Throwable => log.trace(t); react case tEvents: Array[Event] => for (first <- tEvents.headOption) listeners.foreach(_ startGroup first.testName) diff --git a/main/actions/Tests.scala b/main/actions/Tests.scala index a568ab273..9b8013629 100644 --- a/main/actions/Tests.scala +++ b/main/actions/Tests.scala @@ -45,7 +45,7 @@ object Tests final case class Execution(options: Seq[TestOption], parallel: Boolean, subproc: SubProcessPolicy, tags: Seq[(Tag, Int)]) - def apply(frameworks: Map[TestFramework, Framework], testLoader: ClassLoader, discovered: Seq[TestDefinition], config: Execution, noTestsMessage: => String, log: Logger): Task[Output] = + def apply(frameworks: Map[TestFramework, Framework], testLoader: ClassLoader, discovered: Seq[TestDefinition], config: Execution, log: Logger): Task[Output] = { import collection.mutable.{HashSet, ListBuffer, Map, Set} val testFilters = new ListBuffer[String => Boolean] @@ -93,10 +93,10 @@ object Tests def includeTest(test: TestDefinition) = !excludeTestsSet.contains(test.name) && testFilters.forall(filter => filter(test.name)) val tests = discovered.filter(includeTest).toSet.toSeq val arguments = testArgsByFramework.map { case (k,v) => (k, v.toList) } toMap; - testTask(frameworks.values.toSeq, testLoader, tests, noTestsMessage, setup.readOnly, cleanup.readOnly, log, testListeners.readOnly, arguments, config) + testTask(frameworks.values.toSeq, testLoader, tests, setup.readOnly, cleanup.readOnly, log, testListeners.readOnly, arguments, config) } - def testTask(frameworks: Seq[Framework], loader: ClassLoader, tests: Seq[TestDefinition], noTestsMessage: => String, + def testTask(frameworks: Seq[Framework], loader: ClassLoader, tests: Seq[TestDefinition], userSetup: Iterable[ClassLoader => Unit], userCleanup: Iterable[ClassLoader => Unit], log: Logger, testListeners: Seq[TestReportListener], arguments: Map[Framework, Seq[String]], config: Execution): Task[Output] = { @@ -104,7 +104,7 @@ object Tests def partApp(actions: Iterable[ClassLoader => Unit]) = actions.toSeq map {a => () => a(loader) } val (frameworkSetup, runnables, frameworkCleanup) = - TestFramework.testTasks(frameworks, loader, tests, noTestsMessage, log, testListeners, arguments) + TestFramework.testTasks(frameworks, loader, tests, log, testListeners, arguments) val setupTasks = fj(partApp(userSetup) :+ frameworkSetup) val mainTasks = @@ -126,7 +126,7 @@ object Tests def processResults(results: Iterable[(String, TestResult.Value)]): (TestResult.Value, Map[String, TestResult.Value]) = (overall(results.map(_._2)), results.toMap) - def reduce(results: Seq[Task[Output]]): Task[Output] = + def flatten(results: Seq[Task[Output]]): Task[Output] = reduced(results.toIndexedSeq, { case ((v1, m1), (v2, m2)) => (if (v1.id < v2.id) v2 else v1, m1 ++ m2) }) @@ -157,31 +157,35 @@ object Tests (tests, mains.toSet) } - def showResults(log: Logger, results: (TestResult.Value, Map[String, TestResult.Value])): Unit = + def showResults(log: Logger, results: (TestResult.Value, Map[String, TestResult.Value]), noTestsMessage: =>String): Unit = { + if (results._2.isEmpty) + log.info(noTestsMessage) + else { import TestResult.{Error, Failed, Passed} - def select(Tpe: TestResult.Value) = results._2 collect { case (name, Tpe) => name } + def select(Tpe: TestResult.Value) = results._2 collect { case (name, Tpe) => name } - val failures = select(Failed) - val errors = select(Error) - val passed = select(Passed) + val failures = select(Failed) + val errors = select(Error) + val passed = select(Passed) - def show(label: String, level: Level.Value, tests: Iterable[String]): Unit = - if(!tests.isEmpty) - { - log.log(level, label) - log.log(level, tests.mkString("\t", "\n\t", "")) - } + def show(label: String, level: Level.Value, tests: Iterable[String]): Unit = + if(!tests.isEmpty) + { + log.log(level, label) + log.log(level, tests.mkString("\t", "\n\t", "")) + } - show("Passed tests:", Level.Debug, passed ) - show("Failed tests:", Level.Error, failures) - show("Error during tests:", Level.Error, errors) + show("Passed tests:", Level.Debug, passed ) + show("Failed tests:", Level.Error, failures) + show("Error during tests:", Level.Error, errors) - if(!failures.isEmpty || !errors.isEmpty) - error("Tests unsuccessful") + if(!failures.isEmpty || !errors.isEmpty) + error("Tests unsuccessful") + } } - final case class TestGroup(name: String, tests: Seq[TestDefinition], config: Execution) + final case class Group(name: String, tests: Seq[TestDefinition], config: Execution) } diff --git a/testing/TestFramework.scala b/testing/TestFramework.scala index 4e5883bad..2261f497e 100644 --- a/testing/TestFramework.scala +++ b/testing/TestFramework.scala @@ -129,7 +129,6 @@ object TestFramework def testTasks(frameworks: Seq[Framework], testLoader: ClassLoader, tests: Seq[TestDefinition], - noTestsMessage: => String, log: Logger, listeners: Seq[TestReportListener], testArgsByFramework: Map[Framework, Seq[String]]): @@ -138,7 +137,7 @@ object TestFramework val arguments = testArgsByFramework withDefaultValue Nil val mappedTests = testMap(frameworks, tests, arguments) if(mappedTests.isEmpty) - (() => (), Nil, _ => () => log.info(noTestsMessage) ) + (() => (), Nil, _ => () => () ) else createTestTasks(testLoader, mappedTests, log, listeners) } diff --git a/testing/agent/src/main/java/sbt/ForkMain.java b/testing/agent/src/main/java/sbt/ForkMain.java index f935c20da..6112cd6c2 100755 --- a/testing/agent/src/main/java/sbt/ForkMain.java +++ b/testing/agent/src/main/java/sbt/ForkMain.java @@ -15,11 +15,9 @@ import java.util.ArrayList; import java.util.List; public class ForkMain { - public static final String TestsDone = "TestsDone"; - public static final String ErrorTag = "[error]"; - public static final String WarnTag = "[warn]"; - public static final String InfoTag = "[info]"; - public static final String DebugTag = "[debug]"; + public static enum Tags { + Error, Warn, Info, Debug, Done; + } static class SubclassFingerscan implements TestFingerprint, Serializable { private boolean isModule; @@ -95,18 +93,18 @@ public class ForkMain { Logger[] loggers = { new Logger() { public boolean ansiCodesSupported() { return false; } - void print(Object obj) { + void write(Object obj) { try { os.writeObject(obj); } catch (IOException e) { System.err.println("Cannot write to socket"); } } - public void error(String s) { print(new String[]{ErrorTag, s}); } - public void warn(String s) { print(new String[]{WarnTag, s}); } - public void info(String s) { print(new String[]{InfoTag, s}); } - public void debug(String s) { print(new String[]{DebugTag, s}); } - public void trace(Throwable t) { print(t); } + public void error(String s) { write(new Object[]{Tags.Error, s}); } + public void warn(String s) { write(new Object[]{Tags.Warn, s}); } + public void info(String s) { write(new Object[]{Tags.Info, s}); } + public void debug(String s) { write(new Object[]{Tags.Debug, s}); } + public void trace(Throwable t) { write(t); } } }; @@ -144,7 +142,7 @@ public class ForkMain { os.writeObject(events.toArray(new ForkEvent[events.size()])); } } - os.writeObject(TestsDone); + os.writeObject(Tags.Done); is.readObject(); } }