/* 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()
}