summaryrefslogtreecommitdiff
path: root/examples/scala-js/partest/src/main/scala/scala/tools
diff options
context:
space:
mode:
Diffstat (limited to 'examples/scala-js/partest/src/main/scala/scala/tools')
-rw-r--r--examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala220
-rw-r--r--examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/PartestInterface.scala119
-rw-r--r--examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/ScalaJSPartest.scala203
-rw-r--r--examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/ScalaJSPartestOptions.scala109
4 files changed, 651 insertions, 0 deletions
diff --git a/examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala b/examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala
new file mode 100644
index 0000000..6857142
--- /dev/null
+++ b/examples/scala-js/partest/src/main/scala/scala/tools/nsc/MainGenericRunner.scala
@@ -0,0 +1,220 @@
+package scala.tools.nsc
+
+/* Super hacky overriding of the MainGenericRunner used by partest */
+
+import scala.scalajs.ir
+
+import scala.scalajs.tools.sem.Semantics
+import scala.scalajs.tools.classpath._
+import scala.scalajs.tools.classpath.builder._
+import scala.scalajs.tools.logging._
+import scala.scalajs.tools.io._
+import scala.scalajs.tools.optimizer.ScalaJSOptimizer
+import scala.scalajs.tools.optimizer.ScalaJSClosureOptimizer
+import scala.scalajs.tools.optimizer.ParIncOptimizer
+import scala.scalajs.tools.env.JSConsole
+
+import scala.scalajs.sbtplugin.env.rhino.RhinoJSEnv
+import scala.scalajs.sbtplugin.env.nodejs.NodeJSEnv
+import scala.scalajs.sbtplugin.JSUtils._
+
+import scala.tools.partest.scalajs.ScalaJSPartestOptions._
+
+import java.io.File
+import scala.io.Source
+
+import Properties.{ versionString, copyrightString }
+import GenericRunnerCommand._
+
+class ScalaConsoleJSConsole extends JSConsole {
+ def log(msg: Any) = scala.Console.out.println(msg.toString)
+}
+
+class MainGenericRunner {
+ def errorFn(ex: Throwable): Boolean = {
+ ex.printStackTrace()
+ false
+ }
+ def errorFn(str: String): Boolean = {
+ scala.Console.err println str
+ false
+ }
+
+ val optMode = OptMode.fromId(sys.props("scalajs.partest.optMode"))
+
+ def noWarnMissing = {
+ import ScalaJSOptimizer._
+
+ for {
+ fname <- sys.props.get("scalajs.partest.noWarnFile").toList
+ line <- Source.fromFile(fname).getLines
+ if !line.startsWith("#")
+ } yield line.split('.') match {
+ case Array(className) => NoWarnClass(className)
+ case Array(className, methodName) => NoWarnMethod(className, methodName)
+ }
+ }
+
+ def readSemantics() = {
+ val opt = sys.props.get("scalajs.partest.compliantSems")
+ opt.fold(Semantics.Defaults) { str =>
+ val sems = str.split(',')
+ Semantics.compliantTo(sems.toList)
+ }
+ }
+
+ def process(args: Array[String]): Boolean = {
+ val command = new GenericRunnerCommand(args.toList, (x: String) => errorFn(x))
+ import command.{ settings, howToRun, thingToRun }
+
+ if (!command.ok) return errorFn("\n" + command.shortUsageMsg)
+ else if (settings.version) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString))
+ else if (command.shouldStopWithInfo) return errorFn("shouldStopWithInfo")
+
+ if (howToRun != AsObject)
+ return errorFn("Scala.js runner can only run an object")
+
+ // Load basic Scala.js classpath (used for running or further packaging)
+ val usefulClasspathEntries = for {
+ url <- settings.classpathURLs
+ f = urlToFile(url)
+ if (f.isDirectory || f.getName.startsWith("scalajs-library"))
+ } yield f
+ val classpath =
+ PartialClasspathBuilder.build(usefulClasspathEntries).resolve()
+
+ val logger = new ScalaConsoleLogger(Level.Warn)
+ val jsConsole = new ScalaConsoleJSConsole
+
+ val mainObjName = ir.Definitions.encodeClassName(thingToRun)
+ val baseRunner = runnerJSFile(mainObjName, command.arguments)
+ val semantics = readSemantics()
+
+ def fastOpted = fastOptimize(classpath, mainObjName, logger, semantics)
+ def fullOpted = fullOptimize(classpath, mainObjName, logger,
+ baseRunner, semantics.optimized)
+
+ val runner = {
+ if (optMode == FullOpt)
+ fullOptRunner()
+ else
+ baseRunner
+ }
+
+ val env =
+ if (optMode == NoOpt) new RhinoJSEnv(semantics)
+ else new NodeJSEnv
+
+ val runClasspath = optMode match {
+ case NoOpt => classpath
+ case FastOpt => fastOpted
+ case FullOpt => fullOpted
+ }
+
+ env.jsRunner(runClasspath, runner, logger, jsConsole).run()
+
+ true
+ }
+
+ private def runnerJSFile(mainObj: String, args: List[String]) = {
+ val jsObj = "ScalaJS.m." + mainObj
+ val jsArgs = argArray(args)
+ new MemVirtualJSFile("Generated launcher file").
+ withContent(s"$jsObj().main__AT__V($jsArgs);")
+ }
+
+ /** constructs a scala.Array[String] with the given elements */
+ private def argArray(args: List[String]) = {
+ s"""ScalaJS.makeNativeArrayWrapper(
+ ScalaJS.d.T.getArrayOf(),
+ ${listToJS(args)})"""
+ }
+
+ private def fastOptimize(
+ classpath: IRClasspath,
+ mainObjName: String,
+ logger: Logger,
+ semantics: Semantics) = {
+ import ScalaJSOptimizer._
+
+ val optimizer = newScalaJSOptimizer(semantics)
+ val output = WritableMemVirtualJSFile("partest fastOpt file")
+
+ optimizer.optimizeCP(
+ Inputs(classpath,
+ manuallyReachable = fastOptReachable(mainObjName),
+ noWarnMissing = noWarnMissing
+ ),
+ OutputConfig(
+ output = output,
+ wantSourceMap = false,
+ checkIR = true
+ ),
+ logger)
+ }
+
+ private def fastOptReachable(mainObjName: String) = {
+ import ScalaJSOptimizer._
+ List(
+ ReachObject(mainObjName),
+ ReachMethod(mainObjName + '$', "main__AT__V", static = false)
+ )
+ }
+
+ private def fullOptimize(
+ classpath: IRClasspath,
+ mainObjName: String,
+ logger: Logger,
+ runner: VirtualJSFile,
+ semantics: Semantics) = {
+ import ScalaJSClosureOptimizer._
+
+ val fastOptimizer = newScalaJSOptimizer(semantics)
+ val fullOptimizer = new ScalaJSClosureOptimizer(semantics)
+ val output = WritableMemVirtualJSFile("partest fullOpt file")
+ val exportFile = fullOptExportFile(runner)
+
+ fullOptimizer.optimizeCP(fastOptimizer, Inputs(
+ input = ScalaJSOptimizer.Inputs(
+ classpath,
+ manuallyReachable = fastOptReachable(mainObjName),
+ noWarnMissing = noWarnMissing),
+ additionalExports = exportFile :: Nil),
+ OutputConfig(
+ output,
+ checkIR = true,
+ wantSourceMap = false),
+ logger)
+
+ }
+
+ private def newScalaJSOptimizer(semantics: Semantics) =
+ new ScalaJSOptimizer(semantics, new ParIncOptimizer(_))
+
+ /** generates an exporter statement for the google closure compiler that runs
+ * what the normal test would
+ */
+ private def fullOptExportFile(runnerFile: VirtualJSFile) = {
+ new MemVirtualJSFile("partest fullOpt exports").withContent(
+ s"""this["runFullOptPartest"] = function() { ${runnerFile.content} };"""
+ )
+ }
+
+ private def fullOptRunner() = new MemVirtualJSFile("partest fullOpt runner").
+ withContent("runFullOptPartest();")
+
+ private def urlToFile(url: java.net.URL) = {
+ try {
+ new File(url.toURI())
+ } catch {
+ case e: java.net.URISyntaxException => new File(url.getPath())
+ }
+ }
+}
+
+object MainGenericRunner extends MainGenericRunner {
+ def main(args: Array[String]) {
+ if (!process(args))
+ sys.exit(1)
+ }
+}
diff --git a/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/PartestInterface.scala b/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/PartestInterface.scala
new file mode 100644
index 0000000..0dc2189
--- /dev/null
+++ b/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/PartestInterface.scala
@@ -0,0 +1,119 @@
+/* NOTE
+ * Most of this file is copy-pasted from
+ * https://github.com/scala/scala-partest-interface
+ * It is unfortunately not configurable enough, hence the duplication
+ */
+
+package scala.tools.partest
+package scalajs
+
+import scala.language.reflectiveCalls
+
+import sbt.testing.Fingerprint
+import sbt.testing.TaskDef
+import sbt.testing.EventHandler
+import sbt.testing.Logger
+import sbt.testing.Task
+import sbt.testing.AnnotatedFingerprint
+import java.net.URLClassLoader
+import java.io.File
+
+object Framework {
+ // as partest is not driven by test classes discovered by sbt, need to add this marker fingerprint to definedTests
+ val fingerprint = new AnnotatedFingerprint { def isModule = true; def annotationName = "partest" }
+
+ // TODO how can we export `fingerprint` so that a user can just add this to their build.sbt
+ // definedTests in Test += new sbt.TestDefinition("partest", fingerprint, true, Array())
+}
+class Framework extends sbt.testing.Framework {
+ def fingerprints: Array[Fingerprint] = Array(Framework.fingerprint)
+ def name: String = "partest"
+
+ def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): sbt.testing.Runner =
+ new Runner(args, remoteArgs, testClassLoader)
+}
+
+/** Represents one run of a suite of tests.
+ */
+case class Runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader) extends sbt.testing.Runner {
+ /** Returns an array of tasks that when executed will run tests and suites determined by the
+ * passed <code>TaskDef</code>s.
+ *
+ * <p>
+ * Each returned task, when executed, will run tests and suites determined by the
+ * test class name, fingerprints, "explicitly specified" field, and selectors of one of the passed <code>TaskDef</code>s.
+ * </p>
+ *
+ * <p>
+ * This <code>tasks</code> method may be called with <code>TaskDef</code>s containing the same value for <code>testClassName</code> but
+ * different fingerprints. For example, if both a class and its companion object were test classes, the <code>tasks</code> method could be
+ * passed an array containing <code>TaskDef</code>s with the same name but with a different value for <code>fingerprint.isModule</code>.
+ * </p>
+ *
+ * <p>
+ * A test framework may "reject" a requested task by returning no <code>Task</code> for that <code>TaskDef</code>.
+ * </p>
+ *
+ * @param taskDefs the <code>TaskDef</code>s for requested tasks
+ * @return an array of <code>Task</code>s
+ * @throws IllegalStateException if invoked after <code>done</code> has been invoked.
+ */
+ def tasks(taskDefs: Array[TaskDef]): Array[sbt.testing.Task] =
+ taskDefs map (PartestTask(_, args): sbt.testing.Task)
+
+ /** Indicates the client is done with this <code>Runner</code> instance.
+ *
+ * @return a possibly multi-line summary string, or the empty string if no summary is provided -- TODO
+ */
+ def done(): String = ""
+}
+
+/** Run partest in this VM. Assumes we're running in a forked VM!
+ *
+ * TODO: make configurable
+ */
+case class PartestTask(taskDef: TaskDef, args: Array[String]) extends Task {
+
+ // Get scala version through test name
+ val scalaVersion = taskDef.fullyQualifiedName.stripPrefix("partest-")
+
+ /** Executes this task, possibly returning to the client new tasks to execute. */
+ def execute(eventHandler: EventHandler, loggers: Array[Logger]): Array[Task] = {
+ val forkedCp = scala.util.Properties.javaClassPath
+ val classLoader = new URLClassLoader(forkedCp.split(java.io.File.pathSeparator).map(new File(_).toURI.toURL))
+
+ if (Runtime.getRuntime().maxMemory() / (1024*1024) < 800)
+ loggers foreach (_.warn(s"""Low heap size detected (~ ${Runtime.getRuntime().maxMemory() / (1024*1024)}M). Please add the following to your build.sbt: javaOptions in Test += "-Xmx1G""""))
+
+ val maybeOptions =
+ ScalaJSPartestOptions(args, str => loggers.foreach(_.error(str)))
+
+ maybeOptions foreach { options =>
+ val runner = SBTRunner(
+ Framework.fingerprint, eventHandler, loggers,
+ new File(s"../partest/fetchedSources/${scalaVersion}"),
+ classLoader, null, null, Array.empty[String], options, scalaVersion)
+
+ try runner execute Array("run", "pos", "neg")
+ catch {
+ case ex: ClassNotFoundException =>
+ loggers foreach { l => l.error("Please make sure partest is running in a forked VM by including the following line in build.sbt:\nfork in Test := true") }
+ throw ex
+ }
+ }
+
+ Array()
+ }
+
+ type SBTRunner = { def execute(kinds: Array[String]): String }
+
+ // use reflection to instantiate scala.tools.partest.scalajs.ScalaJSSBTRunner,
+ // casting to the structural type SBTRunner above so that method calls on the result will be invoked reflectively as well
+ private def SBTRunner(partestFingerprint: Fingerprint, eventHandler: EventHandler, loggers: Array[Logger], testRoot: File, testClassLoader: URLClassLoader, javaCmd: File, javacCmd: File, scalacArgs: Array[String], options: ScalaJSPartestOptions, scalaVersion: String): SBTRunner = {
+ val runnerClass = Class.forName("scala.tools.partest.scalajs.ScalaJSSBTRunner")
+ runnerClass.getConstructors()(0).newInstance(partestFingerprint, eventHandler, loggers, testRoot, testClassLoader, javaCmd, javacCmd, scalacArgs, options, scalaVersion).asInstanceOf[SBTRunner]
+ }
+
+ /** A possibly zero-length array of string tags associated with this task. */
+ def tags: Array[String] = Array()
+}
diff --git a/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/ScalaJSPartest.scala b/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/ScalaJSPartest.scala
new file mode 100644
index 0000000..edd0ea9
--- /dev/null
+++ b/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/ScalaJSPartest.scala
@@ -0,0 +1,203 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Sébastien Doeraene
+ */
+
+package scala.tools.partest
+package scalajs
+
+import nest._
+import Path._
+
+import scala.tools.nsc.{ Global, Settings }
+import scala.tools.nsc.reporters.{ Reporter }
+import scala.tools.nsc.plugins.Plugin
+
+import scala.scalajs.compiler.ScalaJSPlugin
+
+import scala.io.Source
+
+import sbt.testing.{ EventHandler, Logger, Fingerprint }
+import java.io.File
+import java.net.URLClassLoader
+
+trait ScalaJSDirectCompiler extends DirectCompiler {
+ override def newGlobal(settings: Settings, reporter: Reporter): PartestGlobal = {
+ new PartestGlobal(settings, reporter) {
+ override protected def loadRoughPluginsList(): List[Plugin] = {
+ (super.loadRoughPluginsList() :+
+ Plugin.instantiate(classOf[ScalaJSPlugin], this))
+ }
+ }
+ }
+}
+
+class ScalaJSRunner(testFile: File, suiteRunner: SuiteRunner,
+ scalaJSOverridePath: String, options: ScalaJSPartestOptions,
+ noWarnFile: File) extends nest.Runner(testFile, suiteRunner) {
+
+ private val compliantSems: List[String] = {
+ scalaJSConfigFile("sem").fold(List.empty[String]) { file =>
+ Source.fromFile(file).getLines.toList
+ }
+ }
+
+ override val checkFile: File = {
+ scalaJSConfigFile("check") getOrElse {
+ // this is super.checkFile, but apparently we can't do that
+ new FileOps(testFile).changeExtension("check")
+ }
+ }
+
+ private def scalaJSConfigFile(ext: String): Option[File] = {
+ val overrideFile = s"$scalaJSOverridePath/$kind/$fileBase.$ext"
+ val url = getClass.getResource(overrideFile)
+ Option(url).map(url => new File(url.toURI))
+ }
+
+ override def newCompiler = new DirectCompiler(this) with ScalaJSDirectCompiler
+ override def extraJavaOptions = {
+ super.extraJavaOptions ++ Seq(
+ s"-Dscalajs.partest.noWarnFile=${noWarnFile.getAbsolutePath}",
+ s"-Dscalajs.partest.optMode=${options.optMode.id}",
+ s"-Dscalajs.partest.compliantSems=${compliantSems.mkString(",")}"
+ )
+ }
+}
+
+trait ScalaJSSuiteRunner extends SuiteRunner {
+
+ // Stuff to mix in
+
+ val options: ScalaJSPartestOptions
+
+ /** Full scala version name. Used to discover blacklist (etc.) files */
+ val scalaVersion: String
+
+ // Stuff we provide
+
+ override def banner: String = {
+ import scala.scalajs.ir.ScalaJSVersions.{ current => currentVersion }
+
+ super.banner.trim + s"""
+ |Scala.js version is: $currentVersion
+ |Scala.js options are:
+ |optimizer: ${options.optMode.shortStr}
+ |testFilter: ${options.testFilter.descr}
+ """.stripMargin
+ }
+
+ override def runTest(testFile: File): TestState = {
+ // Mostly copy-pasted from SuiteRunner.runTest(), unfortunately :-(
+ val runner = new ScalaJSRunner(testFile, this, listDir, options, noWarnFile)
+
+ // when option "--failed" is provided execute test only if log
+ // is present (which means it failed before)
+ val state =
+ if (failed && !runner.logFile.canRead)
+ runner.genPass()
+ else {
+ val (state, elapsed) =
+ try timed(runner.run())
+ catch {
+ case t: Throwable => throw new RuntimeException(s"Error running $testFile", t)
+ }
+ NestUI.reportTest(state)
+ runner.cleanup()
+ state
+ }
+ onFinishTest(testFile, state)
+ }
+
+ override def runTestsForFiles(kindFiles: Array[File],
+ kind: String): Array[TestState] = {
+ super.runTestsForFiles(kindFiles.filter(shouldUseTest), kind)
+ }
+
+ private lazy val listDir =
+ s"/scala/tools/partest/scalajs/$scalaVersion"
+
+ private lazy val buglistedTestFileNames =
+ readTestList(s"$listDir/BuglistedTests.txt")
+
+ private lazy val blacklistedTestFileNames =
+ readTestList(s"$listDir/BlacklistedTests.txt")
+
+ private lazy val whitelistedTestFileNames =
+ readTestList(s"$listDir/WhitelistedTests.txt")
+
+ private lazy val noWarnFile: File = {
+ val url = getClass.getResource(s"$listDir/NoDCEWarn.txt")
+ assert(url != null, "Need NoDCEWarn.txt file")
+ new File(url.toURI).getAbsolutePath()
+ }
+
+ private def readTestList(resourceName: String): Set[String] = {
+ val source = scala.io.Source.fromURL(getClass.getResource(resourceName))
+
+ val fileNames = for {
+ line <- source.getLines
+ trimmed = line.trim
+ if trimmed != "" && !trimmed.startsWith("#")
+ } yield extendShortTestName(trimmed)
+
+ fileNames.toSet
+ }
+
+ private def extendShortTestName(testName: String) = {
+ val srcDir = PathSettings.srcDir
+ (srcDir / testName).toCanonical.getAbsolutePath
+ }
+
+ private lazy val testFilter: String => Boolean = {
+ import ScalaJSPartestOptions._
+ options.testFilter match {
+ case UnknownTests => { absPath =>
+ !blacklistedTestFileNames.contains(absPath) &&
+ !whitelistedTestFileNames.contains(absPath) &&
+ !buglistedTestFileNames.contains(absPath)
+ }
+ case BlacklistedTests => blacklistedTestFileNames
+ case BuglistedTests => buglistedTestFileNames
+ case WhitelistedTests => whitelistedTestFileNames
+ case SomeTests(names) => names.map(extendShortTestName _).toSet
+ }
+ }
+
+ private def shouldUseTest(testFile: File): Boolean = {
+ val absPath = testFile.toCanonical.getAbsolutePath
+ testFilter(absPath)
+ }
+}
+
+/* Pre-mixin ScalaJSSuiteRunner in SBTRunner, because this is looked up
+ * via reflection from the sbt partest interface of Scala.js
+ */
+class ScalaJSSBTRunner(
+ partestFingerprint: Fingerprint,
+ eventHandler: EventHandler,
+ loggers: Array[Logger],
+ testRoot: File,
+ testClassLoader: URLClassLoader,
+ javaCmd: File,
+ javacCmd: File,
+ scalacArgs: Array[String],
+ val options: ScalaJSPartestOptions,
+ val scalaVersion: String
+) extends SBTRunner(
+ partestFingerprint, eventHandler, loggers, "test/files", testClassLoader,
+ javaCmd, javacCmd, scalacArgs
+) with ScalaJSSuiteRunner {
+
+ // The test root for partest is read out through the system properties,
+ // not passed as an argument
+ sys.props("partest.root") = testRoot.getAbsolutePath()
+
+ // Partests take at least 5h. We double, just to be sure. (default is 4 hours)
+ sys.props("partest.timeout") = "10 hours"
+
+ // Set showDiff on global UI module
+ if (options.showDiff)
+ NestUI.setDiffOnFail()
+
+}
diff --git a/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/ScalaJSPartestOptions.scala b/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/ScalaJSPartestOptions.scala
new file mode 100644
index 0000000..1f1680a
--- /dev/null
+++ b/examples/scala-js/partest/src/main/scala/scala/tools/partest/scalajs/ScalaJSPartestOptions.scala
@@ -0,0 +1,109 @@
+package scala.tools.partest.scalajs
+
+class ScalaJSPartestOptions private (
+ val testFilter: ScalaJSPartestOptions.TestFilter,
+ val optMode: ScalaJSPartestOptions.OptMode,
+ val showDiff: Boolean
+)
+
+object ScalaJSPartestOptions {
+
+ sealed abstract class TestFilter {
+ def descr: String
+ }
+ case object UnknownTests extends TestFilter {
+ override def descr: String = "Unknown"
+ }
+ case object BlacklistedTests extends TestFilter {
+ override def descr: String = "Blacklisted"
+ }
+ case object WhitelistedTests extends TestFilter {
+ override def descr: String = "Whitelisted"
+ }
+ case object BuglistedTests extends TestFilter {
+ override def descr: String = "Buglisted"
+ }
+ case class SomeTests(names: List[String]) extends TestFilter {
+ override def descr: String = "Custom " + this.toString
+ override def toString() =
+ names.map(x => s""""$x"""").mkString("[", ", ", "]")
+ }
+
+ sealed abstract class OptMode {
+ def shortStr: String
+ def id: String
+ }
+ object OptMode {
+ def fromId(id: String): OptMode = id match {
+ case "none" => NoOpt
+ case "fast" => FastOpt
+ case "full" => FullOpt
+ case _ => sys.error(s"Unknown optimization mode: $id")
+ }
+ }
+ case object NoOpt extends OptMode {
+ def shortStr: String = "None"
+ def id: String = "none"
+ }
+ case object FastOpt extends OptMode {
+ def shortStr: String = "Fast"
+ def id: String = "fast"
+ }
+ case object FullOpt extends OptMode {
+ def shortStr: String = "Full"
+ def id: String = "full"
+ }
+
+ def apply(args: Array[String],
+ errorReporter: String => Unit): Option[ScalaJSPartestOptions] = {
+
+ var failed = false
+
+ var filter: Option[TestFilter] = None
+ var optMode: OptMode = NoOpt
+ var showDiff: Boolean = false
+
+ def error(msg: String) = {
+ failed = true
+ errorReporter(msg)
+ }
+
+ def setFilter(newFilter: TestFilter) = (filter, newFilter) match {
+ case (Some(SomeTests(oldNames)), SomeTests(newNames)) =>
+ // Merge test names
+ filter = Some(SomeTests(oldNames ++ newNames))
+ case (Some(fil), newFilter) =>
+ error(s"You cannot specify twice what tests to use (already specified: $fil, new: $newFilter)")
+ case (None, newFilter) =>
+ filter = Some(newFilter)
+ }
+
+ for (arg <- args) arg match {
+ case "--fastOpt" =>
+ optMode = FastOpt
+ case "--noOpt" =>
+ optMode = NoOpt
+ case "--fullOpt" =>
+ optMode = FullOpt
+ case "--blacklisted" =>
+ setFilter(BlacklistedTests)
+ case "--buglisted" =>
+ setFilter(BuglistedTests)
+ case "--whitelisted" =>
+ setFilter(WhitelistedTests)
+ case "--unknown" =>
+ setFilter(UnknownTests)
+ case "--showDiff" =>
+ showDiff = true
+ case _ =>
+ setFilter(SomeTests(arg :: Nil))
+ }
+
+ if (failed) None
+ else Some {
+ new ScalaJSPartestOptions(
+ filter.getOrElse(WhitelistedTests), optMode, showDiff)
+ }
+ }
+
+}