Josh's patch for passing arguments to test-* tasks.

This commit is contained in:
Mark Harrah 2009-12-23 00:10:53 -05:00
parent 04e50bd218
commit 3fcdca4ef7
4 changed files with 67 additions and 46 deletions

View File

@ -1,5 +1,5 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah, David MacIver
* Copyright 2008, 2009 Mark Harrah, David MacIver, Josh Cough
*/
package sbt
@ -255,15 +255,17 @@ abstract class BasicScalaProject extends ScalaProject with BasicDependencyProjec
protected def consoleAction = basicConsoleTask.dependsOn(testCompile, copyResources, copyTestResources) describedAs ConsoleDescription
protected def docAction = scaladocTask(mainLabel, mainSources, mainDocPath, docClasspath, documentOptions).dependsOn(compile) describedAs DocDescription
protected def docTestAction = scaladocTask(testLabel, testSources, testDocPath, docClasspath, documentOptions).dependsOn(testCompile) describedAs TestDocDescription
protected def testAction = defaultTestTask(testOptions)
protected def testOnlyAction = testQuickMethod(testCompileConditional.analysis, testOptions)(options =>
defaultTestTask(options)) describedAs(TestOnlyDescription)
protected def testQuickAction = defaultTestQuickMethod(false) describedAs(TestQuickDescription)
protected def testFailedAction = defaultTestQuickMethod(true) describedAs(TestFailedDescription)
protected def defaultTestQuickMethod(failedOnly: Boolean) =
testQuickMethod(testCompileConditional.analysis, testOptions)(options => defaultTestTask(quickOptions(failedOnly) ::: options.toList))
protected def defaultTestTask(testOptions: => Seq[TestOption]) =
testTask(testFrameworks, testClasspath, testCompileConditional.analysis, testOptions).dependsOn(testCompile, copyResources, copyTestResources) describedAs TestDescription
protected def testAction = defaultTestTask(Nil, testOptions)
protected def testOnlyAction = testQuickMethod(testCompileConditional.analysis, testOptions)((testArgs, options) => {
defaultTestTask(testArgs, options)
}) describedAs(TestOnlyDescription)
protected def testQuickAction = defaultTestQuickMethod(false) describedAs(TestQuickDescription)
protected def testFailedAction = defaultTestQuickMethod(true) describedAs(TestFailedDescription)
protected def defaultTestQuickMethod(failedOnly: Boolean) =
testQuickMethod(testCompileConditional.analysis, testOptions)((args, options) => defaultTestTask(args, quickOptions(failedOnly) ::: options.toList))
protected def defaultTestTask(testArgs: Seq[String], testOptions: => Seq[TestOption]) =
testTask(testFrameworks, testClasspath, testCompileConditional.analysis, testArgs, testOptions).dependsOn(testCompile, copyResources, copyTestResources) describedAs TestDescription
override def packageToPublishActions: Seq[ManagedTask] = `package` :: Nil

View File

@ -1,5 +1,5 @@
/* sbt -- Simple Build Tool
* Copyright 2009 Steven Blundy, Mark Harrah
* Copyright 2009 Steven Blundy, Mark Harrah, Josh Cough
*/
package sbt
@ -15,8 +15,8 @@ trait IntegrationTesting extends NotNull
trait ScalaIntegrationTesting extends IntegrationTesting
{ self: ScalaProject =>
protected def integrationTestTask(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis, options: => Seq[TestOption]) =
testTask(frameworks, classpath, analysis, options)
protected def integrationTestTask(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis, testArgs: Seq[String], options: => Seq[TestOption]) =
testTask(frameworks, classpath, analysis, testArgs, options)
}
trait BasicScalaIntegrationTesting extends BasicIntegrationTesting with MavenStyleIntegrationTestPaths
@ -34,7 +34,7 @@ trait BasicIntegrationTesting extends ScalaIntegrationTesting with IntegrationTe
val integrationTestCompileConditional = new CompileConditional(integrationTestCompileConfiguration, buildCompiler)
protected def integrationTestAction = integrationTestTask(integrationTestFrameworks, integrationTestClasspath, integrationTestCompileConditional.analysis, integrationTestOptions) dependsOn integrationTestCompile describedAs IntegrationTestCompileDescription
protected def integrationTestAction = integrationTestTask(integrationTestFrameworks, integrationTestClasspath, integrationTestCompileConditional.analysis, Nil, integrationTestOptions) dependsOn integrationTestCompile describedAs IntegrationTestCompileDescription
protected def integrationTestCompileAction = integrationTestCompileTask() dependsOn compile describedAs IntegrationTestDescription
protected def integrationTestCompileTask() = task{ integrationTestCompileConditional.run }

View File

