diff options
author | Philipp Haller <hallerp@gmail.com> | 2008-10-31 11:54:42 +0000 |
---|---|---|
committer | Philipp Haller <hallerp@gmail.com> | 2008-10-31 11:54:42 +0000 |
commit | 2ed15b9b352621d5ccb6e1e62ae77ee505829b11 (patch) | |
tree | f79bee63d371eebede2393ee8888905cb0fb3f77 | |
parent | 009af5c5334458d386e5dda1adb7d114b3f9430b (diff) | |
download | scala-2ed15b9b352621d5ccb6e1e62ae77ee505829b11.tar.gz scala-2ed15b9b352621d5ccb6e1e62ae77ee505829b11.tar.bz2 scala-2ed15b9b352621d5ccb6e1e62ae77ee505829b11.zip |
Merged multi-file, javac and pos5 support from ...
Merged multi-file, javac and pos5 support from trunk.
10 files changed, 488 insertions, 180 deletions
diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala index f62cd732bf..39eb91da0a 100644 --- a/src/partest/scala/tools/partest/PartestTask.scala +++ b/src/partest/scala/tools/partest/PartestTask.scala @@ -23,6 +23,9 @@ class PartestTask extends Task { def addConfiguredPosTests(input: FileSet): Unit = posFiles = Some(input) + def addConfiguredPos5Tests(input: FileSet): Unit = + pos5Files = Some(input) + def addConfiguredNegTests(input: FileSet): Unit = negFiles = Some(input) @@ -64,6 +67,9 @@ class PartestTask extends Task { def setJavaCmd(input: File): Unit = javacmd = Some(input) + def setJavacCmd(input: File): Unit = + javaccmd = Some(input) + def setScalacOpts(opts: String): Unit = scalacOpts = Some(opts) @@ -72,10 +78,12 @@ class PartestTask extends Task { private var classpath: Option[Path] = 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 pos5Files: Option[FileSet] = None private var negFiles: Option[FileSet] = None private var runFiles: Option[FileSet] = None private var residentFiles: Option[FileSet] = None @@ -85,14 +93,29 @@ class PartestTask extends Task { private var scalacOpts: Option[String] = None private var timeout: Option[String] = None - private def getPosFiles: Array[File] = - if (!posFiles.isEmpty) { - val files = posFiles.get - (files.getDirectoryScanner(getProject).getIncludedFiles map { fs => new File(files.getDir(getProject), fs) }) + private def getFilesAndDirs(fileSet: Option[FileSet]): Array[File] = + if (!fileSet.isEmpty) { + val files = fileSet.get + val dir = files.getDir(getProject) + val fileTests = (files.getDirectoryScanner(getProject).getIncludedFiles map { fs => + new File(dir, fs) }) + val dirTests = dir.listFiles(new java.io.FileFilter { + def accept(file: File) = + file.isDirectory && + (!file.getName().equals(".svn")) && + (!file.getName().endsWith(".obj")) + }) + (dirTests ++ fileTests).toArray } else Array() + private def getPosFiles: Array[File] = + getFilesAndDirs(posFiles) + + private def getPos5Files: Array[File] = + getFilesAndDirs(pos5Files) + private def getNegFiles: Array[File] = if (!negFiles.isEmpty) { val files = negFiles.get @@ -182,6 +205,8 @@ class PartestTask extends Task { setFileManagerBooleanProperty("failed", runFailed) if (!javacmd.isEmpty) setFileManagerStringProperty("JAVACMD", javacmd.get.getAbsolutePath) + if (!javaccmd.isEmpty) + setFileManagerStringProperty("JAVAC_CMD", javaccmd.get.getAbsolutePath) setFileManagerStringProperty("CLASSPATH", classpath.get.list.mkString(File.pathSeparator)) setFileManagerStringProperty("LATEST_LIB", scalaLibrary.get.getAbsolutePath) if (!scalacOpts.isEmpty) @@ -199,6 +224,13 @@ class PartestTask extends Task { allFailures += failures } + if (getPos5Files.size > 0) { + log("Compiling files that are expected to build") + val (successes, failures) = runTestsForFiles(getPos5Files, "pos") + allSucesses += successes + allFailures += failures + } + if (getNegFiles.size > 0) { log("Compiling files that are expected to fail") val (successes, failures) = runTestsForFiles(getNegFiles, "neg") diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala index 8206e55ae2..7371adb637 100644 --- a/src/partest/scala/tools/partest/nest/AntRunner.scala +++ b/src/partest/scala/tools/partest/nest/AntRunner.scala @@ -23,7 +23,7 @@ class AntRunner extends DirectRunner { val fileManager = new FileManager { var JAVACMD: String = "java" - + var JAVAC_CMD: String = "javac" var CLASSPATH: String = _ var EXT_CLASSPATH: String = _ var LATEST_LIB: String = _ diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index b35e5e6079..1cf0879f3f 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -7,10 +7,10 @@ package scala.tools.partest.nest -import scala.tools.nsc.{Global, Settings, CompilerCommand} +import scala.tools.nsc.{Global, Settings, CompilerCommand, FatalError} import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import java.io.{File, BufferedReader, PrintWriter, FileWriter, StringWriter} +import java.io.{File, BufferedReader, PrintWriter, FileReader, FileWriter, StringWriter} class ExtConsoleReporter(override val settings: Settings, reader: BufferedReader, var writer: PrintWriter) extends ConsoleReporter(settings, reader, writer) { def this(settings: Settings) = { @@ -20,8 +20,7 @@ class ExtConsoleReporter(override val settings: Settings, reader: BufferedReader } abstract class SimpleCompiler { - def compile(file: File, kind: String): Boolean - def compile(file: File, kind: String, log: File): Boolean + def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean } class TestSettings(fileMan: FileManager) extends { @@ -56,27 +55,59 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { Console.in, new PrintWriter(new StringWriter)) - def compile(file: File, kind: String, log: File): Boolean = { + def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean = { val testSettings = newSettings val logWriter = new FileWriter(log) - val args = List.fromArray(fileManager.SCALAC_OPTS.split("\\s")) + + // check whether there is a ".flags" file + val testBase = { + val logBase = fileManager.basename(log.getName) + logBase.substring(0, logBase.length-4) + } + val argsFile = new File(log.getParentFile, testBase+".flags") + val argString = if (argsFile.exists) { + val fileReader = new FileReader(argsFile) + val reader = new BufferedReader(fileReader) + val options = reader.readLine() + reader.close() + options + } else "" + val allOpts = fileManager.SCALAC_OPTS+" "+argString + NestUI.verbose("scalac options: "+allOpts) + val args = List.fromArray(allOpts.split("\\s")) val command = new CompilerCommand(args, testSettings, x => {}, false) val global = newGlobal(command.settings, logWriter) val testRep: ExtConsoleReporter = global.reporter.asInstanceOf[ExtConsoleReporter] val test: TestFile = kind match { - case "pos" => PosTestFile(file, fileManager) - case "neg" => NegTestFile(file, fileManager) - case "run" => RunTestFile(file, fileManager) - case "jvm" => JvmTestFile(file, fileManager) - case "jvm5" => Jvm5TestFile(file, fileManager) - case "shootout" => ShootoutTestFile(file, fileManager) + case "pos" => PosTestFile(files(0), fileManager, out.isEmpty) + case "neg" => NegTestFile(files(0), fileManager, out.isEmpty) + case "run" => RunTestFile(files(0), fileManager, out.isEmpty) + case "jvm" => JvmTestFile(files(0), fileManager, out.isEmpty) + case "jvm5" => Jvm5TestFile(files(0), fileManager, out.isEmpty) + case "shootout" => ShootoutTestFile(files(0), fileManager, out.isEmpty) + case "scalacheck" => + ScalaCheckTestFile(files(0), fileManager, out.isEmpty) } test.defineSettings(testSettings) + out match { + case Some(outDir) => + testSettings.outdir.value = outDir.getAbsolutePath + testSettings.classpath.value = testSettings.classpath.value+ + File.pathSeparator+outDir.getAbsolutePath + case None => + // do nothing + } - val toCompile = List(file.getPath) + val toCompile = files.map(_.getPath) try { - (new global.Run) compile toCompile + 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 @@ -90,6 +121,7 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { !testRep.hasErrors } +/* def compile(file: File, kind: String): Boolean = { val testSettings = newSettings val testRep = newReporter(testSettings) @@ -119,7 +151,7 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { return false } !testRep.hasErrors - } + }*/ } class ReflectiveCompiler(val fileManager: ConsoleFileManager) extends SimpleCompiler { @@ -147,19 +179,8 @@ class ReflectiveCompiler(val fileManager: ConsoleFileManager) extends SimpleComp * This exception is handled in the shouldCompile and shouldFailCompile * methods of class CompileManager. */ - def compile(file: File, kind: String): Boolean = { - val fileArgs: Array[AnyRef] = Array(file, kind) - val res = sepCompileMethod.invoke(sepCompiler, fileArgs: _*).asInstanceOf[java.lang.Boolean] - res.booleanValue() - } - - /* 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(file: File, kind: String, log: File): Boolean = { - val fileArgs: Array[AnyRef] = Array(file, kind, log) + def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean = { + val fileArgs: Array[AnyRef] = Array(out, files, kind, log) val res = sepCompileMethod2.invoke(sepCompiler, fileArgs: _*).asInstanceOf[java.lang.Boolean] res.booleanValue() } @@ -180,7 +201,7 @@ class CompileManager(val fileManager: FileManager) { val delay = fileManager.timeout.toLong - def withTimeout(file: File)(thunk: => Boolean): Boolean = { + def withTimeout(files: List[File])(thunk: => Boolean): Boolean = { createSeparateCompiler() val parent = self @@ -201,7 +222,7 @@ class CompileManager(val fileManager: FileManager) { case (From, result: Boolean) => result } case t: Throwable => - NestUI.verbose("while invoking compiler ("+file+"):") + NestUI.verbose("while invoking compiler ("+files+"):") NestUI.verbose("caught "+t) t.printStackTrace if (t.getCause != null) @@ -213,9 +234,16 @@ class CompileManager(val fileManager: FileManager) { /* This method returns true iff compilation succeeds. */ - def shouldCompile(file: File, kind: String, log: File): Boolean = - withTimeout(file) { - compiler.compile(file, kind, log) + def shouldCompile(files: List[File], kind: String, log: File): Boolean = + withTimeout(files) { + 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 = + withTimeout(files) { + compiler.compile(Some(out), files, kind, log) } /* This method returns true iff compilation fails @@ -223,8 +251,19 @@ class CompileManager(val fileManager: FileManager) { * * If the compiler crashes, this method returns false. */ - def shouldFailCompile(file: File, kind: String, log: File): Boolean = - withTimeout(file) { - !compiler.compile(file, kind, log) + def shouldFailCompile(files: List[File], kind: String, log: File): Boolean = + withTimeout(files) { + !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 = + withTimeout(files) { + !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 index cb0f87cb88..55f74dd1d3 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala @@ -43,6 +43,8 @@ class ConsoleFileManager extends FileManager { NestUI.verbose("CLASSPATH: "+CLASSPATH) var JAVACMD = System.getProperty("scalatest.javacmd", "java") + var JAVAC_CMD = System.getProperty("scalatest.javac_cmd", "javac") + val prefixFile = { val cwd = System.getProperty("user.dir") if (cwd != null) @@ -86,8 +88,31 @@ else } val TESTROOT = testRootFile.getAbsolutePath + var srcDirName: String = "" + + val srcDir: File = { + val srcDirProp = System.getProperty("partest.srcdir") + val src = + if (srcDirProp != null) { + srcDirName = srcDirProp + new File(testRootFile, srcDirName) + } else { + srcDirName = "files" + new File(testRootFile, srcDirName) + } + if (src.isDirectory) + src.getCanonicalFile + else { + val path = TESTROOT + File.separator + "files" + NestUI.failure("Source directory \"" + path + "\" not found") + exit(1) + } + } + + LIB_DIR = (new File(testRootFile.getParentFile, "lib")).getCanonicalFile.getAbsolutePath + CLASSPATH = CLASSPATH + File.pathSeparator + { - val libs = new File(TESTROOT, "files/lib") + val libs = new File(srcDir, "lib") // add all jars in libs (libs.listFiles(new FilenameFilter { def accept(dir: File, name: String) = name endsWith ".jar" @@ -123,46 +148,92 @@ else latestCompFile = prefixFile(testBuild+"/lib/scala-compiler.jar") latestPartestFile = prefixFile(testBuild+"/lib/scala-partest.jar") } else { - val dists = new File(testParent, "dists") - val build = new File(testParent, "build") - // in case of an installed dist, testRootFile is one level deeper - val bin = new File(testParent.getParentFile, "bin") + def setupQuick() { + NestUI.verbose("Running build/quick") + latestFile = prefixFile("build/quick/bin") + latestLibFile = prefixFile("build/quick/classes/library") + latestActFile = 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") + latestActFile = prefixFileWith(p, "lib/scala-library.jar") + latestCompFile = prefixFileWith(p, "lib/scala-compiler.jar") + latestPartestFile = prefixFileWith(p, "lib/scala-partest.jar") + } - if (dists.isDirectory) { - NestUI.verbose("Running on DISTRIBUTION") + def setupDist() { + NestUI.verbose("Running dists/latest") latestFile = prefixFile("dists/latest/bin") latestLibFile = prefixFile("dists/latest/lib/scala-library.jar") latestActFile = 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.isDirectory && (new File(build, "pack/lib/scala-library.jar")).exists) { - NestUI.verbose("Running on SuperSABBUS PACK") + + def setupPack() { + NestUI.verbose("Running build/pack") latestFile = prefixFile("build/pack/bin") latestLibFile = prefixFile("build/pack/lib/scala-library.jar") latestActFile = prefixFile("build/pack/lib/scala-library.jar") latestCompFile = prefixFile("build/pack/lib/scala-compiler.jar") latestPartestFile = prefixFile("build/pack/lib/scala-partest.jar") } - else if (build.isDirectory) { - NestUI.verbose("Running on SABBUS QUICK") - latestFile = prefixFile("build/quick/bin") - latestLibFile = prefixFile("build/quick/lib/library") - latestActFile = prefixFile("build/quick/lib/actors") - latestCompFile = prefixFile("build/quick/lib/compiler") - latestPartestFile = prefixFile("build/quick/lib/partest") - } - else if (bin.isDirectory) { - NestUI.verbose("Running on INSTALLED DIST") + + def max(a: Long, b: Long) = if (a > b) a else b + + val dists = new File(testParent, "dists") + val build = new File(testParent, "build") + // in case of an installed dist, testRootFile is one level deeper + val bin = new File(testParent.getParentFile, "bin") + + // detect most recent build + val quickTime = + max(prefixFile("build/quick/classes/compiler/compiler.properties").lastModified, + prefixFile("build/quick/classes/library/library.properties").lastModified) + val packTime = + max(prefixFile("build/pack/lib/scala-compiler.jar").lastModified, + prefixFile("build/pack/lib/scala-library.jar").lastModified) + val distTime = + max(prefixFile("dists/latest/lib/scala-compiler.jar").lastModified, + prefixFile("dists/latest/lib/scala-library.jar").lastModified) + val instTime = { val p = testParent.getParentFile - latestFile = prefixFileWith(p, "bin") - latestLibFile = prefixFileWith(p, "lib/scala-library.jar") - latestActFile = prefixFileWith(p, "lib/scala-library.jar") - latestCompFile = prefixFileWith(p, "lib/scala-compiler.jar") - latestPartestFile = prefixFileWith(p, "lib/scala-partest.jar") + max(prefixFileWith(p, "lib/scala-compiler.jar").lastModified, + prefixFileWith(p, "lib/scala-library.jar").lastModified) + } + + if (quickTime > packTime) { // pack ruled out + if (quickTime > distTime) { // dist ruled out + if (quickTime > instTime) // inst ruled out + setupQuick() + else + setupInst() + } else { // quick ruled out + if (distTime > instTime) // inst ruled out + setupDist() + else + setupInst() + } + } else { // quick ruled out + if (packTime > distTime) { // dist ruled out + if (packTime > instTime) // inst ruled out + setupPack() + else + setupInst() + } else { // pack ruled out + if (distTime > instTime) // inst ruled out + setupDist() + else + setupInst() + } } - else - error("Scala binaries could not be found") + latestFjbgFile = prefixFile("lib/fjbg.jar") } BIN_DIR = latestFile.getAbsolutePath @@ -201,37 +272,30 @@ else // initialize above fields findLatest() - val srcDir: File = { - val src = new File(TESTROOT, "files") - if (src.isDirectory) - src.getCanonicalFile - else { - val path = TESTROOT + File.separator + "files" - NestUI.failure("Source directory \"" + path + "\" not found") - exit(1) - } - } - - private def basename(name: String): String = { - val inx = name.lastIndexOf(".") - if (inx < 0) name else name.substring(0, inx) - } - var testFiles: List[File] = List() - def getFiles(kind: String, doCheck: Boolean, ending: String): List[File] = { - val filter = new FilenameFilter { - def accept(dir: File, name: String): Boolean = name endsWith ending - } + def getFiles(kind: String, doCheck: Boolean, filter: Option[(String, Boolean)]): List[File] = { val dir = new File(srcDir, kind) NestUI.verbose("look in "+dir+" for tests") if (dir.isDirectory) { if (!testFiles.isEmpty) { val dirpath = dir.getAbsolutePath testFiles filter { _.getParentFile.getAbsolutePath == dirpath } - } else if (doCheck) - dir.listFiles(filter).toList - else // skip + } else if (doCheck) filter match { + case Some((ending, enableDirs)) => + val filter = new FilenameFilter { + def accept(dir: File, name: String) = + name.endsWith(ending) || + (enableDirs && (name != ".svn") && (!name.endsWith(".obj")) && + (new File(dir, name)).isDirectory) + } + dir.listFiles(filter).toList + case None => + val filter = new FilenameFilter { + def accept(dir: File, name: String) = name != ".svn" + } + dir.listFiles(filter).toList + } else // skip Nil } else { NestUI.failure("Directory \"" + dir.getPath + "\" not found") @@ -240,6 +304,6 @@ else } def getFiles(kind: String, doCheck: Boolean): List[File] = - getFiles(kind, doCheck, ".scala") + getFiles(kind, doCheck, Some((".scala", true))) } diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala index 1ffb992661..668b2d0a45 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala @@ -10,8 +10,6 @@ package scala.tools.partest.nest import java.io.{File, PrintStream, FileOutputStream, BufferedReader, InputStreamReader, StringWriter, PrintWriter} -import scala.actors.Actor._ - class ConsoleRunner extends DirectRunner with RunnerUtils { var fileManager: ConsoleFileManager = _ @@ -27,12 +25,11 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { private var resCheck = false private var shootoutCheck = false private var scriptCheck = false + private var scalacheckCheck = false private var runAll = false private var testFiles: List[File] = List() - private val con = new PrintStream(Console.out) - private var out = con private val errors = Integer.parseInt(System.getProperty("scalatest.errors", "0")) @@ -47,9 +44,16 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { case "--res" => true case "--shootout" => true case "--script" => true + case "--scalacheck" => true case _ => false } + def denotesTestFile(arg: String) = + arg.endsWith(".scala") || arg.endsWith(".res") + + def denotesTestDir(arg: String) = + (new File(arg)).isDirectory + def main(argstr: String) { // tokenize args. filter: "".split("\\s") yields Array("") var args = List.fromArray(argstr.split("\\s")).remove(_ == "") @@ -60,7 +64,11 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { // find out which build to test val (buildPath, args1) = searchAndRemovePath("--buildpath", args) val (classPath, args2) = searchAndRemovePath("--classpath", args1) - args = args2 + val (srcPath, args3) = searchAndRemovePath("--srcpath", args2) + args = args3 + + if (!srcPath.isEmpty) + System.setProperty("partest.srcdir", srcPath.get) fileManager = if (!buildPath.isEmpty) @@ -76,7 +84,11 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { } else // auto detection, see ConsoleFileManager.findLatest new ConsoleFileManager - if (!args.exists(denotesTestSet(_)) && !args.exists(_.endsWith(".scala"))) runAll = true + if (!args.exists(denotesTestSet(_)) && + !args.exists(denotesTestFile(_)) && + !args.exists(denotesTestDir(_))) + runAll = true + for (arg <- args) { arg match { case "--all" => runAll = true @@ -89,6 +101,7 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { case "--res" => resCheck = true case "--shootout" => shootoutCheck = true case "--script" => scriptCheck = true + case "--scalacheck" => scalacheckCheck = true case "--verbose" => NestUI._verbose = true case "--show-diff" => fileManager.showDiff = true @@ -97,25 +110,19 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { case "--version" => //todo: printVersion case "--ansi" => NestUI.initialize(NestUI.MANY) case _ => - if (arg endsWith ".scala") { + if (denotesTestFile(arg) || denotesTestDir(arg)) { val file = new File(arg) - if (file.isFile) { + if (file.exists) { NestUI.verbose("adding test file "+file) testFiles = file :: testFiles } else { NestUI.failure("File \"" + arg + "\" not found\n") System.exit(1) } - } else if (out eq con) { - val file = new File(arg) - if (file.isFile || file.createNewFile) - out = new PrintStream(new FileOutputStream(file)) - else { - NestUI.failure("Result file \"" + arg + "\" not found\n") - System.exit(1) - } - } else + } else { + NestUI.failure("Invalid option \""+arg+"\"\n") NestUI.usage() + } } } @@ -140,7 +147,7 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { val vmName = System.getProperty("java.vm.name", "")+" (build "+ System.getProperty("java.vm.version", "")+", "+ System.getProperty("java.vm.info", "")+")" - val vmOpts = System.getProperty("scalatest.java_options", "?") + val vmOpts = fileManager.JAVA_OPTS NestUI.outline("Java binaries in: "+vmBin+"\n") NestUI.outline("Java runtime is: "+vmName+"\n") NestUI.outline("Java options are: "+vmOpts+"\n") @@ -179,7 +186,7 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { def runTests(kind: String, check: Boolean, msg: String): (Int, Int) = { if (check) { val kindFiles = if (kind == "res") //TODO: is there a nicer way? - fileManager.getFiles(kind, check, ".res") + fileManager.getFiles(kind, check, Some((".res", false))) else fileManager.getFiles(kind, check) if (!kindFiles.isEmpty) { @@ -201,14 +208,15 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { def kindOf(f: File): String = { val firstName = absName(f) - val filesPos = firstName.indexOf("files") + val len = fileManager.srcDirName.length + val filesPos = firstName.indexOf(fileManager.srcDirName) if (filesPos == -1) { NestUI.failure("invalid test file: "+firstName+"\n") Predef.exit(1) } else { - val k = firstName.substring(filesPos+6, filesPos+6+3) + val k = firstName.substring(filesPos+len+1, filesPos+len+1+3) val short = if (k == "jvm") { - if (firstName.substring(filesPos+6, filesPos+6+4) == "jvm5") "jvm5" + if (firstName.substring(filesPos+len+1, filesPos+len+1+4) == "jvm5") "jvm5" else k } else k val shortKinds = List("pos", "neg", "run", "jvm", "jvm5", "res") @@ -216,6 +224,7 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { else short match { case "sho" => "shootout" case "scr" => "script" + case "sca" => "scalacheck" } } } @@ -240,6 +249,7 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { resCheck = true shootoutCheck = true scriptCheck = true + scalacheckCheck = true } val results = List(runTestsFiles, runTests("pos", posCheck, "Testing compiler (on files whose compilation should succeed)"), @@ -249,7 +259,8 @@ class ConsoleRunner extends DirectRunner with RunnerUtils { runTests("jvm5", jvm5Check, "Testing JVM backend"), runTests("res", resCheck, "Testing resident compiler"), runTests("shootout", shootoutCheck, "Testing shootout tests"), - runTests("script", scriptCheck, "Testing script tests")) + runTests("script", scriptCheck, "Testing script tests"), + runTests("scalacheck", scalacheckCheck, "Testing ScalaCheck tests")) 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/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index 36e051e221..9a959b428b 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -12,6 +12,11 @@ import java.net.URI trait FileManager { + def basename(name: String): String = { + val inx = name.lastIndexOf(".") + if (inx < 0) name else name.substring(0, inx) + } + def deleteRecursive(dir: File) { if (dir.isDirectory) { for (file <- dir.list) deleteRecursive(new File(dir, file)) @@ -45,15 +50,18 @@ trait FileManager { var JAVACMD: String + var JAVAC_CMD: String var CLASSPATH: String var LATEST_LIB: String + var LIB_DIR: String = "" var showDiff = false var showLog = false var failed = false var SCALAC_OPTS = System.getProperty("scalatest.scalac_opts", "-deprecation") + var JAVA_OPTS = System.getProperty("scalatest.java_opts", "") var timeout = "1200000" } diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala index e9c0aeebd6..ecddd8d946 100644 --- a/src/partest/scala/tools/partest/nest/NestUI.scala +++ b/src/partest/scala/tools/partest/nest/NestUI.scala @@ -66,21 +66,32 @@ object NestUI { println(" <testfile>: list of files ending in '.scala'") println(" <resfile>: a file not ending in '.scala'") println(" <options>:") - println(" --all run all tests") - println(" --pos next files test a compilation success") - println(" --neg next files test a compilation failure") - println(" --run next files test the interpreter and all backends") - println(" --jvm next files test the JVM backend") - println(" --jvm5 next files test the JVM backend") - println(" --res next files test the resident compiler") - println(" --shootout next files are shootout tests") - println(" --script next files test the script runner") - println(" --pack pick compiler / library in build/pack, and run all tests") - println(" --four pick compiler / library in build/four-pack, and run all tests") - println(" --verbose display progress information") - //println(" --version display version information") println - println("version 0.9.1") + 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(" --jvm5 run JVM backend tests (-target:jvm-1.5)") + println(" --res run resident compiler tests") + println(" --script run script runner tests") + println(" --shootout run shootout tests") + println + println(" Other options:") + println(" --pack pick compiler/library in build/pack, and run all tests") + println(" --four pick compiler/library in build/four-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 + println("version 0.9.2") println("maintained by Philipp Haller (EPFL)") exit(1) } diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala index 17b4ff0d3e..7afe1a4a1a 100644 --- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala +++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala @@ -40,13 +40,9 @@ class ReflectiveRunner extends RunnerUtils { import fileManager.{latestCompFile, latestLibFile, latestActFile, latestPartestFile, latestFjbgFile} - val sepUrls = if (!classPath.isEmpty) - Array(latestCompFile.toURL, latestLibFile.toURL, - latestActFile.toURL, latestPartestFile.toURL, - latestFjbgFile.toURL) - else - Array(latestCompFile.toURL, latestLibFile.toURL, - latestActFile.toURL, latestPartestFile.toURL) + val sepUrls = Array(latestCompFile.toURL, latestLibFile.toURL, + latestActFile.toURL, latestPartestFile.toURL, + latestFjbgFile.toURL) val sepLoader = new java.net.URLClassLoader(sepUrls, null) @@ -68,10 +64,10 @@ class ReflectiveRunner extends RunnerUtils { System.setProperty("env.classpath", newClasspath) System.setProperty("scala.home", "") if (fileManager.debug) { - println("java.class.path: "+System.getProperty("java.class.path")) - println("env.classpath: "+System.getProperty("env.classpath")) - println("sun.boot.class.path: "+System.getProperty("sun.boot.class.path")) - println("java.ext.dirs: "+System.getProperty("java.ext.dirs")) + println("java.class.path: "+System.getProperty("java.class.path")) + println("env.classpath: "+System.getProperty("env.classpath")) + println("sun.boot.class.path: "+System.getProperty("sun.boot.class.path")) + println("java.ext.dirs: "+System.getProperty("java.ext.dirs")) } val sepRunnerClass = diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala index 10b12aae29..f577c79705 100644 --- a/src/partest/scala/tools/partest/nest/TestFile.scala +++ b/src/partest/scala/tools/partest/nest/TestFile.scala @@ -10,7 +10,7 @@ package scala.tools.partest.nest import java.io.{File, BufferedReader, FileReader} import scala.tools.nsc.Settings -class TestFile(kind: String, val file: File, val fileManager: FileManager) { +class TestFile(kind: String, val file: File, val fileManager: FileManager, createOutDir: Boolean) { val dir = file.getParentFile val dirpath = dir.getAbsolutePath val fileBase: String = basename(file.getName) @@ -18,12 +18,13 @@ class TestFile(kind: String, val file: File, val fileManager: FileManager) { // @mutates settings protected def baseSettings(settings: Settings) { settings.classpath.value = dirpath - settings.outdir.value = { - val outDir = new File(dir, fileBase + "-" + kind + ".obj") - if (!outDir.exists) - outDir.mkdir() - outDir.toString - } + if (createOutDir) + settings.outdir.value = { + val outDir = new File(dir, fileBase + "-" + kind + ".obj") + if (!outDir.exists) + outDir.mkdir() + outDir.toString + } // add additional flags found in 'testname.flags' val flagsFile = new File(dir, fileBase + ".flags") @@ -47,7 +48,7 @@ class TestFile(kind: String, val file: File, val fileManager: FileManager) { override def toString(): String = kind+" "+file } -case class PosTestFile(override val file: File, override val fileManager: FileManager) extends TestFile("pos", file, fileManager) { +case class PosTestFile(override val file: File, override val fileManager: FileManager, createOutDir: Boolean) extends TestFile("pos", file, fileManager, createOutDir) { override def defineSettings(settings: Settings) { baseSettings(settings) settings.classpath.value = fileManager.CLASSPATH @@ -55,7 +56,7 @@ case class PosTestFile(override val file: File, override val fileManager: FileMa } } -case class NegTestFile(override val file: File, override val fileManager: FileManager) extends TestFile("neg", file, fileManager) { +case class NegTestFile(override val file: File, override val fileManager: FileManager, createOutDir: Boolean) extends TestFile("neg", file, fileManager, createOutDir) { override def defineSettings(settings: Settings) { baseSettings(settings) settings.classpath.value = fileManager.CLASSPATH @@ -63,14 +64,21 @@ case class NegTestFile(override val file: File, override val fileManager: FileMa } } -case class RunTestFile(override val file: File, override val fileManager: FileManager) extends TestFile("run", file, fileManager) { +case class RunTestFile(override val file: File, override val fileManager: FileManager, createOutDir: Boolean) extends TestFile("run", file, fileManager, createOutDir) { + override def defineSettings(settings: Settings) { + baseSettings(settings) + settings.classpath.value = fileManager.CLASSPATH + } +} + +case class ScalaCheckTestFile(override val file: File, override val fileManager: FileManager, createOutDir: Boolean) extends TestFile("scalacheck", file, fileManager, createOutDir) { override def defineSettings(settings: Settings) { baseSettings(settings) settings.classpath.value = fileManager.CLASSPATH } } -case class JvmTestFile(override val file: File, override val fileManager: FileManager) extends TestFile("jvm", file, fileManager) { +case class JvmTestFile(override val file: File, override val fileManager: FileManager, createOutDir: Boolean) extends TestFile("jvm", file, fileManager, createOutDir) { override def defineSettings(settings: Settings) { baseSettings(settings) settings.classpath.value = fileManager.CLASSPATH @@ -78,7 +86,7 @@ case class JvmTestFile(override val file: File, override val fileManager: FileMa } } -case class Jvm5TestFile(override val file: File, override val fileManager: FileManager) extends TestFile("jvm5", file, fileManager) { +case class Jvm5TestFile(override val file: File, override val fileManager: FileManager, createOutDir: Boolean) extends TestFile("jvm5", file, fileManager, createOutDir) { override def defineSettings(settings: Settings) { baseSettings(settings) settings.classpath.value = fileManager.CLASSPATH @@ -87,7 +95,7 @@ case class Jvm5TestFile(override val file: File, override val fileManager: FileM } } -case class ShootoutTestFile(override val file: File, override val fileManager: FileManager) extends TestFile("shootout", file, fileManager) { +case class ShootoutTestFile(override val file: File, override val fileManager: FileManager, createOutDir: Boolean) extends TestFile("shootout", file, fileManager, createOutDir) { override def defineSettings(settings: Settings) { baseSettings(settings) settings.classpath.value = fileManager.CLASSPATH diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala index 86df4abbde..d73a11dff7 100644 --- a/src/partest/scala/tools/partest/nest/Worker.scala +++ b/src/partest/scala/tools/partest/nest/Worker.scala @@ -96,6 +96,8 @@ class Worker(val fileManager: FileManager) extends Actor { def createOutputDir(dir: File, fileBase: String, kind: String): File = { val outDir = new File(dir, fileBase + "-" + kind + ".obj") + if (!outDir.exists) + outDir.mkdir() createdOutputDirs = outDir :: createdOutputDirs outDir } @@ -163,6 +165,66 @@ class Worker(val fileManager: FileManager) extends Actor { } } + 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 "+outDir+File.pathSeparator+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 = 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() + try { + proc.exitValue() + } catch { + case e: 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") @@ -176,11 +238,15 @@ class Worker(val fileManager: FileManager) extends Actor { } else "" NestUI.verbose("JAVA_OPTS: "+argString) + val cp = System.getProperty("java.class.path", ".") + NestUI.verbose("java.class.path: "+cp) + def quote(path: String) = "\""+path+"\"" val cmd = JAVACMD+ " "+argString+ + " "+JAVA_OPTS+ " -classpath "+outDir+File.pathSeparator+CLASSPATH+ " -Djava.library.path="+logFile.getParentFile.getAbsolutePath+ " -Dscalatest.output="+outDir.getAbsolutePath+ @@ -191,19 +257,7 @@ class Worker(val fileManager: FileManager) extends Actor { " 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() + runCommand(cmd, logFile) if (fileManager.showLog) { // produce log as string in `log` @@ -269,6 +323,12 @@ class Worker(val fileManager: FileManager) extends Actor { var diff = "" var log = "" + /** 1. Creates log file and output directory. + * 2. Runs <code>script</code> function, providing log file and + * output directory as arguments. + * 3. Prints test result. + * 4. Shows log/diff if enabled. + */ def runInContext(file: File, kind: String, script: (File, File) => Unit) { // when option "--failed" is provided // execute test only if log file is present @@ -286,13 +346,16 @@ class Worker(val fileManager: FileManager) extends Actor { 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 { script(logFile, outDir) } catch { case e: Exception => - e.printStackTrace + val writer = new PrintWriter(new FileWriter(logFile), true) + e.printStackTrace(writer) + writer.close() succeeded = false } @@ -315,12 +378,48 @@ class Worker(val fileManager: FileManager) extends Actor { } } + def compileFilesIn(dir: File, kind: String, logFile: File, outDir: File) { + val testFiles = dir.listFiles.toList + val javaFiles = testFiles.filter(_.getName.endsWith(".java")) + val scalaFiles = testFiles.filter(_.getName.endsWith(".scala")) + if (!(scalaFiles.isEmpty && javaFiles.isEmpty) && + !compileMgr.shouldCompile(outDir, javaFiles ::: scalaFiles, kind, logFile)) { + NestUI.verbose("compilation of "+scalaFiles+" failed\n") + succeeded = false + } else + if (!javaFiles.isEmpty) { + succeeded = javac(outDir, javaFiles, logFile) + if (succeeded) { + scalaFiles foreach { scalaFile => + if (!compileMgr.shouldCompile(outDir, List(scalaFile), kind, logFile)) { + NestUI.verbose("compilation of "+scalaFile+" failed\n") + succeeded = false + } + } + } + } + } + + def failCompileFilesIn(dir: File, kind: String, logFile: File, outDir: File) { + val testFiles = dir.listFiles.toList + val javaFiles = testFiles.filter(_.getName.endsWith(".java")) + val scalaFiles = testFiles.filter(_.getName.endsWith(".scala")) + if (!(scalaFiles.isEmpty && javaFiles.isEmpty) && + !compileMgr.shouldFailCompile(outDir, javaFiles ::: scalaFiles, kind, logFile)) { + NestUI.verbose("compilation of "+scalaFiles+" failed\n") + succeeded = false + } + } + def runJvmTest(file: File, kind: String) { runInContext(file, kind, (logFile: File, outDir: File) => { - if (!compileMgr.shouldCompile(file, kind, logFile)) { + if (file.isDirectory) { + compileFilesIn(file, kind, logFile, outDir) + } else if (!compileMgr.shouldCompile(List(file), kind, logFile)) { NestUI.verbose("compilation of "+file+" failed\n") succeeded = false - } else { // run test + } + if (succeeded) { // run test val fileBase = basename(file.getName) val dir = file.getParentFile @@ -343,21 +442,61 @@ class Worker(val fileManager: FileManager) extends Actor { } 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 "scalacheck" => for (file <- files) + runInContext(file, kind, (logFile: File, outDir: File) => { + if (file.isDirectory) { + compileFilesIn(file, kind, logFile, outDir) + } else if (!compileMgr.shouldCompile(List(file), kind, logFile)) { + NestUI.verbose("compilation of "+file+" failed\n") + succeeded = false + } + if (succeeded) { + NestUI.verbose("compilation of "+file+" succeeded\n") + + val libs = new File(fileManager.LIB_DIR) + val urls = List((new File(libs, "ScalaCheck.jar")).toURL, + (new File(libs, "ScalaCheckHelper.jar")).toURL) + val outURL = outDir.getCanonicalFile.toURL + val urlArr = (outURL :: urls).toArray + NestUI.verbose("loading classes from:") + urlArr foreach {url => NestUI.verbose(url.toString)} + val loader = new java.net.URLClassLoader(urlArr, fileManager.getClass.getClassLoader) + + (try { + Some(Class.forName("ScalaCheckHelper", true, loader)) + } catch { + case se: SecurityException => None + case cnfe: ClassNotFoundException => None + }) match { + case None => + NestUI.verbose("cannot find ScalaCheckHelper class") + succeeded = false + case Some(clazz) => + val method = clazz.getMethod("passed", Array(classOf[File], classOf[Array[URL]]): _*) + val res = method.invoke(null, Array(logFile, urlArr): _*).asInstanceOf[String] + NestUI.verbose("ScalaCheck result: "+res) + succeeded = res.equals("ok") } - }) - } + } + }) + case "pos" => for (file <- files) + runInContext(file, kind, (logFile: File, outDir: File) => { + if (file.isDirectory) { + compileFilesIn(file, kind, logFile, outDir) + } else if (!compileMgr.shouldCompile(List(file), kind, logFile)) { + NestUI.verbose("compilation of "+file+" failed\n") + succeeded = false + } + }) case "neg" => for (file <- files) { runInContext(file, kind, (logFile: File, outDir: File) => { - if (!compileMgr.shouldFailCompile(file, kind, logFile)) { + if (file.isDirectory) { + failCompileFilesIn(file, kind, logFile, outDir) + } else if (!compileMgr.shouldFailCompile(List(file), kind, logFile)) { succeeded = false - } else { // compare log file to check file + } + if (succeeded) { // compare log file to check file val fileBase = basename(file.getName) val dir = file.getParentFile if (!existsCheckFile(dir, fileBase, kind)) { @@ -493,7 +632,7 @@ class Worker(val fileManager: FileManager) extends Actor { System.setOut(oldStdOut) System.setErr(oldStdErr) - val tempLogFile = new File(dir, ".temp.log") + val tempLogFile = new File(dir, fileBase+".temp.log") val logFileReader = new BufferedReader(new FileReader(logFile)) val tempLogFilePrinter = new PrintWriter(new FileWriter(tempLogFile)) val appender = @@ -588,7 +727,7 @@ class Worker(val fileManager: FileManager) extends Actor { try { // *catch-all* // 4. compile testFile - if (!compileMgr.shouldCompile(testFile, kind, logFile)) { + if (!compileMgr.shouldCompile(List(testFile), kind, logFile)) { NestUI.verbose("compilation of "+file+" failed\n") succeeded = false } else { |