org.scalatest.tools.ScalaTestAntTask.scala Maven / Gradle / Ivy
Show all versions of scalatest_2.11.0-M3 Show documentation
package org.scalatest.tools
import scala.collection.mutable.ListBuffer
import org.apache.tools.ant.BuildException
import org.apache.tools.ant.Task
import org.apache.tools.ant.types.Path
import org.apache.tools.ant.AntClassLoader
import org.apache.tools.ant.taskdefs.Java
/**
*
* An ant task to run ScalaTest. Instructions on how to specify various
* options are below. See the scaladocs for the Runner
class for a description
* of what each of the options does.
*
*
*
* To use the ScalaTest ant task, you must first define it in your ant file using taskdef
.
* Here's an example:
*
*
*
* <path id="scalatest.classpath">
* <pathelement location="${lib}/scalatest.jar"/>
* <pathelement location="${lib}/scala-library.jar"/>
* </path>
*
* <target name="main" depends="dist">
* <taskdef name="scalatest" classname="org.scalatest.tools.ScalaTestAntTask">
* <classpath refid="scalatest.classpath"/>
* </taskdef>
*
* <scalatest ...
* </target>
*
*
*
* Once defined, you use the task by specifying information in a scalatest
element:
*
*
*
* <scalatest ...>
* ...
* </scalatest>
*
*
*
* You can place key value pairs into the configMap
using nested <config>
elements,
* like this:
*
*
*
* <scalatest>
* <config name="dbname" value="testdb"/>
* <config name="server" value="192.168.1.188"/>
*
*
*
* You can specify a runpath using either a runpath
attribute and/or nested
* <runpath>
elements, using standard ant path notation:
*
*
*
* <scalatest runpath="serviceuitest-1.1beta4.jar:myjini">
*
*
* or
*
*
* <scalatest>
* <runpath>
* <pathelement location="serviceuitest-1.1beta4.jar"/>
* <pathelement location="myjini"/>
* </runpath>
*
*
*
* To add a URL to your runpath, use a <runpathurl>
element
* (since ant paths don't support URLs):
*
*
*
* <scalatest>
* <runpathurl url="http://foo.com/bar.jar"/>
*
*
*
* You can specify reporters using nested <reporter>
elements, where the type
* attribute must be one of the following:
*
*
*
* -
graphic
* -
file
* -
junitxml
* -
stdout
* -
stderr
* -
reporterclass
*
*
*
* Each may include a config
attribute to specify the reporter configuration.
* Types file
, junitxml
and reporterclass
require additional attributes
* filename
, directory
, and classname
, respectively:
*
*
*
* <scalatest>
* <reporter type="stdout" config="FAB"/>
* <reporter type="file" filename="test.out"/>
* <reporter type="junitxml" directory="target"/>
* <reporter type="reporterclass" classname="my.ReporterClass"/>
*
*
*
* Specify tags to include and/or exclude using <tagsToInclude>
and
* <tagsToExclude>
elements, like this:
*
*
*
* <scalatest>
* <tagsToInclude>
* CheckinTests
* FunctionalTests
* </tagsToInclude>
*
* <tagsToExclude>
* SlowTests
* NetworkTests
* </tagsToExclude>
*
*
*
* To specify suites to run, use either a suite
attribute or nested
* <suite>
elements:
*
*
*
* <scalatest suite="com.artima.serviceuitest.ServiceUITestkit">
*
*
*
* or
*
*
*
* <scalatest>
* <suite classname="com.artima.serviceuitest.ServiceUITestkit"/>
*
*
*
* To specify suites using members-only or wildcard package names, use
* either the membersonly
or wildcard
attributes, or nested
* <membersonly>
or <wildcard>
elements:
*
*
*
* <scalatest membersonly="com.artima.serviceuitest">
*
*
*
* or
*
*
*
* <scalatest wildcard="com.artima.joker">
*
*
*
* or
*
*
*
* <scalatest>
* <membersonly package="com.artima.serviceuitest"/>
* <wildcard package="com.artima.joker"/>
*
*
*
* Use attribute suffixes="[pipe-delimited list of suffixes]"
* to specify that only classes whose names end in one of the specified suffixes
* should be included in discovery searches for Suites to test. This can
* be used to improve discovery time or to limit the scope of a test. E.g.:
*
*
*
* <scalatest suffixes="Spec|Suite">
*
*
*
* Use attribute parallel="true"
to specify parallel execution of suites.
* (If the parallel
attribute is left out or set to false, suites will be executed sequentially by one thread.)
* When parallel
is true, you can include an optional numthreads
attribute to specify the number
* of threads to be created in thread pool (e.g., numthreads="10"
).
*
*
*
* Use attribute haltonfailure="true"
to cause ant to fail the
* build if there's a test failure.
*
*
*
* Use attribute fork="true"
to cause ant to run the tests in
* a separate process.
*
*
*
* When fork
is true
, attribute maxmemory
may be used to specify
* the maximum memory size that will be passed to the forked jvm. For example, the following setting
* will cause "-Xmx1280M"
to be passed to the java command used to
* run the tests.
*
*
*
* <scalatest maxmemory="1280M">
*
*
*
* When fork
is true, nested <jvmarg>
elements may be used
* to pass additional arguments to the forked jvm.
* For example, if you are running into 'PermGen space' memory errors,
* you could add the following jvmarg
to bump up the JVM's MaxPermSize
value:
*
*
*
* <jvmarg value="-XX:MaxPermSize=128m"/>
*
*
* @author George Berger
*/
class ScalaTestAntTask extends Task {
private var includes: String = null
private var excludes: String = null
private var maxMemory: String = null
private var suffixes: String = null
private var parallel = false
private var haltonfailure = false
private var fork = false
private var spanScaleFactor = 1.0
private var numthreads = 0
private val runpath = new ListBuffer[String]
private val jvmArgs = new ListBuffer[String]
private val suites = new ListBuffer[String]
private val membersonlys = new ListBuffer[String]
private val wildcards = new ListBuffer[String]
private val testNGSuites = new ListBuffer[String]
private val chosenStyles = new ListBuffer[String]
private val reporters = new ListBuffer[ReporterElement]
private val properties = new ListBuffer[NameValuePair]
/**
* Executes the task.
*/
override def execute {
val args = new ListBuffer[String]
addSuiteArgs(args)
addReporterArgs(args)
addPropertyArgs(args)
addIncludesArgs(args)
addExcludesArgs(args)
addRunpathArgs(args)
addTestNGSuiteArgs(args)
addParallelArg(args)
addSuffixesArg(args)
addChosenStyles(args)
addSpanScaleFactorArg(args)
val argsArray = args.toArray
val success = if (fork) javaTaskRunner(args.toList)
else Runner.run(argsArray)
if (!success && haltonfailure)
throw new BuildException("ScalaTest run failed.")
}
private def javaTaskRunner(args: List[String]): Boolean = {
val java = new Java
java.bindToOwner(this)
java.init()
java.setFork(true)
java.setClassname("org.scalatest.tools.Runner")
val classLoader = getClass.getClassLoader.asInstanceOf[AntClassLoader]
java.setClasspath(new Path(getProject, classLoader.getClasspath))
if (maxMemory != null) java.createJvmarg.setValue("-Xmx" + maxMemory)
for (jvmArg <- jvmArgs)
java.createJvmarg.setValue(jvmArg)
for (arg <- args)
java.createArg.setValue(arg)
val result = java.executeJava
return (result == 0)
}
//
// Adds '-R runpath' arg pair to args list if a runpath
// element or attribute was specified for task.
//
private def addRunpathArgs(args: ListBuffer[String]) {
if (runpath.size > 0) {
args += "-R"
args += getSpacedOutPathStr(runpath.toList)
}
}
private def addTestNGSuiteArgs(args: ListBuffer[String]) {
if (testNGSuites.size > 0) {
args += "-b"
args += getSpacedOutPathStr(testNGSuites.toList)
}
}
private def addChosenStyles(args: ListBuffer[String]) {
chosenStyles.foreach { style =>
args += "-y"
args += style
}
}
//
// Adds '-P' arg to args list if 'parallel' attribute was
// specified true for task.
//
private def addParallelArg(args: ListBuffer[String]) {
if (parallel) {
args += "-P" + (if (numthreads > 0) ("" + numthreads) else "")
}
}
//
// Add -F arg to args list if spanScaleFactor attribute was
// specified for task
//
private def addSpanScaleFactorArg(args: ListBuffer[String]) {
args += "-F"
args += spanScaleFactor.toString
}
//
// Adds '-q' arg to args list if 'suffixes' attribute was
// specified for task.
//
private def addSuffixesArg(args: ListBuffer[String]) {
if (suffixes != null) {
args += "-q"
args += suffixes
}
}
//
// Adds '-n includes-list' arg pair to args list if a
// element was supplied for task.
//
private def addIncludesArgs(args: ListBuffer[String]) {
if (includes != null) {
args += "-n"
args += singleSpace(includes)
}
}
//
// Adds '-l excludes-list' arg pair to args list if an
// element was supplied for task.
//
private def addExcludesArgs(args: ListBuffer[String]) {
if (excludes != null) {
args += "-l"
args += singleSpace(excludes)
}
}
//
// Adds '-Dname=value' argument to args list for each nested
// element supplied for task.
//
private def addPropertyArgs(args: ListBuffer[String]) {
for (pair <- properties)
args += "-D" + pair.getName + "=" + pair.getValue
}
//
// Adds '-s classname' argument to args list for each suite
// specified for task. Adds '-m packagename' for each
// membersonly element specified, and '-w packagename' for
// each wildcard element specified.
//
private def addSuiteArgs(args: ListBuffer[String]) {
for (suite <- suites) {
if (suite == null)
throw new BuildException(
"missing classname attribute for element")
args += "-s"
args += suite
}
for (packageName <- membersonlys) {
if (packageName == null)
throw new BuildException(
"missing package attribute for element")
args += "-m"
args += packageName
}
for (packageName <- wildcards) {
if (packageName == null)
throw new BuildException(
"missing package attribute for element")
args += "-w"
args += packageName
}
}
//
// Adds appropriate reporter options to args list for each
// nested reporter element specified for task. Defaults to
// stdout if no reporter specified.
//
private def addReporterArgs(args: ListBuffer[String]) {
if (reporters.size == 0)
args += "-o"
for (reporter <- reporters) {
reporter.getType match {
case "stdout" => addReporterOption(args, reporter, "-o")
case "stderr" => addReporterOption(args, reporter, "-e")
case "graphic" => addReporterOption(args, reporter, "-g")
case "file" => addFileReporter(args, reporter)
case "xml" => addXmlReporter(args, reporter)
case "junitxml" => addXmlReporter(args, reporter)
case "html" => addHtmlReporter(args, reporter)
case "reporterclass" => addReporterClass(args, reporter)
case t =>
throw new BuildException("unexpected reporter type [" + t + "]")
}
}
}
//
// Adds specified option to args for reporter. Appends reporter
// config string to option if specified, e.g. "-eFAB".
//
private def addReporterOption(args: ListBuffer[String],
reporter: ReporterElement,
option: String)
{
val config = reporter.getConfig
if (config == null) args += option
else args += option + config
}
//
// Adds '-f' file reporter option to args. Appends reporter
// config string to option if specified. Adds reporter's
// filename as additional argument, e.g. "-fFAB", "filename".
//
private def addFileReporter(args: ListBuffer[String],
reporter: ReporterElement)
{
addReporterOption(args, reporter, "-f")
if (reporter.getFilename == null)
throw new BuildException(
"reporter type 'file' requires 'filename' attribute")
args += reporter.getFilename
}
//
// Adds '-u' xml reporter option to args. Adds reporter's
// directory as additional argument, e.g. "-u", "directory".
//
private def addXmlReporter(args: ListBuffer[String],
reporter: ReporterElement)
{
addReporterOption(args, reporter, "-u")
if (reporter.getDirectory == null)
throw new BuildException(
"reporter type 'xml' requires 'directory' attribute")
args += reporter.getDirectory
if (reporter.getType == "xml")
Console.err.println("WARNING: reporter type 'xml' is deprecated " +
"- please use 'junitxml' instead")
}
//
// Adds '-h' html reporter option to args. Appends reporter
// config string to option if specified. Adds reporter's
// filename as additional argument, e.g. "-hFAB", "filename".
//
private def addHtmlReporter(args: ListBuffer[String],
reporter: ReporterElement)
{
addReporterOption(args, reporter, "-h")
if (reporter.getFilename == null)
throw new BuildException(
"reporter type 'html' requires 'filename' attribute")
args += reporter.getFilename
}
//
// Adds '-C' reporter class option to args. Appends
// reporter config string to option if specified. Adds
// reporter's classname as additional argument, e.g. "-RFAB",
// "my.ReporterClass".
//
private def addReporterClass(args: ListBuffer[String],
reporter: ReporterElement)
{
addReporterOption(args, reporter, "-C")
if (reporter.getClassName == null)
throw new BuildException(
"reporter type 'reporterclass' requires 'classname' attribute")
args += reporter.getClassName
}
/**
* Sets value of the runpath
attribute.
*/
def setRunpath(runpath: Path) {
for (element <- runpath.list) {
this.runpath += element
}
}
/**
* Sets value of the haltonfailure
attribute.
*/
def setHaltonfailure(haltonfailure: Boolean) {
this.haltonfailure = haltonfailure
}
/**
* Sets value of the fork
attribute.
*/
def setFork(fork: Boolean) {
this.fork = fork
}
/**
* Sets value of the suffixes
attribute.
*/
def setSuffixes(suffixes: String) {
this.suffixes = suffixes
}
/**
* Sets value of the maxmemory
attribute.
*/
def setMaxmemory(max: String) {
this.maxMemory = max
}
/**
* Sets value of the testngsuites
attribute.
*/
def setTestNGSuites(testNGSuitePath: Path) {
for (element <- testNGSuitePath.list)
this.testNGSuites += element
}
/**
* Sets value of the concurrent
attribute.
* Note: The concurrent
attribute has been deprecated and will be removed in a future version of ScalaTest.
* Please use the parallel
attribute instead.
*/
@deprecated("Please use parallel instead")
def setConcurrent(concurrent: Boolean) {
Console.err.println("WARNING: 'concurrent' attribute is deprecated " +
"- please use 'parallel' instead")
this.parallel = concurrent
}
/**
* Sets value of the numthreads
attribute.
*/
def setNumthreads(numthreads: Int) {
this.numthreads = numthreads
}
/**
* Sets value of the parallel
attribute.
*/
def setParallel(parallel: Boolean) {
this.parallel = parallel
}
/**
* Sets value of the spanScaleFactor
attribute.
*/
def setSpanScaleFactor(spanScaleFactor: Double) {
this.spanScaleFactor = spanScaleFactor
}
/**
* Sets value from nested element runpath
.
*/
def addConfiguredRunpath(runpath: Path) {
for (element <- runpath.list)
this.runpath += element
}
/**
* Sets value from nested element testngsuites
.
*/
def addConfiguredTestNGSuites(testNGSuitePath: Path) {
for (element <- testNGSuitePath.list)
this.testNGSuites += element
}
/**
* Sets value from nested element runpathurl
.
*/
def addConfiguredRunpathUrl(runpathurl: RunpathUrl) {
runpath += runpathurl.getUrl
}
/**
* Sets value from nested element jvmarg
.
*/
def addConfiguredJvmArg(arg: JvmArg) {
jvmArgs += arg.getValue
}
/**
* Sets values from nested element property
.
* The property
attribute has been deprecated and will be removed in a future version of ScalaTest.
* Please use the config
attribute instead.
*/
@deprecated("Please use config instead")
def addConfiguredProperty(property: NameValuePair) {
Console.err.println("WARNING: is deprecated - " +
"please use instead [name: " +
property.getName + "]")
properties += property
}
/**
* Sets values from nested element config
.
*/
def addConfiguredConfig(config: NameValuePair) {
properties += config
}
/**
* Sets value of suite
attribute.
*/
def setSuite(suite: String) {
suites += suite
}
/**
* Sets value of membersonly
attribute.
*/
def setMembersonly(packageName: String) {
membersonlys += packageName
}
/**
* Sets value of wildcard
attribute.
*/
def setWildcard(packageName: String) {
wildcards += packageName
}
/**
* Sets value of style
attribute.
*/
def setStyle(style: String) {
chosenStyles += style
}
/**
* Sets value from nested element suite
.
*/
def addConfiguredSuite(suite: SuiteElement) {
suites += suite.getClassName
}
/**
* Sets value from nested element membersonly
.
*/
def addConfiguredMembersOnly(membersonly: PackageElement) {
membersonlys += membersonly.getPackage
}
/**
* Sets value from nested element wildcard
.
*/
def addConfiguredWildcard(wildcard: PackageElement) {
wildcards += wildcard.getPackage
}
/**
* Sets value from nested element reporter
.
*/
def addConfiguredReporter(reporter: ReporterElement) {
reporters += reporter
}
/**
* Sets value from nested element tagsToInclude
.
*/
def addConfiguredTagsToInclude(tagsToInclude: TextElement) {
this.includes = tagsToInclude.getText
}
def addConfiguredStyle(style: StyleElement) {
this.chosenStyles += style.getName
}
/**
* Sets value from nested element includes
.
* The includes
attribute has been deprecated and will be removed in a future version of ScalaTest.
* Please use the tagsToInclude
attribute instead.
*/
@deprecated("Please use tagsToInclude instead")
def addConfiguredIncludes(includes: TextElement) {
Console.err.println("WARNING: 'includes' is deprecated - " +
"use 'tagsToInclude' instead [includes: " +
includes.getText + "]")
this.includes = includes.getText
}
/**
* Sets value from nested element excludes
.
*/
def addConfiguredTagsToExclude(tagsToExclude: TextElement) {
this.excludes = tagsToExclude.getText
}
/**
* Sets value from nested element excludes
.
* The excludes
attribute has been deprecated and will be removed in a future version of ScalaTest.
* Please use the tagsToExclude
attribute instead.
*/
@deprecated("Please use tagsToExclude instead")
def addConfiguredExcludes(excludes: TextElement) {
Console.err.println("WARNING: 'excludes' is deprecated - " +
"use 'tagsToExclude' instead [excludes: " +
excludes.getText + "]")
this.excludes = excludes.getText
}
//
// Translates a list of strings making up a path into a
// single space-delimited string. Uses backslashes to escape
// spaces within individual path elements, since that's what
// Runner's -p option expects.
//
private def getSpacedOutPathStr(path: List[String]): String = {
path.map(_.replaceAll(" ", """\\ """)).mkString("", " ", "")
}
//
// Translates a whitespace-delimited string into a
// whitespace-delimited string, but not the same whitespace. Trims
// off leading and trailing whitespace and converts inter-element
// whitespace to a single space.
//
private def singleSpace(str: String): String = {
str.trim.replaceAll("\\s+", " ")
}
}
//
// Class to hold data from