@ -1,5 +1,5 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah, David MacIver
* Copyright 2008, 2009 Mark Harrah, David MacIver, Josh Cough
*/
package sbt
@ -67,6 +67,7 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje
case class ExcludeTests(tests: Iterable[String]) extends TestOption
case class TestListeners(listeners: Iterable[TestReportListener]) extends TestOption
case class TestFilter(filterTest: String => Boolean) extends TestOption
case class TestFrameworkArgument(arg: String) extends TestOption
case class JarManifest(m: Manifest) extends PackageOption
{
@ -149,13 +150,14 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje
def copyTask(sources: PathFinder, destinationDirectory: Path): Task =
task { FileUtilities.copy(sources.get, destinationDirectory, log).left.toOption }
def testTask(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis, options: TestOption*): Task =
testTask(frameworks, classpath, analysis, options)
def testTask(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis, options: => Seq[TestOption]): Task =
def testTask(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis, testArgs: Seq[String], options: TestOption*): Task =
testTask(frameworks, classpath, analysis, testArgs, options)
def testTask(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis,
testArgs: Seq[String], options: => Seq[TestOption]): Task =
{
def work =
{
val (begin, work, end) = testTasks(frameworks, classpath, analysis, options)
val (begin, work, end) = testTasks(frameworks, classpath, analysis, testArgs, options)
val beginTasks = begin.map(toTask).toSeq // test setup tasks
val workTasks = work.map(w => toTask(w) dependsOn(beginTasks : _*)) // the actual tests
val endTasks = end.map(toTask).toSeq // tasks that perform test cleanup and are run regardless of success of tests
@ -249,7 +251,8 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje
}
}
protected def incrementImpl(v: BasicVersion): Version = v.incrementMicro
protected def testTasks(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis, options: => Seq[TestOption]) = {
protected def testTasks(frameworks: Seq[TestFramework], classpath: PathFinder, analysis: CompileAnalysis, testArgs: Seq[String],
options: => Seq[TestOption]) = {
import scala.collection.mutable.HashSet
val testFilters = new ListBuffer[String => Boolean]
@ -276,18 +279,22 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje
}
def includeTest(test: TestDefinition) = !excludeTestsSet.contains(test.testClassName) && testFilters.forall(filter => filter(test.testClassName))
val tests = HashSet.empty[TestDefinition] ++ analysis.allTests.filter(includeTest)
TestFramework.testTasks(frameworks, classpath.get, buildScalaInstance.loader, tests.toSeq, log, testListeners.readOnly, false, setup.readOnly, cleanup.readOnly)
TestFramework.testTasks(frameworks, classpath.get, buildScalaInstance.loader, tests.toSeq, log, testListeners.readOnly, false, setup.readOnly, cleanup.readOnly, testArgs)
}
private def flatten[T](i: Iterable[Iterable[T]]) = i.flatMap(x => x)
protected def testQuickMethod(testAnalysis: CompileAnalysis, options: => Seq[TestOption])(toRun: Seq[TestOption] => Task) =
multiTask(testAnalysis.allTests.map(_.testClassName).toList) { includeFunction =>
toRun(TestFilter(includeFunction) :: options.toList)
protected def testQuickMethod(testAnalysis: CompileAnalysis, options: => Seq[TestOption])(toRun: (Seq[String],Seq[TestOption]) => Task) = {
val analysis = testAnalysis.allTests.map(_.testClassName).toList
multiTask(analysis) { (args,includeFunction) => {
toRun(args, TestFilter(includeFunction) :: options.toList)
}
}
}
protected final def maximumErrors[T <: ActionOption](options: Seq[T]) =
(for( MaxCompileErrors(maxErrors) <- options) yield maxErrors).firstOption.getOrElse(DefaultMaximumCompileErrors)
}
trait WebScalaProject extends ScalaProject
{
@deprecated protected def prepareWebappTask(webappContents: PathFinder, warPath: => Path, classpath: PathFinder, extraJars: => Iterable[File]): Task =
@ -344,14 +351,19 @@ object ScalaProject
}
trait MultiTaskProject extends Project
{
def multiTask(allTests: => List[String])(run: (String => Boolean) => Task) =
def multiTask(allTests: => List[String])(run: (List[String], (String => Boolean)) => Task): MethodTask = {
task { tests =>
val (testNames, separator :: testArgs) = tests.toList.span(! _.startsWith("--"))
def filterInclude =
{
val (exactFilters, testFilters) = tests.toList.map(GlobFilter.apply).partition(_.isInstanceOf[ExactFilter])
val (exactFilters, testFilters) = testNames.toList.map(GlobFilter.apply).partition(_.isInstanceOf[ExactFilter])
val includeTests = exactFilters.map(_.asInstanceOf[ExactFilter].matchName)
val toCheck = scala.collection.mutable.HashSet(includeTests: _*)
toCheck --= allTests
if(!toCheck.isEmpty && log.atLevel(Level.Warn))
{
log.warn("Test(s) not found:")
@ -361,13 +373,13 @@ trait MultiTaskProject extends Project
(test: String) => includeTestsSet.contains(test) || testFilters.exists(_.accept(test))
}
val includeFunction =
if(tests.isEmpty)
if(testNames.isEmpty)
(test: String) => true
else
filterInclude
run(includeFunction)
run(testArgs, includeFunction)
} completeWith allTests
}
}
trait ExecProject extends Project
{
@ -396,4 +408,4 @@ trait Exec extends SimpleScalaProject
{
lazy val sh = task { args => execOut { Process("sh" :: "-c" :: args.mkString(" ") :: Nil) } }
lazy val exec = task { args => execOut { Process(args) } }
}
}

View File

@ -1,5 +1,5 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Steven Blundy, Mark Harrah
* Copyright 2008, 2009 Steven Blundy, Mark Harrah, Josh Cough
*/
package sbt
@ -69,15 +69,15 @@ final class NamedTestTask(val name: String, action: => Option[String]) extends N
object TestFramework
{
def runTests(frameworks: Seq[TestFramework], classpath: Iterable[Path], scalaLoader: ClassLoader, tests: Seq[TestDefinition], log: Logger,
listeners: Seq[TestReportListener]) =
{
val (start, runTests, end) = testTasks(frameworks, classpath, scalaLoader, tests, log, listeners, true, Nil, Nil)
def run(tasks: Iterable[NamedTestTask]) = tasks.foreach(_.run())
run(start)
run(runTests)
run(end)
}
// def runTests(frameworks: Seq[TestFramework], classpath: Iterable[Path], scalaLoader: ClassLoader,
// tests: Seq[TestDefinition], testArgs: Seq[String], log: Logger, listeners: Seq[TestReportListener]) =
// {
// val (start, runTests, end) = testTasks(frameworks, classpath, scalaLoader, tests, log, listeners, true, Nil, Nil, Nil)
// def run(tasks: Iterable[NamedTestTask]) = tasks.foreach(_.run())
// run(start)
// run(runTests)
// run(end)
// }
private val ScalaCompilerJarPackages = "scala.tools.nsc." :: "jline." :: "ch.epfl.lamp." :: Nil
@ -89,9 +89,16 @@ object TestFramework
import scala.collection.{Map, Set}
def testTasks(frameworks: Seq[TestFramework], classpath: Iterable[Path], scalaLoader: ClassLoader, tests: Seq[TestDefinition], log: Logger,
listeners: Seq[TestReportListener], endErrorsEnabled: Boolean, setup: Iterable[() => Option[String]],
cleanup: Iterable[() => Option[String]]): (Iterable[NamedTestTask], Iterable[NamedTestTask], Iterable[NamedTestTask]) =
def testTasks(frameworks: Seq[TestFramework],
classpath: Iterable[Path],
scalaLoader: ClassLoader,
tests: Seq[TestDefinition],
log: Logger,
listeners: Seq[TestReportListener],
endErrorsEnabled: Boolean,
setup: Iterable[() => Option[String]],
cleanup: Iterable[() => Option[String]],
testArgs: Seq[String]): (Iterable[NamedTestTask], Iterable[NamedTestTask], Iterable[NamedTestTask]) =
{
val loader = createTestLoader(classpath, scalaLoader)
val rawFrameworks = frameworks.flatMap(_.create(loader, log))
@ -99,7 +106,7 @@ object TestFramework
if(mappedTests.isEmpty)
(new NamedTestTask(TestStartName, None) :: Nil, Nil, new NamedTestTask(TestFinishName, { log.info("No tests to run."); None }) :: Nil )
else
createTestTasks(loader, mappedTests, log, listeners, endErrorsEnabled, setup, cleanup)
createTestTasks(loader, mappedTests, log, listeners, endErrorsEnabled, setup, cleanup, testArgs)
}
private def testMap(frameworks: Seq[Framework], tests: Seq[TestDefinition]): Map[Framework, Set[TestDefinition]] =
{
@ -127,7 +134,7 @@ object TestFramework
private def createTestTasks(loader: ClassLoader, tests: Map[Framework, Set[TestDefinition]], log: Logger,
listeners: Seq[TestReportListener], endErrorsEnabled: Boolean, setup: Iterable[() => Option[String]],
cleanup: Iterable[() => Option[String]]) =
cleanup: Iterable[() => Option[String]], testArgs: Seq[String]) =
{
val testsListeners = listeners.filter(_.isInstanceOf[TestsListener]).map(_.asInstanceOf[TestsListener])
def foreachListenerSafe(f: TestsListener => Unit): Unit = safeForeach(testsListeners, log)(f)
@ -151,7 +158,7 @@ object TestFramework
val oldLoader = Thread.currentThread.getContextClassLoader
Thread.currentThread.setContextClassLoader(loader)
try {
runner.run(testDefinition, Nil) match
runner.run(testDefinition, testArgs) match
{
case Error => result() = Error; Some("ERROR occurred during testing.")
case Failed => result() = Failed; Some("Test FAILED")