summaryrefslogtreecommitdiff
path: root/src/partest
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-05-06 16:37:13 +0000
committerPaul Phillips <paulp@improving.org>2010-05-06 16:37:13 +0000
commitc55b106f503d5e712e69823cfeb1cab2460221eb (patch)
treea1af091d9a2eeb16ee4747930511db4996c47140 /src/partest
parentcb35c38f14f6a53c38966bde8e64dcfa9af17918 (diff)
downloadscala-c55b106f503d5e712e69823cfeb1cab2460221eb.tar.gz
scala-c55b106f503d5e712e69823cfeb1cab2460221eb.tar.bz2
scala-c55b106f503d5e712e69823cfeb1cab2460221eb.zip
Rolled partest back to r21328.
changes necessary to plug it back in while preserving everything which has happened since then in tests and such, but we should be the lookout for overreversion. Review by phaller (but as a formality, I don't think it requires direct review.)
Diffstat (limited to 'src/partest')
-rw-r--r--src/partest/README76
-rw-r--r--src/partest/scala/tools/partest/Actions.scala231
-rw-r--r--src/partest/scala/tools/partest/Alarms.scala86
-rw-r--r--src/partest/scala/tools/partest/BuildContributors.scala102
-rw-r--r--src/partest/scala/tools/partest/Categories.scala70
-rw-r--r--src/partest/scala/tools/partest/Compilable.scala106
-rw-r--r--src/partest/scala/tools/partest/Config.scala129
-rw-r--r--src/partest/scala/tools/partest/Dispatcher.scala162
-rw-r--r--src/partest/scala/tools/partest/Entities.scala74
-rw-r--r--src/partest/scala/tools/partest/Housekeeping.scala187
-rw-r--r--src/partest/scala/tools/partest/Partest.scala81
-rw-r--r--src/partest/scala/tools/partest/PartestDefaults.scala30
-rw-r--r--src/partest/scala/tools/partest/PartestSpec.scala104
-rw-r--r--src/partest/scala/tools/partest/PartestTask.scala287
-rw-r--r--src/partest/scala/tools/partest/Results.scala121
-rw-r--r--src/partest/scala/tools/partest/Runner.scala36
-rw-r--r--src/partest/scala/tools/partest/Statistics.scala46
-rw-r--r--src/partest/scala/tools/partest/Universe.scala96
-rw-r--r--src/partest/scala/tools/partest/ant/JavaTask.scala57
-rw-r--r--src/partest/scala/tools/partest/antlib.xml3
-rw-r--r--src/partest/scala/tools/partest/category/AllCategories.scala20
-rw-r--r--src/partest/scala/tools/partest/category/Analysis.scala64
-rw-r--r--src/partest/scala/tools/partest/category/Compiler.scala140
-rw-r--r--src/partest/scala/tools/partest/category/Runner.scala108
-rw-r--r--src/partest/scala/tools/partest/io/ANSIWriter.scala58
-rw-r--r--src/partest/scala/tools/partest/io/JUnitReport.scala38
-rw-r--r--src/partest/scala/tools/partest/io/Logging.scala137
-rw-r--r--src/partest/scala/tools/partest/nest/AntRunner.scala30
-rw-r--r--src/partest/scala/tools/partest/nest/CompileManager.scala197
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleFileManager.scala190
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleRunner.scala209
-rw-r--r--src/partest/scala/tools/partest/nest/Diff.java (renamed from src/partest/scala/tools/partest/io/Diff.java)2
-rw-r--r--src/partest/scala/tools/partest/nest/DiffPrint.java (renamed from src/partest/scala/tools/partest/io/DiffPrint.java)2
-rw-r--r--src/partest/scala/tools/partest/nest/DirectRunner.scala78
-rw-r--r--src/partest/scala/tools/partest/nest/FileManager.scala110
-rw-r--r--src/partest/scala/tools/partest/nest/NestRunner.scala16
-rw-r--r--src/partest/scala/tools/partest/nest/NestUI.scala118
-rw-r--r--src/partest/scala/tools/partest/nest/PathSettings.scala41
-rw-r--r--src/partest/scala/tools/partest/nest/ReflectiveRunner.scala88
-rw-r--r--src/partest/scala/tools/partest/nest/RunnerUtils.scala29
-rw-r--r--src/partest/scala/tools/partest/nest/TestFile.scala49
-rw-r--r--src/partest/scala/tools/partest/nest/Worker.scala1071
-rw-r--r--src/partest/scala/tools/partest/package.scala59
-rw-r--r--src/partest/scala/tools/partest/util/package.scala61
-rw-r--r--src/partest/scala/tools/partest/utils/PrintMgr.scala52
-rw-r--r--src/partest/scala/tools/partest/utils/Properties.scala (renamed from src/partest/scala/tools/partest/Properties.scala)4
46 files changed, 2657 insertions, 2398 deletions
diff --git a/src/partest/README b/src/partest/README
index c7673fe2f8..81876fc810 100644
--- a/src/partest/README
+++ b/src/partest/README
@@ -1,50 +1,32 @@
-If you're looking for something to read, I suggest running ../test/partest
-with no arguments, which at this moment prints this:
+How partest choses the compiler / library:
-Usage: partest [<options>] [<test> <test> ...]
- <test>: a path to a test designator, typically a .scala file or a directory.
- Examples: files/pos/test1.scala, files/res/bug785
+ * ''-Dpartest.build=build/four-pack'' -> will search for libraries in
+ ''lib'' directory of given path
+ * ''--pack'' -> will set ''partest.build=build/pack'', and run all tests.
+ add ''--[kind]'' to run a selected set of tests.
+ * auto detection:
+ - partest.build property -> ''bin'' / ''lib'' directories
+ - distribution (''dists/latest'')
+ - supersabbus pack (''build/pack'')
+ - sabbus quick (''build/quick'')
+ - installed dist (test files in ''misc/scala-test/files'')
- Test categories:
- --all run all tests (default, unless no options given)
- --pos Compile files that are expected to build
- --neg Compile files that are expected to fail
- --run Test JVM backend
- --jvm Test JVM backend
- --res Run resident compiler scenarii
- --buildmanager Run Build Manager scenarii
- --scalacheck Run Scalacheck tests
- --script Run script files
- --shootout Run shootout tests
- --scalap Run scalap tests
+How partest choses test files: the test files must be accessible from
+the directory on which partest is run. So the test files must be either
+at:
+ * ./test/files
+ * ./files (cwd is "test")
+ * ./misc/scala-test/files (installed scala distribution)
- Test "smart" categories:
- --grep run all tests with a source file containing <expr>
- --failed run all tests which failed on the last run
-
- Specifying paths and additional flags, ~ means repository root:
- --rootdir path from ~ to partest (default: test)
- --builddir path from ~ to test build (default: build/pack)
- --srcdir path from --rootdir to sources (default: files)
- --javaopts flags to java on all runs (overrides JAVA_OPTS)
- --scalacopts flags to scalac on all tests (overrides SCALAC_OPTS)
- --pack alias for --builddir build/pack
- --quick alias for --builddir build/quick
-
- Options influencing output:
- --trace show the individual steps taken by each test
- --show-diff show diff between log and check file
- --show-log show log on failures
- --dry-run do not run tests, only show their traces.
- --terse be less verbose (almost silent except for failures)
- --verbose be more verbose (additive with --trace)
- --debug maximum debugging output
- --ansi print output in color
-
- Other options:
- --timeout Timeout in seconds
- --cleanup delete all stale files and dirs before run
- --nocleanup do not delete any logfiles or object dirs
- --stats collect and print statistics about the tests
- --validate examine test filesystem for inconsistencies
- --version print version
+Other arguments:
+ * --pos next files test a compilation success
+ * --neg next files test a compilation failure
+ * --run next files test the interpreter and all backends
+ * --jvm next files test the JVM backend
+ * --res next files test the resident compiler
+ * --buildmanager next files test the build manager
+ * --shootout next files are shootout tests
+ * --script next files test the script runner
+ * ''-Dpartest.scalac_opts=...'' -> add compiler options
+ * ''--verbose'' -> print verbose messages
+ * ''-Dpartest.debug=true'' -> print debug messages
diff --git a/src/partest/scala/tools/partest/Actions.scala b/src/partest/scala/tools/partest/Actions.scala
deleted file mode 100644
index cb60152b71..0000000000
--- a/src/partest/scala/tools/partest/Actions.scala
+++ /dev/null
@@ -1,231 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala Parallel Testing **
-** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.tools
-package partest
-
-import util._
-import nsc.io._
-
-trait Actions {
- partest: Universe =>
-
- class TestSequence(val actions: List[TestStep]) extends AbsTestSequence {
- }
-
- implicit def createSequence(xs: List[TestStep]) = new TestSequence(xs)
-
- trait ExecSupport {
- self: TestEntity =>
-
- def execEnv: Map[String, String] = {
- val map = assembleEnvironment()
- val cwd = execCwd.toList map ("CWD" -> _.path)
-
- map ++ cwd
- }
- def execCwd = if (commandFile.isFile) Some(sourcesDir) else None
-
- def runExec(args: List[String]): Boolean = {
- val cmd = fromArgs(args)
-
- if (isVerbose) {
- trace("runExec: " + execEnv.mkString("ENV(", "\n", "\n)"))
- execCwd foreach (x => trace("CWD(" + x + ")"))
- }
-
- trace("runExec: " + cmd)
- isDryRun || execAndLog(cmd)
- }
-
- /** Runs <code>command</code> redirecting standard out and
- * error out to <code>output</code> file.
- */
- private def runCommandOld(command: String, output: java.io.File): Int = {
- import java.io._
- import nest.StreamAppender
-
- // NestUI.verbose("running command:\n"+command)
- val proc = Runtime.getRuntime.exec(command)
- val in = proc.getInputStream
- val err = proc.getErrorStream
- val writer = new PrintWriter(new FileWriter(output), true)
- val inApp = StreamAppender(in, writer)
- val errApp = StreamAppender(err, writer)
- val async = new Thread(errApp)
- async.start()
- inApp.run()
- async.join()
- writer.close()
-
- try proc.exitValue()
- catch { case _: IllegalThreadStateException => 0 }
- }
-
- /** Exec a process to run a command. Assumes 0 exit value is success.
- * Of necessity, also treats no available exit value as success.
- */
- protected def execAndLog(cmd: String): Boolean = {
- runCommandOld(cmd, logFile.jfile) == 0
-
- // var proc: Process = null
- //
- // val result = interruptMeIn(cmd, testTimeout) {
- // loggingResult {
- // proc = Process.exec(toArgs(cmd), execEnv, execCwd.orNull, true)
- // proc.slurp()
- // }
- // proc != null && (proc.waitFor() == 0)
- // }
- // result getOrElse {
- // warning("Process never terminated: '%s'" format cmd)
- // if (proc != null)
- // proc.destroy()
- //
- // false
- // }
- }
- }
-
- trait ScriptableTest {
- self: TestEntity =>
-
- /** Translates a line from a .cmds file into a teststep.
- */
- def customTestStep(line: String): TestStep = {
- trace("customTestStep: " + line)
- val (cmd, rest) = line span (x => !Character.isWhitespace(x))
- def qualify(name: String) = sourcesDir / name path
- val args = toArgs(rest) map qualify
- def fail: TestStep = (_: TestEntity) => error("Parse error: did not understand '%s'" format line)
-
- val f: TestEntity => Boolean = cmd match {
- case "scalac" => _ scalac args
- case "javac" => _ javac args
- case "scala" => _ runScala args
- case _ => fail
- }
- f
- }
- }
-
- trait CompilableTest extends CompileExecSupport {
- self: TestEntity =>
-
- def sourceFiles = location.walk collect { case f: File if isJavaOrScala(f) => f } toList
- def allSources = sourceFiles map (_.path)
- def scalaSources = sourceFiles filter isScala map (_.path)
- def javaSources = sourceFiles filter isJava map (_.path)
-
- /** If there are mixed java and scala files, the standard compilation
- * sequence is:
- *
- * scalac with all files
- * javac with only java files
- * scalac with only scala files
- *
- * This should be expanded to encompass other strategies so we know how
- * well they're working or not working - notably, it would be very useful
- * to know exactly when and how two-pass compilation fails.
- */
- def compile() = {
- trace("compile: " + sourceFiles)
-
- def compileJava() = javac(javaSources)
- def compileScala() = scalac(scalaSources)
- def compileAll() = scalac(allSources)
- def compileMixed() = compileAll() && compileJava() && compileScala()
-
- if (scalaSources.nonEmpty && javaSources.nonEmpty) compileMixed()
- else compileScala()
- }
- }
-
- trait DiffableTest {
- self: TestEntity =>
-
- def checkFile: File = withExtension("check").toFile
- def checkFileRequired =
- returning(checkFile.isFile)(res => if (!res) warnAndLog("A checkFile at '%s' is mandatory.\n" format checkFile.path))
-
- lazy val sourceFileNames = sourceFiles map (_.name)
-
- /** Given the difficulty of verifying that any selective approach works
- * everywhere, the algorithm now is to look for the name of any known
- * source file for this test, and if seen, remove all the non-whitespace
- * preceding it. (Paths with whitespace don't work anyway.) This should
- * wipe out all slashes, backslashes, C:\, cygwin/windows differences,
- * and whatever else makes a simple diff not simple.
- *
- * The log and check file are both transformed, which I don't think is
- * correct -- only the log should be -- but doing it this way until I
- * can clarify martin's comments in #3283.
- */
- def normalizePaths(s: String) =
- sourceFileNames.foldLeft(s)((res, name) => res.replaceAll("""\S+\Q%s\E""" format name, name))
-
- /** The default cleanup normalizes paths relative to sourcesDir,
- * absorbs line terminator differences by going to lines and back,
- * and trims leading or trailing whitespace.
- */
- def diffCleanup(f: File) = safeLines(f) map normalizePaths mkString "\n" trim
-
- /** diffFiles requires actual Files as arguments but the output we want
- * is the post-processed versions of log/check, so we resort to tempfiles.
- */
- lazy val diffOutput = {
- if (!checkFile.exists) "" else {
- val input = diffCleanup(checkFile)
- val output = diffCleanup(logFile)
- def asFile(s: String) = returning(File.makeTemp("partest-diff"))(_ writeAll s)
-
- if (input == output) ""
- else diffFiles(asFile(input), asFile(output))
- }
- }
- private def checkTraceName = tracePath(checkFile)
- private def logTraceName = tracePath(logFile)
- private def isDiffConfirmed = checkFile.exists && (diffOutput == "")
-
- private def sendTraceMsg() {
- def result =
- if (isDryRun) ""
- else if (isDiffConfirmed) " [passed]"
- else if (checkFile.exists) " [failed]"
- else " [unchecked]"
-
- trace("diff %s %s%s".format(checkTraceName, logTraceName, result))
- }
-
- /** If optional is true, a missing check file is considered
- * a successful diff. Necessary since many categories use
- * checkfiles in an ad hoc manner.
- */
- def runDiff() = {
- sendTraceMsg()
-
- def updateCheck = (
- isUpdateCheck && {
- val formatStr = "** diff %s %s: " + (
- if (checkFile.exists) "failed, updating '%s' and marking as passed."
- else if (diffOutput == "") "not creating checkFile at '%s' as there is no output."
- else "was unchecked, creating '%s' for future tests."
- ) + "\n"
-
- normal(formatStr.format(checkTraceName, logTraceName, checkFile.path))
- if (diffOutput != "") normal(diffOutput)
-
- checkFile.writeAll(diffCleanup(logFile), "\n")
- true
- }
- )
-
- isDryRun || isDiffConfirmed || (updateCheck || !checkFile.exists)
- }
- }
-}
diff --git a/src/partest/scala/tools/partest/Alarms.scala b/src/partest/scala/tools/partest/Alarms.scala
deleted file mode 100644
index f38d8d6268..0000000000
--- a/src/partest/scala/tools/partest/Alarms.scala
+++ /dev/null
@@ -1,86 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools
-package partest
-
-import java.util.{ Timer, TimerTask }
-
-trait Alarms {
- self: Universe =>
-
- def interruptMeIn[T](debugMsg: String, seconds: Int)(body: => T): Option[T] = {
- val thisThread = currentThread
- val alarm = new SimpleAlarm(seconds * 1000) set thisThread.interrupt()
- debug("interruptMeIn(%d) '%s'".format(seconds, debugMsg))
-
- try { Some(body) }
- catch { case _: InterruptedException => debug("Received interrupted exception.") ; None }
- finally { debug("Cancelling interruptMeIn '%s'" format debugMsg) ; alarm.cancel() ; Thread.interrupted() }
- }
-
- case class AlarmerAction(secs: Int, action: () => Unit) extends Runnable {
- override def run() = action()
- }
-
- /** Set any number of alarms up with tuples of the form:
- * seconds to alarm -> Function0[Unit] to execute
- */
- class Alarmer(alarms: AlarmerAction*) {
- import java.util.concurrent._
-
- val exec = Executors.newSingleThreadScheduledExecutor()
- alarms foreach (x => exec.schedule(x, x.secs, TimeUnit.SECONDS))
- exec.shutdown()
-
- def cancelAll() = exec.shutdownNow()
- }
-
- class SimpleAlarm(timeout: Long) {
- private val alarm = new Timer
-
- /** Start a timer, running the given body if it goes off.
- */
- def set(body: => Unit) = returning(new TimerTask { def run() = body })(alarm.schedule(_, timeout))
-
- /** Cancel the timer.
- */
- def cancel() = alarm.cancel()
- }
-
- trait TestAlarms {
- test: TestEntity =>
-
- private def warning1 = AlarmerAction(testWarning, () => warning(
- """|I've been waiting %s seconds for this to complete:
- | %s
- |It may be stuck, or if not, it should be broken into smaller tests.
- |""".stripMargin.format(testWarning, test))
- )
- private def warning2 = AlarmerAction(testWarning * 2, () => warning(
- """|Now I've been waiting %s seconds for this to complete:
- | %s
- |If partest seems hung it would be a good place to look.
- |""".stripMargin.format(testWarning * 2, test))
- )
-
- def startAlarms(onTimeout: => Unit) =
- if (isNoAlarms) new Alarmer() // for alarm debugging
- else new Alarmer(Seq(warning1, warning2, AlarmerAction(testTimeout, () => onTimeout)): _*)
- }
-
- // Thread.setDefaultUncaughtExceptionHandler(new UncaughtException)
- // class UncaughtException extends Thread.UncaughtExceptionHandler {
- // def uncaughtException(t: Thread, e: Throwable) {
- // Console.println("Uncaught in %s: %s".format(t, e))
- // }
- // }
- //
- // lazy val logger = File("/tmp/partest.log").bufferedWriter()
- // def flog(msg: String) = logger synchronized {
- // logger write (msg + "\n")
- // logger.flush()
- // }
-}
diff --git a/src/partest/scala/tools/partest/BuildContributors.scala b/src/partest/scala/tools/partest/BuildContributors.scala
deleted file mode 100644
index 64c7e07bc3..0000000000
--- a/src/partest/scala/tools/partest/BuildContributors.scala
+++ /dev/null
@@ -1,102 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-
-import nsc.io._
-import nsc.util.ClassPath
-
-trait BuildContributors {
- universe: Universe =>
-
- /** A trait mixed into types which contribute a portion of the values.
- * The basic mechanism is the TestBuild, TestCategory, and TestEntity
- * can each contribute to each value. They are assembled at the last
- * moment by the ContributorAssembler (presently the TestEntity.)
- */
- trait BuildContributor {
- def javaFlags: List[String]
- def scalacFlags: List[String]
- def classpathPaths: List[Path]
- def buildProperties: List[(String, Any)]
- def buildEnvironment: Map[String, String]
- }
-
- trait ContributorAssembler {
- def contributors: List[BuildContributor]
- def assemble[T](what: BuildContributor => List[T]): List[T] = contributors flatMap what
-
- /** !!! This will need work if we want to achieve real composability,
- * but it can wait for the demand.
- */
- def assembleScalacArgs(args: List[String]) = assemble(_.scalacFlags) ++ args
- def assembleJavaArgs(args: List[String]) = assemble(_.javaFlags) ++ args
- def assembleProperties() = assemble(_.buildProperties)
- def assembleClasspaths(paths: List[Path]) = assemble(_.classpathPaths) ++ paths
- def assembleEnvironment() = assemble(_.buildEnvironment.toList).toMap
-
- def createClasspathString() = ClassPath fromPaths (assembleClasspaths(Nil) : _*)
- def createPropertyString() = assembleProperties() map { case (k, v) => "-D%s=%s".format(k, v.toString) }
- }
-
- trait BuildContribution extends BuildContributor {
- self: TestBuild =>
-
- /** The base classpath and system properties.
- * !!! TODO - this should adjust itself depending on the build
- * being tested, because pack and quick at least need different jars.
- */
- def classpathPaths = List[Path](library, compiler, partest, fjbg) ++ forkJoinPath
- def buildProperties = List(
- "scala.home" -> testBuildDir,
- "partest.lib" -> library, // used in jvm/inner
- "java.awt.headless" -> true,
- "user.language" -> "en",
- "user.country" -> "US",
- "partest.debug" -> isDebug,
- "partest.verbose" -> isVerbose
- // Disabled because there are no natives tests.
- // "java.library.path" -> srcLibDir
- )
- def javaFlags: List[String] = toArgs(javaOpts)
- def scalacFlags: List[String] = toArgs(scalacOpts)
-
- /** We put the build being tested's /bin directory in the front of the
- * path so the scripts and such written to execute "scala" will use this
- * build and not whatever happens to be on their path.
- */
- private def modifiedPath = ClassPath.join(scalaBin.path, Properties.envOrElse("PATH", ""))
- def buildEnvironment = Map("PATH" -> modifiedPath)
- }
-
- trait CategoryContribution extends BuildContributor {
- self: DirBasedCategory =>
-
- /** Category-wide classpath additions placed in <category>/lib. */
- private def libContents = root / "lib" ifDirectory (_.list.toList)
-
- def classpathPaths = libContents getOrElse Nil
- def buildProperties = Nil
- def javaFlags = Nil
- def scalacFlags = Nil
- def buildEnvironment = Map()
- }
-
- trait TestContribution extends BuildContributor with ContributorAssembler {
- self: TestEntity =>
-
- def jarsInTestDir = location.walk collect { case f: File if f hasExtension "jar" => f } toList
-
- def contributors = List(build, category, self)
- def javaFlags = safeArgs(javaOptsFile)
- def scalacFlags = safeArgs(scalaOptsFile)
- def classpathPaths = jarsInTestDir :+ outDir
- def buildProperties = List(
- "partest.output" -> outDir.toAbsolute, // used in jvm/inner
- "partest.cwd" -> outDir.parent.toAbsolute // used in shootout tests
- )
- def buildEnvironment = Map("JAVA_OPTS" -> fromArgs(assembleJavaArgs(Nil)))
- }
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/Categories.scala b/src/partest/scala/tools/partest/Categories.scala
deleted file mode 100644
index 172cca74b4..0000000000
--- a/src/partest/scala/tools/partest/Categories.scala
+++ /dev/null
@@ -1,70 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala Parallel Testing **
-** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.tools
-package partest
-
-import nsc.Settings
-import nsc.io._
-import nsc.util.{ ClassPath }
-
-trait Categories {
- self: Universe =>
-
- trait TestCategory extends AbsTestCategory {
- def kind: String
- def startMessage: String = "Executing test group"
- def testSequence: TestSequence
-
- class TestSettings(entity: TestEntity, error: String => Unit) extends Settings(error) {
- def this(entity: TestEntity) = this(entity, Console println _)
-
- deprecation.value = false
- encoding.value = "ISO-8859-1"
- classpath.value = entity.testClasspath
- outdir.value = entity.outDir.path
- }
-
- def createSettings(entity: TestEntity): TestSettings = new TestSettings(entity)
- def createTest(location: Path): TestEntity =
- if (location.isFile) TestFile(this, location.toFile)
- else if (location.isDirectory) TestDirectory(this, location.toDirectory)
- else error("Failed to create test at '%s'" format location)
-
- /** Category test identification.
- */
- def denotesTestFile(p: Path) = p.isFile && (p hasExtension "scala")
- def denotesTestDir(p: Path) = p.isDirectory && !ignorePath(p)
- def denotesTest(p: Path) = denotesTestDir(p) || denotesTestFile(p)
-
- /** This should verify that all necessary files are present.
- * By default it delegates to denotesTest.
- */
- def denotesValidTest(p: Path) = denotesTest(p)
- }
-
- abstract class DirBasedCategory(val kind: String) extends TestCategory with CategoryContribution {
- lazy val root = Directory(src / kind).normalize
- def enumerate = root.list filter denotesTest map createTest toList
-
- /** Standard actions. These can be overridden either on the
- * Category level or by individual tests.
- */
- def compile: TestStep = (_: TestEntity).compile()
- def checkFileRequired: TestStep = (_: TestEntity).checkFileRequired
- def diff: TestStep = (_: TestEntity).diff()
- def run: TestStep = (_: TestEntity).run()
- def exec: TestStep = (_: TestEntity).exec()
-
- /** Combinators.
- */
- def not(f: TestStep): TestStep = !f(_: TestEntity)
-
- override def toString = kind
- }
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/Compilable.scala b/src/partest/scala/tools/partest/Compilable.scala
deleted file mode 100644
index ddaa277842..0000000000
--- a/src/partest/scala/tools/partest/Compilable.scala
+++ /dev/null
@@ -1,106 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-
-import scala.tools.nsc.io._
-import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError }
-import scala.tools.nsc.util.{ ClassPath }
-import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
-
-trait PartestCompilation {
- self: Universe =>
-
- trait CompileExecSupport extends ExecSupport {
- self: TestEntity =>
-
- def javacpArg = "-classpath " + testClasspath
- def scalacpArg = "-usejavacp"
-
- /** Not used, requires tools.jar.
- */
- // def javacInternal(args: List[String]) = {
- // import com.sun.tools.javac.Main
- // Main.compile(args.toArray, logWriter)
- // }
-
- def javac(args: List[String]): Boolean = {
- val allArgString = fromArgs(javacpArg :: javacOpts :: args)
-
- // javac -d outdir -classpath <basepath> <files>
- val cmd = "%s -d %s %s".format(javacCmd, outDir, allArgString)
- def traceMsg =
- if (isVerbose) cmd
- else "%s -d %s %s".format(tracePath(Path(javacCmd)), tracePath(outDir), fromArgs(args))
-
- trace(traceMsg)
-
- isDryRun || execAndLog(cmd)
- }
-
- def scalac(args: List[String]): Boolean = {
- val allArgs = assembleScalacArgs(args)
- val (global, files) = newGlobal(allArgs)
- def nonFileArgs = if (isVerbose) global.settings.recreateArgs else assembleScalacArgs(Nil)
- def traceArgs = fromArgs(nonFileArgs ++ (files map tracePath))
- def traceMsg = "scalac " + traceArgs
-
- trace(traceMsg)
- isDryRun || global.partestCompile(files, true)
- }
-
- /** Actually running the test, post compilation.
- * Normally args will be List("Test", "jvm"), main class and arg to it.
- */
- def runScala(args: List[String]): Boolean = {
- val scalaRunnerClass = "scala.tools.nsc.MainGenericRunner"
-
- // java $JAVA_OPTS <javaopts> -classpath <cp>
- val javaCmdAndOptions = javaCmd +: assembleJavaArgs(List(javacpArg))
- // MainGenericRunner -usejavacp <scalacopts> Test jvm
- val scalaCmdAndOptions = List(scalaRunnerClass, scalacpArg) ++ assembleScalacArgs(args)
- // Assembled
- val cmd = fromArgs(javaCmdAndOptions ++ createPropertyString() ++ scalaCmdAndOptions)
-
- def traceMsg = if (isVerbose) cmd else fromArgs(javaCmd :: args)
- trace("runScala: " + traceMsg)
-
- isDryRun || execAndLog(cmd)
- }
-
- def newReporter(settings: Settings) = new ConsoleReporter(settings, Console.in, logWriter)
-
- class PartestGlobal(settings: Settings, val creporter: ConsoleReporter) extends Global(settings, creporter) {
- def partestCompile(files: List[String], printSummary: Boolean): Boolean = {
- try { new Run compile files }
- catch {
- case FatalError(msg) => creporter.error(null, "fatal error: " + msg)
- case ae: AssertionError => creporter.error(null, ""+ae)
- case te: TypeError => creporter.error(null, ""+te)
- case ex =>
- creporter.error(null, ""+ex)
- throw ex
- }
-
- if (printSummary)
- creporter.printSummary
-
- creporter.flush()
- !creporter.hasErrors
- }
- }
-
- def newGlobal(args: List[String]): (PartestGlobal, List[String]) = {
- val settings = category createSettings self
- val command = new CompilerCommand(args, settings)
- val reporter = newReporter(settings)
-
- if (!command.ok)
- debug("Error parsing arguments: '%s'".format(args mkString ", "))
-
- (new PartestGlobal(command.settings, reporter), command.files)
- }
- }
-}
diff --git a/src/partest/scala/tools/partest/Config.scala b/src/partest/scala/tools/partest/Config.scala
deleted file mode 100644
index 288a3034e9..0000000000
--- a/src/partest/scala/tools/partest/Config.scala
+++ /dev/null
@@ -1,129 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-
-import io._
-import nsc.io._
-import Properties._
-
-trait Config {
- universe: Universe =>
-
- lazy val src = absolutize(srcDir).toDirectory
- lazy val build = new TestBuild()
-
- def javaHomeEnv = envOrElse("JAVA_HOME", null)
- def javaCmd = envOrElse("JAVACMD", "java")
- def javacCmd = Option(javaHomeEnv) map (x => Path(x) / "bin" / "javac" path) getOrElse "javac"
-
- /** Values related to actors. The timeouts are in seconds. On a dry
- * run we only allocate one worker so the output isn't interspersed.
- */
- def workerTimeout = 3600 // 1 hour, probably overly generous
- def numWorkers = if (isDryRun) 1 else propOrElse("partest.actors", "8").toInt
- def expectedErrors = propOrElse("partest.errors", "0").toInt
- def poolSize = (wrapAccessControl(propOrNone("actors.corePoolSize")) getOrElse "16").toInt
-
- def allScalaFiles = src.deepFiles filter (_ hasExtension "scala")
- def allObjDirs = src.deepDirs filter (_ hasExtension "obj")
- def allLogFiles = src.deepFiles filter (_ hasExtension "log")
- def allClassFiles = src.deepFiles filter (_ hasExtension "class")
-
- class TestBuild() extends BuildContribution {
- import nsc.util.ClassPath
-
- /** Scala core libs.
- */
- val library = pathForComponent("library")
- val compiler = pathForComponent("compiler")
- val partest = pathForComponent("partest")
- val scalap = pathForComponent("scalap", "%s.jar")
-
- /** Scala supplementary libs - these are not all needed for all build targets,
- * and some of them are copied inside other jars in later targets. However quick
- * for instance cannot be run without some of these.
- */
- val fjbg = pathForLibrary("fjbg")
- val msil = pathForLibrary("msil")
- val forkjoin = pathForLibrary("forkjoin")
- val scalacheck = pathForLibrary("scalacheck")
-
- /** Other interesting paths.
- */
- val scalaBin = testBuildDir / "bin"
-
- /** A hack for now to get quick running.
- */
- def needsForkJoin = {
- val loader = nsc.util.ScalaClassLoader.fromURLs(List(library.toURL))
- val fjMarker = "scala.concurrent.forkjoin.ForkJoinTask"
- val clazz = loader.tryToLoadClass(fjMarker)
-
- if (clazz.isDefined) debug("Loaded ForkJoinTask OK, don't need jar.")
- else debug("Could not load ForkJoinTask, putting jar on classpath.")
-
- clazz.isEmpty
- }
- lazy val forkJoinPath: List[Path] = if (needsForkJoin) List(forkjoin) else Nil
-
- /** Internal **/
- private def repo = partestDir.parent.normalize
- // XXX - is this needed? Where?
- //
- // private val pluginOptionString = "-Xplugin:"
- // private def updatedPluginPath(options: String): String = {
- // val (pluginArgs, rest) = toArgs(options) partition (_ startsWith pluginOptionString)
- // // join all plugin paths as one classpath
- // val pluginPaths = ClassPath.join(pluginArgs map (_ stripPrefix pluginOptionString): _*)
- // // map all paths to absolute
- // val newPath = ClassPath.map(pluginPaths, x => absolutize(x).path)
- // // recreate option
- // val pluginOption = if (newPath == "") None else Some(pluginOptionString + newPath)
- //
- // fromArgs(rest ::: pluginOption.toList)
- // }
-
- private def pathForComponent(what: String, jarFormat: String = "scala-%s.jar"): Path = {
- def asDir = testBuildDir / "classes" / what
- def asJar = testBuildDir / "lib" / jarFormat.format(what)
-
- if (asDir.isDirectory) asDir
- else if (asJar.isFile) asJar
- else ""
- }
- private def pathForLibrary(what: String) = File(repo / "lib" / (what + ".jar"))
- }
-
- def printConfigBanner() = {
- debug("Java VM started with arguments: '%s'" format fromArgs(Process.javaVmArguments))
- debug("System Properties:\n" + util.allPropertiesString())
-
- normal(configBanner())
- }
-
- /** Treat an access control failure as None. */
- private def wrapAccessControl[T](body: => Option[T]): Option[T] =
- try body catch { case _: java.security.AccessControlException => None }
-
- private def configBanner() = {
- val javaBin = Path(javaHome) / "bin"
- val javaInfoString = "%s (build %s, %s)".format(javaVmName, javaVmVersion, javaVmInfo)
-
- List(
- "Scala compiler classes in: " + testBuildDir,
- "Scala version is: " + nsc.Properties.versionMsg,
- "Scalac options are: " + universe.scalacOpts,
- "Java binaries in: " + javaBin,
- "Java runtime is: " + javaInfoString,
- "Java runtime options: " + (Process.javaVmArguments mkString " "),
- "Javac options are: " + universe.javacOpts,
- "Java options are: " + universe.javaOpts,
- "Source directory is: " + src,
- "Selected categories: " + (selectedCategories mkString " "),
- ""
- ) mkString "\n"
- }
-}
diff --git a/src/partest/scala/tools/partest/Dispatcher.scala b/src/partest/scala/tools/partest/Dispatcher.scala
deleted file mode 100644
index 2a9d99ab60..0000000000
--- a/src/partest/scala/tools/partest/Dispatcher.scala
+++ /dev/null
@@ -1,162 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- * @author Philipp Haller
- */
-
-package scala.tools
-package partest
-
-import scala.tools.nsc.io._
-import scala.actors.{ Actor, TIMEOUT }
-import scala.actors.Actor._
-import scala.collection.immutable
-import scala.util.control.Exception.ultimately
-
-/** The machinery for concurrent execution of tests. Each Worker
- * is given a bundle of tests, which it runs sequentially and then
- * sends a report back to the dispatcher.
- */
-trait Dispatcher {
- partest: Universe =>
-
- /** The public entry point. The given filter narrows down the list of
- * tests to run.
- */
- def runSelection(categories: List[TestCategory], filt: TestEntity => Boolean = _ => true): CombinedTestResults = {
- // Setting scala.home informs tests where to obtain their jars.
- setProp("scala.home", testBuildDir.path)
-
- val allTests = allCategories flatMap (_.enumerate)
- val selected = allTests filter filt
- val groups = selected groupBy (_.category)
- val count = selected.size
-
- if (count == 0) return CombinedTestResults(0, 0, 0, Nil)
- else if (count == allTests.size) verbose("Running all %d tests." format count)
- else verbose("Running %d/%d tests: %s".format(count, allTests.size, toStringTrunc(selected map (_.label) mkString ", ")))
-
- allCategories collect { case x if groups contains x => runCategory(x, groups(x)) } reduceLeft (_ ++ _)
- }
-
- private def parallelizeTests(tests: List[TestEntity]): immutable.Map[TestEntity, TestResult] = {
- // propagate verbosity
- if (isDebug) scala.actors.Debug.level = 3
-
- // "If elected, I guarantee a slice of tests for every worker!"
- val groups = tests grouped ((tests.size / numWorkers) + 1) toList
-
- // "Workers, line up for assignments!"
- val workers =
- for ((slice, workerNum) <- groups.zipWithIndex) yield {
- returning(new Worker(workerNum)) { worker =>
- worker.start()
- worker ! TestsToRun(slice)
- }
- }
-
- normal("Started %d workers with ~%d tests each.\n".format(groups.size, groups.head.size))
-
- /** Listening for news from the proletariat.
- */
- (workers map { w =>
- receiveWithin(workerTimeout * 1000) {
- case ResultsOfRun(resultMap) => resultMap
- case TIMEOUT =>
- warning("Worker %d timed out." format w.workerNum)
- // mark all the worker's tests as having timed out - should be hard to miss
- // immutable.Map[TestEntity, TestResult]()
- groups(w.workerNum) map (x => (x -> new Timeout(x))) toMap
- }
- }) reduceLeft (_ ++ _)
- }
-
- private def runCategory(category: TestCategory, tests: List[TestEntity]): CombinedTestResults = {
- val kind = category.kind
- normal("%s (%s tests in %s)\n".format(category.startMessage, tests.size, category))
-
- val (milliSeconds, resultMap) = timed2(parallelizeTests(tests))
- val (passed, failed) = resultsToStatistics(resultMap mapValues (_.state))
- val failures = resultMap.values filterNot (_.passed) toList
-
- CombinedTestResults(passed, failed, milliSeconds, failures)
- }
-
- /** A Worker is given a bundle of tests and runs them all sequentially.
- */
- class Worker(val workerNum: Int) extends Actor {
- def act() {
- react { case TestsToRun(tests) =>
- val master = sender
- runTests(tests)(results => master ! ResultsOfRun(results))
- }
- }
-
- /** Runs the tests. Passes the result Map to onCompletion when done.
- */
- private def runTests(tests: List[TestEntity])(onCompletion: immutable.Map[TestEntity, TestResult] => Unit) {
- var results = new immutable.HashMap[TestEntity, TestResult] // maps tests to results
- val numberOfTests = tests.size
- val testIterator = tests.iterator
- def processed = results.size
- def isComplete = testIterator.isEmpty
-
- def atThreshold(num: Double) = {
- require(num >= 0 && num <= 1.0)
- ((processed - 1).toDouble / numberOfTests <= num) && (processed.toDouble / numberOfTests >= num)
- }
-
- def extraMessage = {
- // for now quiet for normal people
- if (isVerbose || isTrace || isDebug) {
- if (isComplete) "(#%d 100%%)" format workerNum
- else if (isVerbose) "(#%d %d/%d)".format(workerNum, processed, numberOfTests)
- else if (isTrace && atThreshold(0.5)) "(#%d 50%%)" format workerNum
- else ""
- }
- else ""
- }
-
- def countAndReport(result: TestResult) {
- val TestResult(test, state) = result
- // refuse to count an entity twice
- if (results contains test)
- return warning("Received duplicate result for %s: was %s, now %s".format(test, results(test), state))
-
- // increment the counter for this result state
- results += (test -> result)
-
- // show on screen
- if (isDryRun) normal("\n") // blank line between dry run traces
- else result show extraMessage
-
- // remove log if successful
- if (result.passed)
- test.deleteLog()
-
- // Respond to master if this Worker is complete
- if (isComplete)
- onCompletion(results)
- }
-
- Actor.loopWhile(testIterator.hasNext) {
- val parent = self
- // pick a test and set some alarms
- val test = testIterator.next
- val alarmer = test startAlarms (parent ! new Timeout(test))
-
- actor {
- ultimately(alarmer.cancelAll()) {
- // Calling isSuccess forces the lazy val "process" inside the test, running it.
- val res = test.isSuccess
- // Cancel the alarms and alert the media.
- parent ! TestResult(test, res)
- }
- }
-
- react {
- case x: TestResult => countAndReport(x)
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/Entities.scala b/src/partest/scala/tools/partest/Entities.scala
deleted file mode 100644
index bea505b594..0000000000
--- a/src/partest/scala/tools/partest/Entities.scala
+++ /dev/null
@@ -1,74 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- * @author Philipp Haller
- */
-
-package scala.tools
-package partest
-
-import nsc.io._
-
-trait Entities {
- self: Universe =>
-
- abstract class TestEntity extends AbsTestEntity
- with TestContribution
- with TestHousekeeping
- with TestAlarms
- with EntityLogging
- with CompilableTest
- with ScriptableTest
- with DiffableTest {
- def location: Path
- def category: TestCategory
-
- lazy val label = location.stripExtension
- lazy val testClasspath = returning(createClasspathString())(x => vtrace("testClasspath: " + x))
-
- /** Was this test successful? Calling this for the first time forces
- * lazy val "process" which actually runs the test.
- */
- def isSuccess = process
-
- /** Some standard files, which may or may not be present.
- */
- def scalaOptsFile = withExtension("flags").toFile // opts to scalac
- def javaOptsFile = withExtension("javaopts").toFile // opts to java (but not javac)
- def commandFile = withExtension("cmds").toFile // sequence of commands to execute
- def logFile = withExtension("log").toFile // collected output
-
- /** Some standard directories.
- */
- def outDir = withExtension("obj").toDirectory // output dir, e.g. files/pos/t14.obj
- def categoryDir = location.parent.normalize // category dir, e.g. files/pos/
- def sourcesDir = location ifDirectory (_.normalize) getOrElse categoryDir
-
- /** Standard arguments for run, exec, diff.
- */
- def argumentsToRun = List("Test", "jvm")
- def argumentsToExec = List(location.path)
-
- /** Using a .cmds file for a custom test sequence.
- */
- def commandList = safeLines(commandFile)
- def testSequence =
- if (commandFile.isFile && commandList.nonEmpty) commandList map customTestStep
- else category.testSequence
-
- def run() = runScala(argumentsToRun)
- def exec() = runExec(argumentsToExec)
- def diff() = runDiff() // checkFile, logFile
-
- /** The memoized result of the test run.
- */
- private lazy val process = {
- val outcome = runWrappers(testSequence.actions forall (f => f(this)))
-
- // an empty outcome means we've been interrupted and are shutting down.
- outcome getOrElse false
- }
- }
-
- case class TestDirectory(category: TestCategory, location: Directory) extends TestEntity { }
- case class TestFile(category: TestCategory, location: File) extends TestEntity { }
-}
diff --git a/src/partest/scala/tools/partest/Housekeeping.scala b/src/partest/scala/tools/partest/Housekeeping.scala
deleted file mode 100644
index a624ca8adb..0000000000
--- a/src/partest/scala/tools/partest/Housekeeping.scala
+++ /dev/null
@@ -1,187 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-
-import scala.util.control.Exception.catching
-import util._
-import nsc.io._
-import Process.runtime
-import Properties._
-
-/** An agglomeration of code which is low on thrills. Hopefully
- * it operates so quietly in the background that you never have to
- * look at this file.
- */
-trait Housekeeping {
- self: Universe =>
-
- /** Orderly shutdown on ctrl-C. */
- @volatile private var _shuttingDown = false
- protected def setShuttingDown() = {
- /** Whatever we want to do as shutdown begins goes here. */
- if (!_shuttingDown) {
- warning("Received shutdown signal, partest is cleaning up...\n")
- _shuttingDown = true
- }
- }
- def isShuttingDown = _shuttingDown
-
- /** Execute some code with a shutdown hook in place. This is
- * motivated by the desire not to leave the filesystem full of
- * junk when someone ctrl-Cs a test run.
- */
- def withShutdownHook[T](hook: => Unit)(body: => T): Option[T] =
- /** Java doesn't like it if you keep adding and removing shutdown
- * hooks after shutdown has begun, so we trap the failure.
- */
- catching(classOf[IllegalStateException]) opt {
- val t = new Thread() {
- override def run() = {
- setShuttingDown()
- hook
- }
- }
- runtime addShutdownHook t
-
- try body
- finally runtime removeShutdownHook t
- }
-
- /** Search for a directory, possibly given only a name, by starting
- * at the current dir and walking upward looking for it at each level.
- */
- protected def searchForDir(name: String): Directory = {
- val result = Path(name) ifDirectory (x => x.normalize) orElse {
- val cwd = Directory.Current getOrElse error("user.dir property not set")
- val dirs = cwd :: cwd.parents map (_ / name)
-
- Path onlyDirs dirs map (_.normalize) headOption
- }
-
- result getOrElse error("Fatal: could not find directory '%s'" format name)
- }
-
- /** Paths we ignore for most purposes.
- */
- def ignorePath(x: Path) = {
- (x.name startsWith ".") ||
- (x.isDirectory && ((x.name == "lib") || x.hasExtension("obj", "svn")))
- }
- /** Make a possibly relative path absolute using partestDir as the base.
- */
- def absolutize(path: String) = Path(path) toAbsoluteWithRoot partestDir
-
- /** Go on a deleting binge.
- */
- def cleanupAll() {
- if (isNoCleanup)
- return
-
- val (dirCount, fileCount) = (cleanupObjDirs(), cleanupLogs() + cleanupJunk())
- if (dirCount + fileCount > 0)
- normal("Cleaned up %d directories and %d files.\n".format(dirCount, fileCount))
- }
-
- def cleanupObjDirs() = countTrue(allObjDirs collect { case x if x.exists => x.deleteRecursively() })
- def cleanupJunk() = countTrue(allClassFiles collect { case x if x.exists => x.delete() })
- def cleanupLogs() = countTrue(allLogFiles collect { case x if x.exists => x.delete() })
-
- /** Look through every file in the partest directory and ask around
- * to make sure someone knows him. Complain about strangers.
- */
- def validateAll() {
- def denotesTest(p: Path) = allCategories exists (_ denotesTest p)
- def isMSILcheck(p: Path) = p.name endsWith "-msil.check"
-
- def analyzeCategory(cat: DirBasedCategory) = {
- val allTests = cat.enumerate
- val otherPaths = cat.root walkFilter (x => !ignorePath(x)) filterNot (cat denotesTest _) filterNot isMSILcheck toList
- val count = otherPaths.size
-
- println("Validating %d non-test paths in %s.".format(count, cat.kind))
-
- for (path <- otherPaths) {
- (allTests find (_ acknowledges path)) match {
- case Some(test) => if (isVerbose) println(" OK: '%s' is claimed by '%s'".format(path, test.label))
- case _ => println(">> Unknown path '%s'" format path)
- }
- }
- }
-
- allCategories collect { case x: DirBasedCategory => analyzeCategory(x) }
- }
-
- trait TestHousekeeping {
- self: TestEntity =>
-
- /** Calculating derived files. Given a test like
- * files/run/foo.scala or files/run/foo/
- * This creates paths like foo.check, foo.flags, etc.
- */
- def withExtension(extension: String) = categoryDir / "%s.%s".format(label, extension)
-
- /** True for a path if this test acknowledges it belongs to this test.
- * Overridden by some categories.
- */
- def acknowledges(path: Path): Boolean = {
- val loc = location.normalize
- val knownPaths = List(scalaOptsFile, javaOptsFile, commandFile, logFile, checkFile) ++ jarsInTestDir
- def isContainedSource = location.isDirectory && isJavaOrScala(path) && (path.normalize startsWith loc)
-
- (knownPaths exists (_ isSame path)) || isContainedSource
- }
-
- /** This test "responds to" this String. This could mean anything -- it's a
- * way of specifying ad-hoc collections of tests to exercise only a subset of tests.
- * At present it looks for the given String in all the test sources.
- */
- def respondsToString(str: String) = containsString(str)
- def containsString(str: String) = {
- debug("Checking %s for \"%s\"".format(sourceFiles mkString ", ", str))
- sourceFiles map safeSlurp exists (_ contains str)
- }
-
- def possiblyTimed[T](body: => T): T = {
- if (isStats) timed(recordTestTiming(label, _))(body)
- else body
- }
-
- private def prepareForTestRun() = {
- // make sure we have a clean slate
- deleteLog(force = true)
- if (outDir.exists)
- outDir.deleteRecursively()
-
- // recreate object dir
- outDir createDirectory true
- }
- def deleteOutDir() = outDir.deleteRecursively()
- def deleteShutdownHook() = { debug("Shutdown hook deleting " + outDir) ; deleteOutDir() }
-
- protected def runWrappers[T](body: => T): Option[T] = {
- prepareForTestRun()
-
- withShutdownHook(deleteShutdownHook()) {
- loggingOutAndErr {
- val result = possiblyTimed { body }
- if (!isNoCleanup)
- deleteOutDir()
-
- result
- }
- }
- }
-
- override def toString = location.path
- override def equals(other: Any) = other match {
- case x: TestEntity => location.normalize == x.location.normalize
- case _ => false
- }
- override def hashCode = location.normalize.hashCode
- }
-
- private def countTrue(f: => Iterator[Boolean]) = f filter (_ == true) length
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/Partest.scala b/src/partest/scala/tools/partest/Partest.scala
deleted file mode 100644
index b3fe9a98ef..0000000000
--- a/src/partest/scala/tools/partest/Partest.scala
+++ /dev/null
@@ -1,81 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-
-import nsc.io._
-import nsc.util._
-import category.AllCategories
-
-/** Global object for a Partest run. It is completely configured by the list
- * of arguments passed to the constructor (although there are a few properties
- * and environment variables which can influence matters.) See PartestSpec.scala
- * for the complete list.
- */
-class Partest(args: List[String]) extends {
- val parsed = PartestSpec(args: _*)
-} with Universe with PartestSpec with cmd.Instance with AllCategories {
-
- if (parsed.propertyArgs.nonEmpty)
- debug("Partest property args: " + fromArgs(parsed.propertyArgs))
-
- debug("Partest created with args: " + fromArgs(args))
-
- def helpMsg = PartestSpec.helpMsg
-
- // The abstract values from Universe.
- lazy val testBuildDir = searchForDir(buildDir)
- lazy val partestDir = searchForDir(rootDir)
- lazy val allCategories = List(Pos, Neg, Run, Jvm, Res, Shootout, Scalap, Scalacheck, BuildManager, Script)
- lazy val selectedCategories = if (isAllImplied) allCategories else specifiedCats
-
- def specifiedTests = parsed.residualArgs map (x => Path(x).normalize)
- def specifiedKinds = testKinds filter (x => isSet(x) || (runSets contains x))
- def specifiedCats = specifiedKinds flatMap (x => allCategories find (_.kind == x))
- def isAllImplied = isAll || (specifiedTests.isEmpty && specifiedKinds.isEmpty)
-
- /** Assembles a filter based on command line options which restrict the test set
- * --grep limits to only matching tests
- * --failed limits to only recently failed tests (log file is present)
- * --<category> limits to only the given tests and categories (but --all overrides)
- * path/to/Test limits to only the given tests and categories
- */
- lazy val filter = {
- def indivFilter(test: TestEntity) = specifiedTests contains test.location.normalize
- def categoryFilter(test: TestEntity) = specifiedCats contains test.category
- def indivOrCat(test: TestEntity) = isAllImplied || indivFilter(test) || categoryFilter(test) // combines previous two
-
- def failedFilter(test: TestEntity) = !isFailed || (test.logFile exists)
- def grepFilter(test: TestEntity) = grepExpr.isEmpty || (test containsString grepExpr.get)
- def combinedFilter(x: TestEntity) = indivOrCat(x) && failedFilter(x) && grepFilter(x) // combines previous three
-
- combinedFilter _
- }
-
- def launchTestSuite() = {
- def onTimeout() = {
- warning("Partest test run timed out after " + timeout + " seconds.\n")
- System.exit(-1)
- }
- val alarm = new Alarmer(AlarmerAction(timeout, () => onTimeout()))
-
- try runSelection(selectedCategories, filter)
- finally alarm.cancelAll()
- }
-}
-
-object Partest {
- def fromBuild(dir: String, args: String*): Partest = apply("--builddir" +: dir +: args: _*)
- def apply(args: String*): Partest = new Partest(args.toList)
-
- // builds without partest jars won't actually work
- def starr() = fromBuild("")
- def locker() = fromBuild("build/locker")
- def quick() = fromBuild("build/quick")
- def pack() = fromBuild("build/pack")
- def strap() = fromBuild("build/strap")
- def dist() = fromBuild("dists/latest")
-}
-
diff --git a/src/partest/scala/tools/partest/PartestDefaults.scala b/src/partest/scala/tools/partest/PartestDefaults.scala
new file mode 100644
index 0000000000..139c54dedd
--- /dev/null
+++ b/src/partest/scala/tools/partest/PartestDefaults.scala
@@ -0,0 +1,30 @@
+package scala.tools
+package partest
+
+import nsc.io.{ File, Path, Process, Directory }
+import util.{ PathResolver }
+import nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
+
+object PartestDefaults {
+ import nsc.Properties._
+ private def wrapAccessControl[T](body: => Option[T]): Option[T] =
+ try body catch { case _: java.security.AccessControlException => None }
+
+ def testRootName = propOrNone("partest.root")
+ def srcDirName = propOrElse("partest.srcdir", "files")
+ def testRootDir = testRootName map (x => Directory(x))
+
+ def classPath = PathResolver.Environment.javaUserClassPath // XXX
+
+ def javaCmd = propOrElse("partest.javacmd", "java")
+ def javacCmd = propOrElse("partest.javac_cmd", "javac")
+ def javaOpts = propOrElse("partest.java_opts", "")
+ def scalacOpts = propOrElse("partest.scalac_opts", "-deprecation")
+
+ def testBuild = propOrNone("partest.build")
+ def errorCount = propOrElse("partest.errors", "0").toInt
+ def numActors = propOrElse("partest.actors", "8").toInt
+ def poolSize = wrapAccessControl(propOrNone("actors.corePoolSize"))
+
+ def timeout = "1200000"
+}
diff --git a/src/partest/scala/tools/partest/PartestSpec.scala b/src/partest/scala/tools/partest/PartestSpec.scala
deleted file mode 100644
index c25119b3af..0000000000
--- a/src/partest/scala/tools/partest/PartestSpec.scala
+++ /dev/null
@@ -1,104 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools
-package partest
-
-import nsc.io._
-import cmd._
-
-/** This takes advantage of bits of scala goodness to fully define a command
- * line program with a minimum of duplicated code. When the specification object
- * is created, the vals are evaluated in order and each of them side effects
- * a private accumulator. What emerges is a full list of the valid unary
- * and binary arguments, as well as autogenerated help.
- */
-trait PartestSpec extends Spec with Meta.StdOpts with Interpolation {
- def referenceSpec = PartestSpec
- def programInfo = Spec.Info("partest", "", "scala.tools.partest.Runner")
- private val kind = new Spec.Accumulator[String]()
- protected def testKinds = kind.get
-
- private implicit val tokenizeString = FromString.ArgumentsFromString // String => List[String]
-
- help("""
- |# Pro Tip! Instant bash completion: `partest --bash` (note backticks)
- |Usage: partest [<options>] [<test> <test> ...]
- | <test>: a path to a test designator, typically a .scala file or a directory.
- | Examples: files/pos/test1.scala, files/res/bug785
- |
- | Test categories:""".stripMargin)
-
- val isAll = ("all" / "run all tests (default, unless no options given)" --?)
- (kind("pos") / "Compile files that are expected to build" --?)
- (kind("neg") / "Compile files that are expected to fail" --?)
- (kind("run") / "Test JVM backend" --?)
- (kind("jvm") / "Test JVM backend" --?)
- (kind("res") / "Run resident compiler scenarii" --?)
- (kind("buildmanager") / "Run Build Manager scenarii" --?)
- (kind("scalacheck") / "Run Scalacheck tests" --?)
- (kind("script") / "Run script files" --?)
- (kind("shootout") / "Run shootout tests" --?)
- (kind("scalap") / "Run scalap tests" --?)
-
- heading ("""Test "smart" categories:""")
- val grepExpr = "grep" / "run all tests with a source file containing <expr>" --|
- val isFailed = "failed" / "run all tests which failed on the last run" --?
-
- heading ("Specifying paths and additional flags, ~ means repository root:")
-
- val rootDir = "rootdir" / "path from ~ to partest" defaultTo "test"
- val buildDir = "builddir" / "path from ~ to test build" defaultTo "build/pack"
- val srcDir = "srcdir" / "path from --rootdir to sources" defaultTo "files"
- val javaOpts = "javaopts" / "flags to java on all runs" defaultToEnv "JAVA_OPTS"
- val javacOpts = "javacopts" / "flags to javac on all runs" defaultToEnv "JAVAC_OPTS"
- val scalacOpts = "scalacopts" / "flags to scalac on all tests" defaultToEnv "SCALAC_OPTS"
-
- "pack" / "" expandTo ("--builddir", "build/pack")
- "quick" / "" expandTo ("--builddir", "build/quick")
-
- heading ("Options influencing output:")
- val isTrace = "trace" / "show the individual steps taken by each test" --?
- val isShowDiff = "show-diff" / "show diff between log and check file" --?
- val isShowLog = "show-log" / "show log on failures" --?
- val isDryRun = "dry-run" / "do not run tests, only show their traces." --?
- val isTerse = "terse" / "be less verbose (almost silent except for failures)" --?
- val isVerbose = "verbose" / "be more verbose (additive with --trace)" --?
- val isDebug = "debug" / "maximum debugging output" --?
- val isAnsi = "ansi" / "print output in color" --?
-
- heading ("Other options:")
- val timeout = "timeout" / "Overall timeout in seconds" defaultTo 7200
- val testWarning = "test-warning" / "Test warning in seconds" defaultTo 90
- val testTimeout = "test-timeout" / "Test timeout in seconds" defaultTo 900
- val isCleanup = "cleanup" / "delete all stale files and dirs before run" --?
- val isNoCleanup = "nocleanup" / "do not delete any logfiles or object dirs" --?
- val isStats = "stats" / "collect and print statistics about the tests" --?
- val isValidate = "validate" / "examine test filesystem for inconsistencies" --?
- val isUpdateCheck = "update-check" / "overwrite checkFile if diff fails" --?
-
- "version" / "print version" --> runAndExit(println(Properties.versionMsg))
-
- // no help for anything below this line - secret options
- // mostly intended for property configuration.
- val runSets = ("runsets" --^) getOrElse Nil
- val isNoAlarms = "noalarms" --?
- val isInsideAnt = "is-in-ant" --?
-}
-
-object PartestSpec extends PartestSpec with Property {
- lazy val propMapper = new PropertyMapper(PartestSpec) {
- override def isPassThrough(key: String) = key == "partest.options"
- }
-
- type ThisCommandLine = PartestCommandLine
- class PartestCommandLine(args: List[String]) extends SpecCommandLine(args) {
- override def errorFn(msg: String) = printAndExit("Error: " + msg)
-
- def propertyArgs = PartestSpec.propertyArgs
- }
-
- override def creator(args: List[String]): PartestCommandLine = new PartestCommandLine(args)
-}
diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala
new file mode 100644
index 0000000000..230a6f73ec
--- /dev/null
+++ b/src/partest/scala/tools/partest/PartestTask.scala
@@ -0,0 +1,287 @@
+/* __ *\
+** ________ ___ / / ___ Scala Parallel Testing **
+** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+package scala.tools
+package partest
+
+import scala.actors.Actor._
+import scala.util.Properties.setProp
+import scala.tools.nsc.io.{ Directory, Path => SPath }
+import nsc.Settings
+import nsc.util.ClassPath
+import util.PathResolver
+import scala.tools.ant.sabbus.CompilationPathProperty
+
+import java.io.File
+import java.net.URLClassLoader
+import java.lang.reflect.Method
+
+import org.apache.tools.ant.Task
+import org.apache.tools.ant.types.{Path, Reference, FileSet}
+
+class PartestTask extends Task with CompilationPathProperty {
+
+ def addConfiguredPosTests(input: FileSet) {
+ posFiles = Some(input)
+ }
+
+ def addConfiguredNegTests(input: FileSet) {
+ negFiles = Some(input)
+ }
+
+ def addConfiguredRunTests(input: FileSet) {
+ runFiles = Some(input)
+ }
+
+ def addConfiguredJvmTests(input: FileSet) {
+ jvmFiles = Some(input)
+ }
+
+ def addConfiguredResidentTests(input: FileSet) {
+ residentFiles = Some(input)
+ }
+
+ def addConfiguredBuildManagerTests(input: FileSet) {
+ buildManagerFiles = Some(input)
+ }
+
+ def addConfiguredScalacheckTests(input: FileSet) {
+ scalacheckFiles = Some(input)
+ }
+
+ def addConfiguredScriptTests(input: FileSet) {
+ scriptFiles = Some(input)
+ }
+
+ def addConfiguredShootoutTests(input: FileSet) {
+ shootoutFiles = Some(input)
+ }
+
+ def addConfiguredScalapTests(input: FileSet) {
+ scalapFiles = Some(input)
+ }
+
+ def setSrcDir(input: String) {
+ srcDir = Some(input)
+ }
+
+ def setClasspath(input: Path) {
+ if (classpath.isEmpty)
+ classpath = Some(input)
+ else
+ classpath.get.append(input)
+ }
+
+ def createClasspath(): Path = {
+ if (classpath.isEmpty) classpath = Some(new Path(getProject()))
+ classpath.get.createPath()
+ }
+
+ def setClasspathref(input: Reference) {
+ createClasspath().setRefid(input)
+ }
+
+ def setShowLog(input: Boolean) {
+ showLog = input
+ }
+
+ def setShowDiff(input: Boolean) {
+ showDiff = input
+ }
+
+ def setErrorOnFailed(input: Boolean) {
+ errorOnFailed = input
+ }
+
+ def setJavaCmd(input: File) {
+ javacmd = Some(input)
+ }
+
+ def setJavacCmd(input: File) {
+ javaccmd = Some(input)
+ }
+
+ def setScalacOpts(opts: String) {
+ scalacOpts = Some(opts)
+ }
+
+ def setTimeout(delay: String) {
+ timeout = Some(delay)
+ }
+
+ def setDebug(input: Boolean) {
+ debug = input
+ }
+
+ def setJUnitReportDir(input: File) {
+ jUnitReportDir = Some(input)
+ }
+
+ private var classpath: Option[Path] = None
+ private var srcDir: Option[String] = None
+ private var javacmd: Option[File] = None
+ private var javaccmd: Option[File] = None
+ private var showDiff: Boolean = false
+ private var showLog: Boolean = false
+ private var runFailed: Boolean = false
+ private var posFiles: Option[FileSet] = None
+ private var negFiles: Option[FileSet] = None
+ private var runFiles: Option[FileSet] = None
+ private var jvmFiles: Option[FileSet] = None
+ private var residentFiles: Option[FileSet] = None
+ private var buildManagerFiles: Option[FileSet] = None
+ private var scalacheckFiles: Option[FileSet] = None
+ private var scriptFiles: Option[FileSet] = None
+ private var shootoutFiles: Option[FileSet] = None
+ private var scalapFiles: Option[FileSet] = None
+ private var errorOnFailed: Boolean = false
+ private var scalacOpts: Option[String] = None
+ private var timeout: Option[String] = None
+ private var jUnitReportDir: Option[File] = None
+ private var debug = false
+
+ def fileSetToDir(fs: FileSet) = Directory(fs getDir getProject)
+ def fileSetToArray(fs: FileSet): Array[SPath] = {
+ val root = fileSetToDir(fs)
+ (fs getDirectoryScanner getProject).getIncludedFiles map (root / _)
+ }
+
+ private def getFiles(fileSet: Option[FileSet]): Array[File] = fileSet match {
+ case None => Array()
+ case Some(fs) => fileSetToArray(fs) filterNot (_ hasExtension "log") map (_.jfile)
+ }
+
+ private def getFilesAndDirs(fileSet: Option[FileSet]): Array[File] = fileSet match {
+ case None => Array()
+ case Some(fs) =>
+ def shouldExclude(name: String) = (name endsWith ".obj") || (name startsWith ".")
+
+ val fileTests = getFiles(Some(fs)) filterNot (x => shouldExclude(x.getName))
+ val dirTests: Iterator[SPath] = fileSetToDir(fs).dirs filterNot (x => shouldExclude(x.name))
+ val dirResult = dirTests.toList.toArray map (_.jfile)
+
+ dirResult ++ fileTests
+ }
+
+ private def getPosFiles = getFilesAndDirs(posFiles)
+ private def getNegFiles = getFilesAndDirs(negFiles)
+ private def getRunFiles = getFiles(runFiles)
+ private def getJvmFiles = getFilesAndDirs(jvmFiles)
+ private def getResidentFiles = getFiles(residentFiles)
+ private def getBuildManagerFiles = getFilesAndDirs(buildManagerFiles)
+ private def getScalacheckFiles = getFiles(scalacheckFiles)
+ private def getScriptFiles = getFiles(scriptFiles)
+ private def getShootoutFiles = getFiles(shootoutFiles)
+ private def getScalapFiles = getFiles(scalapFiles)
+
+ override def execute() {
+ if (isPartestDebug)
+ setProp("partest.debug", "true")
+
+ srcDir foreach (x => setProp("partest.srcdir", x))
+
+ val classpath = this.compilationPath getOrElse error("Mandatory attribute 'compilationPath' is not set.")
+
+ val scalaLibrary = {
+ (classpath.list map { fs => new File(fs) }) find { f =>
+ f.getName match {
+ case "scala-library.jar" => true
+ case "library" if (f.getParentFile.getName == "classes") => true
+ case _ => false
+ }
+ }
+ } getOrElse error("Provided classpath does not contain a Scala library.")
+
+ val antRunner = new scala.tools.partest.nest.AntRunner
+ val antFileManager = antRunner.fileManager
+
+ antFileManager.showDiff = showDiff
+ antFileManager.showLog = showLog
+ antFileManager.failed = runFailed
+ antFileManager.CLASSPATH = ClassPath.join(classpath.list: _*)
+ antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath
+
+ javacmd foreach (x => antFileManager.JAVACMD = x.getAbsolutePath)
+ javaccmd foreach (x => antFileManager.JAVAC_CMD = x.getAbsolutePath)
+ scalacOpts foreach (antFileManager.SCALAC_OPTS = _)
+ timeout foreach (antFileManager.timeout = _)
+
+ type TFSet = (Array[File], String, String)
+ val testFileSets = List(
+ (getPosFiles, "pos", "Compiling files that are expected to build"),
+ (getNegFiles, "neg", "Compiling files that are expected to fail"),
+ (getRunFiles, "run", "Compiling and running files"),
+ (getJvmFiles, "jvm", "Compiling and running files"),
+ (getResidentFiles, "res", "Running resident compiler scenarii"),
+ (getBuildManagerFiles, "buildmanager", "Running Build Manager scenarii"),
+ (getScalacheckFiles, "scalacheck", "Running scalacheck tests"),
+ (getScriptFiles, "script", "Running script files"),
+ (getShootoutFiles, "shootout", "Running shootout tests"),
+ (getScalapFiles, "scalap", "Running scalap tests")
+ )
+
+ def runSet(set: TFSet): (Int, Int, Iterable[String]) = {
+ val (files, name, msg) = set
+ if (files.isEmpty) (0, 0, List())
+ else {
+ log(msg)
+ val results: Iterable[(String, Int)] = antRunner.reflectiveRunTestsForFiles(files, name)
+ val (succs, fails) = resultsToStatistics(results)
+
+ val failed: Iterable[String] = results collect {
+ case (path, 1) => path + " [FAILED]"
+ case (path, 2) => path + " [TIMOUT]"
+ }
+
+ // create JUnit Report xml files if directory was specified
+ jUnitReportDir foreach { d =>
+ d.mkdir
+
+ val report = testReport(name, results, succs, fails)
+ scala.xml.XML.save(d.getAbsolutePath+"/"+name+".xml", report)
+ }
+
+ (succs, fails, failed)
+ }
+ }
+
+ val _results = testFileSets map runSet
+ val allSuccesses = _results map (_._1) sum
+ val allFailures = _results map (_._2) sum
+ val allFailedPaths = _results flatMap (_._3)
+
+ def f = if (errorOnFailed && allFailures > 0) error(_) else log(_: String)
+ def s = if (allFailures > 1) "s" else ""
+ val msg =
+ if (allFailures > 0)
+ "Test suite finished with %d case%s failing:\n".format(allFailures, s)+
+ allFailedPaths.mkString("\n")
+ else if (allSuccesses == 0) "There were no tests to run."
+ else "Test suite finished with no failures."
+
+ f(msg)
+ }
+ def oneResult(res: (String, Int)) =
+ <testcase name={res._1}>{
+ res._2 match {
+ case 0 => scala.xml.NodeSeq.Empty
+ case 1 => <failure message="Test failed"/>
+ case 2 => <failure message="Test timed out"/>
+ }
+ }</testcase>
+
+ def testReport(kind: String, results: Iterable[(String, Int)], succs: Int, fails: Int) =
+ <testsuite name={kind} tests={(succs + fails).toString} failures={fails.toString}>
+ <properties/>
+ {
+ results.map(oneResult(_))
+ }
+ </testsuite>
+}
diff --git a/src/partest/scala/tools/partest/Results.scala b/src/partest/scala/tools/partest/Results.scala
deleted file mode 100644
index 5d0e300136..0000000000
--- a/src/partest/scala/tools/partest/Results.scala
+++ /dev/null
@@ -1,121 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-
-import scala.collection.immutable
-
-trait Results {
- self: Universe =>
-
- /** A collection of tests for a Worker.
- */
- case class TestsToRun(entities: List[TestEntity])
-
- /** The response from a Worker who has been given TestsToRun.
- */
- case class ResultsOfRun(results: immutable.Map[TestEntity, TestResult])
-
- /** The result of a single test. (0: OK, 1: FAILED, 2: TIMEOUT)
- */
- sealed abstract class TestResult(val state: Int, val description: String) {
- def entity: TestEntity
-
- def passed = state == 0
- def colorize(s: String): String
- def show(msg: String) =
- if (!isShuttingDown)
- showResult(colorize(description), msg)
-
- private def outputPrefix = if (isInsideAnt) "" else markNormal("partest: ")
- private def name = src relativize entity.location // e.g. "neg/test.scala"
- private def showResult(status: String, extraMsg: String) =
- normal(outputPrefix + "[...]/%-40s [%s] %s\n".format(name, status, extraMsg))
-
- override def equals(other: Any) = other match {
- case x: TestResult => entity == x.entity
- case _ => false
- }
- override def hashCode = entity.hashCode
- override def toString = "%s [%s]".format(entity, description)
- }
-
- class Success(val entity: TestEntity) extends TestResult(0, " OK ") {
- def colorize(s: String) = markSuccess(s)
- override def show(msg: String) = if (!isTerse) super.show(msg)
- }
- class Failure(val entity: TestEntity) extends TestResult(1, " FAILED ") {
- def colorize(s: String) = markFailure(s)
-
- override def show(msg: String) = {
- super.show(msg)
-
- if (isShowDiff || isTrace)
- normal(entity.diffOutput)
-
- if (isShowLog || isTrace)
- normal(toStringTrunc(entity.failureMessage(), 1600))
- }
- override def toString = List(super.toString, toStringTrunc(entity.failureMessage(), 400)) mkString "\n"
- }
- class Timeout(val entity: TestEntity) extends TestResult(2, "TIME OUT") {
- def colorize(s: String) = markFailure(s)
- }
-
- object TestResult {
- def apply(entity: TestEntity, success: Boolean) =
- if (success) new Success(entity)
- else new Failure(entity)
-
- def apply(entity: TestEntity, state: Int) = state match {
- case 0 => new Success(entity)
- case 1 => new Failure(entity)
- case 2 => new Timeout(entity)
- }
- def unapply(x: Any) = x match {
- case x: TestResult => Some((x.entity, x.state))
- case _ => None
- }
- }
-
- /** The combined results of any number of tests.
- */
- case class CombinedTestResults(
- passed: Int,
- failed: Int,
- elapsedMilliseconds: Long,
- failures: List[TestResult]
- ) {
- // housekeeping
- val elapsedSecs = elapsedMilliseconds / 1000
- val elapsedMins = elapsedSecs / 60
- val elapsedHrs = elapsedMins / 60
- val dispMins = elapsedMins - elapsedHrs * 60
- val dispSecs = elapsedSecs - elapsedMins * 60
-
- def total = passed + failed
- def hasFailures = failed > 0
- def exitCode = if (expectedErrors == failed) 0 else 1
-
- def ++(x: CombinedTestResults) = CombinedTestResults(
- passed + x.passed,
- failed + x.failed,
- elapsedMilliseconds + x.elapsedMilliseconds,
- failures ::: x.failures
- )
-
- def elapsedString = "%02d:%02d:%02d".format(elapsedHrs, dispMins, dispSecs)
- def failuresString = {
- if (failures.isEmpty) ""
- else "Summary of failures:" :: failures mkString ("\n", "\n", "")
- }
-
- override def toString =
- if (total == 0) "There were no tests to run."
- else if (isDryRun) "%d tests would be run." format total
- else if (hasFailures) "%d of %d tests failed (elapsed time: %s)".format(failed, total, elapsedString) + failuresString
- else "All %d tests were successful (elapsed time: %s)".format(total, elapsedString)
- }
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/Runner.scala b/src/partest/scala/tools/partest/Runner.scala
deleted file mode 100644
index 1a28e60896..0000000000
--- a/src/partest/scala/tools/partest/Runner.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- * @author Philipp Haller
- */
-
-package scala.tools
-package partest
-
-import nsc.io._
-
-object Runner {
- def main(args: Array[String]) {
- val runner = Partest(args: _*)
- import runner._
-
- if (args.isEmpty) return println(helpMsg)
- if (isValidate) return validateAll()
-
- printConfigBanner()
-
- if (isCleanup)
- cleanupAll()
-
- val result = launchTestSuite()
- val exitCode = result.exitCode
- val message = "\n" + result + "\n"
-
- if (exitCode == 0) success(message)
- else failure(message)
-
- if (isStats)
- showTestStatistics()
-
- System exit exitCode
- }
-}
diff --git a/src/partest/scala/tools/partest/Statistics.scala b/src/partest/scala/tools/partest/Statistics.scala
deleted file mode 100644
index 2ea3c6e8f0..0000000000
--- a/src/partest/scala/tools/partest/Statistics.scala
+++ /dev/null
@@ -1,46 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- * @author Philipp Haller
- */
-
-package scala.tools
-package partest
-
-import scala.collection.mutable.HashMap
-
-trait Statistics {
- /** Only collected when --stats is given. */
- lazy val testStatistics = new HashMap[String, Long]
-
- /** Given function and block of code, evaluates code block,
- * calls function with milliseconds elapsed, and returns block result.
- */
- def timed[T](f: Long => Unit)(body: => T): T = {
- val start = System.currentTimeMillis
- val result = body
- val end = System.currentTimeMillis
-
- f(end - start)
- result
- }
- /** Times body and returns both values.
- */
- def timed2[T](body: => T): (Long, T) = {
- var milliSeconds = 0L
- val result = timed(x => milliSeconds = x)(body)
-
- (milliSeconds, result)
- }
-
- def resultsToStatistics(results: Iterable[(_, Int)]): (Int, Int) =
- (results partition (_._2 == 0)) match {
- case (winners, losers) => (winners.size, losers.size)
- }
-
- def recordTestTiming(name: String, milliseconds: Long) =
- synchronized { testStatistics(name) = milliseconds }
-
- def showTestStatistics() {
- testStatistics.toList sortBy (-_._2) foreach { case (k, v) => println("%s: %.2f seconds".format(k, (v.toDouble / 1000))) }
- }
-}
diff --git a/src/partest/scala/tools/partest/Universe.scala b/src/partest/scala/tools/partest/Universe.scala
deleted file mode 100644
index 942fc1a8be..0000000000
--- a/src/partest/scala/tools/partest/Universe.scala
+++ /dev/null
@@ -1,96 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala Parallel Testing **
-** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.tools
-package partest
-
-import nsc.io._
-import category.AllCategories
-import io.Logging
-
-/** The high level view of the partest infrastructure.
- */
-abstract class Universe
- extends Entities
- with BuildContributors
- with Logging
- with Dispatcher
- with Statistics
- with Housekeeping
- with Results
- with PartestCompilation
- with PartestSpec
- with Config
- with Alarms
- with Actions
- with Categories {
-
- /** The abstract values from which all else is derived. */
- def partestDir: Directory
- def testBuildDir: Directory
- def allCategories: List[TestCategory]
- def selectedCategories: List[TestCategory]
-
- /** Some plausibly abstract types. */
- type TestBuild <: BuildContributor // e.g. quick, pack
- type TestCategory <: AbsTestCategory // e.g. pos, neg, run
- type TestEntity <: AbsTestEntity // e.g. files/pos/test25.scala
- type TestSequence <: AbsTestSequence // e.g. compile, run, diff
-
- /** Although TestStep isn't much more than Function1 right now,
- * it exists this way so it can become more capable.
- */
- implicit def f1ToTestStep(f: TestEntity => Boolean): TestStep =
- new TestStep { def apply(test: TestEntity) = f(test) }
-
- abstract class TestStep extends (TestEntity => Boolean) {
- def apply(test: TestEntity): Boolean
- }
-
- /** An umbrella category of tests, such as "pos" or "run".
- */
- trait AbsTestCategory extends BuildContributor {
- type TestSettings
-
- def kind: String
- def testSequence: TestSequence
- def denotesTest(location: Path): Boolean
-
- def createTest(location: Path): TestEntity
- def createSettings(entity: TestEntity): TestSettings
- def enumerate: List[TestEntity]
- }
-
- /** A single test. It may involve multiple files, but only a
- * single path is used to designate it.
- */
- trait AbsTestEntity extends BuildContributor {
- def category: TestCategory
- def location: Path
- def onException(x: Throwable): Unit
- def testClasspath: String
-
- /** Most tests will use the sequence defined by the category,
- * but the test can override and define a custom sequence.
- */
- def testSequence: TestSequence
-
- /** True if this test recognizes the given path as a piece of it.
- * For validation purposes.
- */
- def acknowledges(path: Path): Boolean
- }
-
- /** Every TestEntity is partly characterized by a series of actions
- * which are applied to the TestEntity in the given order. The test
- * passes if all those actions return true, fails otherwise.
- */
- trait AbsTestSequence {
- def actions: List[TestStep]
- }
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/ant/JavaTask.scala b/src/partest/scala/tools/partest/ant/JavaTask.scala
deleted file mode 100644
index 6740554dd8..0000000000
--- a/src/partest/scala/tools/partest/ant/JavaTask.scala
+++ /dev/null
@@ -1,57 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala Parallel Testing **
-** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.tools
-package partest
-package ant
-
-import org.apache.tools.ant.Task
-import org.apache.tools.ant.taskdefs.Java
-import org.apache.tools.ant.types.Environment
-
-import scala.tools.nsc.io._
-import scala.tools.nsc.util.ClassPath
-import cmd.Spec._
-
-class JavaTask extends Java {
- override def getTaskName() = "partest"
- private val scalaRunnerClass = "scala.tools.nsc.MainGenericRunner"
- private val partestRunnerClass = "scala.tools.partest.Runner"
- def defaultJvmArgs = "-Xms64M -Xmx768M -Xss768K -XX:MaxPermSize=96M"
-
- protected def rootDir = prop("partest.rootdir") getOrElse (baseDir / "test").path
- protected def partestJVMArgs = prop("partest.jvm.args") getOrElse defaultJvmArgs
- protected def runnerArgs = List("-usejavacp", partestRunnerClass, "--javaopts", partestJVMArgs)
-
- private def baseDir = Directory(getProject.getBaseDir)
- private def prop(s: String) = Option(getProject getProperty s)
- private def jvmline(s: String) = returning(createJvmarg())(_ setLine s)
- private def addArg(s: String) = returning(createArg())(_ setValue s)
-
- private def newKeyValue(key: String, value: String) =
- returning(new Environment.Variable)(x => { x setKey key ; x setValue value })
-
- def setDefaults() {
- setFork(true)
- setFailonerror(true)
- getProject.setSystemProperties()
- setClassname(scalaRunnerClass)
- addSysproperty(newKeyValue("partest.is-in-ant", "true"))
- jvmline(partestJVMArgs)
- runnerArgs foreach addArg
-
- // do we want basedir or rootDir to be the cwd?
- // setDir(Path(rootDir).jfile)
- }
-
- override def init() = {
- super.init()
- setDefaults()
- }
-}
-
diff --git a/src/partest/scala/tools/partest/antlib.xml b/src/partest/scala/tools/partest/antlib.xml
index af36f11368..b3b98e853f 100644
--- a/src/partest/scala/tools/partest/antlib.xml
+++ b/src/partest/scala/tools/partest/antlib.xml
@@ -1,3 +1,4 @@
<antlib>
- <taskdef name="partest" classname="scala.tools.partest.ant.JavaTask"/>
+ <taskdef name="partest"
+ classname="scala.tools.partest.PartestTask"/>
</antlib>
diff --git a/src/partest/scala/tools/partest/category/AllCategories.scala b/src/partest/scala/tools/partest/category/AllCategories.scala
deleted file mode 100644
index 953f80324b..0000000000
--- a/src/partest/scala/tools/partest/category/AllCategories.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala Parallel Testing **
-** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.tools
-package partest
-package category
-
-trait AllCategories extends Compiler with Analysis with Runner {
- self: Universe =>
-
- object Pos extends DirBasedCategory("pos") { lazy val testSequence: TestSequence = List(compile) }
- object Neg extends DirBasedCategory("neg") { lazy val testSequence: TestSequence = List(checkFileRequired, not(compile), diff) }
- object Run extends DirBasedCategory("run") { lazy val testSequence: TestSequence = List(compile, run, diff) }
- object Jvm extends DirBasedCategory("jvm") { lazy val testSequence: TestSequence = List(compile, run, diff) }
-}
diff --git a/src/partest/scala/tools/partest/category/Analysis.scala b/src/partest/scala/tools/partest/category/Analysis.scala
deleted file mode 100644
index 2c6c208ee5..0000000000
--- a/src/partest/scala/tools/partest/category/Analysis.scala
+++ /dev/null
@@ -1,64 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-package category
-
-import java.lang.{ ClassLoader => JavaClassLoader }
-import java.net.URL
-import nsc.util.ScalaClassLoader
-import nsc.io._
-
-class PartestClassLoader(urls: Array[URL], parent: JavaClassLoader) extends ScalaClassLoader.URLClassLoader(urls, parent) {
- def this(urls: Array[URL]) = this(urls, null)
- def bytes(path: String) = findBytesForClassName(path)
- def singleton(path: String) = tryToInitializeClass(path).get getField "MODULE$" get null
-
- /** Calls a method in an object via reflection.
- */
- def apply[T](className: String, methodName: String)(args: Any*): T = {
- def fail = error("Reflection failed on %s.%s".format(className, methodName))
- val clazz = tryToLoadClass(className) getOrElse fail
- val obj = singleton(className)
- val m = clazz.getMethods find (x => x.getName == methodName && x.getParameterTypes.size == args.size) getOrElse fail
-
- m.invoke(obj, args map (_.asInstanceOf[AnyRef]): _*).asInstanceOf[T]
- }
-}
-
-trait Analysis {
- self: Universe =>
-
- object Scalap extends DirBasedCategory("scalap") {
- val testSequence: TestSequence = List(checkFileRequired, compile, run, diff)
- override def denotesTest(p: Path) = p.isDirectory && (p.toDirectory.files exists (_.name == "result.test"))
- override def createTest(location: Path) = new ScalapTest(location)
-
- class ScalapTest(val location: Path) extends TestEntity {
- val category = Scalap
- val scalapMain = "scala.tools.scalap.Main$"
- val scalapMethod = "decompileScala"
-
- override def classpathPaths = super.classpathPaths :+ build.scalap
- override def checkFile = File(location / "result.test")
-
- private def runnerURLs = build.classpathPaths ::: classpathPaths map (_.toURL)
- private def createClassLoader = new PartestClassLoader(runnerURLs.toArray, this.getClass.getClassLoader)
-
- val isPackageObject = containsString("package object")
- val suffix = if (isPackageObject) ".package" else ""
- val className = location.name.capitalize + suffix
-
- override def run() = loggingResult {
- def loader = createClassLoader
- def bytes = loader.bytes(className)
-
- trace("scalap %s".format(className))
- if (isDryRun) ""
- else loader[String](scalapMain, scalapMethod)(bytes, isPackageObject)
- }
- }
- }
-}
diff --git a/src/partest/scala/tools/partest/category/Compiler.scala b/src/partest/scala/tools/partest/category/Compiler.scala
deleted file mode 100644
index 49775d5031..0000000000
--- a/src/partest/scala/tools/partest/category/Compiler.scala
+++ /dev/null
@@ -1,140 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-package category
-
-import nsc.io._
-import nsc.reporters._
-import nsc.{ Settings, CompilerCommand }
-import scala.tools.nsc.interactive.RefinedBuildManager
-import util.copyPath
-
-trait Compiler {
- self: Universe =>
-
- /** Resident Compiler.
- * $SCALAC -d dir.obj -Xresident -sourcepath . "$@"
- */
- object Res extends DirBasedCategory("res") {
- lazy val testSequence: TestSequence = List(checkFileRequired, compile, diff)
-
- override def denotesTest(p: Path) = p.isDirectory && resFile(p).isFile
- override def createTest(location: Path) = new ResidentTest(location.toDirectory)
-
- override def createSettings(entity: TestEntity): TestSettings =
- returning(super.createSettings(entity)) { settings =>
- settings.resident.value = true
- settings.sourcepath.value = entity.sourcesDir.path
- }
-
- class ResidentTest(val location: Directory) extends TestEntity {
- val category = Res
- override def sourcesDir = categoryDir
-
- override def acknowledges(p: Path) =
- super.acknowledges(p) || (resFile(location) isSame p)
-
- private def residentCompilerCommands = safeLines(resFile(location))
- private def compileResident(global: PartestGlobal, lines: List[String]) = {
- def printPrompt = global inform "nsc> "
- val results =
- lines map { line =>
- printPrompt
- trace("compile " + line)
- isDryRun || global.partestCompile(toArgs(line) map (categoryDir / _ path), false)
- }
-
- printPrompt
-
- /** Note - some res tests are really "neg" style tests, so we can't
- * use the return value of the compile. The diff catches failures.
- */
- true // results forall (_ == true)
- }
-
- override def compile() = compileResident(newGlobal(Nil)._1, residentCompilerCommands)
- }
- private[Res] def resFile(p: Path) = p.toFile addExtension "res"
- }
-
- object BuildManager extends DirBasedCategory("buildmanager") {
- lazy val testSequence: TestSequence = List(checkFileRequired, compile, diff)
- override def denotesTest(p: Path) = p.isDirectory && testFile(p).isFile
- override def createTest(location: Path) = new BuildManagerTest(location.toDirectory)
-
- override def createSettings(entity: TestEntity): TestSettings =
- returning[TestSettings](super.createSettings(entity)) { settings =>
- settings.Ybuildmanagerdebug.value = true
- settings.sourcepath.value = entity.sourcesDir.path
- }
-
- class PartestBuildManager(settings: Settings, val reporter: ConsoleReporter) extends RefinedBuildManager(settings) {
- def errorFn(msg: String) = Console println msg
-
- override protected def newCompiler(newSettings: Settings) =
- new BuilderGlobal(newSettings, reporter)
-
- private def filesToSet(pre: String, fs: List[String]): Set[AbstractFile] =
- fs flatMap (s => Option(AbstractFile getFile (Path(settings.sourcepath.value) / s path))) toSet
-
- def buildManagerCompile(line: String): Boolean = {
- val prompt = "builder > "
- reporter printMessage (prompt + line)
- val command = new CompilerCommand(toArgs(line), settings)
- val files = filesToSet(settings.sourcepath.value, command.files)
-
- update(files, Set.empty)
- true
- }
- }
-
- private[BuildManager] def testFile(p: Path) = (p / p.name addExtension "test").toFile
-
- class BuildManagerTest(val location: Directory) extends TestEntity {
- val category = BuildManager
-
- override def sourcesDir = outDir
- override def sourceFiles = Path onlyFiles (location walkFilter (_ != changesDir) filter isJavaOrScala toList)
- override def checkFile = File(location / location.name addExtension "check")
-
- override def acknowledges(p: Path) = super.acknowledges(p) || (p isSame testFile(location))
-
- def buildManagerCommands = safeLines(testFile(location))
- def changesDir = Directory(location / (location.name + ".changes"))
-
- override def compile() = {
- val settings = createSettings(this)
- val pbm = new PartestBuildManager(settings, newReporter(settings))
-
- // copy files
- for (source <- sourceFiles) {
- val target = outDir / (location.normalize relativize source)
- copyPath(source, target.toFile)
- }
-
- def runUpdate(line: String) = {
- val Array(srcName, replacement) = line split "=>"
- copyPath(File(changesDir / replacement), File(outDir / srcName))
- }
-
- def sendCommand(line: String): Boolean = {
- val compileRegex = """^>>compile (.*)$""".r
- val updateRegex = """^>>update\s+(.*)""".r
- trace("send: " + (line drop 2))
-
- isDryRun || (line match {
- case compileRegex(xs) => pbm.buildManagerCompile(xs)
- case updateRegex(line) => runUpdate(line)
- })
- }
-
- // send each line to the build manager
- buildManagerCommands forall sendCommand
- }
- }
- }
-}
-
diff --git a/src/partest/scala/tools/partest/category/Runner.scala b/src/partest/scala/tools/partest/category/Runner.scala
deleted file mode 100644
index 10bf5794a9..0000000000
--- a/src/partest/scala/tools/partest/category/Runner.scala
+++ /dev/null
@@ -1,108 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala Parallel Testing **
-** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.tools
-package partest
-package category
-
-import nsc.io._
-
-trait Runner {
- self: Universe =>
-
- /** Shootout.
- */
- object Shootout extends DirBasedCategory("shootout") {
- lazy val testSequence: TestSequence = List(compile, run, diff)
-
- override def denotesTest(p: Path) = isScala(p) && runner(p).isFile
- override def createTest(location: Path) = new ShootoutTest(location.toFile)
-
- class ShootoutTest(val location: File) extends TestEntity {
- val category = Shootout
- // The files in shootout are very free form, so acknowledge anything close.
- override def acknowledges(p: Path) =
- (p.parent.normalize isSame Shootout.root) && (p.name startsWith label)
-
- private def generated = File(outDir / "test.scala")
- private def runnerFile = runner(location)
- override def sourceFiles = List(generated)
-
- override def compile() = {
- trace("generate %s from %s, %s".format(tracePath(generated), tracePath(location), tracePath(runnerFile)))
- // generate source file (even on dry run, we need the path)
- generated.writeAll(location.slurp(), runnerFile.slurp())
-
- // compile generated file
- super.compile()
- }
- }
-
- private[Shootout] def runner(p: Path) = p addExtension "runner" toFile
- }
-
- object Scalacheck extends DirBasedCategory("scalacheck") {
- lazy val testSequence: TestSequence = List(compile, run)
- override def createTest(location: Path) = new ScalacheckTest(location)
-
- class ScalacheckTest(val location: Path) extends TestEntity {
- val category = Scalacheck
-
- import build.{ scalacheck, forkjoin }
- import org.scalacheck.Properties
- import org.scalacheck.Test.{ checkProperties, defaultParams, Result }
-
- override def classpathPaths = super.classpathPaths ::: List(scalacheck, forkjoin)
- private def arrayURLs = Array(scalacheck, outDir) map (_.toURL)
-
- /** For reasons I'm not entirely clear on, I've written all this
- * to avoid a source dependency on scalacheck.
- */
- class ScalacheckClassLoader extends PartestClassLoader(arrayURLs, this.getClass.getClassLoader) {
- type ScalacheckResult = { def passed: Boolean }
-
- def propCallback(name: String, passed: Int, discarded: Int): Unit = ()
- def testCallback(name: String, result: AnyRef): Unit = ()
-
- val test = singleton("Test$")
- val params = apply[AnyRef]("org.scalacheck.Test$", "defaultParams")()
- val result = apply[Seq[(String, AnyRef)]]("org.scalacheck.Test$", "checkProperties")(test, params, propCallback _, testCallback _)
-
- def allResults() =
- for ((prop, res) <- result) yield {
- ScalacheckTest.this.trace("%s: %s".format(prop, res))
- res.asInstanceOf[ScalacheckResult].passed
- }
-
- def check() = allResults forall (_ == true)
- }
-
- override def run() = {
- trace("scalacheck runs via classloader with: %s".format(arrayURLs mkString ", "))
- isDryRun || (new ScalacheckClassLoader check)
- }
- }
- }
-
- object Script extends DirBasedCategory("script") {
- val testSequence: TestSequence = List(exec, diff)
- override def createTest(location: Path) = new ScriptTest(location)
-
- class ScriptTest(val location: Path) extends TestEntity {
- val category = Script
- val scriptFile = if (location.isDirectory) location / (label + ".scala") else location
- val argsFile = withExtension("args").toFile
- def batFile = scriptFile changeExtension "bat"
- def script = if (Properties.isWin) batFile else scriptFile
-
- override def acknowledges(p: Path) = super.acknowledges(p) || (List(argsFile, batFile) exists (_ isSame p))
- override def execCwd = Some(sourcesDir)
- override def argumentsToExec = script.path :: safeArgs(argsFile)
- }
- }
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/io/ANSIWriter.scala b/src/partest/scala/tools/partest/io/ANSIWriter.scala
deleted file mode 100644
index 0ddcd97a5f..0000000000
--- a/src/partest/scala/tools/partest/io/ANSIWriter.scala
+++ /dev/null
@@ -1,58 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- * @author Philipp Haller
- */
-
-package scala.tools
-package partest
-package io
-
-import java.io.{ Writer, PrintWriter, OutputStream, OutputStreamWriter }
-
-object ANSIWriter {
- val NONE = 0
- val SOME = 1
- val MANY = 2
-
- def apply(isAnsi: Boolean) = if (isAnsi) MANY else NONE
-}
-import ANSIWriter._
-
-class ANSIWriter(writer: Writer) extends PrintWriter(writer, true) {
- def this(out: OutputStream) = this(new OutputStreamWriter(out))
- def colorful: Int = NONE
-
- protected val manyColors = List(
- Console.BOLD + Console.BLACK,
- Console.BOLD + Console.GREEN,
- Console.BOLD + Console.RED,
- Console.BOLD + Console.YELLOW,
- Console.RESET
- )
- protected val someColors = List(
- Console.BOLD + Console.BLACK,
- Console.RESET,
- Console.BOLD + Console.BLACK,
- Console.BOLD + Console.BLACK,
- Console.RESET
- )
- protected val noColors = List("", "", "", "", "")
-
- lazy val List(_outline, _success, _failure, _warning, _default) = colorful match {
- case NONE => noColors
- case SOME => someColors
- case MANY => manyColors
- case _ => noColors
- }
-
- private def wrprint(msg: String): Unit = synchronized {
- print(msg)
- flush()
- }
-
- def outline(msg: String) = wrprint(_outline + msg + _default)
- def success(msg: String) = wrprint(_success + msg + _default)
- def failure(msg: String) = wrprint(_failure + msg + _default)
- def warning(msg: String) = wrprint(_warning + msg + _default)
- def normal(msg: String) = wrprint(_default + msg)
-}
diff --git a/src/partest/scala/tools/partest/io/JUnitReport.scala b/src/partest/scala/tools/partest/io/JUnitReport.scala
deleted file mode 100644
index 63ae200020..0000000000
--- a/src/partest/scala/tools/partest/io/JUnitReport.scala
+++ /dev/null
@@ -1,38 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-package io
-
-/** This is disabled for the moment but I can fix it up if anyone
- * is using it.
- */
-class JUnitReport {
- // create JUnit Report xml files if directory was specified
- // def junitReport(dir: Directory) = {
- // dir.mkdir()
- // val report = testReport(set.kind, results, succs, fails)
- // XML.save("%s/%s.xml".format(d.toAbsolute.path, set.kind), report)
- // }
-
- // def oneResult(res: (TestEntity, Int)) =
- // <testcase name={res._1.path}>{
- // res._2 match {
- // case 0 => scala.xml.NodeSeq.Empty
- // case 1 => <failure message="Test failed"/>
- // case 2 => <failure message="Test timed out"/>
- // }
- // }</testcase>
- //
- // def testReport(kind: String, results: Iterable[(TestEntity, Int)], succs: Int, fails: Int) = {
- // <testsuite name={kind} tests={(succs + fails).toString} failures={fails.toString}>
- // <properties/>
- // {
- // results.map(oneResult(_))
- // }
- // </testsuite>
- // }
- //
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/io/Logging.scala b/src/partest/scala/tools/partest/io/Logging.scala
deleted file mode 100644
index 52239ffb2c..0000000000
--- a/src/partest/scala/tools/partest/io/Logging.scala
+++ /dev/null
@@ -1,137 +0,0 @@
-package scala.tools
-package partest
-package io
-
-import java.io.{ StringWriter, PrintWriter, Writer }
-import scala.tools.nsc.io._
-import scala.util.control.ControlThrowable
-
-trait Logging {
- universe: Universe =>
-
- class PartestANSIWriter extends ANSIWriter(Console.out) {
- override def colorful: Int = ANSIWriter(universe.isAnsi)
- private def printIf(cond: Boolean, msg: String) =
- if (cond) { outline("debug: ") ; println(msg) }
-
- val verbose = printIf(isVerbose || isDebug, _: String)
- val debug = printIf(isDebug, _: String)
- }
-
- lazy val NestUI = new PartestANSIWriter()
-
- import NestUI.{ _outline, _success, _failure, _warning, _default }
-
- def markOutline(msg: String) = _outline + msg + _default
- def markSuccess(msg: String) = _success + msg + _default
- def markFailure(msg: String) = _failure + msg + _default
- def markWarning(msg: String) = _warning + msg + _default
- def markNormal(msg: String) = _default + msg
-
- def outline(msg: String) = NestUI outline msg
- def success(msg: String) = NestUI success msg
- def failure(msg: String) = NestUI failure msg
- def warning(msg: String) = NestUI warning msg
- def normal(msg: String) = NestUI normal msg
-
- def verbose(msg: String) = NestUI verbose msg
- def debug(msg: String) = NestUI debug msg
-
- trait EntityLogging {
- self: TestEntity =>
-
- lazy val logWriter = new LogWriter(logFile)
-
- /** Redirect stdout and stderr to logFile, run body, return result.
- */
- def loggingOutAndErr[T](body: => T): T = {
- val log = logFile.printStream(append = true)
-
- try Console.withOut(log) {
- Console.withErr(log) {
- body
- }
- }
- finally log.close()
- }
-
- /** What to print in a failure summary.
- */
- def failureMessage() = if (diffOutput != "") diffOutput else safeSlurp(logFile)
-
- /** For tracing. Outputs a line describing the next action. tracePath
- * is a path wrapper which prints name or full path depending on verbosity.
- */
- def trace(msg: String) = if (isTrace || isDryRun) System.err.println(">> [%s] %s".format(label, msg))
-
- def tracePath(path: Path): String = if (isVerbose) path.path else path.name
- def tracePath(path: String): String = tracePath(Path(path))
-
- /** v == verbose.
- */
- def vtrace(msg: String) = if (isVerbose) trace(msg)
-
- /** Run body, writes result to logFile. Any throwable is
- * caught, stringified, and written to the log.
- */
- def loggingResult(body: => String) =
- try returning(true)(_ => logFile writeAll body)
- catch {
- case x: ControlThrowable => throw x
- case x: InterruptedException => debug(this + " received interrupt, failing.\n") ; false
- case x: Throwable => logException(x)
- }
-
- def throwableToString(x: Throwable): String = {
- val w = new StringWriter
- x.printStackTrace(new PrintWriter(w))
- w.toString
- }
-
- def warnAndLog(str: String) = {
- warning(toStringTrunc(str, 800))
- logWriter append str
- }
-
- def warnAndLogException(msg: String, ex: Throwable) =
- warnAndLog(msg + throwableToString(ex))
-
- def deleteLog(force: Boolean = false) =
- if (universe.isNoCleanup && !force) debug("Not cleaning up " + logFile)
- else logFile.deleteIfExists()
-
- def onException(x: Throwable) { logException(x) }
- def logException(x: Throwable) = {
- val msg = throwableToString(x)
- if (!isTerse)
- normal(msg)
-
- logWriter append msg
- false
- }
- }
-
- /** A writer which doesn't create the file until a write comes in.
- */
- class LazilyCreatedWriter(log: File) extends Writer {
- @volatile private var isCreated = false
- private lazy val underlying = {
- isCreated = true
- log.bufferedWriter()
- }
-
- def flush() = if (isCreated) underlying.flush()
- def close() = if (isCreated) underlying.close()
- def write(chars: Array[Char], off: Int, len: Int) = {
- underlying.write(chars, off, len)
- underlying.flush()
- }
- }
-
- class LogWriter(log: File) extends PrintWriter(new LazilyCreatedWriter(log), true) {
- override def print(s: String) = {
- super.print(s)
- flush()
- }
- }
-} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala
new file mode 100644
index 0000000000..cb819720fc
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/AntRunner.scala
@@ -0,0 +1,30 @@
+/* __ *\
+** ________ ___ / / ___ Scala Parallel Testing **
+** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.File
+import scala.tools.nsc.io.{ Directory }
+
+class AntRunner extends DirectRunner {
+
+ val fileManager = new FileManager {
+ var JAVACMD: String = "java"
+ var JAVAC_CMD: String = "javac"
+ var CLASSPATH: String = _
+ var LATEST_LIB: String = _
+ val testRootPath: String = "test"
+ val testRootDir: Directory = Directory(testRootPath)
+ }
+
+ def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String) =
+ runTestsForFiles(kindFiles.toList, kind)
+}
diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala
new file mode 100644
index 0000000000..22568ad2d0
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/CompileManager.scala
@@ -0,0 +1,197 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io }
+import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
+import scala.tools.nsc.util.ClassPath
+import scala.tools.util.PathResolver
+import io.Path
+
+import java.io.{ File, BufferedReader, PrintWriter, FileReader, Writer, FileWriter, StringWriter }
+import File.pathSeparator
+
+class ExtConsoleReporter(override val settings: Settings, reader: BufferedReader, var writer: PrintWriter)
+extends ConsoleReporter(settings, reader, writer) {
+ def this(settings: Settings) = this(settings, Console.in, new PrintWriter(new FileWriter("/dev/null")))
+}
+
+abstract class SimpleCompiler {
+ def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean
+}
+
+class TestSettings(fileMan: FileManager) extends Settings(_ => ()) { }
+
+class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler {
+ def newGlobal(settings: Settings, reporter: Reporter): Global =
+ new Global(settings, reporter)
+
+ def newGlobal(settings: Settings, logWriter: FileWriter): Global = {
+ val rep = newReporter(settings, logWriter)
+ rep.shortname = true
+ newGlobal(settings, rep)
+ }
+
+ def newSettings(out: Option[String]) = {
+ val settings = new TestSettings(fileManager)
+ settings.usejavacp.value = true
+ settings.deprecation.value = true
+ settings.nowarnings.value = false
+ settings.encoding.value = "ISO-8859-1" // XXX why?
+
+ val classpathElements = settings.classpath.value :: fileManager.LATEST_LIB :: out.toList
+ settings.classpath.value = ClassPath.join(classpathElements: _*)
+ out foreach (settings.outdir.value = _)
+
+ settings
+ }
+
+ def newReporter(sett: Settings, writer: Writer = new StringWriter) =
+ new ExtConsoleReporter(sett, Console.in, new PrintWriter(writer))
+
+ private def updatePluginPath(options: String): String = {
+ val dir = fileManager.testRootDir
+ def absolutize(path: String) = Path(path) match {
+ case x if x.isAbsolute => x.path
+ case x => (fileManager.testRootDir / x).toAbsolute.path
+ }
+
+ val (opt1, opt2) = (options split "\\s").toList partition (_ startsWith "-Xplugin:")
+ val plugins = opt1 map (_ stripPrefix "-Xplugin:") flatMap (_ split pathSeparator) map absolutize
+ val pluginOption = if (opt1.isEmpty) Nil else List("-Xplugin:" + (plugins mkString pathSeparator))
+
+ (opt2 ::: pluginOption) mkString " "
+ }
+
+ def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean = {
+ val testSettings = newSettings(out map (_.getAbsolutePath))
+ val logWriter = new FileWriter(log)
+
+ // check whether there is a ".flags" file
+ val flagsFileName = "%s.flags" format (basename(log.getName) dropRight 4) // 4 is "-run" or similar
+ val argString = (io.File(log).parent / flagsFileName) ifFile (x => updatePluginPath(x.slurp())) getOrElse ""
+ val allOpts = fileManager.SCALAC_OPTS+" "+argString
+ val args = (allOpts split "\\s").toList
+
+ NestUI.verbose("scalac options: "+allOpts)
+
+ val command = new CompilerCommand(args, testSettings)
+ val global = newGlobal(command.settings, logWriter)
+ val testRep: ExtConsoleReporter = global.reporter.asInstanceOf[ExtConsoleReporter]
+
+ val testFileFn: (File, FileManager) => TestFile = kind match {
+ case "pos" => PosTestFile.apply
+ case "neg" => NegTestFile.apply
+ case "run" => RunTestFile.apply
+ case "jvm" => JvmTestFile.apply
+ case "shootout" => ShootoutTestFile.apply
+ case "scalap" => ScalapTestFile.apply
+ case "scalacheck" => ScalaCheckTestFile.apply
+ }
+ val test: TestFile = testFileFn(files.head, fileManager)
+ test.defineSettings(command.settings, out.isEmpty)
+ val toCompile = files map (_.getPath)
+
+ try {
+ NestUI.verbose("compiling "+toCompile)
+ try new global.Run compile toCompile
+ catch {
+ case FatalError(msg) =>
+ testRep.error(null, "fatal error: " + msg)
+ }
+
+ testRep.printSummary
+ testRep.writer.flush
+ testRep.writer.close
+ }
+ catch {
+ case e =>
+ e.printStackTrace()
+ return false
+ }
+ finally logWriter.close()
+
+ !testRep.hasErrors
+ }
+}
+
+// class ReflectiveCompiler(val fileManager: ConsoleFileManager) extends SimpleCompiler {
+// import fileManager.{latestCompFile, latestPartestFile}
+//
+// val sepUrls = Array(latestCompFile.toURI.toURL, latestPartestFile.toURI.toURL)
+// //NestUI.verbose("constructing URLClassLoader from URLs "+latestCompFile+" and "+latestPartestFile)
+//
+// val sepLoader = new java.net.URLClassLoader(sepUrls, null)
+//
+// val sepCompilerClass =
+// sepLoader.loadClass("scala.tools.partest.nest.DirectCompiler")
+// val sepCompiler = sepCompilerClass.newInstance()
+//
+// // needed for reflective invocation
+// val fileClass = Class.forName("java.io.File")
+// val stringClass = Class.forName("java.lang.String")
+// val sepCompileMethod =
+// sepCompilerClass.getMethod("compile", fileClass, stringClass)
+// val sepCompileMethod2 =
+// sepCompilerClass.getMethod("compile", fileClass, stringClass, fileClass)
+//
+// /* This method throws java.lang.reflect.InvocationTargetException
+// * if the compiler crashes.
+// * This exception is handled in the shouldCompile and shouldFailCompile
+// * methods of class CompileManager.
+// */
+// def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean = {
+// val res = sepCompileMethod2.invoke(sepCompiler, out, files, kind, log).asInstanceOf[java.lang.Boolean]
+// res.booleanValue()
+// }
+// }
+
+class CompileManager(val fileManager: FileManager) {
+ var compiler: SimpleCompiler = new /*ReflectiveCompiler*/ DirectCompiler(fileManager)
+
+ var numSeparateCompilers = 1
+ def createSeparateCompiler() = {
+ numSeparateCompilers += 1
+ compiler = new /*ReflectiveCompiler*/ DirectCompiler(fileManager)
+ }
+
+ /* This method returns true iff compilation succeeds.
+ */
+ def shouldCompile(files: List[File], kind: String, log: File): Boolean = {
+ createSeparateCompiler()
+ compiler.compile(None, files, kind, log)
+ }
+
+ /* This method returns true iff compilation succeeds.
+ */
+ def shouldCompile(out: File, files: List[File], kind: String, log: File): Boolean = {
+ createSeparateCompiler()
+ compiler.compile(Some(out), files, kind, log)
+ }
+
+ /* This method returns true iff compilation fails
+ * _and_ the compiler does _not_ crash or loop.
+ *
+ * If the compiler crashes, this method returns false.
+ */
+ def shouldFailCompile(files: List[File], kind: String, log: File): Boolean = {
+ createSeparateCompiler()
+ !compiler.compile(None, files, kind, log)
+ }
+
+ /* This method returns true iff compilation fails
+ * _and_ the compiler does _not_ crash or loop.
+ *
+ * If the compiler crashes, this method returns false.
+ */
+ def shouldFailCompile(out: File, files: List[File], kind: String, log: File): Boolean = {
+ createSeparateCompiler()
+ !compiler.compile(Some(out), files, kind, log)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
new file mode 100644
index 0000000000..58d16a3f45
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
@@ -0,0 +1,190 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{ File, FilenameFilter, IOException, StringWriter }
+import java.net.URI
+import scala.util.Properties.{ propOrElse, scalaCmd, scalacCmd }
+import scala.tools.util.PathResolver
+import scala.tools.nsc.{ Settings }
+import scala.tools.nsc.{ io, util }
+import util.{ ClassPath }
+import io.{ Path, Directory }
+import File.pathSeparator
+import ClassPath.{ join }
+import PathResolver.{ Environment, Defaults }
+import RunnerUtils._
+
+
+class ConsoleFileManager extends FileManager {
+ var testBuild: Option[String] = PartestDefaults.testBuild
+ def testBuildFile = testBuild map (testParent / _)
+
+ var testClasses: Option[String] = None
+
+ def this(buildPath: String, rawClasses: Boolean) = {
+ this()
+ if (rawClasses)
+ testClasses = Some(buildPath)
+ else
+ testBuild = Some(buildPath)
+ // re-run because initialization of default
+ // constructor must be updated
+ findLatest()
+ }
+
+ def this(buildPath: String) = {
+ this(buildPath, false)
+ }
+
+ def this(buildPath: String, rawClasses: Boolean, moreOpts: String) = {
+ this(buildPath, rawClasses)
+ SCALAC_OPTS = SCALAC_OPTS+" "+moreOpts
+ }
+
+ lazy val srcDir = PathSettings.srcDir
+ lazy val testRootDir = PathSettings.testRoot
+ lazy val testRootPath = testRootDir.toAbsolute.path
+ def testParent = testRootDir.parent
+
+ var CLASSPATH = PartestDefaults.classPath
+ var JAVACMD = PartestDefaults.javaCmd
+ var JAVAC_CMD = PartestDefaults.javacCmd
+
+
+ NestUI.verbose("CLASSPATH: "+CLASSPATH)
+
+ if (!srcDir.isDirectory) {
+ NestUI.failure("Source directory \"" + srcDir.path + "\" not found")
+ exit(1)
+ }
+
+ CLASSPATH = {
+ val libs = (srcDir / Directory("lib")).files filter (_ hasExtension "jar") map (_.normalize.path)
+
+ // add all jars in libs
+ (CLASSPATH :: libs.toList) mkString pathSeparator
+ }
+
+ def findLatest() {
+ NestUI.verbose("test parent: "+testParent)
+
+ def prefixFileWith(parent: File, relPath: String) = (io.File(parent) / relPath).normalize
+ def prefixFile(relPath: String) = (testParent / relPath).normalize
+
+ if (!testClasses.isEmpty) {
+ testClassesDir = Path(testClasses.get).normalize.toDirectory
+ NestUI.verbose("Running with classes in "+testClassesDir)
+
+ latestFile = testClassesDir.parent / "bin"
+ latestLibFile = testClassesDir / "library"
+ latestCompFile = testClassesDir / "compiler"
+ latestPartestFile = testClassesDir / "partest"
+ latestFjbgFile = testParent / "lib" / "fjbg.jar"
+ }
+ else if (testBuild.isDefined) {
+ val dir = Path(testBuild.get)
+ NestUI.verbose("Running on "+dir)
+ latestFile = dir / "bin"
+ latestLibFile = dir / "lib/scala-library.jar"
+ latestCompFile = dir / "lib/scala-compiler.jar"
+ latestPartestFile = dir / "lib/scala-partest.jar"
+ }
+ else {
+ def setupQuick() {
+ NestUI.verbose("Running build/quick")
+ latestFile = prefixFile("build/quick/bin")
+ latestLibFile = prefixFile("build/quick/classes/library")
+ latestCompFile = prefixFile("build/quick/classes/compiler")
+ latestPartestFile = prefixFile("build/quick/classes/partest")
+ }
+
+ def setupInst() {
+ NestUI.verbose("Running dist (installed)")
+ val p = testParent.getParentFile
+ latestFile = prefixFileWith(p, "bin")
+ latestLibFile = prefixFileWith(p, "lib/scala-library.jar")
+ latestCompFile = prefixFileWith(p, "lib/scala-compiler.jar")
+ latestPartestFile = prefixFileWith(p, "lib/scala-partest.jar")
+ }
+
+ def setupDist() {
+ NestUI.verbose("Running dists/latest")
+ latestFile = prefixFile("dists/latest/bin")
+ latestLibFile = prefixFile("dists/latest/lib/scala-library.jar")
+ latestCompFile = prefixFile("dists/latest/lib/scala-compiler.jar")
+ latestPartestFile = prefixFile("dists/latest/lib/scala-partest.jar")
+ }
+
+ def setupPack() {
+ NestUI.verbose("Running build/pack")
+ latestFile = prefixFile("build/pack/bin")
+ latestLibFile = prefixFile("build/pack/lib/scala-library.jar")
+ latestCompFile = prefixFile("build/pack/lib/scala-compiler.jar")
+ latestPartestFile = prefixFile("build/pack/lib/scala-partest.jar")
+ }
+
+ val dists = testParent / "dists"
+ val build = testParent / "build"
+ // in case of an installed dist, testRootDir is one level deeper
+ val bin = testParent.parent / "bin"
+
+ def mostRecentOf(base: String, names: String*) =
+ names map (x => prefixFile(base + "/" + x).lastModified) reduceLeft (_ max _)
+
+ // detect most recent build
+ val quickTime = mostRecentOf("build/quick/classes", "compiler/compiler.properties", "library/library.properties")
+ val packTime = mostRecentOf("build/pack/lib", "scala-compiler.jar", "scala-library.jar")
+ val distTime = mostRecentOf("dists/latest/lib", "scala-compiler.jar", "scala-library.jar")
+ val instTime = mostRecentOf("lib", "scala-compiler.jar", "scala-library.jar")
+
+ val pairs = Map(
+ (quickTime, () => setupQuick()),
+ (packTime, () => setupPack()),
+ (distTime, () => setupDist()),
+ (instTime, () => setupInst())
+ )
+
+ // run setup based on most recent time
+ pairs(pairs.keys max)()
+
+ latestFjbgFile = prefixFile("lib/fjbg.jar")
+ }
+
+ LATEST_LIB = latestLibFile.getAbsolutePath
+ }
+
+ var LATEST_LIB: String = ""
+
+ var latestFile: File = _
+ var latestLibFile: File = _
+ var latestCompFile: File = _
+ var latestPartestFile: File = _
+ var latestFjbgFile: File = _
+ var testClassesDir: Directory = _
+ // initialize above fields
+ findLatest()
+
+ var testFiles: List[io.Path] = Nil
+
+ def getFiles(kind: String, cond: Path => Boolean): List[File] = {
+ def ignoreDir(p: Path) = List("svn", "obj") exists (p hasExtension _)
+
+ val dir = Directory(srcDir / kind)
+
+ if (dir.isDirectory) NestUI.verbose("look in %s for tests" format dir)
+ else NestUI.failure("Directory '%s' not found" format dir)
+
+ val files =
+ if (testFiles.nonEmpty) testFiles filter (_.parent isSame dir)
+ else dir.list filterNot ignoreDir filter cond toList
+
+ ( if (failed) files filter (x => logFileExists(x, kind)) else files ) map (_.jfile)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
new file mode 100644
index 0000000000..eae79f23af
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
@@ -0,0 +1,209 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{File, PrintStream, FileOutputStream, BufferedReader,
+ InputStreamReader, StringWriter, PrintWriter}
+import utils.Properties._
+import RunnerUtils._
+import scala.tools.nsc.Properties.{ versionMsg, setProp }
+import scala.tools.nsc.util.CommandLineParser
+import scala.tools.nsc.io
+import scala.tools.nsc.interpreter.returning
+import io.{ Path, Process }
+
+class ConsoleRunner extends DirectRunner {
+ import PathSettings.{ srcDir, testRoot }
+
+ case class TestSet(kind: String, filter: Path => Boolean, msg: String)
+
+ val testSets = {
+ val pathFilter: Path => Boolean = _ hasExtension "scala"
+
+ List(
+ TestSet("pos", pathFilter, "Testing compiler (on files whose compilation should succeed)"),
+ TestSet("neg", pathFilter, "Testing compiler (on files whose compilation should fail)"),
+ TestSet("run", pathFilter, "Testing JVM backend"),
+ TestSet("jvm", pathFilter, "Testing JVM backend"),
+ TestSet("res", x => x.isFile && (x hasExtension "res"), "Testing resident compiler"),
+ TestSet("buildmanager", _.isDirectory, "Testing Build Manager"),
+ TestSet("shootout", pathFilter, "Testing shootout tests"),
+ TestSet("script", pathFilter, "Testing script tests"),
+ TestSet("scalacheck", pathFilter, "Testing ScalaCheck tests"),
+ TestSet("scalap", _.isDirectory, "Run scalap decompiler tests")
+ )
+ }
+
+ var fileManager: ConsoleFileManager = _
+
+ private var testFiles: List[File] = List()
+ private val errors = PartestDefaults.errorCount
+ private val testSetKinds = testSets map (_.kind)
+ private val testSetArgs = testSets map ("--" + _.kind)
+ private val testSetArgMap = testSetArgs zip testSets toMap
+
+ def denotesTestSet(arg: String) = testSetArgs contains arg
+ def denotesTestFile(arg: String) = (arg endsWith ".scala") || (arg endsWith ".res")
+ def denotesTestDir(arg: String) = Path(arg).isDirectory
+ def denotesTestPath(arg: String) = denotesTestDir(arg) || denotesTestFile(arg)
+
+ private def printVersion { NestUI outline (versionMsg + "\n") }
+
+ private val unaryArgs = List(
+ "--pack", "--all", "--verbose", "--show-diff", "--show-log",
+ "--failed", "--version", "--ansi", "--debug"
+ ) ::: testSetArgs
+
+ private val binaryArgs = List(
+ "--grep", "--srcpath", "--buildpath", "--classpath"
+ )
+
+ def main(argstr: String) {
+ val parsed = CommandLineParser(argstr) withUnaryArgs unaryArgs withBinaryArgs binaryArgs
+ val args = parsed.residualArgs
+
+ /** Early return on no args, version, or invalid args */
+ if (argstr == "") return NestUI.usage()
+ if (parsed isSet "--version") return printVersion
+ if (args exists (x => !denotesTestPath(x))) {
+ val invalid = (args filterNot denotesTestPath).head
+ NestUI.failure("Invalid argument '%s'\n" format invalid)
+ return NestUI.usage()
+ }
+
+ parsed get "--srcpath" foreach (x => setProp("partest.srcdir", x))
+
+ fileManager =
+ if (parsed isSet "--buildpath") new ConsoleFileManager(parsed("--buildpath"))
+ else if (parsed isSet "--classpath") new ConsoleFileManager(parsed("--classpath"), true)
+ else if (parsed isSet "--pack") new ConsoleFileManager("build/pack")
+ else new ConsoleFileManager // auto detection, see ConsoleFileManager.findLatest
+
+ def argNarrowsTests(x: String) = denotesTestSet(x) || denotesTestFile(x) || denotesTestDir(x)
+
+ NestUI._verbose = parsed isSet "--verbose"
+ fileManager.showDiff = parsed isSet "--show-diff"
+ fileManager.showLog = parsed isSet "--show-log"
+ fileManager.failed = parsed isSet "--failed"
+
+ if (parsed isSet "--ansi") NestUI initialize NestUI.MANY
+ if (parsed isSet "--timeout") fileManager.timeout = parsed("--timeout")
+ if (parsed isSet "--debug") setProp("partest.debug", "true")
+
+ def addTestFile(file: File) = {
+ if (!file.exists)
+ NestUI.failure("Test file '%s' not found, skipping.\n" format file)
+ else {
+ NestUI.verbose("adding test file " + file)
+ testFiles +:= file
+ }
+ }
+
+ // If --grep is given we suck in every file it matches.
+ parsed get "--grep" foreach { expr =>
+ val allFiles = srcDir.deepList() filter (_ hasExtension "scala") map (_.toFile) toList
+ val files = allFiles filter (_.slurp() contains expr)
+
+ if (files.isEmpty) NestUI.failure("--grep string '%s' matched no files." format expr)
+ else NestUI.verbose("--grep string '%s' matched %d file(s)".format(expr, files.size))
+
+ files foreach (x => addTestFile(x.jfile))
+ }
+ args foreach (x => addTestFile(new File(x)))
+
+ // If no file arguments were given, we assume --all
+ val enabledTestSets: List[TestSet] = {
+ val enabledArgs = testSetArgs filter parsed.isSet
+
+ if (args.isEmpty && !(parsed isSet "--grep") && (enabledArgs.isEmpty || (parsed isSet "--all"))) testSets
+ else enabledArgs map testSetArgMap
+ }
+
+ val dir =
+ if (fileManager.testClasses.isDefined) fileManager.testClassesDir
+ else fileManager.testBuildFile getOrElse {
+ fileManager.latestCompFile.getParentFile.getParentFile.getCanonicalFile
+ }
+
+ val vmBin = javaHome + File.separator + "bin"
+ val vmName = "%s (build %s, %s)".format(javaVmName, javaVmVersion, javaVmInfo)
+ val vmOpts = fileManager.JAVA_OPTS
+
+ NestUI.verbose("enabled test sets: " + (enabledTestSets map (_.kind) mkString " "))
+
+ List(
+ "Scala compiler classes in: " + dir,
+ "Scala version is: " + versionMsg,
+ "Scalac options are: " + fileManager.SCALAC_OPTS,
+ "Java binaries in: " + vmBin,
+ "Java runtime is: " + vmName,
+ "Java options are: " + vmOpts,
+ "Source directory is: " + srcDir,
+ ""
+ ) foreach (x => NestUI outline (x + "\n"))
+
+ val start = System.currentTimeMillis
+ val (successes, failures) = testCheckAll(enabledTestSets)
+ val end = System.currentTimeMillis
+
+ val total = successes + failures
+
+ val elapsedSecs = (end - start)/1000
+ val elapsedMins = elapsedSecs/60
+ val elapsedHrs = elapsedMins/60
+ val dispMins = elapsedMins - elapsedHrs * 60
+ val dispSecs = elapsedSecs - elapsedMins * 60
+
+ val dispElapsed = {
+ def form(num: Long) = if (num < 10) "0"+num else ""+num
+ form(elapsedHrs)+":"+form(dispMins)+":"+form(dispSecs)
+ }
+
+ println
+ if (failures == 0)
+ NestUI.success("All of "+total+" tests were successful (elapsed time: "+dispElapsed+")\n")
+ else
+ NestUI.failure(failures+" of "+total+" tests failed (elapsed time: "+dispElapsed+")\n")
+
+ System exit ( if (failures == errors) 0 else 1 )
+ }
+
+ def runTests(testSet: TestSet): (Int, Int) = {
+ val TestSet(kind, filter, msg) = testSet
+
+ fileManager.getFiles(kind, filter) match {
+ case Nil => NestUI.verbose("test dir empty\n") ; (0, 0)
+ case files =>
+ NestUI.verbose("test files: "+files)
+ NestUI.outline("\n"+msg+"\n")
+ resultsToStatistics(runTestsForFiles(files, kind))
+ }
+ }
+
+ /**
+ * @return (success count, failure count)
+ */
+ def testCheckAll(enabledSets: List[TestSet]): (Int, Int) = {
+ def kindOf(f: File) = (srcDir relativize Path(f).normalize).segments.head
+
+ val (valid, invalid) = testFiles partition (x => testSetKinds contains kindOf(x))
+ invalid foreach (x => NestUI.failure("Invalid test file '%s', skipping.\n" format x))
+
+ val runTestsFileLists =
+ for ((kind, files) <- valid groupBy kindOf toList) yield {
+ NestUI.outline("\nTesting individual files\n")
+ resultsToStatistics(runTestsForFiles(files, kind))
+ }
+
+ NestUI.verbose("Run sets: "+enabledSets)
+ val results = runTestsFileLists ::: (enabledSets map runTests)
+
+ (results map (_._1) sum, results map (_._2) sum)
+ }
+}
diff --git a/src/partest/scala/tools/partest/io/Diff.java b/src/partest/scala/tools/partest/nest/Diff.java
index c7a3d42f30..abd09d0293 100644
--- a/src/partest/scala/tools/partest/io/Diff.java
+++ b/src/partest/scala/tools/partest/nest/Diff.java
@@ -1,6 +1,6 @@
// $Id$
-package scala.tools.partest.io;
+package scala.tools.partest.nest;
import java.util.Hashtable;
diff --git a/src/partest/scala/tools/partest/io/DiffPrint.java b/src/partest/scala/tools/partest/nest/DiffPrint.java
index 2b2ad93ec7..494bc06e4a 100644
--- a/src/partest/scala/tools/partest/io/DiffPrint.java
+++ b/src/partest/scala/tools/partest/nest/DiffPrint.java
@@ -1,6 +1,6 @@
// $Id$
-package scala.tools.partest.io;
+package scala.tools.partest.nest;
import java.io.*;
import java.util.Vector;
diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala
new file mode 100644
index 0000000000..f774320f4e
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala
@@ -0,0 +1,78 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{File, PrintStream, FileOutputStream, BufferedReader,
+ InputStreamReader, StringWriter, PrintWriter}
+import java.util.StringTokenizer
+import scala.util.Properties.{ setProp }
+import scala.tools.nsc.io.Directory
+
+import scala.actors.Actor._
+import scala.actors.TIMEOUT
+
+trait DirectRunner {
+
+ def fileManager: FileManager
+
+ import PartestDefaults.numActors
+
+ if (isPartestDebug)
+ scala.actors.Debug.level = 3
+
+ if (PartestDefaults.poolSize.isEmpty) {
+ scala.actors.Debug.info("actors.corePoolSize not defined")
+ setProp("actors.corePoolSize", "16")
+ }
+
+ def runTestsForFiles(kindFiles: List[File], kind: String): scala.collection.immutable.Map[String, Int] = {
+ val len = kindFiles.length
+ val (testsEach, lastFrag) = (len/numActors, len%numActors)
+ val last = numActors-1
+ val workers = for (i <- List.range(0, numActors)) yield {
+ val toTest = kindFiles.slice(i*testsEach, (i+1)*testsEach)
+ val worker = new Worker(fileManager)
+ worker.start()
+ if (i == last)
+ worker ! RunTests(kind, (kindFiles splitAt (last*testsEach))._2)
+ else
+ worker ! RunTests(kind, toTest)
+ worker
+ }
+
+ var logsToDelete: List[File] = List()
+ var outdirsToDelete: List[File] = List()
+ var results = new scala.collection.immutable.HashMap[String, Int]
+ workers foreach { w =>
+ receiveWithin(3600 * 1000) {
+ case Results(res, logs, outdirs) =>
+ logsToDelete :::= logs filter (_.toDelete)
+ outdirsToDelete :::= outdirs
+ results ++= res
+ case TIMEOUT =>
+ // add at least one failure
+ NestUI.verbose("worker timed out; adding failed test")
+ results += ("worker timed out; adding failed test" -> 2)
+ }
+ }
+
+ if (isPartestDebug)
+ fileManager.showTestTimings()
+
+ if (!isPartestDebug) {
+ for (x <- logsToDelete ::: outdirsToDelete) {
+ NestUI.verbose("deleting "+x)
+ Directory(x).deleteRecursively()
+ }
+ }
+
+ results
+ }
+
+}
diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala
new file mode 100644
index 0000000000..bdbb34b3c4
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/FileManager.scala
@@ -0,0 +1,110 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{File, FilenameFilter, IOException, StringWriter,
+ FileInputStream, FileOutputStream, BufferedReader,
+ FileReader, PrintWriter, FileWriter}
+import java.net.URI
+import scala.tools.nsc.io.{ Path, Directory }
+import scala.collection.mutable.HashMap
+
+trait FileManager {
+ /**
+ * Compares two files using a Java implementation of the GNU diff
+ * available at http://www.bmsi.com/java/#diff.
+ *
+ * @param f1 the first file to be compared
+ * @param f2 the second file to be compared
+ * @return the text difference between the compared files
+ */
+ def compareFiles(f1: File, f2: File): String = {
+ val diffWriter = new StringWriter
+ val args = Array(f1.getCanonicalPath(), f2.getCanonicalPath())
+
+ DiffPrint.doDiff(args, diffWriter)
+ val res = diffWriter.toString
+ if (res startsWith "No") "" else res
+ }
+
+ def testRootDir: Directory
+ def testRootPath: String
+
+ var JAVACMD: String
+ var JAVAC_CMD: String
+
+ var CLASSPATH: String
+ var LATEST_LIB: String
+
+ var showDiff = false
+ var showLog = false
+ var failed = false
+
+ var SCALAC_OPTS = PartestDefaults.scalacOpts
+ var JAVA_OPTS = PartestDefaults.javaOpts
+ var timeout = PartestDefaults.timeout
+
+ /** Only when --debug is given. */
+ lazy val testTimings = new HashMap[String, Long]
+ def recordTestTiming(name: String, milliseconds: Long) =
+ synchronized { testTimings(name) = milliseconds }
+ def showTestTimings() {
+ testTimings.toList sortBy (-_._2) foreach { case (k, v) => println("%s: %s".format(k, v)) }
+ }
+
+ def getLogFile(dir: File, fileBase: String, kind: String): LogFile =
+ new LogFile(dir, fileBase + "-" + kind + ".log")
+
+ def getLogFile(file: File, kind: String): LogFile = {
+ val dir = file.getParentFile
+ val fileBase = basename(file.getName)
+ getLogFile(dir, fileBase, kind)
+ }
+
+ def logFileExists(file: File, kind: String) =
+ getLogFile(file, kind).canRead
+
+ def overwriteFileWith(dest: File, file: File) =
+ dest.isFile && copyFile(file, dest)
+
+
+ def copyFile(from: File, dest: File): Boolean = {
+ def copyFile0(from: File, to: File): Boolean =
+ try {
+ val appender = StreamAppender(from, to)
+ appender.run()
+ appender.closeAll()
+ true
+ } catch {
+ case _: IOException => false
+ }
+
+ if (from.isDirectory) {
+ assert(dest.isDirectory, "cannot copy directory to file")
+ val subDir:Directory = Path(dest) / Directory(from.getName)
+ subDir.createDirectory()
+ from.listFiles.toList.forall(copyFile(_, subDir))
+ } else
+ copyFile0(from, if (dest.isDirectory) new File(dest, from.getName) else dest)
+ }
+
+ def mapFile(file: File, suffix: String, dir: File, replace: String => String) {
+ val tmpFile = File.createTempFile("tmp", suffix, dir) // prefix required by API
+
+ val appender = StreamAppender(file, tmpFile)
+ appender.runAndMap(replace)
+ appender.closeAll()
+
+ val appender2 = StreamAppender(tmpFile, file)
+ appender2.run()
+ appender2.closeAll()
+
+ tmpFile.delete()
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/NestRunner.scala b/src/partest/scala/tools/partest/nest/NestRunner.scala
new file mode 100644
index 0000000000..158521875e
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/NestRunner.scala
@@ -0,0 +1,16 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+object NestRunner {
+ def main(args: Array[String]) {
+ val argstr = args.mkString(" ")
+ (new ReflectiveRunner).main(argstr)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala
new file mode 100644
index 0000000000..efff4e8375
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/NestUI.scala
@@ -0,0 +1,118 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.PrintWriter
+
+object NestUI {
+
+ val NONE = 0
+ val SOME = 1
+ val MANY = 2
+
+ private var _outline = ""
+ private var _success = ""
+ private var _failure = ""
+ private var _warning = ""
+ private var _default = ""
+
+ def initialize(number: Int) = number match {
+ case MANY =>
+ _outline = Console.BOLD + Console.BLACK
+ _success = Console.BOLD + Console.GREEN
+ _failure = Console.BOLD + Console.RED
+ _warning = Console.BOLD + Console.YELLOW
+ _default = Console.RESET
+ case SOME =>
+ _outline = Console.BOLD + Console.BLACK
+ _success = Console.RESET
+ _failure = Console.BOLD + Console.BLACK
+ _warning = Console.BOLD + Console.BLACK
+ _default = Console.RESET
+ case _ =>
+ }
+
+ def outline(msg: String) = print(_outline + msg + _default)
+ def outline(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_outline + msg + _default)
+ }
+
+ def success(msg: String) = print(_success + msg + _default)
+ def success(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_success + msg + _default)
+ }
+
+ def failure(msg: String) = print(_failure + msg + _default)
+ def failure(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_failure + msg + _default)
+ }
+
+ def warning(msg: String) = print(_warning + msg + _default)
+ def warning(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_warning + msg + _default)
+ }
+
+ def normal(msg: String) = print(_default + msg)
+ def normal(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_default + msg)
+ }
+
+ def usage() {
+ println("Usage: NestRunner [<options>] [<testfile> ..] [<resfile>]")
+ println(" <testfile>: list of files ending in '.scala'")
+ println(" <resfile>: a file not ending in '.scala'")
+ println(" <options>:")
+ println
+ println(" Test categories:")
+ println(" --all run all tests")
+ println(" --pos run compilation tests (success)")
+ println(" --neg run compilation tests (failure)")
+ println(" --run run interpreter and backend tests")
+ println(" --jvm run JVM backend tests")
+ println(" --res run resident compiler tests")
+ println(" --buildmanager run Build Manager tests")
+ println(" --scalacheck run ScalaCheck tests")
+ println(" --script run script runner tests")
+ println(" --shootout run shootout tests")
+ println(" --grep <expr> run all tests whose source file contains <expr>")
+ println
+ println(" Other options:")
+ println(" --pack pick compiler/library in build/pack, and run all tests")
+ println(" --show-log show log")
+ println(" --show-diff show diff between log and check file")
+ println(" --failed run only those tests that failed during the last run")
+ println(" --verbose show progress information")
+ println(" --buildpath set (relative) path to build jars")
+ println(" ex.: --buildpath build/pack")
+ println(" --classpath set (absolute) path to build classes")
+ println(" --srcpath set (relative) path to test source files")
+ println(" ex.: --srcpath pending")
+ println(" --debug enable debugging output")
+ println
+ println(utils.Properties.versionString)
+ println("maintained by Philipp Haller (EPFL)")
+ exit(1)
+ }
+
+ var _verbose = false
+ var _debug = false
+
+ def verbose(msg: String) {
+ if (_verbose) {
+ outline("debug: ")
+ println(msg)
+ }
+ }
+ def debug(msg: String) {
+ if (isPartestDebug) {
+ outline("debug: ")
+ println(msg)
+ }
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala
new file mode 100644
index 0000000000..41bba5782e
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/PathSettings.scala
@@ -0,0 +1,41 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ */
+
+package scala.tools.partest
+package nest
+
+import scala.tools.nsc.Properties.{ setProp, propOrEmpty, propOrNone, propOrElse }
+import scala.tools.nsc.util.ClassPath
+import scala.tools.nsc.io
+import io.{ Path, File, Directory }
+import RunnerUtils._
+import java.net.URLClassLoader
+
+object PathSettings {
+ import PartestDefaults.{ testRootDir, srcDirName }
+
+ private def cwd = Directory.Current getOrElse error("user.dir property not set")
+ private def isPartestDir(d: Directory) = (d.name == "test") && (d / srcDirName isDirectory)
+
+ // Directory <root>/test
+ lazy val testRoot: Directory = testRootDir getOrElse {
+ val candidates: List[Directory] = (cwd :: cwd.parents) flatMap (d => List(d, Directory(d / "test")))
+
+ candidates find isPartestDir getOrElse error("Directory 'test' not found.")
+ }
+
+ // Directory <root>/test/files
+ lazy val srcDir = Directory(testRoot / srcDirName normalize)
+
+ // Directory <root>/test/files/lib
+ lazy val srcLibDir = Directory(srcDir / "lib")
+
+ lazy val scalaCheck = srcLibDir.files find (_.name startsWith "scalacheck") getOrElse {
+ error("No scalacheck jar found in '%s'" format srcLibDir)
+ }
+}
+
+class PathSettings() {
+ // def classpathAsURLs: List[URL]
+}
diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
new file mode 100644
index 0000000000..b3f199a3d6
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
@@ -0,0 +1,88 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import scala.tools.nsc.Properties.{ setProp, propOrEmpty }
+import scala.tools.nsc.util.ClassPath
+import scala.tools.nsc.io
+import io.Path
+import RunnerUtils._
+import java.net.URLClassLoader
+
+/* This class is used to load an instance of DirectRunner using
+ * a custom class loader.
+ * The purpose is to "auto-detect" a good classpath for the
+ * rest of the classes (Worker, CompileManager etc.), so that
+ * the main NestRunner can be started merely by putting its
+ * class on the classpath (ideally).
+ */
+class ReflectiveRunner {
+ // TODO: we might also use fileManager.CLASSPATH
+ // to use the same classes as used by `scala` that
+ // was used to start the runner.
+ val sepRunnerClassName = "scala.tools.partest.nest.ConsoleRunner"
+
+ def main(args: String) {
+ val argList = (args.split("\\s")).toList
+
+ if (isPartestDebug)
+ showAllJVMInfo
+
+ // find out which build to test
+ val buildPath = searchPath("--buildpath", argList)
+ val classPath = searchPath("--classpath", argList)
+ val fileManager =
+ if (!buildPath.isEmpty)
+ new ConsoleFileManager(buildPath.get)
+ else if (!classPath.isEmpty)
+ new ConsoleFileManager(classPath.get, true)
+ else if (argList contains "--pack")
+ new ConsoleFileManager("build/pack")
+ else // auto detection
+ new ConsoleFileManager
+
+ import fileManager.
+ { latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile }
+ val files =
+ Array(latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile) map (x => io.File(x))
+
+ val sepUrls = files map (_.toURL)
+ val sepLoader = new URLClassLoader(sepUrls, null)
+
+ if (isPartestDebug)
+ println("Loading classes from:\n" + sepUrls.mkString("\n"))
+
+ val paths = classPath match {
+ case Some(cp) => Nil
+ case _ => files.toList map (_.path)
+ }
+ val newClasspath = ClassPath.join(paths: _*)
+
+ setProp("java.class.path", newClasspath)
+ setProp("scala.home", "")
+
+ if (isPartestDebug)
+ for (prop <- List("java.class.path", "sun.boot.class.path", "java.ext.dirs"))
+ println(prop + ": " + propOrEmpty(prop))
+
+ try {
+ val sepRunnerClass = sepLoader loadClass sepRunnerClassName
+ val sepRunner = sepRunnerClass.newInstance()
+ val sepMainMethod = sepRunnerClass.getMethod("main", Array(classOf[String]): _*)
+ val cargs: Array[AnyRef] = Array(args)
+ sepMainMethod.invoke(sepRunner, cargs: _*)
+ }
+ catch {
+ case cnfe: ClassNotFoundException =>
+ cnfe.printStackTrace()
+ NestUI.failure(sepRunnerClassName +" could not be loaded from:\n")
+ sepUrls foreach (x => NestUI.failure(x + "\n"))
+ }
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/RunnerUtils.scala b/src/partest/scala/tools/partest/nest/RunnerUtils.scala
new file mode 100644
index 0000000000..24445bb545
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/RunnerUtils.scala
@@ -0,0 +1,29 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+object RunnerUtils {
+ def splitArgs(str: String) = str split "\\s" filterNot (_ == "") toList
+
+ def searchPath(option: String, as: List[String]): Option[String] = as match {
+ case `option` :: r :: _ => Some(r)
+ case _ :: rest => searchPath(option, rest)
+ case Nil => None
+ }
+
+ def searchAndRemovePath(option: String, as: List[String]) = (as indexOf option) match {
+ case -1 => (None, as)
+ case idx => (Some(as(idx + 1)), (as take idx) ::: (as drop (idx + 2)))
+ }
+
+ def searchAndRemoveOption(option: String, as: List[String]) = (as indexOf option) match {
+ case -1 => (false, as)
+ case idx => (true, (as take idx) ::: (as drop (idx + 1)))
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala
new file mode 100644
index 0000000000..741556fdd5
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/TestFile.scala
@@ -0,0 +1,49 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{ File => JFile }
+import scala.tools.nsc.Settings
+import scala.tools.nsc.io._
+
+abstract class TestFile(kind: String) {
+ def file: JFile
+ def fileManager: FileManager
+
+ val dir = file.toAbsolute.parent
+ val fileBase = file.stripExtension
+ lazy val objectDir = dir / "%s-%s.obj".format(fileBase, kind) createDirectory true
+ val flags: Option[String] = dir / "%s.flags".format(fileBase) ifFile { _.slurp().trim }
+
+ def setOutDirTo = objectDir
+
+ def defineSettings(settings: Settings, setOutDir: Boolean) = {
+ settings.classpath append dir.path
+ if (setOutDir)
+ settings.outdir.value = setOutDirTo.path
+
+ flags foreach (settings processArgumentString _)
+ settings.classpath append fileManager.CLASSPATH
+ }
+
+ override def toString(): String = "%s %s".format(kind, file)
+}
+
+case class PosTestFile(file: JFile, fileManager: FileManager) extends TestFile("pos")
+case class NegTestFile(file: JFile, fileManager: FileManager) extends TestFile("neg")
+case class RunTestFile(file: JFile, fileManager: FileManager) extends TestFile("run")
+case class BuildManagerTestFile(file: JFile, fileManager: FileManager) extends TestFile("bm")
+case class ScalaCheckTestFile(file: JFile, fileManager: FileManager) extends TestFile("scalacheck")
+case class JvmTestFile(file: JFile, fileManager: FileManager) extends TestFile("jvm")
+case class ShootoutTestFile(file: JFile, fileManager: FileManager) extends TestFile("shootout") {
+ override def setOutDirTo = file.parent
+}
+case class ScalapTestFile(file: JFile, fileManager: FileManager) extends TestFile("scalap") {
+ override def setOutDirTo = file.parent
+}
diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala
new file mode 100644
index 0000000000..2f81dfd0f7
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/Worker.scala
@@ -0,0 +1,1071 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io._
+import java.net.{ URLClassLoader, URL }
+import java.util.{ Timer, TimerTask }
+
+import scala.util.Properties.{ isWin }
+import scala.tools.nsc.{ ObjectRunner, Settings, CompilerCommand, Global }
+import scala.tools.nsc.io.{ AbstractFile, PlainFile, Path, Directory, File => SFile }
+import scala.tools.nsc.reporters.ConsoleReporter
+import scala.tools.nsc.util.{ ClassPath, FakePos }
+import ClassPath.{ join, split }
+
+import scala.actors.{ Actor, Exit, TIMEOUT }
+import scala.actors.Actor._
+import scala.tools.scalap.scalax.rules.scalasig.{ByteCode, ClassFileParser, ScalaSigAttributeParsers}
+
+import scala.collection.immutable.{ HashMap, Map => ImmMap }
+import scala.collection.Map
+
+import scala.tools.nsc.interactive.{BuildManager, RefinedBuildManager}
+
+case class RunTests(kind: String, files: List[File])
+case class Results(results: ImmMap[String, Int], logs: List[LogFile], outdirs: List[File])
+
+case class LogContext(file: LogFile, writers: Option[(StringWriter, PrintWriter)])
+
+abstract class TestResult {
+ def file: File
+}
+case class Result(override val file: File, context: LogContext) extends TestResult
+case class Timeout(override val file: File) extends TestResult
+
+class LogFile(parent: File, child: String) extends File(parent, child) {
+ var toDelete = false
+}
+
+class Worker(val fileManager: FileManager) extends Actor {
+ import fileManager._
+
+ var reporter: ConsoleReporter = _
+ val timer = new Timer
+
+ def error(msg: String): Unit = reporter.error(
+ FakePos("scalac"),
+ msg + "\n scalac -help gives more information"
+ )
+
+ def act() {
+ react {
+ case RunTests(kind, files) =>
+ // NestUI.verbose("received "+files.length+" to test")
+ val master = sender
+ runTests(kind, files) { results =>
+ master ! Results(results, createdLogFiles, createdOutputDirs)
+ }
+ }
+ }
+
+ def printInfoStart(file: File, printer: PrintWriter) {
+ NestUI.outline("testing: ", printer)
+ val filesdir = file.getAbsoluteFile.getParentFile.getParentFile
+ val testdir = filesdir.getParentFile
+ val totalWidth = 56
+ val name = {
+ // 1. try with [...]/files/run/test.scala
+ val testPathLen = testdir.getAbsolutePath.length
+ val name = file.getAbsolutePath.substring(testPathLen)
+ if (name.length <= totalWidth)
+ name
+ // 2. try with [...]/run/test.scala
+ else {
+ val filesPathLen = filesdir.getAbsolutePath.length
+ file.getAbsolutePath.substring(filesPathLen)
+ }
+ }
+ NestUI.normal("[...]%s%s".format(name, " " * (totalWidth - name.length)), printer)
+ }
+
+ def printInfoEnd(success: Boolean, printer: PrintWriter) {
+ NestUI.normal("[", printer)
+ if (success) NestUI.success(" OK ", printer)
+ else NestUI.failure("FAILED", printer)
+ NestUI.normal("]\n", printer)
+ }
+
+ def printInfoTimeout(printer: PrintWriter) {
+ NestUI.normal("[", printer)
+ NestUI.failure("TIMOUT", printer)
+ NestUI.normal("]\n", printer)
+ }
+
+ var log = ""
+ var createdLogFiles: List[LogFile] = Nil
+ var createdOutputDirs: List[File] = Nil
+
+ def createLogFile(file: File, kind: String): LogFile = {
+ val logFile = fileManager.getLogFile(file, kind)
+ createdLogFiles ::= logFile
+ logFile
+ }
+
+ def createOutputDir(dir: File, fileBase: String, kind: String): File = {
+ val outDir = Path(dir) / Directory("%s-%s.obj".format(fileBase, kind))
+ outDir.createDirectory()
+ createdOutputDirs ::= outDir.jfile
+ outDir.jfile
+ }
+
+ /* Note: not yet used/tested. */
+ // def execTestObjectRunner(file: File, outDir: File, logFile: File) {
+ // val consFM = new ConsoleFileManager
+ //
+ // val classpath: List[URL] = {
+ // import consFM.{ latestCompFile, latestLibFile, latestPartestFile }
+ // val units = (
+ // List(outDir, latestCompFile, latestLibFile, latestPartestFile) :::
+ // ((CLASSPATH split File.pathSeparatorChar).toList map (x => new File(x)))
+ // )
+ // units map (_.toURI.toURL)
+ // }
+ //
+ // NestUI.verbose("ObjectRunner classpath: "+classpath)
+ //
+ // try {
+ // // configure input/output files
+ // val logOut = new FileOutputStream(logFile)
+ // val logWriter = new PrintStream(logOut)
+ //
+ // // grab global lock
+ // fileManager.synchronized {
+ // withOutputRedirected(logWriter) {
+ // System.setProperty("java.library.path", logFile.getParentFile.getCanonicalFile.getAbsolutePath)
+ // System.setProperty("partest.output", outDir.getCanonicalFile.getAbsolutePath)
+ // System.setProperty("partest.lib", LATEST_LIB)
+ // System.setProperty("partest.cwd", outDir.getParent)
+ // ObjectRunner.run(classpath, "Test", List("jvm"))
+ // }
+ // }
+ //
+ // /*val out = new FileOutputStream(logFile, true)
+ // Console.withOut(new PrintStream(out)) {
+ // ObjectRunner.run(classpath, "Test", List("jvm"))
+ // }
+ // out.flush
+ // out.close*/
+ // } catch {
+ // case e: Exception =>
+ // NestUI.verbose(e+" ("+file.getPath+")")
+ // e.printStackTrace()
+ // }
+ // }
+
+ def javac(outDir: File, files: List[File], output: File): Boolean = {
+ // compile using command-line javac compiler
+ val javacCmd = if ((fileManager.JAVAC_CMD.indexOf("${env.JAVA_HOME}") != -1) ||
+ fileManager.JAVAC_CMD.equals("/bin/javac") ||
+ fileManager.JAVAC_CMD.equals("\\bin\\javac"))
+ "javac"
+ else
+ fileManager.JAVAC_CMD
+
+ val cmd = javacCmd+
+ " -d "+outDir.getAbsolutePath+
+ " -classpath "+ join(outDir.toString, CLASSPATH) +
+ " "+files.mkString(" ")
+
+ val (success, msg) = try {
+ val exitCode = runCommand(cmd, output)
+ NestUI.verbose("javac returned exit code: "+exitCode)
+ if (exitCode != 0)
+ (false, "Running \"javac\" failed with exit code: "+exitCode+"\n"+cmd+"\n")
+ else
+ (true, "")
+ } catch {
+ case e: Exception =>
+ val swriter = new StringWriter
+ e.printStackTrace(new PrintWriter(swriter))
+ (false, "Running \"javac\" failed:\n"+cmd+"\n"+swriter.toString+"\n")
+ }
+ if (!success) {
+ val writer = new PrintWriter(new FileWriter(output, true), true)
+ writer.print(msg)
+ writer.close()
+ }
+ success
+ }
+
+ /** Runs <code>command</code> redirecting standard out and
+ * error out to <code>output</code> file.
+ */
+ def runCommand(command: String, output: File): Int = {
+ NestUI.verbose("running command:\n"+command)
+ val proc = Runtime.getRuntime.exec(command)
+ val in = proc.getInputStream
+ val err = proc.getErrorStream
+ val writer = new PrintWriter(new FileWriter(output), true)
+ val inApp = StreamAppender(in, writer)
+ val errApp = StreamAppender(err, writer)
+ val async = new Thread(errApp)
+ async.start()
+ inApp.run()
+ async.join()
+ writer.close()
+
+ try proc.exitValue()
+ catch { case _: IllegalThreadStateException => 0 }
+ }
+
+ def execTest(outDir: File, logFile: File, fileBase: String) {
+ // check whether there is a ".javaopts" file
+ val argsFile = new File(logFile.getParentFile, fileBase+".javaopts")
+ val argString = if (argsFile.exists) {
+ NestUI.verbose("Found javaopts file: "+argsFile)
+ val fileReader = new FileReader(argsFile)
+ val reader = new BufferedReader(fileReader)
+ val options = reader.readLine()
+ reader.close()
+ NestUI.verbose("Found javaopts file '%s', using options: '%s'".format(argsFile, options))
+ options
+ } else ""
+
+ def quote(path: String) = "\""+path+"\""
+
+ // Note! As this currently functions, JAVA_OPTS must precede argString
+ // because when an option is repeated to java only the last one wins.
+ // That means until now all the .javaopts files were being ignored because
+ // they all attempt to change options which are also defined in
+ // partest.java_opts, leading to debug output like:
+ //
+ // debug: Found javaopts file 'files/shootout/message.scala-2.javaopts', using options: '-Xss32k'
+ // debug: java -Xss32k -Xss2m -Xms256M -Xmx1024M -classpath [...]
+ val propertyOptions = List(
+ "-Djava.library.path="+logFile.getParentFile.getAbsolutePath,
+ "-Dpartest.output="+outDir.getAbsolutePath,
+ "-Dpartest.lib="+LATEST_LIB,
+ "-Dpartest.cwd="+outDir.getParent,
+ "-Djavacmd="+JAVACMD,
+ "-Duser.language=en -Duser.country=US"
+ ) ::: (
+ if (isPartestDebug) List("-Dpartest.debug=true") else Nil
+ )
+
+ val cmd = (
+ List(
+ JAVACMD,
+ JAVA_OPTS,
+ argString,
+ "-classpath " + join(outDir.toString, CLASSPATH)
+ ) ::: propertyOptions ::: List(
+ "scala.tools.nsc.MainGenericRunner",
+ "-usejavacp",
+ "Test",
+ "jvm"
+ )
+ ) mkString " "
+
+ runCommand(cmd, logFile)
+
+ if (fileManager.showLog) {
+ // produce log as string in `log`
+ val reader = new BufferedReader(new FileReader(logFile))
+ val swriter = new StringWriter
+ val pwriter = new PrintWriter(swriter, true)
+ val appender = new StreamAppender(reader, pwriter)
+ appender.run()
+ log = swriter.toString
+ }
+ }
+
+ def getCheckFile(dir: File, fileBase: String, kind: String) = {
+ def chkFile(s: String) = Directory(dir) / "%s%s.check".format(fileBase, s)
+ val checkFile = if (chkFile("").isFile) chkFile("") else chkFile("-" + kind)
+
+ if (checkFile.canRead) Some(checkFile) else None
+ }
+
+ def existsCheckFile(dir: File, fileBase: String, kind: String) =
+ getCheckFile(dir, fileBase, kind).isDefined
+
+ def compareOutput(dir: File, fileBase: String, kind: String, logFile: File): String =
+ // if check file exists, compare with log file
+ getCheckFile(dir, fileBase, kind) match {
+ case Some(f) => fileManager.compareFiles(logFile, f.jfile)
+ case _ => file2String(logFile)
+ }
+
+ def file2String(logFile: File) = SFile(logFile).slurp()
+ def isJava(f: File) = SFile(f) hasExtension "java"
+ def isScala(f: File) = SFile(f) hasExtension "scala"
+ def isJavaOrScala(f: File) = isJava(f) || isScala(f)
+
+ /** Runs a list of tests.
+ *
+ * @param kind The test kind (pos, neg, run, etc.)
+ * @param files The list of test files
+ */
+ def runTests(kind: String, files: List[File])(topcont: ImmMap[String, Int] => Unit) {
+ val compileMgr = new CompileManager(fileManager)
+ var errors = 0
+ var succeeded = true
+ var diff = ""
+ var log = ""
+
+ def fail(what: Any) {
+ NestUI.verbose("scalac: compilation of "+what+" failed\n")
+ succeeded = false
+ }
+ def diffCheck(latestDiff: String) = {
+ diff = latestDiff
+ if (latestDiff != "") {
+ NestUI.verbose("output differs from log file\n")
+ succeeded = false
+ }
+ }
+
+ /** 1. Creates log file and output directory.
+ * 2. Runs <code>script</code> function, providing log file and
+ * output directory as arguments.
+ */
+ def runInContext(file: File, kind: String, script: (File, File) => Unit): LogContext = {
+ // when option "--failed" is provided
+ // execute test only if log file is present
+ // (which means it failed before)
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true
+ diff = ""
+ log = ""
+ printInfoStart(file, wr)
+
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+ val dir = file.getParentFile
+ val outDir = createOutputDir(dir, fileBase, kind)
+ NestUI.verbose("output directory: "+outDir)
+
+ // run test-specific code
+ try {
+ if (isPartestDebug) {
+ val t1 = System.currentTimeMillis
+ script(logFile, outDir)
+ val t2 = System.currentTimeMillis
+ fileManager.recordTestTiming(file.getPath, t2 - t1)
+ }
+ else {
+ script(logFile, outDir)
+ }
+ } catch {
+ case e: Exception =>
+ val writer = new PrintWriter(new FileWriter(logFile), true)
+ e.printStackTrace(writer)
+ writer.close()
+ succeeded = false
+ }
+
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ }
+
+ def compileFilesIn(dir: File, kind: String, logFile: File, outDir: File) {
+ val testFiles = dir.listFiles.toList filter isJavaOrScala
+
+ def isInGroup(f: File, num: Int) = SFile(f).stripExtension endsWith ("_" + num)
+ val groups = (0 to 9).toList map (num => testFiles filter (f => isInGroup(f, num)))
+ val noGroupSuffix = testFiles -- groups.flatten
+
+ def compileGroup(g: List[File]) {
+ val (scalaFiles, javaFiles) = g partition isScala
+
+ if (scalaFiles.nonEmpty) {
+ if (!compileMgr.shouldCompile(outDir, javaFiles ::: scalaFiles, kind, logFile))
+ fail(g)
+ }
+
+ if (succeeded && javaFiles.nonEmpty) {
+ succeeded = javac(outDir, javaFiles, logFile)
+ if (succeeded && scalaFiles.nonEmpty && !compileMgr.shouldCompile(outDir, scalaFiles, kind, logFile))
+ fail(scalaFiles)
+ }
+ }
+
+ if (noGroupSuffix.nonEmpty)
+ compileGroup(noGroupSuffix)
+
+ groups foreach (grp => if (succeeded) compileGroup(grp))
+ }
+
+ def failCompileFilesIn(dir: File, kind: String, logFile: File, outDir: File) {
+ val testFiles = dir.listFiles.toList
+ val sourceFiles = testFiles filter isJavaOrScala
+
+ if (sourceFiles.nonEmpty) {
+ if (!compileMgr.shouldFailCompile(outDir, sourceFiles, kind, logFile))
+ fail(testFiles filter isScala)
+ }
+ }
+
+ def runTestCommon(file: File, kind: String, expectFailure: Boolean)(onSuccess: (File, File) => Unit): LogContext =
+ runInContext(file, kind, (logFile: File, outDir: File) => {
+
+ if (file.isDirectory) {
+ val f = if (expectFailure) failCompileFilesIn _ else compileFilesIn _
+ f(file, kind, logFile, outDir)
+ }
+ else {
+ val f: (List[File], String, File) => Boolean =
+ if (expectFailure) compileMgr.shouldFailCompile _
+ else compileMgr.shouldCompile _
+
+ if (!f(List(file), kind, logFile))
+ fail(file)
+ }
+
+ if (succeeded) // run test
+ onSuccess(logFile, outDir)
+ })
+
+ def runJvmTest(file: File, kind: String): LogContext =
+ runTestCommon(file, kind, expectFailure = false)((logFile, outDir) => {
+ val fileBase = basename(file.getName)
+ val dir = file.getParentFile
+
+ //TODO: detect whether we have to use Runtime.exec
+ // val useRuntime = true
+ //
+ // if (useRuntime)
+ // execTest(outDir, logFile, fileBase)
+ // else
+ // execTestObjectRunner(file, outDir, logFile)
+ // // NestUI.verbose(this+" finished running "+fileBase)
+ execTest(outDir, logFile, fileBase)
+
+ diffCheck(compareOutput(dir, fileBase, kind, logFile))
+ })
+
+ def processSingleFile(file: File): LogContext = kind match {
+ case "scalacheck" =>
+ runTestCommon(file, kind, expectFailure = false)((logFile, outDir) => {
+ val consFM = new ConsoleFileManager
+ import consFM.{ latestCompFile, latestLibFile, latestPartestFile }
+
+ NestUI.verbose("compilation of "+file+" succeeded\n")
+
+ val scalacheckURL = PathSettings.scalaCheck.toURL
+ val outURL = outDir.getCanonicalFile.toURI.toURL
+ val classpath: List[URL] =
+ List(outURL, scalacheckURL, latestCompFile.toURI.toURL, latestLibFile.toURI.toURL, latestPartestFile.toURI.toURL).distinct
+
+ NestUI.debug("scalacheck urls")
+ classpath foreach (x => NestUI.debug(x.toString))
+
+ val logWriter = new PrintStream(new FileOutputStream(logFile))
+
+ withOutputRedirected(logWriter) {
+ ObjectRunner.run(classpath, "Test", Nil)
+ }
+
+ NestUI.verbose(SFile(logFile).slurp())
+ // obviously this must be improved upon
+ succeeded = SFile(logFile).lines() forall (_ contains " OK")
+ })
+
+ case "pos" =>
+ runTestCommon(file, kind, expectFailure = false)((_, _) => ())
+
+ case "neg" =>
+ runTestCommon(file, kind, expectFailure = true)((logFile, outDir) => {
+ // compare log file to check file
+ val fileBase = basename(file.getName)
+ val dir = file.getParentFile
+
+ diffCheck(
+ // diff is contents of logFile
+ if (!existsCheckFile(dir, fileBase, kind)) file2String(logFile)
+ else compareOutput(dir, fileBase, kind, logFile)
+ )
+ })
+
+ case "run" | "jvm" =>
+ runJvmTest(file, kind)
+
+ case "buildmanager" =>
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true; diff = ""
+ printInfoStart(file, wr)
+ val (outDir, testFile, changesDir, fileBase) =
+
+ if (!file.isDirectory) {
+ succeeded = false
+ (null, null, null, null)
+ } else {
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+ val outDir = createOutputDir(file, fileBase, kind)
+ if (!outDir.exists) outDir.mkdir()
+ val testFile = new File(file, fileBase + ".test")
+ val changesDir = new File(file, fileBase + ".changes")
+ if (changesDir.isFile || !testFile.isFile) {
+ // if changes exists then it has to be a dir
+ if (!testFile.isFile) NestUI.verbose("invalid build manager test file")
+ if (changesDir.isFile) NestUI.verbose("invalid build manager changes directory")
+ succeeded = false
+ (null, null, null, null)
+ } else {
+ copyTestFiles(file, outDir)
+ NestUI.verbose("outDir: "+outDir)
+ NestUI.verbose("logFile: "+logFile)
+ (outDir, testFile, changesDir, fileBase)
+ }
+ }
+
+ if (succeeded) {
+ // Pre-conditions satisfied
+
+ try {
+ val sourcepath = outDir.getAbsolutePath+File.separator
+
+ // configure input/output files
+ val logWriter = new PrintStream(new FileOutputStream(logFile))
+ val testReader = new BufferedReader(new FileReader(testFile))
+ val logConsoleWriter = new PrintWriter(logWriter)
+
+ // create proper settings for the compiler
+ val settings = new Settings(error)
+ settings.outdir.value = outDir.getCanonicalFile.getAbsolutePath
+ settings.sourcepath.value = sourcepath
+ settings.classpath.value = fileManager.CLASSPATH
+ settings.Ybuildmanagerdebug.value = true
+
+ // simulate Build Manager loop
+ val prompt = "builder > "
+ reporter = new ConsoleReporter(settings, scala.Console.in, logConsoleWriter)
+ val bM: BuildManager =
+ new RefinedBuildManager(settings) {
+ override protected def newCompiler(settings: Settings) =
+ new BuilderGlobal(settings, reporter)
+ }
+
+ val testCompile = (line: String) => {
+ NestUI.verbose("compiling " + line)
+ val args = (line split ' ').toList
+ val command = new CompilerCommand(args, settings)
+ bM.update(filesToSet(settings.sourcepath.value, command.files), Set.empty)
+ !reporter.hasErrors
+ }
+
+ val updateFiles = (line: String) => {
+ NestUI.verbose("updating " + line)
+ val res =
+ ((line split ' ').toList).forall(u => {
+ (u split "=>").toList match {
+ case origFileName::(newFileName::Nil) =>
+ val newFile = new File(changesDir, newFileName)
+ if (newFile.isFile) {
+ val v = overwriteFileWith(new File(outDir, origFileName), newFile)
+ if (!v)
+ NestUI.verbose("'update' operation on " + u + " failed")
+ v
+ } else {
+ NestUI.verbose("File " + newFile + " is invalid")
+ false
+ }
+ case a =>
+ NestUI.verbose("Other =: " + a)
+ false
+ }
+ })
+ if (!res)
+ NestUI.verbose("updating failed")
+ else
+ NestUI.verbose("updating succeeded")
+ res
+ }
+
+ def loop() {
+ val command = testReader.readLine()
+ if ((command ne null) && command.length() > 0) {
+ val commandResult = command match {
+ case s if (s.startsWith(">>update ")) =>
+ updateFiles(s.stripPrefix(">>update "))
+ case s if (s.startsWith(">>compile ")) =>
+ val files = s.stripPrefix(">>compile ")
+ logWriter.println(prompt + files)
+ testCompile(files) // In the end, it can finish with an error
+ case _ =>
+ NestUI.verbose("wrong command in test file: " + command)
+ false
+ }
+
+ if (commandResult) loop()
+
+ } else {
+ NestUI.verbose("finished")
+ succeeded = true
+ }
+ }
+
+ withOutputRedirected(logWriter) {
+ loop()
+ testReader.close()
+ }
+
+ fileManager.mapFile(logFile, "tmp", file, _.replace(sourcepath, ""))
+
+ diffCheck(compareOutput(file, fileBase, kind, logFile))
+ }
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ } else
+ LogContext(logFile, None)
+
+ case "res" => {
+ // when option "--failed" is provided
+ // execute test only if log file is present
+ // (which means it failed before)
+
+ //val (logFileOut, logFileErr) = createLogFiles(file, kind)
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true; diff = ""; log = ""
+ printInfoStart(file, wr)
+
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+ val dir = file.getParentFile
+ val outDir = createOutputDir(dir, fileBase, kind)
+ if (!outDir.exists) outDir.mkdir()
+ val resFile = new File(dir, fileBase + ".res")
+ NestUI.verbose("outDir: "+outDir)
+ NestUI.verbose("logFile: "+logFile)
+ //NestUI.verbose("logFileErr: "+logFileErr)
+ NestUI.verbose("resFile: "+resFile)
+
+ // run compiler in resident mode
+ // $SCALAC -d "$os_dstbase".obj -Xresident -sourcepath . "$@"
+
+ try {
+
+ val sourcedir = logFile.getParentFile.getCanonicalFile
+ val sourcepath = sourcedir.getAbsolutePath+File.separator
+ NestUI.verbose("sourcepath: "+sourcepath)
+
+ val argString =
+ "-d "+outDir.getCanonicalFile.getAbsolutePath+
+ " -Xresident"+
+ " -sourcepath "+sourcepath
+ val argList = argString split ' ' toList
+
+ // configure input/output files
+ val logOut = new FileOutputStream(logFile)
+ val logWriter = new PrintStream(logOut)
+ val resReader = new BufferedReader(new FileReader(resFile))
+ val logConsoleWriter = new PrintWriter(new OutputStreamWriter(logOut))
+
+ // create compiler
+ val settings = new Settings(error)
+ settings.sourcepath.value = sourcepath
+ settings.classpath.value = fileManager.CLASSPATH
+ reporter = new ConsoleReporter(settings, scala.Console.in, logConsoleWriter)
+ val command = new CompilerCommand(argList, settings)
+ object compiler extends Global(command.settings, reporter)
+
+ // simulate resident compiler loop
+ val prompt = "\nnsc> "
+
+ val resCompile = (line: String) => {
+ NestUI.verbose("compiling "+line)
+ val cmdArgs = (line split ' ').toList map (fs => new File(dir, fs).getAbsolutePath)
+ NestUI.verbose("cmdArgs: "+cmdArgs)
+ val sett = new Settings(error)
+ sett.sourcepath.value = sourcepath
+ val command = new CompilerCommand(cmdArgs, sett)
+ (new compiler.Run) compile command.files
+ }
+
+ def loop(action: (String) => Unit) {
+ logWriter.print(prompt)
+ val line = resReader.readLine()
+ if ((line ne null) && line.length() > 0) {
+/*
+ val parent = self
+ self.trapExit = true
+ val child = link {
+ action(line)
+ }
+
+ receiveWithin(fileManager.timeout.toLong) {
+ case TIMEOUT =>
+ NestUI.verbose("action timed out")
+ false
+ case Exit(from, reason) if from == child => reason match {
+ case 'normal => // do nothing
+ case t: Throwable =>
+ NestUI.verbose("while invoking compiler:")
+ NestUI.verbose("caught "+t)
+ t.printStackTrace
+ if (t.getCause != null)
+ t.getCause.printStackTrace
+ false
+ }
+ }
+*/
+ action(line)
+ loop(action)
+ }
+ }
+
+ withOutputRedirected(logWriter) {
+ loop(resCompile)
+ resReader.close()
+ }
+
+ def replaceSlashes(s: String): String = {
+ val path = dir.getAbsolutePath+File.separator
+ // find `path` in `line`
+ val index = s.indexOf(path)
+ val line =
+ if (index != -1)
+ s.substring(0, index) + s.substring(index + path.length, s.length)
+ else s
+ line.replace('\\', '/')
+ }
+
+ fileManager.mapFile(logFile, "tmp", dir, replaceSlashes)
+ diffCheck(compareOutput(dir, fileBase, kind, logFile))
+
+ } catch {
+ case e: Exception =>
+ e.printStackTrace()
+ succeeded = false
+ }
+
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ }
+
+ case "shootout" => {
+ // when option "--failed" is provided
+ // execute test only if log file is present
+ // (which means it failed before)
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true; diff = ""; log = ""
+ printInfoStart(file, wr)
+
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+ val dir = file.getParentFile
+ val outDir = createOutputDir(dir, fileBase, kind)
+ if (!outDir.exists) outDir.mkdir()
+
+ // 2. define file {outDir}/test.scala that contains code to compile/run
+ val testFile = new File(outDir, "test.scala")
+ NestUI.verbose("outDir: "+outDir)
+ NestUI.verbose("logFile: "+logFile)
+ NestUI.verbose("testFile: "+testFile)
+
+ // 3. cat {test}.scala.runner {test}.scala > testFile
+ val runnerFile = new File(dir, fileBase+".scala.runner")
+ val bodyFile = new File(dir, fileBase+".scala")
+ val appender = StreamAppender.concat(new FileInputStream(runnerFile),
+ new FileInputStream(bodyFile),
+ new FileOutputStream(testFile))
+ appender.run()
+
+ try { // *catch-all*
+ // 4. compile testFile
+ if (!compileMgr.shouldCompile(List(testFile), kind, logFile)) {
+ NestUI.verbose("compilation of "+file+" failed\n")
+ succeeded = false
+ } else {
+ NestUI.verbose("compilation of "+testFile+"succeeded")
+ // -------- run test --------
+
+ //TODO: detect whether we have to use Runtime.exec
+ // val useRuntime = true
+ //
+ // if (useRuntime)
+ // execTest(outDir, logFile, fileBase)
+ // else
+ // execTestObjectRunner(file, outDir, logFile)
+
+ execTest(outDir, logFile, fileBase)
+
+ NestUI.verbose(this+" finished running "+fileBase)
+ } // successful compile
+ } catch { // *catch-all*
+ case e: Exception =>
+ NestUI.verbose("caught "+e)
+ succeeded = false
+ }
+
+ diffCheck(compareOutput(dir, fileBase, kind, logFile))
+
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ }
+
+ case "scalap" => {
+
+ runInContext(file, kind, (logFile: File, outDir: File) => {
+ val sourceDir = file.getParentFile
+ val sourceDirName = sourceDir.getName
+
+ // 1. Find file with result text
+ val results = sourceDir.listFiles(new FilenameFilter {
+ def accept(dir: File, name: String) = name == "result.test"
+ })
+
+ if (results.length != 1) {
+ NestUI.verbose("Result file not found in directory " + sourceDirName + " \n")
+ } else {
+ val resFile = results(0)
+ // 2. Compile source file
+ if (!compileMgr.shouldCompile(outDir, List(file), kind, logFile)) {
+ NestUI.verbose("compilerMgr failed to compile %s to %s".format(file, outDir))
+ succeeded = false
+ } else {
+
+ // 3. Decompile file and compare results
+ val isPackageObject = sourceDir.getName.startsWith("package")
+ val className = sourceDirName.capitalize + (if (!isPackageObject) "" else ".package")
+ val url = outDir.toURI.toURL
+ val loader = new URLClassLoader(Array(url), getClass.getClassLoader)
+ val clazz = loader.loadClass(className)
+
+ val byteCode = ByteCode.forClass(clazz)
+ val result = scala.tools.scalap.Main.decompileScala(byteCode.bytes, isPackageObject)
+
+ try {
+ val fstream = new FileWriter(logFile);
+ val out = new BufferedWriter(fstream);
+ out.write(result)
+ out.close();
+ } catch {
+ case e: IOException => NestUI.verbose(e.getMessage()); succeeded = false
+ }
+
+ diffCheck(fileManager.compareFiles(logFile, resFile))
+ }
+ }
+ })
+ }
+
+ case "script" => {
+ // when option "--failed" is provided
+ // execute test only if log file is present
+ // (which means it failed before)
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true; diff = ""; log = ""
+ printInfoStart(file, wr)
+
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+
+ // check whether there is an args file
+ val argsFile = new File(file.getParentFile, fileBase+".args")
+ NestUI.verbose("argsFile: "+argsFile)
+ val argString = if (argsFile.exists) {
+ val swriter = new StringWriter
+ val app = StreamAppender(new BufferedReader(new FileReader(argsFile)),
+ swriter)
+ app.run()
+ " "+swriter.toString
+ } else ""
+
+ try {
+ val cmdString =
+ if (isWin) {
+ val batchFile = new File(file.getParentFile, fileBase+".bat")
+ NestUI.verbose("batchFile: "+batchFile)
+ batchFile.getAbsolutePath
+ }
+ else file.getAbsolutePath
+ val proc = Runtime.getRuntime.exec(cmdString+argString)
+ val in = proc.getInputStream
+ val err = proc.getErrorStream
+ val writer = new PrintWriter(new FileWriter(logFile), true)
+ val inApp = new StreamAppender(new BufferedReader(new InputStreamReader(in)),
+ writer)
+ val errApp = new StreamAppender(new BufferedReader(new InputStreamReader(err)),
+ writer)
+ val async = new Thread(errApp)
+ async.start()
+ inApp.run()
+ async.join()
+
+ writer.close()
+
+ diffCheck(compareOutput(file.getParentFile, fileBase, kind, logFile))
+ } catch { // *catch-all*
+ case e: Exception =>
+ NestUI.verbose("caught "+e)
+ succeeded = false
+ }
+
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ }
+ }
+
+ def reportAll(results: ImmMap[String, Int], cont: ImmMap[String, Int] => Unit) {
+ // NestUI.verbose("finished testing "+kind+" with "+errors+" errors")
+ // NestUI.verbose("created "+compileMgr.numSeparateCompilers+" separate compilers")
+ timer.cancel()
+ cont(results)
+ }
+
+ def reportResult(state: Int, logFile: Option[LogFile], writers: Option[(StringWriter, PrintWriter)]) {
+ val good = (state == 0)
+ if (!good) {
+ errors += 1
+ NestUI.verbose("incremented errors: "+errors)
+ }
+
+ try {
+ // delete log file only if test was successful
+ if (good && !logFile.isEmpty && !isPartestDebug)
+ logFile.get.toDelete = true
+
+ writers match {
+ case Some((swr, wr)) =>
+ if (state == 2)
+ printInfoTimeout(wr)
+ else
+ printInfoEnd(good, wr)
+ wr.flush()
+ swr.flush()
+ NestUI.normal(swr.toString)
+ if (state == 1 && fileManager.showDiff && diff != "")
+ NestUI.normal(diff)
+ if (state == 1 && fileManager.showLog)
+ showLog(logFile.get)
+ case None =>
+ }
+ } catch {
+ case npe: NullPointerException =>
+ }
+ }
+
+ val numFiles = files.size
+ if (numFiles == 0)
+ reportAll(ImmMap(), topcont)
+
+ // maps canonical file names to the test result (0: OK, 1: FAILED, 2: TIMOUT)
+ var status = new HashMap[String, Int]
+
+ var fileCnt = 1
+ Actor.loopWhile(fileCnt <= numFiles) {
+ val parent = self
+
+ actor {
+ val testFile = files(fileCnt-1)
+
+ val ontimeout = new TimerTask {
+ def run() = parent ! Timeout(testFile)
+ }
+ timer.schedule(ontimeout, fileManager.timeout.toLong)
+
+ val context = try {
+ processSingleFile(testFile)
+ } catch {
+ case t: Throwable =>
+ NestUI.verbose("while invoking compiler ("+files+"):")
+ NestUI.verbose("caught "+t)
+ t.printStackTrace
+ if (t.getCause != null)
+ t.getCause.printStackTrace
+ LogContext(null, None)
+ }
+ parent ! Result(testFile, context)
+ }
+
+ react {
+ case res: TestResult =>
+ val path = res.file.getCanonicalPath
+ status.get(path) match {
+ case Some(stat) => // ignore message
+ case None =>
+ res match {
+ case Timeout(_) =>
+ status = status + (path -> 2)
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ printInfoStart(res.file, wr)
+ succeeded = false
+ reportResult(2, None, Some((swr, wr)))
+ case Result(_, logs) =>
+ status = status + (path -> (if (succeeded) 0 else 1))
+ reportResult(
+ if (succeeded) 0 else 1,
+ if (logs != null) Some(logs.file) else None,
+ if (logs != null) logs.writers else None)
+ }
+ if (fileCnt == numFiles)
+ reportAll(status, topcont)
+ fileCnt += 1
+ }
+ }
+ }
+ }
+
+ private def withOutputRedirected(out: PrintStream)(func: => Unit) {
+ val oldStdOut = System.out
+ val oldStdErr = System.err
+
+ try {
+ System.setOut(out)
+ System.setErr(out)
+ func
+ out.flush()
+ out.close()
+ } finally {
+ System.setOut(oldStdOut)
+ System.setErr(oldStdErr)
+ }
+ }
+
+ private def filesToSet(pre: String, fs: List[String]): Set[AbstractFile] =
+ fs flatMap (s => Option(AbstractFile getFile (pre + s))) toSet
+
+ private def copyTestFiles(testDir: File, destDir: File) {
+ val invalidExts = List("changes", "svn", "obj")
+ testDir.listFiles.toList filter (
+ f => (isJavaOrScala(f) && f.isFile) ||
+ (f.isDirectory && !(invalidExts.contains(SFile(f).extension)))) foreach
+ { f => fileManager.copyFile(f, destDir) }
+ }
+
+ def showLog(logFile: File) {
+ try {
+ val logReader = new BufferedReader(new FileReader(logFile))
+ val strWriter = new StringWriter
+ val logWriter = new PrintWriter(strWriter, true)
+ val logAppender = new StreamAppender(logReader, logWriter)
+ logAppender.run()
+ logReader.close()
+ val log = strWriter.toString
+ NestUI.normal(log)
+ } catch {
+ case fnfe: java.io.FileNotFoundException =>
+ NestUI.failure("Couldn't open log file \""+logFile+"\".")
+ }
+ }
+}
diff --git a/src/partest/scala/tools/partest/package.scala b/src/partest/scala/tools/partest/package.scala
index f6d216e379..e9eda6fb75 100644
--- a/src/partest/scala/tools/partest/package.scala
+++ b/src/partest/scala/tools/partest/package.scala
@@ -4,42 +4,37 @@
package scala.tools
-import nsc.io.{ File, Path, Process, Directory }
-import java.nio.charset.CharacterCodingException
+import java.io.{ File => JFile }
+import nsc.io.{ Path, Process, Directory }
+import util.{ PathResolver }
+import nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
package object partest {
- /** The CharacterCodingExceptions are thrown at least on windows trying
- * to read a file like script/utf-8.scala
- */
- private[partest] def safeSlurp(f: File) =
- try if (f.exists) f.slurp() else ""
- catch { case _: CharacterCodingException => "" }
-
- private[partest] def safeLines(f: File) = safeSlurp(f) split """\r\n|\r|\n""" toList
- private[partest] def safeArgs(f: File) = toArgs(safeSlurp(f))
- private[partest] def isJava(f: Path) = f.isFile && (f hasExtension "java")
- private[partest] def isScala(f: Path) = f.isFile && (f hasExtension "scala")
- private[partest] def isJavaOrScala(f: Path) = isJava(f) || isScala(f)
-
- private[partest] def toArgs(line: String) = cmd toArgs line
- private[partest] def fromArgs(args: List[String]) = cmd fromArgs args
-
- /** Strings, argument lists, etc. */
-
- private[partest] def fromAnyArgs(args: List[Any]) = args mkString " " // separate to avoid accidents
- private[partest] def toStringTrunc(x: Any, max: Int = 240) = {
- val s = x.toString
- if (s.length < max) s
- else (s take max) + " [...]"
+ import nest.NestUI
+
+ implicit private[partest] def temporaryPath2File(x: Path): JFile = x.jfile
+ implicit private[partest] def temporaryFile2Path(x: JFile): Path = Path(x)
+
+ def basename(name: String): String = Path(name).stripExtension
+ def resultsToStatistics(results: Iterable[(_, Int)]): (Int, Int) = {
+ val (files, failures) = results map (_._2 == 0) partition (_ == true)
+ (files.size, failures.size)
+ }
+
+ def vmArgString = {
+ val str = Process.javaVmArguments mkString " "
+ "Java VM started with arguments: '%s'" format str
+ }
+
+ def allPropertiesString = {
+ import collection.JavaConversions._
+ System.getProperties.toList.sorted map { case (k, v) => "%s -> %s\n".format(k, v) } mkString
}
- private[partest] def setProp(k: String, v: String) = scala.util.Properties.setProp(k, v)
- /** Pretty self explanatory. */
- def printAndExit(msg: String): Unit = {
- println(msg)
- exit(1)
+ def showAllJVMInfo {
+ NestUI.verbose(vmArgString)
+ NestUI.verbose(allPropertiesString)
}
- /** Apply a function and return the passed value */
- def returning[T](x: T)(f: T => Unit): T = { f(x) ; x }
+ def isPartestDebug = propOrEmpty("partest.debug") == "true"
} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/util/package.scala b/src/partest/scala/tools/partest/util/package.scala
deleted file mode 100644
index bc5470ba5d..0000000000
--- a/src/partest/scala/tools/partest/util/package.scala
+++ /dev/null
@@ -1,61 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2010 LAMP/EPFL
- */
-
-package scala.tools
-package partest
-
-import java.util.{ Timer, TimerTask }
-import java.io.StringWriter
-import nsc.io._
-
-/** Misc code still looking for a good home.
- */
-package object util {
-
- def allPropertiesString() = javaHashtableToString(System.getProperties)
-
- private def javaHashtableToString(table: java.util.Hashtable[_,_]) = {
- import collection.JavaConversions._
- (table.toList map { case (k, v) => "%s -> %s\n".format(k, v) }).sorted mkString
- }
-
- def filesToSet(pre: String, fs: List[String]): Set[AbstractFile] =
- fs flatMap (x => Option(AbstractFile getFile (Path(pre) / x).path)) toSet
-
- /** Copies one Path to another Path, trying to be sensible when one or the
- * other is a Directory. Returns true if it believes it succeeded.
- */
- def copyPath(from: Path, to: Path): Boolean = {
- if (!to.parent.isDirectory)
- to.parent.createDirectory(force = true)
-
- def copyDir = {
- val sub = to / from.name createDirectory true
- from.toDirectory.list forall (x => copyPath(x, sub))
- }
- (from.isDirectory, to.isDirectory) match {
- case (true, true) => copyDir
- case (true, false) => false
- case (false, true) => from.toFile copyTo (to / from.name)
- case (false, false) => from.toFile copyTo to
- }
- }
-
- /**
- * Compares two files using a Java implementation of the GNU diff
- * available at http://www.bmsi.com/java/#diff.
- *
- * @param f1 the first file to be compared
- * @param f2 the second file to be compared
- * @return the text difference between the compared files
- */
- def diffFiles(f1: File, f2: File): String = {
- val diffWriter = new StringWriter
- val args = Array(f1.toAbsolute.path, f2.toAbsolute.path)
-
- io.DiffPrint.doDiff(args, diffWriter)
- val result = diffWriter.toString
- if (result == "No differences") "" else result
- }
-}
diff --git a/src/partest/scala/tools/partest/utils/PrintMgr.scala b/src/partest/scala/tools/partest/utils/PrintMgr.scala
new file mode 100644
index 0000000000..10533130f1
--- /dev/null
+++ b/src/partest/scala/tools/partest/utils/PrintMgr.scala
@@ -0,0 +1,52 @@
+/* __ *\
+** ________ ___ / / ___ Scala Parallel Testing **
+** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+package scala.tools.partest
+package utils
+
+/**
+ * @author Thomas Hofer
+ */
+object PrintMgr {
+
+ val NONE = 0
+ val SOME = 1
+ val MANY = 2
+
+ var outline = ""
+ var success = ""
+ var failure = ""
+ var warning = ""
+ var default = ""
+
+ def initialization(number: Int) = number match {
+ case MANY =>
+ outline = Console.BOLD + Console.BLACK
+ success = Console.BOLD + Console.GREEN
+ failure = Console.BOLD + Console.RED
+ warning = Console.BOLD + Console.YELLOW
+ default = Console.RESET
+ case SOME =>
+ outline = Console.BOLD + Console.BLACK
+ success = Console.RESET
+ failure = Console.BOLD + Console.BLACK
+ warning = Console.BOLD + Console.BLACK
+ default = Console.RESET
+ case _ =>
+ }
+
+ def printOutline(msg: String) = print(outline + msg + default)
+
+ def printSuccess(msg: String) = print(success + msg + default)
+
+ def printFailure(msg: String) = print(failure + msg + default)
+
+ def printWarning(msg: String) = print(warning + msg + default)
+}
diff --git a/src/partest/scala/tools/partest/Properties.scala b/src/partest/scala/tools/partest/utils/Properties.scala
index 4eeb0359ec..237ddea14e 100644
--- a/src/partest/scala/tools/partest/Properties.scala
+++ b/src/partest/scala/tools/partest/utils/Properties.scala
@@ -8,8 +8,8 @@
// $Id$
-package scala.tools
-package partest
+package scala.tools.partest
+package utils
/** Loads partest.properties from the jar. */
object Properties extends scala.util.PropertiesTrait {