mirror of https://github.com/sbt/sbt.git
buffered, separate loggers for each test
This commit is contained in:
parent
e653517c8d
commit
c8fe1a3c1d
|
|
@ -10,6 +10,7 @@ package sbt
|
|||
import Configurations.{Compile, CompilerPlugin, IntegrationTest, Runtime, Test}
|
||||
import complete._
|
||||
import std.TaskExtra._
|
||||
import org.scalatools.testing.{AnnotatedFingerprint, SubclassFingerprint}
|
||||
|
||||
import scala.xml.{Node => XNode,NodeSeq}
|
||||
import org.apache.ivy.core.module.{descriptor, id}
|
||||
|
|
@ -44,6 +45,9 @@ object Defaults
|
|||
))
|
||||
def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(Seq(
|
||||
pollInterval :== 500,
|
||||
logBuffered :== false,
|
||||
logBuffered in testOnly :== true,
|
||||
logBuffered in test :== true,
|
||||
autoCompilerPlugins :== true,
|
||||
internalConfigurationMap :== Configurations.internalMap _,
|
||||
initialize :== (),
|
||||
|
|
@ -219,9 +223,24 @@ object Defaults
|
|||
)
|
||||
|
||||
def testTaskOptions(key: Scoped): Seq[Setting[_]] = inTask(key)( Seq(
|
||||
testListeners <<= (streams, testListeners) map { (s, ls) => TestLogger(s.log) +: ls },
|
||||
testListeners <<= (streams, resolvedScoped, streamsManager, logBuffered in key, testListeners) map { (s, sco, sm, buff, ls) =>
|
||||
TestLogger(s.log, testLogger(sm, test in sco.scope), buff) +: ls
|
||||
},
|
||||
testOptions <<= (testOptions, testListeners) map { (options, ls) => Tests.Listeners(ls) +: options }
|
||||
) )
|
||||
def testLogger(manager: Streams, baseKey: Scoped)(tdef: TestDefinition): Logger =
|
||||
{
|
||||
val scope = baseKey.scope
|
||||
val extra = scope.extra match { case Select(x) => x; case _ => AttributeMap.empty }
|
||||
val key = ScopedKey(scope.copy(extra = Select(testExtra(extra, tdef))), baseKey.key)
|
||||
manager(key).log
|
||||
}
|
||||
def buffered(log: Logger): Logger = new BufferedLogger(FullLogger(log))
|
||||
def testExtra(extra: AttributeMap, tdef: TestDefinition): AttributeMap =
|
||||
{
|
||||
val mod = tdef.fingerprint match { case f: SubclassFingerprint => f.isModule; case f: AnnotatedFingerprint => f.isModule; case _ => false }
|
||||
extra.put(name.key, tdef.name).put(isModule, mod)
|
||||
}
|
||||
|
||||
def testOnlyTask =
|
||||
InputTask( TaskData(definedTests)(testOnlyParser)(Nil) ) { result =>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ object Keys
|
|||
val showTiming = SettingKey[Boolean]("show-timing", "If true, the command success message includes the completion time.")
|
||||
val timingFormat = SettingKey[java.text.DateFormat]("timing-format", "The format used for displaying the completion time.")
|
||||
val logManager = SettingKey[LogManager]("log-manager", "The log manager, which creates Loggers for different contexts.")
|
||||
val logBuffered = SettingKey[Boolean]("log-buffered", "True if logging should be buffered until work completes.")
|
||||
|
||||
// Project keys
|
||||
val projectCommand = AttributeKey[Boolean]("project-command", "Marks Commands that were registered for the current Project.")
|
||||
|
|
@ -154,6 +155,7 @@ object Keys
|
|||
val testOptions = TaskKey[Seq[TestOption]]("test-options", "Options for running tests.")
|
||||
val testFrameworks = SettingKey[Seq[TestFramework]]("test-frameworks", "Registered, although not necessarily present, test frameworks.")
|
||||
val testListeners = TaskKey[Seq[TestReportListener]]("test-listeners", "Defines test listeners.")
|
||||
val isModule = AttributeKey[Boolean]("is-module", "True if the target is a module.")
|
||||
|
||||
// Classpath/Dependency Management Keys
|
||||
type Classpath = Seq[Attributed[File]]
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ object LogManager
|
|||
|
||||
def withScreenLogger(mk: => AbstractLogger): LogManager = withLoggers(mk)
|
||||
|
||||
def withLoggers(screen: => AbstractLogger = defaultScreen, backed: PrintWriter => AbstractLogger = defaultBacked(false)): LogManager =
|
||||
def withLoggers(screen: => AbstractLogger = defaultScreen, backed: PrintWriter => AbstractLogger = defaultBacked(true)): LogManager =
|
||||
new LogManager {
|
||||
def apply(data: Settings[Scope], task: ScopedKey[_], to: PrintWriter): Logger =
|
||||
defaultLogger(data, task, screen, backed(to))
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ object TestFrameworks
|
|||
val SpecsCompat = new TestFramework("sbt.impl.SpecsFramework")
|
||||
}
|
||||
|
||||
class TestFramework(val implClassName: String) extends NotNull
|
||||
class TestFramework(val implClassName: String)
|
||||
{
|
||||
def create(loader: ClassLoader, log: Logger): Option[Framework] =
|
||||
{
|
||||
|
|
@ -34,7 +34,7 @@ class TestFramework(val implClassName: String) extends NotNull
|
|||
catch { case e: ClassNotFoundException => log.debug("Framework implementation '" + implClassName + "' not present."); None }
|
||||
}
|
||||
}
|
||||
final class TestDefinition(val name: String, val fingerprint: Fingerprint) extends NotNull
|
||||
final class TestDefinition(val name: String, val fingerprint: Fingerprint)
|
||||
{
|
||||
override def toString = "Test " + name + " : " + TestFramework.toString(fingerprint)
|
||||
override def equals(t: Any) =
|
||||
|
|
@ -47,8 +47,14 @@ final class TestDefinition(val name: String, val fingerprint: Fingerprint) exten
|
|||
|
||||
final class TestRunner(framework: Framework, loader: ClassLoader, listeners: Seq[TestReportListener], log: Logger)
|
||||
{
|
||||
private[this] val delegate = framework.testRunner(loader, listeners.flatMap(_.contentLogger).toArray)
|
||||
private[this] def run(testDefinition: TestDefinition, handler: EventHandler, args: Array[String]): Unit =
|
||||
{
|
||||
val loggers = listeners.flatMap(_.contentLogger(testDefinition))
|
||||
val delegate = framework.testRunner(loader, loggers.map(_.log).toArray)
|
||||
try { delegateRun(delegate, testDefinition, handler, args) }
|
||||
finally { loggers.foreach( _.flush() ) }
|
||||
}
|
||||
private[this] def delegateRun(delegate: Runner, testDefinition: TestDefinition, handler: EventHandler, args: Array[String]): Unit =
|
||||
(testDefinition.fingerprint, delegate) match
|
||||
{
|
||||
case (simple: TestFingerprint, _) => delegate.run(testDefinition.name, simple, handler, args)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ trait TestReportListener
|
|||
/** called if test completed */
|
||||
def endGroup(name: String, result: TestResult.Value)
|
||||
/** Used by the test framework for logging test results*/
|
||||
def contentLogger: Option[TLogger] = None
|
||||
def contentLogger(test: TestDefinition): Option[ContentLogger] = None
|
||||
}
|
||||
|
||||
trait TestsListener extends TestReportListener
|
||||
|
|
@ -52,7 +52,15 @@ object TestEvent
|
|||
|
||||
object TestLogger
|
||||
{
|
||||
def apply(logger: sbt.Logger): TestLogger = new TestLogger(wrap(logger))
|
||||
def apply(logger: sbt.Logger, logTest: TestDefinition => sbt.Logger, buffered: Boolean): TestLogger =
|
||||
new TestLogger(new TestLogging(wrap(logger), tdef => contentLogger(logTest(tdef), buffered)) )
|
||||
|
||||
def contentLogger(log: sbt.Logger, buffered: Boolean): ContentLogger =
|
||||
{
|
||||
val blog = new BufferedLogger(FullLogger(log))
|
||||
if(buffered) blog.record()
|
||||
new ContentLogger(wrap(blog), () => blog.stopQuietly())
|
||||
}
|
||||
def wrap(logger: sbt.Logger): TLogger =
|
||||
new TLogger
|
||||
{
|
||||
|
|
@ -62,11 +70,14 @@ object TestLogger
|
|||
def debug(s: String) = log(Level.Debug, s)
|
||||
def trace(t: Throwable) = logger.trace(t)
|
||||
private def log(level: Level.Value, s: String) = logger.log(level, s)
|
||||
def ansiCodesSupported() = logger.ansiCodesSupported
|
||||
def ansiCodesSupported() = true//logger.ansiCodesSupported
|
||||
}
|
||||
}
|
||||
class TestLogger(val log: TLogger) extends TestsListener
|
||||
final class TestLogging(val global: TLogger, val logTest: TestDefinition => ContentLogger)
|
||||
final class ContentLogger(val log: TLogger, val flush: () => Unit)
|
||||
class TestLogger(val logging: TestLogging) extends TestsListener
|
||||
{
|
||||
import logging.{global => log, logTest}
|
||||
protected var skipped, errors, passed, failures = 0
|
||||
|
||||
def startGroup(name: String) {}
|
||||
|
|
@ -106,5 +117,5 @@ class TestLogger(val log: TLogger) extends TestsListener
|
|||
case TestResult.Failed => log.error("Failed: " + postfix)
|
||||
}
|
||||
}
|
||||
override def contentLogger: Option[TLogger] = Some(log)
|
||||
override def contentLogger(test: TestDefinition): Option[ContentLogger] = Some(logTest(test))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue