diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Interpreter.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/File.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/package.scala | 1 | ||||
-rw-r--r-- | src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala | 8 | ||||
-rw-r--r-- | src/partest/scala/tools/partest/nest/CompileManager.scala | 3 | ||||
-rw-r--r-- | src/partest/scala/tools/partest/nest/ConsoleRunner.scala | 7 | ||||
-rw-r--r-- | src/partest/scala/tools/partest/nest/FileManager.scala | 46 | ||||
-rw-r--r-- | src/partest/scala/tools/partest/nest/NestUI.scala | 4 | ||||
-rw-r--r-- | src/partest/scala/tools/partest/nest/StreamAppender.scala | 94 | ||||
-rw-r--r-- | src/partest/scala/tools/partest/nest/Worker.scala | 753 | ||||
-rw-r--r-- | test/files/jvm/actor-link-getstate.scala | 4 | ||||
-rw-r--r-- | test/files/res/bug687.check | 3 | ||||
-rw-r--r-- | test/files/run/programmatic-main.scala | 4 |
14 files changed, 378 insertions, 565 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index aca34ec3a0..70e540701b 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -158,7 +158,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable def logThrowable(t: Throwable): Unit = globalError(throwableAsString(t)) def throwableAsString(t: Throwable): String = if (opt.richExes) Exceptional(t).force().context() - else util.stringFromWriter(t printStackTrace _) + else util.stackTraceString(t) // ------------ File interface ----------------------------------------- diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 3425c04277..e5bc1cf732 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -1041,7 +1041,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { } private def bindUnexceptionally(t: Throwable) = { quietBind("lastException", classOf[Throwable], t) - stringFromWriter(t printStackTrace _) + stackTraceString(t) } /** load and run the code using reflection */ diff --git a/src/compiler/scala/tools/nsc/io/File.scala b/src/compiler/scala/tools/nsc/io/File.scala index eddc9c0de6..284fb81125 100644 --- a/src/compiler/scala/tools/nsc/io/File.scala +++ b/src/compiler/scala/tools/nsc/io/File.scala @@ -12,7 +12,7 @@ package io import java.io.{ FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter, - BufferedInputStream, BufferedOutputStream, IOException, PrintStream, File => JFile, Closeable => JCloseable } + BufferedInputStream, BufferedOutputStream, IOException, PrintStream, PrintWriter, File => JFile, Closeable => JCloseable } import java.nio.channels.{ Channel, FileChannel } import scala.io.Codec @@ -105,6 +105,9 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w def bufferedWriter(append: Boolean, codec: Codec): BufferedWriter = new BufferedWriter(writer(append, codec)) + def printWriter(): PrintWriter = new PrintWriter(bufferedWriter(), true) + def printWriter(append: Boolean): PrintWriter = new PrintWriter(bufferedWriter(append), true) + /** Creates a new file and writes all the Strings to it. */ def writeAll(strings: String*): Unit = { val out = bufferedWriter() @@ -121,6 +124,13 @@ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) w def appendAll(strings: String*): Unit = { val out = bufferedWriter(append = true) try strings foreach (out write _) + finally out.close() + } + + /** Calls println on each string (so it adds a newline in the PrintWriter fashion.) */ + def printlnAll(strings: String*): Unit = { + val out = printWriter() + try strings foreach (out println _) finally out close } diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index 06e4de80f9..03c8603a6d 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -58,4 +58,5 @@ package object util { ps.close() bs.toString() } + def stackTraceString(ex: Throwable): String = stringFromWriter(ex printStackTrace _) } diff --git a/src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala b/src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala index 8cebcf1685..3d1cee95c6 100644 --- a/src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala +++ b/src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala @@ -83,12 +83,12 @@ object StreamAppender { class StreamAppender(reader: BufferedReader, writer: PrintWriter) extends Runnable { override def run() = runAndMap(identity) private def lines() = Iterator continually reader.readLine() takeWhile (_ != null) - def closeAll() = { - reader.close() - writer.close() - } def runAndMap(f: String => String) = try lines() map f foreach (writer println _) catch { case e: IOException => e.printStackTrace() } + finally { + reader.close() + writer.close() + } } diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index cec9d60743..6a30aa32af 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -37,10 +37,11 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { } def newSettings(out: Option[String]) = { + // val settings = new Settings(Console.err println _) val settings = new Settings(_ => ()) settings.deprecation.value = true settings.nowarnings.value = false - settings.encoding.value = "ISO-8859-1" // XXX why? + settings.encoding.value = "ISO-8859-1" val classpathElements = fileManager.LATEST_LIB :: out.toList settings.classpath.value = ClassPath.join(classpathElements: _*) diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala index eb5cff4fa5..41ecca7d06 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala @@ -87,7 +87,8 @@ class ConsoleRunner extends DirectRunner { def argNarrowsTests(x: String) = denotesTestSet(x) || denotesTestFile(x) || denotesTestDir(x) NestUI._verbose = parsed isSet "--verbose" - fileManager.showDiff = parsed isSet "--show-diff" + fileManager.showDiff = true + // parsed isSet "--show-diff" fileManager.updateCheck = parsed isSet "--update-check" fileManager.showLog = parsed isSet "--show-log" fileManager.failed = parsed isSet "--failed" @@ -205,7 +206,9 @@ class ConsoleRunner extends DirectRunner { resultsToStatistics(runTestsForFiles(files, kind)) } - NestUI.verbose("Run sets: "+enabledSets) + if (enabledSets.nonEmpty) + 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/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index 589332430a..b0b0c326e4 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -12,7 +12,7 @@ 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.tools.nsc.io.{ Path, Directory, File => SFile } import scala.collection.mutable.HashMap trait FileManager { @@ -50,7 +50,9 @@ trait FileManager { var SCALAC_OPTS = PartestDefaults.scalacOpts var JAVA_OPTS = PartestDefaults.javaOpts var timeout = PartestDefaults.timeout - var oneTestTimeout = 15 * 60 * 1000 // okay, let's try 15 + // how can 15 minutes not be enough? What are you doing, run/lisp.scala? + // You complete in 11 seconds on my machine. + var oneTestTimeout = 60 * 60 * 1000 /** Only when --debug is given. */ lazy val testTimings = new HashMap[String, Long] @@ -64,8 +66,9 @@ trait FileManager { new LogFile(dir, fileBase + "-" + kind + ".log") def getLogFile(file: File, kind: String): LogFile = { - val dir = file.getParentFile + val dir = file.getParentFile val fileBase = basename(file.getName) + getLogFile(dir, fileBase, kind) } @@ -75,38 +78,27 @@ trait FileManager { 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) + from.listFiles.toList forall (copyFile(_, subDir)) + } + else { + val to = if (dest.isDirectory) new File(dest, from.getName) else dest + + try { + SFile(to) writeAll SFile(from).slurp() + true + } + catch { case _: IOException => false } + } } 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() + val f = SFile(file) - tmpFile.delete() + f.printlnAll(f.lines.toList map replace: _*) } } diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala index 38110645ba..2bf7cd0667 100644 --- a/src/partest/scala/tools/partest/nest/NestUI.scala +++ b/src/partest/scala/tools/partest/nest/NestUI.scala @@ -116,4 +116,8 @@ object NestUI { println(msg) } } + def shout(msg: String) { + warning("something is wrong:") + println(msg) + } } diff --git a/src/partest/scala/tools/partest/nest/StreamAppender.scala b/src/partest/scala/tools/partest/nest/StreamAppender.scala deleted file mode 100644 index 8cebcf1685..0000000000 --- a/src/partest/scala/tools/partest/nest/StreamAppender.scala +++ /dev/null @@ -1,94 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2010 LAMP/EPFL - * @author Philipp Haller - */ - -// $Id$ - -package scala.tools.partest -package nest - -import java.io._ - -object StreamAppender { - def wrapIn(in: InputStream): BufferedReader = new BufferedReader(new InputStreamReader(in)) - def wrapIn(reader: Reader): BufferedReader = new BufferedReader(reader) - def wrapIn(str: String): BufferedReader = new BufferedReader(new StringReader(str)) - - def wrapOut(out: OutputStream): PrintWriter = new PrintWriter(new OutputStreamWriter(out), true) - def wrapOut(writer: Writer): PrintWriter = new PrintWriter(writer, true) - def wrapOut(): PrintWriter = wrapOut(new StringWriter) - - def apply(reader: BufferedReader, writer: Writer): StreamAppender = - new StreamAppender(reader, wrapOut(writer)) - - def apply(reader: Reader, writer: Writer): StreamAppender = - apply(wrapIn(reader), writer) - - def apply(in: InputStream, writer: Writer): StreamAppender = - apply(wrapIn(in), writer) - - def apply(str: String, writer: Writer): StreamAppender = - apply(wrapIn(str), writer) - - def apply(in: File, out: File): StreamAppender = - apply(new FileReader(in), new FileWriter(out)) - - def appendToString(in1: InputStream, in2: InputStream): String = { - val swriter1 = new StringWriter - val swriter2 = new StringWriter - val app1 = StreamAppender(wrapIn(in1), swriter1) - val app2 = StreamAppender(wrapIn(in2), swriter2) - - val async = new Thread(app2) - async.start() - app1.run() - async.join() - swriter1.toString + swriter2.toString - } -/* - private def inParallel(t1: Runnable, t2: Runnable, t3: Runnable) { - val thr1 = new Thread(t1) - val thr2 = new Thread(t2) - thr1.start() - thr2.start() - t3.run() - thr1.join() - thr2.join() - } -*/ - private def inParallel(t1: Runnable, t2: Runnable) { - val thr = new Thread(t2) - thr.start() - t1.run() - thr.join() - } - - def concat(in: InputStream, err: InputStream, out: OutputStream) = new Runnable { - override def run() { - val outWriter = wrapOut(out) - val inApp = StreamAppender(in, outWriter) - - val errStringWriter = new StringWriter - val errApp = StreamAppender(wrapIn(err), errStringWriter) - - inParallel(inApp, errApp) - - // append error string to out - StreamAppender(errStringWriter.toString, outWriter).run() - } - } -} - -class StreamAppender(reader: BufferedReader, writer: PrintWriter) extends Runnable { - override def run() = runAndMap(identity) - private def lines() = Iterator continually reader.readLine() takeWhile (_ != null) - def closeAll() = { - reader.close() - writer.close() - } - - def runAndMap(f: String => String) = - try lines() map f foreach (writer println _) - catch { case e: IOException => e.printStackTrace() } -} diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala index 7aa4ccc546..73a09b4733 100644 --- a/src/partest/scala/tools/partest/nest/Worker.scala +++ b/src/partest/scala/tools/partest/nest/Worker.scala @@ -16,21 +16,18 @@ 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, ScalaClassLoader } +import scala.tools.nsc.util.{ ClassPath, FakePos, ScalaClassLoader, stackTraceString } 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.tools.scalap.scalax.rules.scalasig.ByteCode import scala.collection.{ mutable, immutable } -import scala.collection.immutable.{ HashMap, Map => ImmMap } -import scala.collection.Map - -import scala.tools.nsc.interactive.{BuildManager, RefinedBuildManager} +import scala.tools.nsc.interactive.{ BuildManager, RefinedBuildManager } +import scala.sys.process._ case class RunTests(kind: String, files: List[File]) -case class Results(results: ImmMap[String, Int], logs: List[LogFile], outdirs: List[File]) +case class Results(results: Map[String, Int], logs: List[LogFile], outdirs: List[File]) case class LogContext(file: LogFile, writers: Option[(StringWriter, PrintWriter)]) @@ -67,12 +64,11 @@ object Output { private val redirVar = new DynamicVariable[Option[PrintStream]](None) class Redirecter(stream: PrintStream) extends PrintStream(new OutputStream { - private def withStream(f: PrintStream => Unit) = { - if (redirVar.value != None) f(redirVar.value.get) - else f(stream) - } - def write(b: Int) = withStream(_.write(b)) - override def write(b: Array[Byte]) = withStream(_.write(b)) + def write(b: Int) = withStream(_ write b) + + private def withStream(f: PrintStream => Unit) = f(redirVar.value getOrElse stream) + + override def write(b: Array[Byte]) = withStream(_ write b) override def write(b: Array[Byte], off: Int, len: Int) = withStream(_.write(b, off, len)) override def flush = withStream(_.flush) override def close = withStream(_.close) @@ -83,22 +79,16 @@ object Output { object errRedirect extends Redirecter(err) // this supports thread-safe nested output redirects - def withRedirected(newstream: PrintStream)(func: => Unit) { + def withRedirected[T](newstream: PrintStream)(func: => T): T = { // note down old redirect destination // this may be None in which case outRedirect and errRedirect print to stdout and stderr - val oldred = redirVar.value - + val saved = redirVar.value // set new redirecter // this one will redirect both out and err to newstream redirVar.value = Some(newstream) - try { - func - } finally { - // revert to old redirect - // this may be None, which makes outRedirect and errRedirect choose standard outputs again - redirVar.value = oldred - } + try func + finally redirVar.value = saved } } @@ -137,7 +127,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor * I can see what they're doing when the world comes to a premature stop. */ private val filesRemaining = new mutable.HashSet[File] - private def addFilesRemaining(xs: Traversable[File]) = filesRemaining ++= xs + private def addFilesRemaining(xs: Traversable[File]) = synchronized { filesRemaining ++= xs } private var currentTestFile: File = _ private var currentFileStart: Long = System.currentTimeMillis @@ -152,6 +142,18 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor currentTimerTask.kick() } + /** This does something about absolute paths and file separator + * chars before diffing. + */ + private def replaceSlashes(dir: File, s: String): String = { + val path = dir.getAbsolutePath+File.separator + val line = s indexOf path match { + case -1 => s + case idx => (s take idx) + (s drop idx + path.length) + } + line.replace('\\', '/') + } + private def currentFileString = { "Current test file is: %s\n Started: %s (%s seconds ago)\n Current time: %s".format( currentTestFile, @@ -160,11 +162,14 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor new java.util.Date() ) } - private def getNextFile() = synchronized { - currentTestFile = filesRemaining.head - filesRemaining -= currentTestFile - currentFileStart = System.currentTimeMillis - currentTestFile + private def getNextFile(): File = synchronized { + if (filesRemaining.isEmpty) null + else { + currentTestFile = filesRemaining.head + filesRemaining -= currentTestFile + currentFileStart = System.currentTimeMillis + currentTestFile + } } // maps canonical file names to the test result (0: OK, 1: FAILED, 2: TIMOUT) private val status = new mutable.HashMap[String, Int] @@ -173,7 +178,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor } override def toString = ( ">> Partest Worker in state " + getState + ":\n" + - currentFileString + + currentFileString + "\n" + "There are " + filesRemaining.size + " files remaining:\n" + filesRemaining.toList.sortBy(_.toString).map(" " + _ + "\n").mkString("") + "\nstatus hashmap contains " + status.size + " entries:\n" + @@ -203,15 +208,10 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor 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 + val name = file.getAbsolutePath drop testdir.getAbsolutePath.length + if (name.length <= totalWidth) name // 2. try with [...]/run/test.scala - else { - val filesPathLen = filesdir.getAbsolutePath.length - file.getAbsolutePath.substring(filesPathLen) - } + else file.getAbsolutePath drop filesdir.getAbsolutePath.length } NestUI.normal("[...]%s%s".format(name, " " * (totalWidth - name.length)), printer) } @@ -248,67 +248,37 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor def javac(outDir: File, files: List[File], output: File): Boolean = { // compile using command-line javac compiler - 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") + val cmd = "%s -d %s -classpath %s %s".format( + javacCmd, + outDir.getAbsolutePath, + join(outDir.toString, CLASSPATH), + files mkString " " + ) + def fail(msg: String) = { + SFile(output) appendAll msg + false } - if (!success) { - val writer = new PrintWriter(new FileWriter(output, true), true) - writer.print(msg) - writer.close() + try runCommand(cmd, output) match { + case 0 => true + case code => fail("javac failed with exit code " + code + "\n" + cmd + "\n") } - success + catch exHandler(output, "javac command '" + cmd + "' failed:\n") } - /** Runs <code>command</code> redirecting standard out and - * error out to <code>output</code> file. + /** Runs command redirecting standard out and + * error out to output 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 } + (command #> output !) } 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+"\"" + val argsFile = new File(logFile.getParentFile, fileBase + ".javaopts") + val argString = file2String(argsFile) + if (argString != "") + NestUI.verbose("Found javaopts file '%s', using options: '%s'".format(argsFile, argString)) // Note! As this currently functions, JAVA_OPTS must precede argString // because when an option is repeated to java only the last one wins. @@ -318,6 +288,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor // // debug: Found javaopts file 'files/shootout/message.scala-2.javaopts', using options: '-Xss32k' // debug: java -Xss32k -Xss2m -Xms256M -Xmx1024M -classpath [...] + val extras = if (isPartestDebug) List("-Dpartest.debug=true") else Nil val propertyOptions = List( "-Djava.library.path="+logFile.getParentFile.getAbsolutePath, "-Dpartest.output="+outDir.getAbsolutePath, @@ -326,9 +297,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor "-Djavacmd="+JAVACMD, "-Djavaccmd="+javacCmd, "-Duser.language=en -Duser.country=US" - ) ::: ( - if (isPartestDebug) List("-Dpartest.debug=true") else Nil - ) + ) ++ extras val cmd = ( List( @@ -336,7 +305,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor JAVA_OPTS, argString, "-classpath " + join(outDir.toString, CLASSPATH) - ) ::: propertyOptions ::: List( + ) ++ propertyOptions ++ List( "scala.tools.nsc.MainGenericRunner", "-usejavacp", "Test", @@ -355,7 +324,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor 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 + Some(checkFile) filter (_.canRead) } def existsCheckFile(dir: File, fileBase: String, kind: String) = @@ -375,58 +344,83 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor case _ => file2String(logFile) } - def file2String(logFile: File) = SFile(logFile).slurp() + def file2String(f: File) = + try SFile(f).slurp() + catch { case _: FileNotFoundException => "" } + def isJava(f: File) = SFile(f) hasExtension "java" def isScala(f: File) = SFile(f) hasExtension "scala" def isJavaOrScala(f: File) = isJava(f) || isScala(f) def outputLogFile(logFile: File) { - NestUI.normal("Log file '" + logFile + "': \n") val lines = SFile(logFile).lines - for (lin <- lines) NestUI.normal(lin + "\n") + if (lines.nonEmpty) { + NestUI.normal("Log file '" + logFile + "': \n") + lines foreach (x => NestUI.normal(x + "\n")) + } + } + def exHandler(logFile: File): PartialFunction[Throwable, Boolean] = exHandler(logFile, "") + def exHandler(logFile: File, msg: String): PartialFunction[Throwable, Boolean] = { + case e: Exception => + SFile(logFile).writeAll(msg, stackTraceString(e)) + outputLogFile(logFile) // if running the test threw an exception, output log file + false } - /** 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) { + def runTests(kind: String, files: List[File])(topcont: Map[String, Int] => Unit) { val compileMgr = new CompileManager(fileManager) if (kind == "scalacheck") fileManager.CLASSPATH += File.pathSeparator + PathSettings.scalaCheck + // You don't default "succeeded" to true. + var succeeded = false var errors = 0 - var succeeded = true var diff = "" var log = "" - def fail(what: Any) { + def initNextTest() = { + val swr = new StringWriter + val wr = new PrintWriter(swr) + diff = "" + log = "" + + ((swr, wr)) + } + + def fail(what: Any) = { NestUI.verbose("scalac: compilation of "+what+" failed\n") - succeeded = false + false } def diffCheck(latestDiff: String) = { diff = latestDiff - if (latestDiff != "") { - NestUI.verbose("output differs from log file\n") - succeeded = false - } + succeeded = diff == "" + succeeded + } + + def timed[T](body: => T): (T, Long) = { + val t1 = System.currentTimeMillis + val result = body + val t2 = System.currentTimeMillis + + (result, t2 - t1) } /** 1. Creates log file and output directory. - * 2. Runs <code>script</code> function, providing log file and - * output directory as arguments. + * 2. Runs script function, providing log file and output directory as arguments. */ - def runInContext(file: File, kind: String, script: (File, File) => Unit): LogContext = { + def runInContext(file: File, kind: String, script: (File, File) => Boolean): 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 = "" + + if (fileManager.failed && !logFile.canRead) + LogContext(logFile, None) + else { + val (swr, wr) = initNextTest() printInfoStart(file, wr) val fileBase: String = basename(file.getName) @@ -436,132 +430,114 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor NestUI.verbose("output directory: "+outDir) // run test-specific code - try { + succeeded = try { if (isPartestDebug) { - val t1 = System.currentTimeMillis - script(logFile, outDir) - val t2 = System.currentTimeMillis - fileManager.recordTestTiming(file.getPath, t2 - t1) + val (result, millis) = timed(script(logFile, outDir)) + fileManager.recordTestTiming(file.getPath, millis) + result } - else { - script(logFile, outDir) - } - } catch { - case e: Exception => - val writer = new PrintWriter(new FileWriter(logFile), true) - e.printStackTrace(writer) - writer.close() - outputLogFile(logFile) // if running the test threw an exception, output log file - succeeded = false + else script(logFile, outDir) } + catch exHandler(logFile) LogContext(logFile, Some((swr, wr))) - } else - LogContext(logFile, None) + } } - def compileFilesIn(dir: File, kind: String, logFile: File, outDir: File) { + def compileFilesIn(dir: File, kind: String, logFile: File, outDir: File): Boolean = { 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 filterNot (groups.flatten contains) - def compileGroup(g: List[File]) { + def compileGroup(g: List[File]): Boolean = { val (scalaFiles, javaFiles) = g partition isScala + val allFiles = javaFiles ++ scalaFiles - 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) + // scala+java, then java, then scala + (scalaFiles.isEmpty || compileMgr.shouldCompile(outDir, allFiles, kind, logFile) || fail(g)) && { + (javaFiles.isEmpty || javac(outDir, javaFiles, logFile)) && { + (scalaFiles.isEmpty || compileMgr.shouldCompile(outDir, scalaFiles, kind, logFile) || fail(scalaFiles)) + } } } - if (noGroupSuffix.nonEmpty) - compileGroup(noGroupSuffix) - - groups foreach (grp => if (succeeded) compileGroup(grp)) + (noGroupSuffix.isEmpty || compileGroup(noGroupSuffix)) && (groups forall compileGroup) } - def failCompileFilesIn(dir: File, kind: String, logFile: File, outDir: File) { + def failCompileFilesIn(dir: File, kind: String, logFile: File, outDir: File): Boolean = { val testFiles = dir.listFiles.toList val sourceFiles = testFiles filter isJavaOrScala - if (sourceFiles.nonEmpty) { - if (!compileMgr.shouldFailCompile(outDir, sourceFiles, kind, logFile)) - fail(testFiles filter isScala) - } + sourceFiles.isEmpty || compileMgr.shouldFailCompile(outDir, sourceFiles, kind, logFile) || fail(testFiles filter isScala) } - def runTestCommon(file: File, kind: String, expectFailure: Boolean)(onSuccess: (File, File) => Unit, onFail: (File, File) => Unit = (logf, outd) => ()): LogContext = + def runTestCommon(file: File, kind: String, expectFailure: Boolean)( + onSuccess: (File, File) => Boolean, + onFail: (File, File) => Unit = (_, _) => ()): LogContext = + { runInContext(file, kind, (logFile: File, outDir: File) => { + val result = + if (file.isDirectory) { + if (expectFailure) failCompileFilesIn(file, kind, logFile, outDir) + else compileFilesIn(file, kind, logFile, outDir) + } + else { + if (expectFailure) compileMgr.shouldFailCompile(List(file), kind, logFile) + else compileMgr.shouldCompile(List(file), kind, logFile) + } - 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) - else - onFail(logFile, outDir) + if (result) onSuccess(logFile, outDir) + else { onFail(logFile, outDir) ; false } }) + } def runJvmTest(file: File, kind: String): LogContext = runTestCommon(file, kind, expectFailure = false)((logFile, outDir) => { val fileBase = basename(file.getName) val dir = file.getParentFile - execTest(outDir, logFile, 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 succFn: (File, File) => Boolean = { (logFile, outDir) => NestUI.verbose("compilation of "+file+" succeeded\n") - val outURL = outDir.getCanonicalFile.toURI.toURL - + val outURL = outDir.getCanonicalFile.toURI.toURL val logWriter = new PrintStream(new FileOutputStream(logFile)) Output.withRedirected(logWriter) { - // this classloader is test specific - // its parent contains library classes and others - val classloader = ScalaClassLoader.fromURLs(List(outURL), params.scalaCheckParentClassLoader) - classloader.run("Test", Nil) + // this classloader is test specific: its parent contains library classes and others + ScalaClassLoader.fromURLs(List(outURL), params.scalaCheckParentClassLoader).run("Test", Nil) } - NestUI.verbose(SFile(logFile).slurp()) + NestUI.verbose(file2String(logFile)) // obviously this must be improved upon - val lines = SFile(logFile).lines.filter(_.trim != "").toBuffer - succeeded = { - val failures = lines filter (_ startsWith "!") - //val passedok = lines filter (_ startsWith "+") forall (_ contains "OK") - OK may wrap!! - failures.isEmpty + val lines = SFile(logFile).lines map (_.trim) filterNot (_ == "") toBuffer; + if (lines forall (x => !x.startsWith("!"))) { + NestUI.verbose("test for '" + file + "' success: " + succeeded) + true } - if (!succeeded) { + else { NestUI.normal("ScalaCheck test failed. Output:\n") - for (lin <- lines) NestUI.normal(lin + "\n") + lines foreach (x => NestUI.normal(x + "\n")) + false } - NestUI.verbose("test for '" + file + "' success: " + succeeded) - }, (logFile, outDir) => outputLogFile(logFile)) + } + runTestCommon(file, kind, expectFailure = false)( + succFn, + (logFile, outDir) => outputLogFile(logFile) + ) case "pos" => - runTestCommon(file, kind, expectFailure = false)((_, _) => ()) + runTestCommon(file, kind, expectFailure = false)( + (logFile, outDir) => true, + (_, _) => () + ) case "neg" => runTestCommon(file, kind, expectFailure = true)((logFile, outDir) => { @@ -582,39 +558,36 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor case "buildmanager" => val logFile = createLogFile(file, kind) if (!fileManager.failed || logFile.canRead) { - val swr = new StringWriter - val wr = new PrintWriter(swr) - succeeded = true; diff = "" + val (swr, wr) = initNextTest() 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 + val (outDir, testFile, changesDir, fileBase) = ( + if (!file.isDirectory) (null, null, null, null) - } else { - copyTestFiles(file, outDir) - NestUI.verbose("outDir: "+outDir) - NestUI.verbose("logFile: "+logFile) - (outDir, testFile, changesDir, fileBase) + 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") + (null, null, null, null) + } + else { + copyTestFiles(file, outDir) + NestUI.verbose("outDir: "+outDir) + NestUI.verbose("logFile: "+logFile) + (outDir, testFile, changesDir, fileBase) + } } - } + ) - if (succeeded) { + if (outDir != null) { // Pre-conditions satisfied - try { val sourcepath = outDir.getAbsolutePath+File.separator @@ -639,12 +612,14 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor new BuilderGlobal(settings, reporter) } - val testCompile = (line: String) => { + val testCompile: String => Boolean = { line => 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 + command.ok && { + bM.update(filesToSet(settings.sourcepath.value, command.files), Set.empty) + !reporter.hasErrors + } } val updateFiles = (line: String) => { @@ -668,39 +643,35 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor false } }) - if (!res) - NestUI.verbose("updating failed") - else - NestUI.verbose("updating succeeded") + NestUI.verbose("updating " + (if (res) "succeeded" else "failed")) 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 + def loop(): Boolean = { + testReader.readLine() match { + case null | "" => + NestUI.verbose("finished") + true + case s if s startsWith ">>update " => + updateFiles(s stripPrefix ">>update ") && loop() + case s if s startsWith ">>compile " => + val files = s stripPrefix ">>compile " + logWriter.println(prompt + files) + // In the end, it can finish with an error + if (testCompile(files)) loop() + else { + val t = testReader.readLine() + (t == null) || (t == "") } - - if (commandResult) loop() - - } else { - NestUI.verbose("finished") - succeeded = true + case s => + NestUI.verbose("wrong command in test file: " + s) + false } } Output.withRedirected(logWriter) { - loop() - testReader.close() + try loop() + finally testReader.close() } fileManager.mapFile(logFile, "tmp", file, _.replace(sourcepath, ""). replaceAll(java.util.regex.Matcher.quoteReplacement("\\"), "/")) @@ -714,6 +685,9 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor LogContext(logFile, None) case "res" => { + // simulate resident compiler loop + val prompt = "\nnsc> " + // when option "--failed" is provided // execute test only if log file is present // (which means it failed before) @@ -721,9 +695,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor //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 = "" + val (swr, wr) = initNextTest() printInfoStart(file, wr) val fileBase: String = basename(file.getName) @@ -739,9 +711,6 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor // 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) @@ -766,9 +735,6 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor 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) @@ -776,66 +742,26 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor val sett = new Settings(workerError) sett.sourcepath.value = sourcepath val command = new CompilerCommand(cmdArgs, sett) - (new compiler.Run) compile command.files + command.ok && { + (new compiler.Run) compile command.files + !reporter.hasErrors + } } - def loop(action: (String) => Unit) { + def loop(action: String => Boolean): Boolean = { 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) + resReader.readLine() match { + case null | "" => logWriter.flush() ; true + case line => action(line) && loop(action) } } Output.withRedirected(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('\\', '/') + try loop(resCompile) + finally resReader.close() } - - fileManager.mapFile(logFile, "tmp", dir, replaceSlashes) + fileManager.mapFile(logFile, "tmp", dir, replaceSlashes(dir, _)) diffCheck(compareOutput(dir, fileBase, kind, logFile)) - - } catch { - case e => - e.printStackTrace() - succeeded = false - } - LogContext(logFile, Some((swr, wr))) } else LogContext(logFile, None) @@ -847,9 +773,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor // (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 = "" + val (swr, wr) = initNextTest() printInfoStart(file, wr) val fileBase: String = basename(file.getName) @@ -867,44 +791,27 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor // 3. cat {test}.scala.runner {test}.scala > testFile val runnerFile = new File(dir, fileBase+".scala.runner") val bodyFile = new File(dir, fileBase+".scala") - SFile(testFile).writeAll(List(runnerFile, bodyFile) map (f => SFile(f).slurp()): _*) - - 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 + SFile(testFile).writeAll( + file2String(runnerFile), + file2String(bodyFile) + ) + + // 4. compile testFile + val ok = compileMgr.shouldCompile(List(testFile), kind, logFile) + NestUI.verbose("compilation of " + testFile + (if (ok) "succeeded" else "failed")) + if (ok) { + execTest(outDir, logFile, fileBase) + NestUI.verbose(this+" finished running "+fileBase) + diffCheck(compareOutput(dir, fileBase, kind, logFile)) } - diffCheck(compareOutput(dir, fileBase, kind, logFile)) - LogContext(logFile, Some((swr, wr))) - } else + } + else LogContext(logFile, None) } - case "scalap" => { - + case "scalap" => runInContext(file, kind, (logFile: File, outDir: File) => { val sourceDir = file.getParentFile val sourceDirName = sourceDir.getName @@ -916,14 +823,16 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor if (results.length != 1) { NestUI.verbose("Result file not found in directory " + sourceDirName + " \n") - } else { + false + } + 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 { - + false + } + else { // 3. Decompile file and compare results val isPackageObject = sourceDir.getName.startsWith("package") val className = sourceDirName.capitalize + (if (!isPackageObject) "" else ".package") @@ -934,20 +843,11 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor 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 - } - + SFile(logFile) writeAll result diffCheck(fileManager.compareFiles(logFile, resFile)) } } }) - } case "script" => { // when option "--failed" is provided @@ -955,9 +855,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor // (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 = "" + val (swr, wr) = initNextTest() printInfoStart(file, wr) val fileBase: String = basename(file.getName) @@ -966,9 +864,7 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor // check whether there is an args file val argsFile = new File(file.getParentFile, fileBase+".args") NestUI.verbose("argsFile: "+argsFile) - val argString = - if (!argsFile.exists) "" - else " " + SFile(argsFile).slurp() + val argString = file2String(argsFile) try { val cmdString = @@ -978,23 +874,11 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor 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() + succeeded = ((cmdString+argString) #> logFile !) == 0 diffCheck(compareOutput(file.getParentFile, fileBase, kind, logFile)) - } catch { // *catch-all* + } + catch { // *catch-all* case e: Exception => NestUI.verbose("caught "+e) succeeded = false @@ -1006,86 +890,99 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor } } - 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") + def reportAll(results: Map[String, Int], cont: Map[String, Int] => Unit) { timer.cancel() cont(results) } + object TestState { + val Ok = 0 + val Fail = 1 + val Timeout = 2 + } + def reportResult(state: Int, logFile: Option[LogFile], writers: Option[(StringWriter, PrintWriter)]) { - val good = (state == 0) - if (!good) { + val isGood = state == TestState.Ok + val isFail = state == TestState.Fail + val isTimeout = state == TestState.Timeout + + if (!isGood) { errors += 1 NestUI.verbose("incremented errors: "+errors) } - try { - // delete log file only if test was successful - logFile filter (_ => good && !isPartestDebug) foreach (_.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 => + // delete log file only if test was successful + if (isGood && !isPartestDebug) + logFile foreach (_.toDelete = true) + + writers foreach { case (swr, wr) => + if (swr == null || wr == null || fileManager == null || logFile.exists(_ == null)) { + NestUI.normal("Something is wrong, why are you sending nulls here?") + NestUI.normal(List(swr, wr, fileManager, logFile) mkString " ") + } + else { + if (isTimeout) printInfoTimeout(wr) + else printInfoEnd(isGood, wr) + wr.flush() + swr.flush() + NestUI.normal(swr.toString) + if (isFail && fileManager.showDiff && diff != "") + NestUI.normal(diff) + if (isFail && fileManager.showLog) + logFile foreach showLog } - } catch { - case npe: NullPointerException => } } - if (files.isEmpty) reportAll(ImmMap(), topcont) + if (files.isEmpty) reportAll(Map(), topcont) else addFilesRemaining(files) - Actor.loopWhile(filesRemaining.nonEmpty) { + var done = false + + Actor.loopWhile(!done) { val parent = self actor { val testFile = getNextFile() - updateTimerTask(parent ! Timeout(testFile)) - - 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) + if (testFile == null) done = true + else { + updateTimerTask(parent ! Timeout(testFile)) + + val context = + try processSingleFile(testFile) + catch { + case t: Throwable => + NestUI.shout("Caught something while invoking processSingleFile(%s)".format(testFile)) + t.printStackTrace + NestUI.normal("There were " + filesRemaining.size + " files remaining: " + filesRemaining.mkString(", ")) + LogContext(null, None) + } + parent ! Result(testFile, context) + } } react { case res: TestResult => val path = res.file.getCanonicalPath - if (status contains path) () // ignore message + if (status contains path) { + // ignore message + NestUI.debug("Why are we receiving duplicate messages? Received: " + res + "\nPath is " + path) + } else res match { case Timeout(_) => - updateStatus(path, 2) + updateStatus(path, TestState.Timeout) val swr = new StringWriter val wr = new PrintWriter(swr) printInfoStart(res.file, wr) - succeeded = false - reportResult(2, None, Some((swr, wr))) + reportResult(TestState.Timeout, None, Some((swr, wr))) case Result(_, logs) => - updateStatus(path, (if (succeeded) 0 else 1)) + val state = if (succeeded) TestState.Ok else TestState.Fail + updateStatus(path, state) reportResult( - if (succeeded) 0 else 1, - if (logs != null) Some(logs.file) else None, - if (logs != null) logs.writers else None) + state, + Option(logs) map (_.file), + Option(logs) flatMap (_.writers) + ) } if (filesRemaining.isEmpty) { cancelTimerTask() @@ -1107,10 +1004,10 @@ class Worker(val fileManager: FileManager, params: TestRunParams) extends Actor } def showLog(logFile: File) { - try NestUI.normal(SFile(logFile).slurp()) - catch { - case _: java.io.FileNotFoundException => - NestUI.failure("Couldn't open log file \""+logFile+"\".") + file2String(logFile) match { + case "" if logFile.canRead => () + case "" => NestUI.failure("Couldn't open log file: " + logFile + "\n") + case s => NestUI.normal(s) } } } diff --git a/test/files/jvm/actor-link-getstate.scala b/test/files/jvm/actor-link-getstate.scala index c4c33ef752..c24daf2eff 100644 --- a/test/files/jvm/actor-link-getstate.scala +++ b/test/files/jvm/actor-link-getstate.scala @@ -11,7 +11,7 @@ object Slave extends Actor { loop { react { case 'doWork => - Console.err.println("Done") + Console.out.println("Done") reply('done) } } @@ -50,7 +50,7 @@ object Test { Master.start() react { case Exit(from, reason) if (from == Slave) => - Console.err.println(Slave.getState) + Console.out.println(Slave.getState) } } catch { case e: Throwable if !e.isInstanceOf[scala.util.control.ControlThrowable] => diff --git a/test/files/res/bug687.check b/test/files/res/bug687.check index ee9520d1ea..a905c3fbf0 100644 --- a/test/files/res/bug687.check +++ b/test/files/res/bug687.check @@ -6,6 +6,3 @@ method equals:(x$1: Any)Boolean in class Any have same type after erasure: (o: java.lang.Object)Boolean override def equals(o : Object) = false; ^ - -nsc> -nsc> diff --git a/test/files/run/programmatic-main.scala b/test/files/run/programmatic-main.scala index 9c7d0b7095..3a88252fd3 100644 --- a/test/files/run/programmatic-main.scala +++ b/test/files/run/programmatic-main.scala @@ -7,6 +7,8 @@ object Test { val baseargs = Array("-usejavacp", "-bootclasspath", basedir + "/scala-library.jar", "-cp", basedir + "/scala-compiler.jar") def main(args: Array[String]): Unit = { - Main process (baseargs ++ Array("-Xshow-phases")) + Console.withErr(Console.out) { + Main process (baseargs ++ Array("-Xshow-phases")) + } } } |