From a176556bea2482d4c3c86a3604ec1eaa16d0daf1 Mon Sep 17 00:00:00 2001 From: Philipp Haller Date: Fri, 8 Feb 2008 17:43:02 +0000 Subject: More functionality and cleaned-up output --- .../scala/tools/partest/nest/CompileManager.scala | 6 +- .../scala/tools/partest/nest/FileManager.scala | 42 +++--- .../scala/tools/partest/nest/NestRunner.scala | 114 +++++++++++++-- src/partest/scala/tools/partest/nest/NestUI.scala | 18 +++ .../scala/tools/partest/nest/StreamAppender.scala | 30 ++++ .../scala/tools/partest/nest/TestFile.scala | 20 ++- src/partest/scala/tools/partest/nest/Worker.scala | 160 ++++++++++++++++----- 7 files changed, 318 insertions(+), 72 deletions(-) create mode 100644 src/partest/scala/tools/partest/nest/StreamAppender.scala (limited to 'src/partest') diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index 526c59e1a4..b31653ffde 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -43,7 +43,7 @@ class DirectCompiler extends SimpleCompiler { def newReporter(sett: Settings) = new ExtConsoleReporter(sett, Console.in, - new PrintWriter(new FileWriter("/home/phaller/svn/scala3/test/scalac-out"))) + new PrintWriter(new FileWriter("scalac-out"))) val testSettings = newSettings val testRep = newReporter(testSettings) @@ -55,19 +55,17 @@ class DirectCompiler extends SimpleCompiler { case "neg" => NegTestFile(file) case "run" => RunTestFile(file) case "jvm" => JvmTestFile(file) + case "jvm5" => Jvm5TestFile(file) case "shootout" => ShootoutTestFile(file) } test.defineSettings(testSettings) val toCompile = List(file.getPath) try { - println(global + " compiling " + toCompile) (new global.Run) compile toCompile testRep.printSummary testRep.writer.flush testRep.writer.close - println(global + " finished compiling " + file) - println(this+" errors: "+testRep.hasErrors) } catch { case e: Exception => e.printStackTrace() diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index 60f01fe31f..2a205f42a0 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -12,7 +12,7 @@ object FileManager { val PATH_SEP = File.pathSeparatorChar val CLASSPATH = System.getProperty("java.class.path", ".") val PREFIX = System.getProperty("user.dir", ".")+"/.." - val JAVACMD = "java" //TODO: detect + val JAVACMD = System.getProperty("nest.javacmd", "java") /* if [ -d "$PREFIX/test" ]; then @@ -77,16 +77,19 @@ elif [ -d "$PREFIX/bin" ]; then val bin = new File(PREFIX, "bin") if (dists.exists && dists.isDirectory) { + 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") } else if (build.exists && build.isDirectory) { + latestFile = prefixFile("build/quick/bin") latestLibFile = prefixFile("build/quick/lib/library") latestCompFile = prefixFile("build/quick/lib/compiler") latestPartestFile = prefixFile("build/quick/lib/partest") } else if (bin.exists && bin.isDirectory) { + latestFile = prefixFile("bin") latestLibFile = prefixFile("lib/scala-library.jar") latestCompFile = prefixFile("lib/scala-compiler.jar") latestPartestFile = prefixFile("lib/scala-partest.jar") @@ -94,26 +97,32 @@ elif [ -d "$PREFIX/bin" ]; then else error("Scala binaries could not be found") + BIN_DIR = latestFile.getAbsolutePath LATEST_LIB = latestLibFile.getAbsolutePath LATEST_COMP = latestCompFile.getAbsolutePath LATEST_PARTEST = latestPartestFile.getAbsolutePath + SCALA = (new File(latestFile, "scala")).getAbsolutePath + SCALAC_CMD = (new File(latestFile, "scalac")).getAbsolutePath } + var BIN_DIR: String = "" var LATEST_LIB: String = "" var LATEST_COMP: String = "" var LATEST_PARTEST: String = "" + var SCALA: String = "" + var SCALAC_CMD: String = "" + val SCALAC_OPTS = System.getProperty("nest.scalac_opts", "-deprecation -encoding utf8") + + var latestFile: File = _ var latestLibFile: File = _ var latestCompFile: File = _ var latestPartestFile: File = _ // initialize above fields findLatest() -} - -class FileManager { val srcDir = { - val dirname = System.getProperty("scalatest.cwd", "") + val dirname = System.getProperty("nest.cwd", "") val dir = if (dirname.isEmpty) { // guess val libDir = new File(new URI(classOf[Test].getResource("/").toString)) val path = libDir.getAbsolutePath @@ -131,17 +140,26 @@ class FileManager { if (!srcDir.isDirectory) { NestUI.failure("Test directory \"" + srcDir.getAbsolutePath + "\" not found") exit(1) - } else { - NestUI.verbose(srcDir.getAbsolutePath) } + def deleteRecursive(dir: File) { + if (dir.isDirectory) { + for (file <- dir.list) deleteRecursive(new File(dir, file)) + } + dir.delete + } +} + +class FileManager { + var testFiles: List[File] = List() def getFiles(kind: String, doCheck: Boolean): List[File] = { val filter = new FilenameFilter { def accept(dir: File, name: String): Boolean = name endsWith ".scala" } - val dir = new File(srcDir, kind) + val dir = new File(FileManager.srcDir, kind) + NestUI.verbose("look in "+dir+" for tests") if (dir.isDirectory) { if (!testFiles.isEmpty) { val dirpath = dir.getAbsolutePath @@ -155,12 +173,4 @@ class FileManager { Nil } } - - def deleteRecursive(dir: File) { - if (dir.isDirectory) { - for (file <- dir.list) deleteRecursive(new File(dir, file)) - } - dir.delete - } - } diff --git a/src/partest/scala/tools/partest/nest/NestRunner.scala b/src/partest/scala/tools/partest/nest/NestRunner.scala index ea75c94f7c..07e2a2d335 100644 --- a/src/partest/scala/tools/partest/nest/NestRunner.scala +++ b/src/partest/scala/tools/partest/nest/NestRunner.scala @@ -4,7 +4,10 @@ package scala.tools.partest.nest -import java.io.{File, PrintStream, FileOutputStream} +import java.io.{File, PrintStream, FileOutputStream, BufferedReader, + InputStreamReader, StringWriter} + +import scala.actors.Actor._ object NestRunner { private val version = System.getProperty("java.version", "") @@ -13,6 +16,7 @@ object NestRunner { private var posCheck = false private var negCheck = false private var jvmCheck = false + private var jvm5Check = false private var runCheck = false private var shootoutCheck = false @@ -22,6 +26,9 @@ object NestRunner { private val con = new PrintStream(Console.out) private var out = con + private val errors = + Integer.parseInt(System.getProperty("nest.errors", "0")) + def main(args: Array[String]) { NestUI.initialize(NestUI.MANY) @@ -33,6 +40,7 @@ object NestRunner { case "--pos" => posCheck = true case "--neg" => negCheck = true case "--jvm" => jvmCheck = true + case "--jvm5" => jvm5Check = true case "--run" => runCheck = true case "--shootout" => shootoutCheck = true case "--conservative" => conservative = true @@ -45,7 +53,7 @@ object NestRunner { testFiles = file :: testFiles else { NestUI.failure("File \"" + arg + "\" not found") - exit(1) + System.exit(1) } } else if (out eq con) { val file = new File(arg) @@ -53,17 +61,66 @@ object NestRunner { out = new PrintStream(new FileOutputStream(file)) else { NestUI.failure("Result file \"" + arg + "\" not found") - exit(1) + System.exit(1) } } else NestUI.usage() } } - go() + + NestUI.outline("Source directory is : "+FileManager.srcDir.getAbsolutePath+"\n") + NestUI.outline("Scala binaries in : "+FileManager.BIN_DIR+"\n") + + // obtain scalac version + val cmd = FileManager.SCALAC_CMD+" -version" + NestUI.verbose("running "+cmd) + val proc = Runtime.getRuntime.exec(cmd) + val in = proc.getInputStream + val err = proc.getErrorStream + val writer = new StringWriter + val errWriter = new StringWriter + val appender = new StreamAppender(new InputStreamReader(in), writer) + val errApp = new StreamAppender(new InputStreamReader(err), errWriter) + appender.start() + errApp.start() + val exitCode = proc.waitFor() + NestUI.verbose("exit code: "+exitCode) + writer.flush() + errWriter.flush() + val scalaVersion = writer.toString + errWriter.toString + + NestUI.outline("Scala version is : "+scalaVersion) + NestUI.outline("Scalac options are : "+FileManager.SCALAC_OPTS+"\n") + + val start = System.currentTimeMillis + val (successes, failures) = testCheckAll() + 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") + + if (failures == errors) + System.exit(0) + else + System.exit(1) } } - def runTests(kind: String, check: Boolean, msg: String) { + def runTests(kind: String, check: Boolean, msg: String): (Int, Int) = { if (check) { val fileMgr = new FileManager val kindFiles = @@ -71,16 +128,47 @@ object NestRunner { else fileMgr.getFiles(kind, check) if (!kindFiles.isEmpty) { NestUI.outline("\n"+msg+"\n") - val worker = new Worker - worker.runTests(kind, kindFiles) + + val numActors = 4 + 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 + worker.start() + if (i == last) + worker ! RunTests(kind, (kindFiles splitAt (last*testsEach))._2) + else + worker ! RunTests(kind, toTest) + worker + } + var succs = 0; var fails = 0 + workers foreach { w => + receive { + case Results(s, f) => succs += s; fails += f + } + } + (succs, fails) + + //val worker = new Worker + //worker.runTests(kind, kindFiles) + } else { + NestUI.failure("test dir empty") + (0, 0) } - } + } else (0, 0) } - def go() { - runTests("pos", posCheck, "Testing compiler (on files whose compilation should succeed)") - runTests("run", runCheck, "Testing JVM backend") - runTests("jvm", jvmCheck, "Testing JVM backend") + /** + * @return (success count, failure count) + */ + def testCheckAll(): (Int, Int) = { + val results = List(runTests("pos", posCheck, "Testing compiler (on files whose compilation should succeed)"), + runTests("run", runCheck, "Testing JVM backend"), + runTests("jvm", jvmCheck, "Testing JVM backend"), + runTests("jvm5", jvm5Check, "Testing JVM backend")) + results reduceLeft { (p: (Int, Int), q: (Int, Int)) => + (p._1+q._1, p._2+q._2) } } - } diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala index ff68c0d90f..4f295c1111 100644 --- a/src/partest/scala/tools/partest/nest/NestUI.scala +++ b/src/partest/scala/tools/partest/nest/NestUI.scala @@ -4,6 +4,8 @@ package scala.tools.partest.nest +import java.io.PrintWriter + object NestUI { val NONE = 0 @@ -33,13 +35,29 @@ object NestUI { } 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 [] [ ..] []") diff --git a/src/partest/scala/tools/partest/nest/StreamAppender.scala b/src/partest/scala/tools/partest/nest/StreamAppender.scala new file mode 100644 index 0000000000..4412d37ae7 --- /dev/null +++ b/src/partest/scala/tools/partest/nest/StreamAppender.scala @@ -0,0 +1,30 @@ +/* NEST (New Scala Test) + * @author Philipp Haller + */ + +package scala.tools.partest.nest + +import java.io.{Writer, PrintWriter, Reader, BufferedReader, + IOException} + +class StreamAppender(from: Reader, to: Writer) { + private val thr = new Thread(new Runnable { + def run() { + try { + val writer = new PrintWriter(to) + val reader = new BufferedReader(from) + var line = reader.readLine() + while (line != null) { + writer.println(line) + line = reader.readLine() + } + writer.flush() + } catch { + case e: IOException => + e.printStackTrace() + } + } + }) + + def start() { thr.start() } +} diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala index ba023723f5..4312dcebf4 100644 --- a/src/partest/scala/tools/partest/nest/TestFile.scala +++ b/src/partest/scala/tools/partest/nest/TestFile.scala @@ -27,11 +27,8 @@ class TestFile(kind: String, val file: File) { settings.classpath.value = dirpath settings.outdir.value = { val outDir = new File(dir, fileBase + "-" + kind + ".obj") - if (!outDir.exists) { + if (!outDir.exists) outDir.mkdir() - NestUI.outline(this+" created "+outDir+"\n") - } else - NestUI.outline(this+" didn't have to create "+outDir+"\n") outDir.toString } } @@ -64,7 +61,18 @@ case class JvmTestFile(override val file: File) extends TestFile("jvm", file) { override def defineSettings(settings: Settings) { baseSettings(settings) settings.classpath.value = CLASSPATH+PATH_SEP+EXT_CLASSPATH - println("settings.classpath.value="+settings.classpath.value) + //println("settings.classpath.value="+settings.classpath.value) + } +} + +case class Jvm5TestFile(override val file: File) extends TestFile("jvm5", file) { + import FileManager.{CLASSPATH, EXT_CLASSPATH, PATH_SEP} + + override def defineSettings(settings: Settings) { + baseSettings(settings) + settings.classpath.value = CLASSPATH+PATH_SEP+EXT_CLASSPATH + settings.target.value = "jvm-1.5" + //println("settings.classpath.value="+settings.classpath.value) } } @@ -72,6 +80,6 @@ case class ShootoutTestFile(override val file: File) extends TestFile("shootout" override def defineSettings(settings: Settings) { baseSettings(settings) settings.classpath.value = System.getProperty("EXT_CLASSPATH") - println("CLASSPATH="+settings.classpath.value) + //println("CLASSPATH="+settings.classpath.value) } } diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala index 5999871dd6..35a6331314 100644 --- a/src/partest/scala/tools/partest/nest/Worker.scala +++ b/src/partest/scala/tools/partest/nest/Worker.scala @@ -4,20 +4,61 @@ package scala.tools.partest.nest -import java.io.{File, FileInputStream, FileOutputStream, PrintStream} +import java.io.{File, FileInputStream, FileOutputStream, PrintStream, + PrintWriter, StringWriter} + import java.net.URL import scala.tools.nsc.ObjectRunner +import scala.actors.Actor +import scala.actors.Actor._ + import FileManager._ -class Worker { +case class RunTests(kind: String, files: List[File]) +case class Results(succ: Int, fail: Int) + +class Worker extends Actor { + def act() { + react { + case RunTests(kind, files) => + NestUI.verbose("received "+files.length+" to test") + val (succ, fail) = runTests(kind, files) + sender ! Results(succ, fail) + } + } private def basename(name: String): String = { val inx = name.lastIndexOf(".") if (inx < 0) name else name.substring(0, inx) } + def printInfoStart(file: File, printer: PrintWriter) { + NestUI.outline("testing: ", printer) + val dir = file.getParentFile + val dirpath = dir.getAbsolutePath + val name = file.getAbsolutePath.substring(dirpath.length) + val WIDTH = 56 + NestUI.normal("[...]"+name+List.toString(List.make(WIDTH-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) + } + + abstract class TestRun(file: File) { + def beforeRun(): Unit + def runTest(): Unit + def afterRun(): Unit + def doAll() { + beforeRun(); runTest(); afterRun() + } + } + def execTest(outDir: File, logFile: File) { val cmd = JAVACMD+ @@ -81,13 +122,18 @@ class Worker { } } - def runJvmTests(kind: String, files: List[File]) { + def runJvmTests(kind: String, files: List[File]): (Int, Int) = { val compileMgr = new CompileManager var errors = 0 + var success = true for (file <- files) { - var success = true + val swr = new StringWriter + val wr = new PrintWriter(swr) + success = true + printInfoStart(file, wr) + if (!compileMgr.shouldCompile(file, kind)) { - NestUI.failure("compilation of "+file+" failed\n") + NestUI.verbose("compilation of "+file+" failed\n") success = false } else { // -------- run test -------- @@ -100,9 +146,9 @@ class Worker { //TODO: detect whether we have to use Runtime.exec val useRuntime = true - if (useRuntime) + if (useRuntime) { execTest(outDir, logFile) - else { + } else { val classpath: List[URL] = outDir.toURL :: List(file.getParentFile.toURL) ::: @@ -120,50 +166,98 @@ class Worker { out.close } catch { case e: Exception => - NestUI.warning(e+" ("+file.getPath+")") + NestUI.verbose(e+" ("+file.getPath+")") } } NestUI.verbose(this+" finished running "+fileBase) if (!compareOutput(dir, fileBase, kind, logFile)) { - NestUI.failure("output differs from log file\n") + NestUI.verbose("output differs from log file\n") success = false } + + // delete log file and output dir + FileManager.deleteRecursive(outDir) + FileManager.deleteRecursive(logFile) } // successful compile if (!success) { errors += 1 NestUI.verbose("incremented errors: "+errors) } + printInfoEnd(success, wr) + wr.flush() + swr.flush() + NestUI.normal(swr.toString) } // for each file NestUI.verbose("finished testing "+kind+" with "+errors+" errors") NestUI.verbose("created "+compileMgr.numSeparateCompilers+" separate compilers") + (files.length-errors, errors) } - def runTests(kind: String, files: List[File]): Unit = kind match { - case "pos" => - val compileMgr = new CompileManager - var errors = 0 - for (file <- files) { - if (!compileMgr.shouldCompile(file, kind)) - errors += 1 - } - NestUI.verbose("finished testing "+kind+" with "+errors+" errors") - NestUI.verbose("created "+compileMgr.numSeparateCompilers+" separate compilers") - - case "neg" => - val compileMgr = new CompileManager - var errors = 0 - for (file <- files) { - if (!compileMgr.shouldFailCompile(file, kind)) - errors += 1 - } - NestUI.verbose("finished testing "+kind+" with "+errors+" errors") - NestUI.verbose("created "+compileMgr.numSeparateCompilers+" separate compilers") + def runTests(kind: String, files: List[File]): (Int, Int) = { + val compileMgr = new CompileManager + var errors = 0 + var succeeded = true - case "run" => - runJvmTests(kind, files) + abstract class CompileTestRun(file: File, wr: PrintWriter) extends TestRun(file) { + def beforeRun() { succeeded = true; printInfoStart(file, wr) } + def afterRun() { printInfoEnd(succeeded, wr) } + } - case "jvm" => - runJvmTests(kind, files) + kind match { + case "pos" => { + def posTestRun(file: File, wr: PrintWriter) = new CompileTestRun(file, wr) { + def runTest() { + if (!compileMgr.shouldCompile(file, kind)) { + succeeded = false + errors += 1 + } + } + } + for (file <- files) { + val swr = new StringWriter + val wr = new PrintWriter(swr) + val testRun = posTestRun(file, wr) + testRun.doAll() + wr.flush() + swr.flush() + NestUI.normal(swr.toString) + } + NestUI.verbose("finished testing "+kind+" with "+errors+" errors") + NestUI.verbose("created "+compileMgr.numSeparateCompilers+" separate compilers") + (files.length-errors, errors) + } + case "neg" => { + def negTestRun(file: File, wr: PrintWriter) = new CompileTestRun(file, wr) { + def runTest() { + if (!compileMgr.shouldFailCompile(file, kind)) { + succeeded = false + errors += 1 + } + } + } + for (file <- files) { + val swr = new StringWriter + val wr = new PrintWriter(swr) + val testRun = negTestRun(file, wr) + testRun.doAll() + wr.flush() + swr.flush() + NestUI.normal(swr.toString) + } + NestUI.verbose("finished testing "+kind+" with "+errors+" errors") + NestUI.verbose("created "+compileMgr.numSeparateCompilers+" separate compilers") + (files.length-errors, errors) + } + case "run" => { + runJvmTests(kind, files) + } + case "jvm" => { + runJvmTests(kind, files) + } + case "jvm5" => { + runJvmTests(kind, files) + } + } } } -- cgit v1.2.3