worker.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 698 行 · 第 1/2 页
SCALA
698 行
/* NEST (New Scala Test) * @author Philipp Haller */// $Id: Worker.scala 14547 2008-04-07 16:34:10Z phaller $package scala.tools.partest.nestimport java.io.{File, FileInputStream, FileOutputStream, PrintStream, PrintWriter, StringWriter, FileWriter, InputStreamReader, FileReader, OutputStreamWriter, BufferedReader}import java.net.URLimport scala.tools.nsc.{ObjectRunner, GenericRunnerCommand}import scala.actors.Actorimport scala.actors.Actor._case class RunTests(kind: String, files: List[File])case class Results(succ: Int, fail: Int, logs: List[LogFile], outdirs: List[File])class LogFile(parent: File, child: String) extends File(parent, child) { var toDelete = false}class Worker(val fileManager: FileManager) extends Actor { import fileManager._ import scala.tools.nsc.{Settings, CompilerCommand, Global} import scala.tools.nsc.reporters.ConsoleReporter import scala.tools.nsc.util.FakePos var reporter: ConsoleReporter = _ def error(msg: String) { 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 (succ, fail) = runTests(kind, files) sender ! Results(succ, fail, createdLogFiles, createdOutputDirs) } } 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 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("[...]"+name+List.toString(List.make(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) } var log = "" var createdLogFiles: List[LogFile] = List() var createdOutputDirs: List[File] = List() def createLogFile(dir: File, fileBase: String, kind: String): LogFile = { val logFile = new LogFile(dir, fileBase + "-" + kind + ".log") createdLogFiles = logFile :: createdLogFiles logFile } def createLogFile(file: File, kind: String): LogFile = { val dir = file.getParentFile val fileBase = basename(file.getName) createLogFile(dir, fileBase, kind) } def createOutputDir(dir: File, fileBase: String, kind: String): File = { val outDir = new File(dir, fileBase + "-" + kind + ".obj") createdOutputDirs = outDir :: createdOutputDirs outDir } /* Note: not yet used/tested. */ def execTestObjectRunner(file: File, outDir: File, logFile: File) { val consFM = new ConsoleFileManager import consFM.{latestCompFile, latestLibFile, latestActFile, latestPartestFile, latestFjbgFile} val classpath: List[URL] = outDir.toURL :: //List(file.getParentFile.toURL) ::: List(latestCompFile.toURL, latestLibFile.toURL, latestActFile.toURL, latestPartestFile.toURL, latestFjbgFile.toURL) ::: (List.fromString(CLASSPATH, File.pathSeparatorChar) map { x => (new File(x)).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 { val oldStdOut = System.out val oldStdErr = System.err System.setOut(logWriter) System.setErr(logWriter) /* " -Djava.library.path="+logFile.getParentFile.getAbsolutePath+ " -Dscalatest.output="+outDir.getAbsolutePath+ " -Dscalatest.lib="+LATEST_LIB+ " -Dscalatest.cwd="+outDir.getParent+ " -Djavacmd="+JAVACMD+ */ System.setProperty("java.library.path", logFile.getParentFile.getCanonicalFile.getAbsolutePath) System.setProperty("scalatest.output", outDir.getCanonicalFile.getAbsolutePath) System.setProperty("scalatest.lib", LATEST_LIB) System.setProperty("scalatest.cwd", outDir.getParent) ObjectRunner.run(classpath, "Test", List("jvm")) logWriter.flush() logWriter.close() System.setOut(oldStdOut) System.setErr(oldStdErr) } /*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 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("argsFile: "+argsFile) val fileReader = new FileReader(argsFile) val reader = new BufferedReader(fileReader) val options = reader.readLine() reader.close() options } else "" NestUI.verbose("JAVA_OPTS: "+argString) def quote(path: String) = "\""+path+"\"" val cmd = JAVACMD+ " "+argString+ " -classpath "+outDir+File.pathSeparator+CLASSPATH+ " -Djava.library.path="+logFile.getParentFile.getAbsolutePath+ " -Dscalatest.output="+outDir.getAbsolutePath+ " -Dscalatest.lib="+LATEST_LIB+ " -Dscalatest.cwd="+outDir.getParent+ " -Djavacmd="+JAVACMD+ " scala.tools.nsc.MainGenericRunner"+ " Test jvm" NestUI.verbose(cmd) val proc = Runtime.getRuntime.exec(cmd) 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() 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, writer) appender.run() log = swriter.toString } } def existsCheckFile(dir: File, fileBase: String, kind: String) = { val checkFile = { val chkFile = new File(dir, fileBase + ".check") if (chkFile.isFile) chkFile else new File(dir, fileBase + "-" + kind + ".check") } checkFile.exists && checkFile.canRead } def compareOutput(dir: File, fileBase: String, kind: String, logFile: File): String = { // if check file exists, compare with log file val checkFile = { val chkFile = new File(dir, fileBase + ".check") if (chkFile.isFile) chkFile else new File(dir, fileBase + "-" + kind + ".check") } if (!checkFile.exists || !checkFile.canRead) "" else fileManager.compareFiles(logFile, checkFile) } def file2String(logFile: File) = { 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() strWriter.toString } /** 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]): (Int, Int) = { val compileMgr = new CompileManager(fileManager) var errors = 0 var succeeded = true var diff = "" var log = "" def runInContext(file: File, kind: String, script: (File, File) => Unit) { // 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.exists && 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) // run test-specific code try { script(logFile, outDir) } catch { case e: Exception => e.printStackTrace succeeded = false } if (!succeeded) { errors += 1 NestUI.verbose("incremented errors: "+errors) } else { // delete log file only if test was successful logFile.toDelete = true } printInfoEnd(succeeded, wr) wr.flush() swr.flush() //TODO: needed? NestUI.normal(swr.toString) if (!succeeded && fileManager.showDiff && diff != "") NestUI.normal(diff) else if (!succeeded && fileManager.showLog) showLog(logFile) } } def runJvmTest(file: File, kind: String) { runInContext(file, kind, (logFile: File, outDir: File) => { if (!compileMgr.shouldCompile(file, kind, logFile)) { NestUI.verbose("compilation of "+file+" failed\n") succeeded = false } else { // run test 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) diff = compareOutput(dir, fileBase, kind, logFile) if (!diff.equals("")) { NestUI.verbose("output differs from log file\n") succeeded = false } } }) } kind match { case "pos" => for (file <- files) { runInContext(file, kind, (logFile: File, outDir: File) => { if (!compileMgr.shouldCompile(file, kind, logFile)) { NestUI.verbose("compilation of "+file+" failed\n") succeeded = false } }) } case "neg" =>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?