summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2013-03-22 14:39:19 -0700
committerAdriaan Moors <adriaan.moors@typesafe.com>2013-04-04 10:57:42 -0700
commitc6ce61796f66770ca1b4d63fc0a569f064436433 (patch)
treeaa263d2764bcf47f024374d6538d94cc952199eb
parent7bb981a9ebb8700c81eca7062537b02bff9b0035 (diff)
downloadscala-c6ce61796f66770ca1b4d63fc0a569f064436433.tar.gz
scala-c6ce61796f66770ca1b4d63fc0a569f064436433.tar.bz2
scala-c6ce61796f66770ca1b4d63fc0a569f064436433.zip
SI-6289 Partest in technicolor and showing javac errors
Paulptest includes color and simplified test scarfing. Scalap tests are moved to the conventional name and location. Testicolor missed out on Josh Suereth's tweak to sort the files in a compilation round. Restore sortiness to test sources. Testicolor is due to one of Paul's branches on a timeline that apparently did not include the destruction of planet Earth and its colonies by the Xindi. Thanks also to Szabolcs Berecz for his merge effort. Merging is thankless work, but not as thankless as merging in a timeline that actually does terminate in the destruction of your home world and Enterprise. Archer had a supremely difficult choice: rescue humanity or live out his retirement with T'Pol waiting on him hand and foot? I'm sure I don't know how I'd choose.
-rwxr-xr-x[-rw-r--r--]build.xml85
-rw-r--r--src/partest/scala/tools/partest/DirectTest.scala5
-rw-r--r--src/partest/scala/tools/partest/IcodeTest.scala4
-rw-r--r--src/partest/scala/tools/partest/PartestDefaults.scala9
-rw-r--r--src/partest/scala/tools/partest/PartestTask.scala341
-rw-r--r--src/partest/scala/tools/partest/TestKinds.scala67
-rw-r--r--src/partest/scala/tools/partest/TestState.scala54
-rw-r--r--src/partest/scala/tools/partest/nest/AntRunner.scala25
-rw-r--r--src/partest/scala/tools/partest/nest/CompileManager.scala182
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleFileManager.scala33
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleRunner.scala321
-rw-r--r--src/partest/scala/tools/partest/nest/DirectCompiler.scala105
-rw-r--r--src/partest/scala/tools/partest/nest/DirectRunner.scala52
-rw-r--r--src/partest/scala/tools/partest/nest/FileManager.scala47
-rw-r--r--src/partest/scala/tools/partest/nest/NestUI.scala111
-rw-r--r--src/partest/scala/tools/partest/nest/Runner.scala584
-rw-r--r--src/partest/scala/tools/partest/nest/RunnerManager.scala689
-rw-r--r--src/partest/scala/tools/partest/nest/SBTRunner.scala29
-rw-r--r--src/partest/scala/tools/partest/nest/StreamCapture.scala53
-rw-r--r--src/partest/scala/tools/partest/nest/TestFile.scala80
-rw-r--r--src/partest/scala/tools/partest/package.scala151
-rwxr-xr-xtest/build-partest.xml24
-rw-r--r--test/files/neg/choices.check2
-rw-r--r--test/files/neg/choices.flags2
-rw-r--r--test/files/run/reify_this.scala6
-rw-r--r--test/files/scalap/abstractClass.check (renamed from test/files/scalap/abstractClass/result.test)0
-rw-r--r--test/files/scalap/abstractClass.scala (renamed from test/files/scalap/abstractClass/A.scala)0
-rw-r--r--test/files/scalap/abstractMethod.check (renamed from test/files/scalap/abstractMethod/result.test)0
-rw-r--r--test/files/scalap/abstractMethod.scala (renamed from test/files/scalap/abstractMethod/A.scala)0
-rw-r--r--test/files/scalap/caseClass.check (renamed from test/files/scalap/caseClass/result.test)0
-rw-r--r--test/files/scalap/caseClass.scala (renamed from test/files/scalap/caseClass/A.scala)0
-rw-r--r--test/files/scalap/caseObject.check (renamed from test/files/scalap/caseObject/result.test)0
-rw-r--r--test/files/scalap/caseObject.scala (renamed from test/files/scalap/caseObject/A.scala)0
-rw-r--r--test/files/scalap/cbnParam.check (renamed from test/files/scalap/cbnParam/result.test)0
-rw-r--r--test/files/scalap/cbnParam.scala (renamed from test/files/scalap/cbnParam/A.scala)0
-rw-r--r--test/files/scalap/classPrivate.check (renamed from test/files/scalap/classPrivate/result.test)0
-rw-r--r--test/files/scalap/classPrivate.scala (renamed from test/files/scalap/classPrivate/A.scala)0
-rw-r--r--test/files/scalap/classWithExistential.check (renamed from test/files/scalap/classWithExistential/result.test)0
-rw-r--r--test/files/scalap/classWithExistential.scala (renamed from test/files/scalap/classWithExistential/A.scala)0
-rw-r--r--test/files/scalap/classWithSelfAnnotation.check (renamed from test/files/scalap/classWithSelfAnnotation/result.test)0
-rw-r--r--test/files/scalap/classWithSelfAnnotation.scala (renamed from test/files/scalap/classWithSelfAnnotation/A.scala)0
-rw-r--r--test/files/scalap/covariantParam.check (renamed from test/files/scalap/covariantParam/result.test)0
-rw-r--r--test/files/scalap/covariantParam.scala (renamed from test/files/scalap/covariantParam/A.scala)0
-rw-r--r--test/files/scalap/defaultParameter.check (renamed from test/files/scalap/defaultParameter/result.test)0
-rw-r--r--test/files/scalap/defaultParameter.scala (renamed from test/files/scalap/defaultParameter/A.scala)0
-rw-r--r--test/files/scalap/implicitParam.check (renamed from test/files/scalap/implicitParam/result.test)0
-rw-r--r--test/files/scalap/implicitParam.scala (renamed from test/files/scalap/implicitParam/A.scala)0
-rw-r--r--test/files/scalap/packageObject.check (renamed from test/files/scalap/packageObject/result.test)0
-rw-r--r--test/files/scalap/packageObject.scala (renamed from test/files/scalap/packageObject/A.scala)0
-rw-r--r--test/files/scalap/paramClauses.check (renamed from test/files/scalap/paramClauses/result.test)0
-rw-r--r--test/files/scalap/paramClauses.scala (renamed from test/files/scalap/paramClauses/A.scala)0
-rw-r--r--test/files/scalap/paramNames.check (renamed from test/files/scalap/paramNames/result.test)0
-rw-r--r--test/files/scalap/paramNames.scala (renamed from test/files/scalap/paramNames/A.scala)0
-rw-r--r--test/files/scalap/sequenceParam.check (renamed from test/files/scalap/sequenceParam/result.test)0
-rw-r--r--test/files/scalap/sequenceParam.scala (renamed from test/files/scalap/sequenceParam/A.scala)0
-rw-r--r--test/files/scalap/simpleClass.check (renamed from test/files/scalap/simpleClass/result.test)0
-rw-r--r--test/files/scalap/simpleClass.scala (renamed from test/files/scalap/simpleClass/A.scala)0
-rw-r--r--test/files/scalap/traitObject.check (renamed from test/files/scalap/traitObject/result.test)0
-rw-r--r--test/files/scalap/traitObject.scala (renamed from test/files/scalap/traitObject/A.scala)0
-rw-r--r--test/files/scalap/typeAnnotations.check (renamed from test/files/scalap/typeAnnotations/result.test)0
-rw-r--r--test/files/scalap/typeAnnotations.scala (renamed from test/files/scalap/typeAnnotations/A.scala)0
-rw-r--r--test/files/scalap/valAndVar.check (renamed from test/files/scalap/valAndVar/result.test)0
-rw-r--r--test/files/scalap/valAndVar.scala (renamed from test/files/scalap/valAndVar/A.scala)0
-rw-r--r--test/files/scalap/wildcardType.check (renamed from test/files/scalap/wildcardType/result.test)0
-rw-r--r--test/files/scalap/wildcardType.scala (renamed from test/files/scalap/wildcardType/A.scala)0
-rwxr-xr-xtest/partest16
66 files changed, 1480 insertions, 1597 deletions
diff --git a/build.xml b/build.xml
index fa2e9e1d9b..db30b5d5ca 100644..100755
--- a/build.xml
+++ b/build.xml
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="sabbus" default="build" xmlns:artifact="urn:maven-artifact-ant">
+ <include file="test/build-partest.xml" as="partest"/>
+
<description>
SuperSabbus for Scala core, builds the scala library and compiler. It can also package it as a simple distribution, tests it for stable bootstrapping and against the Scala test suite.
</description>
@@ -135,7 +137,7 @@ TODO:
<property name="dists.dir" value="${basedir}/dists"/>
<property name="copyright.string" value="Copyright 2002-2013, LAMP/EPFL"/>
- <property name="partest.version.number" value="0.9.2"/>
+ <property name="partest.version.number" value="0.9.3"/>
<!-- These are NOT the flags used to run SuperSabbus, but the ones written
into the script runners created with scala.tools.ant.ScalaTool -->
@@ -530,7 +532,7 @@ TODO:
<path id="quick.partest.build.path">
<path refid="quick.scalap.build.path"/>
<path refid="partest.extras.classpath"/>
- <pathelement location="${build-quick.dir}/classes/repl"/>
+ <pathelement location="${build-quick.dir}/classes/repl"/>
<pathelement location="${scalacheck.jar}"/>
</path>
@@ -650,11 +652,15 @@ TODO:
<path refid="partest.extras.classpath"/>
</path>
+ <!-- obsolete? -->
+ <!-- TODO - segregate swing tests (there can't be many) -->
+ <!--
<path id="partest.build.path">
<path refid="pack.compiler.path"/>
<fileset dir="${partest.dir}/files/lib" includes="*.jar" />
- <pathelement location="${pack.dir}/lib/scala-swing.jar"/> <!-- TODO - segregate swing tests (there can't be many) -->
+ <pathelement location="${pack.dir}/lib/scala-swing.jar"/>
</path>
+ -->
<path id="test.osgi.compiler.build.path">
<pathelement location="${test.osgi.classes}"/>
@@ -762,8 +768,8 @@ TODO:
<touch file="${build-libs.dir}/@{project}.complete" verbose="no"/>
</then></if>
</sequential>
- </macrodef>
-
+ </macrodef>
+
<target name="asm.done" depends="init"> <simple-javac project="asm" jar="no"/> </target>
<target name="forkjoin.done" depends="init"> <simple-javac project="forkjoin" args="-XDignore.symbol.file"/></target>
@@ -1418,72 +1424,32 @@ TODO:
<stopwatch name="quick.sbt-interface.timer" action="total"/>
</target>
- <property name="partest.srcdir" value="files" /> <!-- TODO: make targets for `pending` and other subdirs -->
+ <!-- See test/build-partest.xml for the macro(s) being used here. -->
- <target name="test.run" depends="pack.done">
- <partest showlog="yes" erroronfailed="yes" javacmd="${java.home}/bin/java"
- timeout="1200000"
- srcdir="${partest.srcdir}"
- scalacopts="${scalac.args.optimise}">
-
- <compilationpath refid="partest.build.path"/>
- <runtests dir="${partest.dir}/${partest.srcdir}/run" includes="*.scala"/>
- <jvmtests dir="${partest.dir}/${partest.srcdir}/jvm" includes="*.scala"/>
- </partest>
+ <target name="test.suite" depends="pack.done">
+ <testSuite/>
</target>
- <target name="test.suite" depends="pack.done">
- <partest showlog="yes" erroronfailed="yes" javacmd="${java.home}/bin/java"
- timeout="2400000"
- srcdir="${partest.srcdir}"
- scalacopts="${scalac.args.optimise}">
- <compilationpath refid="partest.build.path"/>
- <postests dir="${partest.dir}/${partest.srcdir}/pos" includes="*.scala"/>
- <negtests dir="${partest.dir}/${partest.srcdir}/neg" includes="*.scala"/>
- <runtests dir="${partest.dir}/${partest.srcdir}/run" includes="*.scala"/>
- <jvmtests dir="${partest.dir}/${partest.srcdir}/jvm" includes="*.scala"/>
- <residenttests dir="${partest.dir}/${partest.srcdir}/res" includes="*.res"/>
- <scalaptests dir="${partest.dir}/${partest.srcdir}/scalap" includes="**/*.scala"/>
- <scalachecktests dir="${partest.dir}/${partest.srcdir}/scalacheck">
- <include name="*.scala"/>
- </scalachecktests>
- <specializedtests dir="${partest.dir}/${partest.srcdir}/specialized">
- <include name="*.scala"/>
- </specializedtests>
- <instrumentedtests dir="${partest.dir}/${partest.srcdir}/instrumented">
- <include name="*.scala"/>
- </instrumentedtests>
- </partest>
+ <target name="test.suite.color" depends="pack.done">
+ <testSuite colors="8"/>
+ </target>
+
+ <target name="test.run" depends="pack.done">
+ <testSuite kinds="run jvm"/>
</target>
<target name="test.continuations.suite" depends="pack.done">
- <partest showlog="yes" erroronfailed="yes" javacmd="${java.home}/bin/java"
- timeout="2400000"
- srcdir="${partest.srcdir}"
- scalacopts="${scalac.args.optimise} -Xplugin-require:continuations -P:continuations:enable">
- <compilerarg value="-Xpluginsdir"/>
- <compilerarg file="${build-quick.dir}/misc/scala-devel/plugins"/>
- <compilationpath refid="partest.build.path"/>
- <negtests dir="${partest.dir}/${partest.srcdir}/continuations-neg" includes="*.scala"/>
- <runtests dir="${partest.dir}/${partest.srcdir}/continuations-run" includes="*.scala"/>
- </partest>
+ <testSuite kinds="continuations-neg continuations-run"
+ scalacOpts="${scalac.args.optimise} -Xpluginsdir ${build-quick.dir}/misc/scala-devel/plugins -Xplugin-require:continuations -P:continuations:enable"
+ />
</target>
<target name="test.scaladoc" depends="pack.done">
- <partest erroronfailed="yes" scalacopts="${scalac.args.optimise}" showlog="yes">
- <compilationpath refid="partest.build.path"/>
- <runtests dir="${partest.dir}/scaladoc/run" includes="*.scala" />
- <scalachecktests dir="${partest.dir}/scaladoc/scalacheck" includes="*.scala" />
- </partest>
+ <testSuite kinds="run scalacheck" srcdir="scaladoc"/>
</target>
<target name="test.interactive" depends="pack.done">
- <partest erroronfailed="yes" scalacopts="${scalac.args.optimise}" showlog="yes">
- <compilationpath refid="partest.build.path"/>
- <presentationtests dir="${partest.dir}/${partest.srcdir}/presentation">
- <include name="*/*.scala"/>
- </presentationtests>
- </partest>
+ <testSuite kinds="presentation"/>
</target>
<!-- for use in PR validation, where stability is rarely broken, so we're going to use starr for locker,
@@ -1491,7 +1457,6 @@ TODO:
<target name="test.core" depends="test.osgi, test.sbt, test.bc, test.interactive, test.continuations.suite, test.scaladoc, test.suite"/>
<target name="test.done" depends="test.core, test.stability"/>
-
<!-- ===========================================================================
BINARY COMPATIBILITY TESTING
============================================================================ -->
diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala
index 3f61062073..46e9621b31 100644
--- a/src/partest/scala/tools/partest/DirectTest.scala
+++ b/src/partest/scala/tools/partest/DirectTest.scala
@@ -6,7 +6,6 @@
package scala.tools.partest
import scala.tools.nsc._
-import io.Directory
import util.{BatchSourceFile, CommandLineParser}
import reporters.{Reporter, ConsoleReporter}
@@ -21,8 +20,8 @@ abstract class DirectTest extends App {
def show(): Unit
// the test file or dir, and output directory
- def testPath = io.File(sys.props("partest.test-path"))
- def testOutput = io.Directory(sys.props("partest.output"))
+ def testPath = SFile(sys.props("partest.test-path"))
+ def testOutput = Directory(sys.props("partest.output"))
// override to add additional settings with strings
def extraSettings: String = ""
diff --git a/src/partest/scala/tools/partest/IcodeTest.scala b/src/partest/scala/tools/partest/IcodeTest.scala
index f5333cc5f9..b12ec0de61 100644
--- a/src/partest/scala/tools/partest/IcodeTest.scala
+++ b/src/partest/scala/tools/partest/IcodeTest.scala
@@ -5,9 +5,7 @@
package scala.tools.partest
-import scala.tools.nsc._
-import nest.FileUtil._
-import io.Directory
+import scala.tools.partest.nest.FileUtil.compareContents
/** A trait for testing icode. All you need is this in a
* partest source file:
diff --git a/src/partest/scala/tools/partest/PartestDefaults.scala b/src/partest/scala/tools/partest/PartestDefaults.scala
index 5d98a8be81..16f1a6933f 100644
--- a/src/partest/scala/tools/partest/PartestDefaults.scala
+++ b/src/partest/scala/tools/partest/PartestDefaults.scala
@@ -1,13 +1,10 @@
package scala.tools
package partest
-import nsc.io.{ File, Path, Directory }
-import scala.tools.util.PathResolver
-import nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
-import java.lang.Runtime.getRuntime
+import scala.tools.nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
+import java.lang.Runtime.{ getRuntime => runtime }
object PartestDefaults {
- import nsc.Properties._
def testRootName = propOrNone("partest.root")
def srcDirName = propOrElse("partest.srcdir", "files")
@@ -23,7 +20,7 @@ object PartestDefaults {
def testBuild = propOrNone("partest.build")
def errorCount = propOrElse("partest.errors", "0").toInt
- def numThreads = propOrNone("partest.threads") map (_.toInt) getOrElse getRuntime.availableProcessors
+ def numThreads = propOrNone("partest.threads") map (_.toInt) getOrElse runtime.availableProcessors
def timeout = "1200000"
}
diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala
index 13207b16fd..b5b09a753a 100644
--- a/src/partest/scala/tools/partest/PartestTask.scala
+++ b/src/partest/scala/tools/partest/PartestTask.scala
@@ -10,14 +10,10 @@ package scala.tools
package partest
import scala.util.Properties.setProp
-import scala.tools.nsc.io.{ Directory, Path => SPath }
-import nsc.util.ClassPath
-import util.PathResolver
import scala.tools.ant.sabbus.CompilationPathProperty
-import java.io.File
import java.lang.reflect.Method
import org.apache.tools.ant.Task
-import org.apache.tools.ant.types.{Path, Reference, FileSet}
+import org.apache.tools.ant.types.{ Reference, FileSet}
import org.apache.tools.ant.types.Commandline.Argument
/** An Ant task to execute the Scala test suite (NSC).
@@ -26,92 +22,42 @@ import org.apache.tools.ant.types.Commandline.Argument
* - `srcdir`,
* - `classpath`,
* - `classpathref`,
- * - `showlog`,
- * - `showdiff`,
* - `erroronfailed`,
* - `javacmd`,
* - `javaccmd`,
* - `scalacopts`,
- * - `timeout`,
* - `debug`,
* - `junitreportdir`.
*
* It also takes the following parameters as nested elements:
* - `compilationpath`.
- * - `postests`,
- * - `negtests`,
- * - `runtests`,
- * - `jvmtests`,
- * - `residenttests`,
- * - `shootouttests`,
- * - `scalaptests`,
- * - `scalachecktests`,
- * - `specializedtests`,
- * - `instrumentedtests`,
- * - `presentationtests`,
- * - `scripttests`.
*
* @author Philippe Haller
*/
class PartestTask extends Task with CompilationPathProperty {
-
- def addConfiguredPosTests(input: FileSet) {
- posFiles = Some(input)
- }
-
- def addConfiguredNegTests(input: FileSet) {
- negFiles = Some(input)
- }
-
- def addConfiguredRunTests(input: FileSet) {
- runFiles = Some(input)
- }
-
- def addConfiguredJvmTests(input: FileSet) {
- jvmFiles = Some(input)
- }
-
- def addConfiguredResidentTests(input: FileSet) {
- residentFiles = Some(input)
- }
-
- def addConfiguredScalacheckTests(input: FileSet) {
- scalacheckFiles = Some(input)
- }
-
- def addConfiguredScriptTests(input: FileSet) {
- scriptFiles = Some(input)
- }
-
- def addConfiguredShootoutTests(input: FileSet) {
- shootoutFiles = Some(input)
- }
-
- def addConfiguredScalapTests(input: FileSet) {
- scalapFiles = Some(input)
- }
-
- def addConfiguredSpecializedTests(input: FileSet) {
- specializedFiles = Some(input)
- }
-
- def addConfiguredInstrumentedTests(input: FileSet) {
- instrumentedFiles = Some(input)
- }
-
- def addConfiguredPresentationTests(input: FileSet) {
- presentationFiles = Some(input)
- }
-
- def addConfiguredAntTests(input: FileSet) {
- antFiles = Some(input)
- }
-
+ type Path = org.apache.tools.ant.types.Path
+
+ private var kinds: List[String] = Nil
+ private var classpath: Option[Path] = None
+ private var debug = false
+ private var errorOnFailed: Boolean = true
+ private var jUnitReportDir: Option[File] = None
+ private var javaccmd: Option[File] = None
+ private var javacmd: Option[File] = Option(sys.props("java.home")) map (x => new File(x, "bin/java"))
+ private var scalacArgs: Option[Seq[Argument]] = None
+ private var srcDir: Option[String] = None
+ private var colors: Int = 0
def setSrcDir(input: String) {
srcDir = Some(input)
}
+ def setColors(input: String) {
+ try colors = input.toInt catch { case _: NumberFormatException => () }
+ if (colors > 0)
+ sys.props("partest.colors") = colors.toString
+ }
+
def setClasspath(input: Path) {
if (classpath.isEmpty)
classpath = Some(input)
@@ -127,15 +73,6 @@ class PartestTask extends Task with CompilationPathProperty {
def setClasspathref(input: Reference) {
createClasspath().setRefid(input)
}
-
- def setShowLog(input: Boolean) {
- showLog = input
- }
-
- def setShowDiff(input: Boolean) {
- showDiff = input
- }
-
def setErrorOnFailed(input: Boolean) {
errorOnFailed = input
}
@@ -144,6 +81,10 @@ class PartestTask extends Task with CompilationPathProperty {
javacmd = Some(input)
}
+ def setKinds(input: String) {
+ kinds = words(input)
+ }
+
def setJavacCmd(input: File) {
javaccmd = Some(input)
}
@@ -159,10 +100,6 @@ class PartestTask extends Task with CompilationPathProperty {
a
}
- def setTimeout(delay: String) {
- timeout = Some(delay)
- }
-
def setDebug(input: Boolean) {
debug = input
}
@@ -171,172 +108,35 @@ class PartestTask extends Task with CompilationPathProperty {
jUnitReportDir = Some(input)
}
- private var classpath: Option[Path] = None
- private var srcDir: Option[String] = None
- private var javacmd: Option[File] = None
- private var javaccmd: Option[File] = None
- private var showDiff: Boolean = false
- private var showLog: Boolean = false
- private var posFiles: Option[FileSet] = None
- private var negFiles: Option[FileSet] = None
- private var runFiles: Option[FileSet] = None
- private var jvmFiles: Option[FileSet] = None
- private var residentFiles: Option[FileSet] = None
- private var scalacheckFiles: Option[FileSet] = None
- private var scriptFiles: Option[FileSet] = None
- private var shootoutFiles: Option[FileSet] = None
- private var scalapFiles: Option[FileSet] = None
- private var specializedFiles: Option[FileSet] = None
- private var instrumentedFiles: Option[FileSet] = None
- private var presentationFiles: Option[FileSet] = None
- private var antFiles: Option[FileSet] = None
- private var errorOnFailed: Boolean = false
- private var scalacArgs: Option[Seq[Argument]] = None
- private var timeout: Option[String] = None
- private var jUnitReportDir: Option[File] = None
- private var debug = false
-
- def fileSetToDir(fs: FileSet) = Directory(fs getDir getProject)
- def fileSetToArray(fs: FileSet): Array[SPath] = {
- val root = fileSetToDir(fs)
- (fs getDirectoryScanner getProject).getIncludedFiles map (root / _)
- }
-
- private def getFiles(fileSet: Option[FileSet]): Array[File] = fileSet match {
- case None => Array()
- case Some(fs) => fileSetToArray(fs) filterNot (_ hasExtension "log") map (_.jfile)
- }
-
- private def getFilesAndDirs(fileSet: Option[FileSet]): Array[File] = fileSet match {
- case None => Array()
- case Some(fs) =>
- def shouldExclude(name: String) = (name endsWith ".obj") || (name startsWith ".")
- // println("----> " + fileSet)
-
- val fileTests = getFiles(Some(fs)) filterNot (x => shouldExclude(x.getName))
- val dirResult = getDirs(Some(fs)) filterNot (x => shouldExclude(x.getName))
- // println("dirs: " + dirResult.toList)
- // println("files: " + fileTests.toList)
-
- dirResult ++ fileTests
- }
-
- private def getDirs(fileSet: Option[FileSet]): Array[File] = fileSet match {
- case None => Array()
- case Some(fs) =>
- def shouldExclude(name: String) = (name endsWith ".obj") || (name startsWith ".")
-
- val dirTests: Iterator[SPath] = fileSetToDir(fs).dirs filterNot (x => shouldExclude(x.name))
- val dirResult = dirTests.toList.toArray map (_.jfile)
-
- dirResult
- }
-
-
- private def getPosFiles = getFilesAndDirs(posFiles)
- private def getNegFiles = getFilesAndDirs(negFiles)
- private def getRunFiles = getFilesAndDirs(runFiles)
- private def getJvmFiles = getFilesAndDirs(jvmFiles)
- private def getResidentFiles = getFiles(residentFiles)
- private def getScalacheckFiles = getFilesAndDirs(scalacheckFiles)
- private def getScriptFiles = getFiles(scriptFiles)
- private def getShootoutFiles = getFiles(shootoutFiles)
- private def getScalapFiles = getFiles(scalapFiles)
- private def getSpecializedFiles = getFiles(specializedFiles)
- private def getInstrumentedFiles = getFilesAndDirs(instrumentedFiles)
- private def getPresentationFiles = getDirs(presentationFiles)
- private def getAntFiles = getFiles(antFiles)
-
override def execute() {
- val opts = getProject().getProperties() get "env.PARTEST_OPTS"
- if (opts != null && opts.toString != "")
- opts.toString.split(" ") foreach { propDef =>
- log("setting system property " + propDef)
- val kv = propDef split "="
- val key = kv(0) substring 2
- val value = kv(1)
- setProp(key, value)
- }
-
- if (isPartestDebug || debug) {
- setProp("partest.debug", "true")
- nest.NestUI._verbose = true
+ if (debug || sys.props.contains("partest.debug")) {
+ nest.NestUI.setDebug()
}
srcDir foreach (x => setProp("partest.srcdir", x))
val classpath = this.compilationPath getOrElse sys.error("Mandatory attribute 'compilationPath' is not set.")
-
- val scalaLibrary = {
- (classpath.list map { fs => new File(fs) }) find { f =>
- f.getName match {
- case "scala-library.jar" => true
- case "library" if (f.getParentFile.getName == "classes") => true
- case _ => false
- }
- }
- } getOrElse sys.error("Provided classpath does not contain a Scala library.")
-
- val scalaReflect = {
- (classpath.list map { fs => new File(fs) }) find { f =>
- f.getName match {
- case "scala-reflect.jar" => true
- case "reflect" if (f.getParentFile.getName == "classes") => true
- case _ => false
- }
- }
- } getOrElse sys.error("Provided classpath does not contain a Scala reflection library.")
-
- val scalaCompiler = {
- (classpath.list map { fs => new File(fs) }) find { f =>
- f.getName match {
- case "scala-compiler.jar" => true
- case "compiler" if (f.getParentFile.getName == "classes") => true
- case _ => false
- }
- }
- } getOrElse sys.error("Provided classpath does not contain a Scala compiler.")
-
- val scalaPartest = {
- (classpath.list map { fs => new File(fs) }) find { f =>
- f.getName match {
- case "scala-partest.jar" => true
- case "partest" if (f.getParentFile.getName == "classes") => true
- case _ => false
- }
- }
- } getOrElse sys.error("Provided classpath does not contain a Scala partest.")
-
- val scalaActors = {
- (classpath.list map { fs => new File(fs) }) find { f =>
- f.getName match {
- case "scala-actors.jar" => true
- case "actors" if (f.getParentFile.getName == "classes") => true
- case _ => false
- }
- }
- } getOrElse sys.error("Provided classpath does not contain a Scala actors.")
+ val cpfiles = classpath.list map { fs => new File(fs) } toList
+ def findCp(name: String) = cpfiles find (f =>
+ (f.getName == s"scala-$name.jar")
+ || (f.absolutePathSegments endsWith Seq("classes", name))
+ ) getOrElse sys.error(s"Provided classpath does not contain a Scala $name element.")
+
+ val scalaLibrary = findCp("library")
+ val scalaReflect = findCp("reflect")
+ val scalaCompiler = findCp("compiler")
+ val scalaPartest = findCp("partest")
+ val scalaActors = findCp("actors")
def scalacArgsFlat: Option[Seq[String]] = scalacArgs map (_ flatMap { a =>
val parts = a.getParts
- if(parts eq null) Seq[String]() else parts.toSeq
+ if (parts eq null) Nil else parts.toSeq
})
val antRunner = new scala.tools.partest.nest.AntRunner
val antFileManager = antRunner.fileManager
- // this is a workaround for https://issues.scala-lang.org/browse/SI-5433
- // when that bug is fixed, this paragraph of code can be safely removed
- // we hack into the classloader that will become parent classloader for scalac
- // this way we ensure that reflective macro lookup will pick correct Code.lift
- val loader = getClass.getClassLoader.asInstanceOf[org.apache.tools.ant.AntClassLoader]
- val path = new org.apache.tools.ant.types.Path(getProject())
- val newClassPath = ClassPath.join(nest.PathSettings.srcCodeLib.toString, loader.getClasspath)
- path.setPath(newClassPath)
- loader.setClassPath(path)
-
- antFileManager.showDiff = showDiff
- antFileManager.showLog = showLog
+ // antFileManager.failed = runFailed
antFileManager.CLASSPATH = ClassPath.join(classpath.list: _*)
antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath
antFileManager.LATEST_REFLECT = scalaReflect.getAbsolutePath
@@ -347,53 +147,35 @@ class PartestTask extends Task with CompilationPathProperty {
javacmd foreach (x => antFileManager.JAVACMD = x.getAbsolutePath)
javaccmd foreach (x => antFileManager.JAVAC_CMD = x.getAbsolutePath)
scalacArgsFlat foreach (antFileManager.SCALAC_OPTS ++= _)
- timeout foreach (antFileManager.timeout = _)
-
- type TFSet = (Array[File], String, String)
- val testFileSets = List(
- (getPosFiles, "pos", "Compiling files that are expected to build"),
- (getNegFiles, "neg", "Compiling files that are expected to fail"),
- (getRunFiles, "run", "Compiling and running files"),
- (getJvmFiles, "jvm", "Compiling and running files"),
- (getResidentFiles, "res", "Running resident compiler scenarii"),
- (getScalacheckFiles, "scalacheck", "Running scalacheck tests"),
- (getScriptFiles, "script", "Running script files"),
- (getShootoutFiles, "shootout", "Running shootout tests"),
- (getScalapFiles, "scalap", "Running scalap tests"),
- (getSpecializedFiles, "specialized", "Running specialized files"),
- (getInstrumentedFiles, "instrumented", "Running instrumented files"),
- (getPresentationFiles, "presentation", "Running presentation compiler test files"),
- (getAntFiles, "ant", "Running ant task tests")
- )
-
- def runSet(set: TFSet): (Int, Int, Iterable[String]) = {
- val (files, name, msg) = set
+
+ def runSet(kind: String, files: Array[File]): (Int, Int, List[String]) = {
if (files.isEmpty) (0, 0, List())
else {
- log(msg)
- val results: Iterable[(String, TestState)] = antRunner.reflectiveRunTestsForFiles(files, name)
- val (succs, fails) = resultsToStatistics(results)
+ log(s"Running ${files.length} tests in '$kind' at $now")
+ // log(s"Tests: ${files.toList}")
+ val results = antRunner.reflectiveRunTestsForFiles(files, kind)
+ val (passed, failed) = results partition (_.isOk)
+ val numPassed = passed.size
+ val numFailed = failed.size
+ def failedMessages = failed map (_.longStatus)
- val failed: Iterable[String] = results collect {
- case (path, TestState.Fail) => path + " [FAILED]"
- case (path, TestState.Timeout) => path + " [TIMOUT]"
- }
+ log(s"Completed '$kind' at $now")
// create JUnit Report xml files if directory was specified
jUnitReportDir foreach { d =>
d.mkdir
- val report = testReport(name, results, succs, fails)
- scala.xml.XML.save(d.getAbsolutePath+"/"+name+".xml", report)
+ val report = testReport(kind, results, numPassed, numFailed)
+ scala.xml.XML.save(d.getAbsolutePath+"/"+kind+".xml", report)
}
- (succs, fails, failed)
+ (numPassed, numFailed, failedMessages)
}
}
- val _results = testFileSets map runSet
- val allSuccesses = _results map (_._1) sum
- val allFailures = _results map (_._2) sum
+ val _results = kinds map (k => runSet(k, TestKinds testsFor k map (_.jfile) toArray))
+ val allSuccesses = _results map (_._1) sum
+ val allFailures = _results map (_._2) sum
val allFailedPaths = _results flatMap (_._3)
def f = if (errorOnFailed && allFailures > 0) (sys error _) else log(_: String)
@@ -408,20 +190,17 @@ class PartestTask extends Task with CompilationPathProperty {
f(msg)
}
- private def oneResult(res: (String, TestState)) =
- <testcase name={res._1}>{
- res._2 match {
- case TestState.Ok => scala.xml.NodeSeq.Empty
- case TestState.Fail => <failure message="Test failed"/>
- case TestState.Timeout => <failure message="Test timed out"/>
- }
+ private def oneResult(res: TestState) =
+ <testcase name={res.testIdent}>{
+ if (res.isOk) scala.xml.NodeSeq.Empty
+ else <failure message="Test failed"/>
}</testcase>
- private def testReport(kind: String, results: Iterable[(String, TestState)], succs: Int, fails: Int) =
+ private def testReport(kind: String, results: Iterable[TestState], succs: Int, fails: Int) =
<testsuite name={kind} tests={(succs + fails).toString} failures={fails.toString}>
<properties/>
{
- results.map(oneResult(_))
+ results map oneResult
}
</testsuite>
}
diff --git a/src/partest/scala/tools/partest/TestKinds.scala b/src/partest/scala/tools/partest/TestKinds.scala
new file mode 100644
index 0000000000..ec682690ca
--- /dev/null
+++ b/src/partest/scala/tools/partest/TestKinds.scala
@@ -0,0 +1,67 @@
+package scala.tools
+package partest
+
+import nest.PathSettings.srcDir
+
+object TestKinds {
+ val standardKinds = "pos neg run jvm res buildmanager scalacheck scalap specialized instrumented presentation ant" split "\\s+" toList
+ val standardArgs = standardKinds map ("--" + _)
+
+ def denotesTestFile(p: Path) = p.isFile && p.hasExtension("scala", "res", "xml")
+ def denotesTestDir(p: Path) = kindOf(p) match {
+ case "res" => false
+ case _ => p.isDirectory && p.extension == ""
+ }
+ def denotesTestPath(p: Path) = denotesTestDir(p) || denotesTestFile(p)
+
+ // TODO
+ def isTestForPartest(p: Path) = (
+ (p.name == "intentional-failure.scala")
+ || (p.path contains "test-for-partest")
+ )
+
+ def kindOf(p: Path) = {
+ p.toAbsolute.segments takeRight 2 head
+
+ // (srcDir relativize p.toCanonical).segments match {
+ // case (".." :: "scaladoc" :: xs) => xs.head
+ // case xs => xs.head
+ // }
+ }
+ def logOf(p: Path) = {
+ p.parent / s"${p.stripExtension}-${kindOf(p)}.log"
+ // p.parent / s"${p.stripExtension}.log"
+ }
+
+ // true if a test path matches the --grep expression.
+ private def pathMatchesExpr(path: Path, expr: String) = {
+ // Matches the expression if any source file contains the expr,
+ // or if the checkfile contains it, or if the filename contains
+ // it (the last is case-insensitive.)
+ def matches(p: Path) = (
+ (p.path.toLowerCase contains expr.toLowerCase)
+ || (p.fileContents contains expr)
+ )
+ def candidates = {
+ (path changeExtension "check") +: {
+ if (path.isFile) List(path)
+ else path.toDirectory.deepList() filter (_.isJavaOrScala) toList
+ }
+ }
+
+ (candidates exists matches)
+ }
+
+ def groupedTests(paths: List[Path]): List[(String, List[Path])] =
+ (paths.distinct groupBy kindOf).toList sortBy (standardKinds indexOf _._1)
+
+ /** Includes tests for testing partest. */
+ private def allTestsForKind(kind: String): List[Path] =
+ (srcDir / kind toDirectory).list.toList filter denotesTestPath
+
+ def testsForPartest: List[Path] = standardKinds flatMap allTestsForKind filter isTestForPartest
+ def testsFor(kind: String): List[Path] = allTestsForKind(kind) filterNot isTestForPartest
+ def grepFor(expr: String): List[Path] = standardTests filter (t => pathMatchesExpr(t, expr))
+ def standardTests: List[Path] = standardKinds flatMap testsFor
+ def failedTests: List[Path] = standardTests filter (p => logOf(p).isFile)
+}
diff --git a/src/partest/scala/tools/partest/TestState.scala b/src/partest/scala/tools/partest/TestState.scala
new file mode 100644
index 0000000000..ce8e72f616
--- /dev/null
+++ b/src/partest/scala/tools/partest/TestState.scala
@@ -0,0 +1,54 @@
+package scala.tools.partest
+
+import scala.tools.nsc.FatalError
+import scala.tools.nsc.util.stackTraceString
+
+sealed abstract class TestState {
+ def testFile: File
+ def what: String
+ def reason: String
+ def transcript: List[String]
+
+ def isOk = false
+ def isSkipped = false
+ def testIdent = testFile.testIdent
+ def transcriptString = transcript.mkString("\n")
+
+ def identAndReason = testIdent + reasonString
+ def status = s"$what - $identAndReason"
+ def longStatus = status + transcriptString
+ def reasonString = if (reason == "") "" else s" [$reason]"
+
+ override def toString = status
+}
+
+object TestState {
+ case class Uninitialized(testFile: File) extends TestState {
+ def what = "uninitialized"
+ def reason = what
+ def transcript = Nil
+ }
+ case class Pass(testFile: File) extends TestState {
+ final override def isOk = true
+ def what = "pass"
+ def transcript: List[String] = Nil
+ def reason = ""
+ }
+ case class Skip(testFile: File, reason: String) extends TestState {
+ override def isOk = true
+ final override def isSkipped = true
+ def transcript: List[String] = Nil
+ def what = "skip"
+ }
+ case class Fail(testFile: File, reason: String, transcript: List[String]) extends TestState {
+ def what = "fail"
+ }
+ case class Crash(testFile: File, caught: Throwable, transcript: List[String]) extends TestState {
+ def what = "crash"
+ def reason = s"caught $caught_s - ${caught.getMessage}"
+
+ private def caught_s = (caught.getClass.getName split '.').last
+ private def stack_s = stackTraceString(caught)
+ override def transcriptString = nljoin(super.transcriptString, caught_s)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala
index 93045b8c1d..1d3b79171b 100644
--- a/src/partest/scala/tools/partest/nest/AntRunner.scala
+++ b/src/partest/scala/tools/partest/nest/AntRunner.scala
@@ -10,24 +10,21 @@
package scala.tools.partest
package nest
-import java.io.File
-import scala.tools.nsc.io.{ Directory }
-
class AntRunner extends DirectRunner {
val fileManager = new FileManager {
- var JAVACMD: String = "java"
- var JAVAC_CMD: String = "javac"
- var CLASSPATH: String = _
- var LATEST_LIB: String = _
- var LATEST_REFLECT: String = _
- var LATEST_COMP: String = _
- var LATEST_PARTEST: String = _
- var LATEST_ACTORS: String = _
- val testRootPath: String = "test"
- val testRootDir: Directory = Directory(testRootPath)
+ var JAVACMD: String = "java"
+ var JAVAC_CMD: String = "javac"
+ var CLASSPATH: String = _
+ var LATEST_LIB: String = _
+ var LATEST_REFLECT: String = _
+ var LATEST_COMP: String = _
+ var LATEST_PARTEST: String = _
+ var LATEST_ACTORS: String = _
+ val testRootPath: String = "test"
+ val testRootDir: Directory = Directory(testRootPath)
}
- def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String) =
+ def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String): List[TestState] =
runTestsForFiles(kindFiles.toList, kind)
}
diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala
deleted file mode 100644
index a8694cc0d6..0000000000
--- a/src/partest/scala/tools/partest/nest/CompileManager.scala
+++ /dev/null
@@ -1,182 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2013 LAMP/EPFL
- * @author Philipp Haller
- */
-
-// $Id$
-
-package scala.tools.partest
-package nest
-
-import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io }
-import scala.reflect.io.{ Directory, File => SFile, FileOperationException }
-import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
-import scala.tools.nsc.util.{ ClassPath, FakePos }
-import scala.tools.nsc.Properties.{ setProp, propOrEmpty }
-import scala.tools.util.PathResolver
-import io.Path
-import java.io.{ File, BufferedReader, PrintWriter, FileReader, Writer, FileWriter, StringWriter }
-import File.pathSeparator
-
-sealed abstract class CompilationOutcome {
- def merge(other: CompilationOutcome): CompilationOutcome
- def isPositive = this eq CompileSuccess
- def isNegative = this eq CompileFailed
-}
-case object CompileSuccess extends CompilationOutcome {
- def merge(other: CompilationOutcome) = other
-}
-case object CompileFailed extends CompilationOutcome {
- def merge(other: CompilationOutcome) = if (other eq CompileSuccess) this else other
-}
-case object CompilerCrashed extends CompilationOutcome {
- def merge(other: CompilationOutcome) = this
-}
-
-class ExtConsoleReporter(settings: Settings, val writer: PrintWriter) extends ConsoleReporter(settings, Console.in, writer) {
- shortname = true
-}
-
-class TestSettings(cp: String, error: String => Unit) extends Settings(error) {
- def this(cp: String) = this(cp, _ => ())
-
- nowarnings.value = false
- encoding.value = "UTF-8"
- classpath.value = cp
-}
-
-abstract class SimpleCompiler {
- def compile(out: Option[File], files: List[File], kind: String, log: File): CompilationOutcome
-}
-
-class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler {
- def newGlobal(settings: Settings, reporter: Reporter): Global =
- Global(settings, reporter)
-
- def newGlobal(settings: Settings, logWriter: FileWriter): Global =
- newGlobal(settings, new ExtConsoleReporter(settings, new PrintWriter(logWriter)))
-
- def newSettings(): TestSettings = new TestSettings(fileManager.LATEST_LIB)
- def newSettings(outdir: String): TestSettings = {
- val cp = ClassPath.join(fileManager.LATEST_LIB, outdir)
- val s = new TestSettings(cp)
- s.outdir.value = outdir
-
- s
- }
-
- implicit class Copier(f: SFile) {
- // But what if f is bigger than CHUNK?!
- def copyTo(dest: Path) {
- dest.toFile writeAll f.slurp
- }
- }
-
- // plugin path can be relative to test root, or cwd is out
- private def updatePluginPath(options: String, out: Option[File], srcdir: Directory): String = {
- val dir = fileManager.testRootDir
- def pathOrCwd(p: String) =
- if (p == "." && out.isDefined) {
- val plugxml = "scalac-plugin.xml"
- val pout = Path(out.get)
- val pd = (srcdir / plugxml).toFile
- if (pd.exists) pd copyTo (pout / plugxml)
- pout
- } else Path(p)
- def absolutize(path: String) = pathOrCwd(path) match {
- case x if x.isAbsolute => x.path
- case x => (dir / x).toAbsolute.path
- }
-
- val (opt1, opt2) = (options split "\\s").toList partition (_ startsWith "-Xplugin:")
- val plugins = opt1 map (_ stripPrefix "-Xplugin:") flatMap (_ split pathSeparator) map absolutize
- val pluginOption = if (opt1.isEmpty) Nil else List("-Xplugin:" + (plugins mkString pathSeparator))
-
- (opt2 ::: pluginOption) mkString " "
- }
-
- def compile(out: Option[File], files: List[File], kind: String, log: File): CompilationOutcome = {
- val testSettings = out match {
- case Some(f) => newSettings(f.getAbsolutePath)
- case _ => newSettings()
- }
- val logWriter = new FileWriter(log)
-
- // this api has no notion of srcdir, so fake it
- val fstFile = SFile(files(0))
- val srcdir = fstFile.parent
-
- // check whether there is a ".flags" file
- def convertFlags(f: SFile) = updatePluginPath(f.slurp(), out, srcdir)
- val logFile = basename(log.getName)
- val flagsFileName = "%s.flags" format (logFile.substring(0, logFile.lastIndexOf("-")))
- val argString = (SFile(log).parent / flagsFileName) ifFile (convertFlags) getOrElse ""
-
- // slurp local flags (e.g., "A_1.flags")
- def isInGroup(num: Int) = fstFile.stripExtension endsWith ("_" + num)
- val inGroup = (1 to 9) flatMap (group => if (isInGroup(group)) List(group) else List())
- val localFlagsList = if (inGroup.nonEmpty) {
- val localArgString = (srcdir / (fstFile.stripExtension + ".flags")) ifFile (convertFlags) getOrElse ""
- localArgString.split(' ').toList.filter(_.length > 0)
- } else List()
-
- val allOpts = fileManager.SCALAC_OPTS.toList ::: argString.split(' ').toList.filter(_.length > 0) ::: localFlagsList
- val args = allOpts.toList
-
- NestUI.verbose("scalac options: "+allOpts)
-
- val command = new CompilerCommand(args, testSettings)
- val global = newGlobal(command.settings, logWriter)
- val testRep: ExtConsoleReporter = global.reporter.asInstanceOf[ExtConsoleReporter]
-
- val testFileFn: (File, FileManager) => TestFile = kind match {
- case "pos" => PosTestFile.apply
- case "neg" => NegTestFile.apply
- case "run" => RunTestFile.apply
- case "jvm" => JvmTestFile.apply
- case "shootout" => ShootoutTestFile.apply
- case "scalap" => ScalapTestFile.apply
- case "scalacheck" => ScalaCheckTestFile.apply
- case "specialized" => SpecializedTestFile.apply
- case "instrumented" => InstrumentedTestFile.apply
- case "presentation" => PresentationTestFile.apply
- case "ant" => AntTestFile.apply
- }
- val test: TestFile = testFileFn(files.head, fileManager)
- if (!test.defineSettings(command.settings, out.isEmpty)) {
- testRep.error(FakePos("partest"), test.flags match {
- case Some(flags) => "bad flags: " + flags
- case _ => "bad settings: " + command.settings
- })
- }
-
- val toCompile = files map (_.getPath)
-
- try {
- NestUI.verbose("compiling "+toCompile)
- NestUI.verbose("with classpath: "+global.classPath.toString)
- NestUI.verbose("and java classpath: "+ propOrEmpty("java.class.path"))
- try {
- if (command.shouldStopWithInfo) logWriter append (command getInfoMessage global)
- else new global.Run compile toCompile
- } catch {
- case FatalError(msg) =>
- testRep.error(null, "fatal error: " + msg)
- return CompilerCrashed
- }
-
- testRep.printSummary()
- testRep.writer.close()
- }
- finally logWriter.close()
-
- if (testRep.hasErrors || command.shouldStopWithInfo) CompileFailed
- else CompileSuccess
- }
-}
-
-class CompileManager(val fileManager: FileManager) {
- private def newCompiler = new DirectCompiler(fileManager)
- def attemptCompile(outdir: Option[File], sources: List[File], kind: String, log: File): CompilationOutcome =
- newCompiler.compile(outdir, sources, kind, log)
-}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
index 0ec3f60bf5..b436675d3a 100644
--- a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
+++ b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
@@ -3,20 +3,15 @@
* @author Philipp Haller
*/
-// $Id$
+
package scala.tools.partest
package nest
-import java.io.{ File, FilenameFilter, IOException, StringWriter }
+import java.io.{ FilenameFilter, IOException }
import java.net.URI
import scala.util.Properties.{ propOrElse, scalaCmd, scalacCmd }
-import scala.tools.util.PathResolver
import scala.tools.nsc.{ io, util }
-import util.{ ClassPath }
-import io.{ Path, Directory }
-import File.pathSeparator
-import ClassPath.{ join }
import PathResolver.{ Environment, Defaults }
class ConsoleFileManager extends FileManager {
@@ -55,7 +50,7 @@ class ConsoleFileManager extends FileManager {
var JAVAC_CMD = PartestDefaults.javacCmd
- NestUI.verbose("CLASSPATH: "+CLASSPATH)
+ vlog("CLASSPATH: "+CLASSPATH)
if (!srcDir.isDirectory) {
NestUI.failure("Source directory \"" + srcDir.path + "\" not found")
@@ -70,14 +65,14 @@ class ConsoleFileManager extends FileManager {
}
def findLatest() {
- NestUI.verbose("test parent: "+testParent)
+ vlog("test parent: "+testParent)
- def prefixFileWith(parent: File, relPath: String) = (io.File(parent) / relPath).toCanonical
+ def prefixFileWith(parent: File, relPath: String) = (SFile(parent) / relPath).toCanonical
def prefixFile(relPath: String) = (testParent / relPath).toCanonical
if (!testClasses.isEmpty) {
testClassesDir = Path(testClasses.get).toCanonical.toDirectory
- NestUI.verbose("Running with classes in "+testClassesDir)
+ vlog("Running with classes in "+testClassesDir)
latestLibFile = testClassesDir / "library"
latestActorsFile = testClassesDir / "library" / "actors"
@@ -87,7 +82,7 @@ class ConsoleFileManager extends FileManager {
}
else if (testBuild.isDefined) {
val dir = Path(testBuild.get)
- NestUI.verbose("Running on "+dir)
+ vlog("Running on "+dir)
latestLibFile = dir / "lib/scala-library.jar"
latestActorsFile = dir / "lib/scala-actors.jar"
latestReflectFile = dir / "lib/scala-reflect.jar"
@@ -96,7 +91,7 @@ class ConsoleFileManager extends FileManager {
}
else {
def setupQuick() {
- NestUI.verbose("Running build/quick")
+ vlog("Running build/quick")
latestLibFile = prefixFile("build/quick/classes/library")
latestActorsFile = prefixFile("build/quick/classes/library/actors")
latestReflectFile = prefixFile("build/quick/classes/reflect")
@@ -105,7 +100,7 @@ class ConsoleFileManager extends FileManager {
}
def setupInst() {
- NestUI.verbose("Running dist (installed)")
+ vlog("Running dist (installed)")
val p = testParent.getParentFile
latestLibFile = prefixFileWith(p, "lib/scala-library.jar")
latestActorsFile = prefixFileWith(p, "lib/scala-actors.jar")
@@ -115,7 +110,7 @@ class ConsoleFileManager extends FileManager {
}
def setupDist() {
- NestUI.verbose("Running dists/latest")
+ vlog("Running dists/latest")
latestLibFile = prefixFile("dists/latest/lib/scala-library.jar")
latestActorsFile = prefixFile("dists/latest/lib/scala-actors.jar")
latestReflectFile = prefixFile("dists/latest/lib/scala-reflect.jar")
@@ -124,7 +119,7 @@ class ConsoleFileManager extends FileManager {
}
def setupPack() {
- NestUI.verbose("Running build/pack")
+ vlog("Running build/pack")
latestLibFile = prefixFile("build/pack/lib/scala-library.jar")
latestActorsFile = prefixFile("build/pack/lib/scala-actors.jar")
latestReflectFile = prefixFile("build/pack/lib/scala-reflect.jar")
@@ -170,11 +165,13 @@ class ConsoleFileManager extends FileManager {
var latestReflectFile: File = _
var latestCompFile: File = _
var latestPartestFile: File = _
- def latestScalapFile: File = (latestLibFile.parent / "scalap.jar").jfile
+ //def latestScalapFile: File = (latestLibFile.parent / "scalap.jar").jfile
+ //def latestScalapFile: File = new File(latestLibFile.getParentFile, "scalap.jar")
var testClassesDir: Directory = _
// initialize above fields
findLatest()
+ /*
def getFiles(kind: String, cond: Path => Boolean): List[File] = {
def ignoreDir(p: Path) = List("svn", "obj") exists (p hasExtension _)
@@ -187,4 +184,6 @@ class ConsoleFileManager extends FileManager {
( if (failed) files filter (x => logFileExists(x, kind)) else files ) map (_.jfile)
}
+ */
+ var latestFjbgFile: File = _
}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
index fd4d52f603..ddd42f5601 100644
--- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
+++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
@@ -3,83 +3,110 @@
* @author Philipp Haller
*/
-// $Id$
-
-package scala.tools.partest
+package scala.tools
+package partest
package nest
-import java.io.{File, PrintStream, FileOutputStream, BufferedReader,
- InputStreamReader, StringWriter, PrintWriter}
import utils.Properties._
import scala.tools.nsc.Properties.{ versionMsg, setProp }
import scala.tools.nsc.util.CommandLineParser
-import scala.tools.nsc.io
-import io.{ Path }
import scala.collection.{ mutable, immutable }
+import PathSettings.srcDir
+import TestKinds._
class ConsoleRunner extends DirectRunner {
- import PathSettings.{ srcDir, testRoot }
-
- case class TestSet(kind: String, filter: Path => Boolean, msg: String)
- private def stdFilter(p: Path) = p.isDirectory || (p hasExtension "scala")
- private def antFilter(p: Path) = p.isFile && (p endsWith "build.xml")
-
- val testSets = {
- List(
- TestSet("pos", stdFilter, "Testing compiler (on files whose compilation should succeed)"),
- TestSet("neg", stdFilter, "Testing compiler (on files whose compilation should fail)"),
- TestSet("run", stdFilter, "Testing interpreter and backend"),
- TestSet("jvm", stdFilter, "Testing JVM backend"),
- TestSet("res", x => x.isFile && (x hasExtension "res"), "Testing resident compiler"),
- TestSet("shootout", stdFilter, "Testing shootout tests"),
- TestSet("script", stdFilter, "Testing script tests"),
- TestSet("scalacheck", stdFilter, "Testing ScalaCheck tests"),
- TestSet("scalap", _.isDirectory, "Run scalap decompiler tests"),
- TestSet("specialized", stdFilter, "Testing specialized tests"),
- TestSet("instrumented", stdFilter, "Testing instrumented tests"),
- TestSet("presentation", _.isDirectory, "Testing presentation compiler tests."),
- TestSet("ant", antFilter, "Run Ant task tests.")
- )
- }
+ import NestUI._
+ import NestUI.color._
+
+ // So we can ctrl-C a test run and still hear all
+ // the buffered failure info.
+ scala.sys addShutdownHook issueSummaryReport()
var fileManager: ConsoleFileManager = _
- private var testFiles: List[File] = List()
- private val errors = PartestDefaults.errorCount
- private val testSetKinds = testSets map (_.kind)
- private val testSetArgs = testSets map ("--" + _.kind)
- private val testSetArgMap = testSetArgs zip testSets toMap
+ private var totalTests = 0
+ private val passedTests = mutable.ListBuffer[TestState]()
+ private val failedTests = mutable.ListBuffer[TestState]()
+
+ def comment(s: String) = echo(magenta("# " + s))
+ def levyJudgment() = {
+ if (totalTests == 0) echoMixed("No tests to run.")
+ else if (elapsedMillis == 0) echoMixed("Test Run ABORTED")
+ else if (isSuccess) echoPassed("Test Run PASSED")
+ else echoFailed("Test Run FAILED")
+ }
+
+ def passFailString(passed: Int, failed: Int, skipped: Int): String = {
+ val total = passed + failed + skipped
+ val isSuccess = failed == 0
+ def p0 = s"$passed/$total"
+ def p = ( if (isSuccess) bold(green(p0)) else p0 ) + " passed"
+ def f = if (failed == 0) "" else bold(red("" + failed)) + " failed"
+ def s = if (skipped == 0) "" else bold(yellow("" + skipped)) + " skipped"
+
+ oempty(p, f, s) mkString ", "
+ }
+
+ private var summarizing = false
+ private var elapsedMillis = 0L
+ private var expectedFailures = 0
+ private def isSuccess = failedTests.size == expectedFailures
+
+ def issueSummaryReport() {
+ // Don't run twice
+ if (!summarizing) {
+ summarizing = true
+
+ val passed0 = passedTests.toList
+ val failed0 = failedTests.toList
+ val passed = passed0.size
+ val failed = failed0.size
+ val skipped = totalTests - (passed + failed)
+ val passFail = passFailString(passed, failed, skipped)
+ val elapsed = if (elapsedMillis > 0) " (elapsed time: " + elapsedString(elapsedMillis) + ")" else ""
+ val message = passFail + elapsed
+
+ if (failed0.nonEmpty) {
+ echo(bold(cyan("##### Transcripts from failed tests #####\n")))
+ failed0 foreach { state =>
+ comment("partest " + state.testFile)
+ echo(state.transcriptString + "\n")
+ }
+ }
- private def printVersion() { NestUI outline (versionMsg + "\n") }
+ echo(message)
+ levyJudgment()
+ }
+ }
private val unaryArgs = List(
- "--pack", "--all", "--verbose", "--show-diff", "--show-log",
+ "--pack", "--all",
+ "--terse", "--verbose", "--show-diff", "--show-log", "--self-test",
"--failed", "--update-check", "--version", "--ansi", "--debug", "--help"
- ) ::: testSetArgs
+ ) ::: standardArgs
private val binaryArgs = List(
"--grep", "--srcpath", "--buildpath", "--classpath"
)
- // true if a test path matches the --grep expression.
- private def pathMatchesExpr(path: Path, expr: String) = {
- def pred(p: Path) = file2String(p.toFile) contains expr
- def greppable(f: Path) = f.isFile && (f hasExtension ("scala", "java"))
- def any(d: Path) = d.toDirectory.deepList() exists (f => greppable(f) && pred(f))
-
- (path.isFile && pred(path)) ||
- (path.isDirectory && any(path)) ||
- (pred(path changeExtension "check"))
- }
-
def main(argstr: String) {
val parsed = CommandLineParser(argstr) withUnaryArgs unaryArgs withBinaryArgs binaryArgs
- val args = onlyValidTestPaths(parsed.residualArgs)
- /* Early return on no args, version, or invalid args */
- if (argstr == "") return NestUI.usage()
- if (parsed isSet "--version") return printVersion
- if (parsed isSet "--help") return NestUI.usage()
+ if (parsed isSet "--debug") NestUI.setDebug()
+ if (parsed isSet "--verbose") NestUI.setVerbose()
+ if (parsed isSet "--terse") NestUI.setTerse()
+
+ // Early return on no args, version, or invalid args
+ if (parsed isSet "--version") return echo(versionMsg)
+ if ((argstr == "") || (parsed isSet "--help")) return NestUI.usage()
+
+ val (individualTests, invalid) = parsed.residualArgs map (p => Path(p)) partition denotesTestPath
+ if (invalid.nonEmpty) {
+ if (isPartestVerbose)
+ invalid foreach (p => echoWarning(s"Discarding invalid test path " + p))
+ else if (!isPartestTerse)
+ echoWarning(s"Discarding ${invalid.size} invalid test paths")
+ }
parsed get "--srcpath" foreach (x => setProp("partest.srcdir", x))
@@ -89,144 +116,102 @@ class ConsoleRunner extends DirectRunner {
else if (parsed isSet "--pack") new ConsoleFileManager("build/pack")
else new ConsoleFileManager // auto detection, see ConsoleFileManager.findLatest
- NestUI._verbose = parsed isSet "--verbose"
- fileManager.showDiff = true
- // parsed isSet "--show-diff"
fileManager.updateCheck = parsed isSet "--update-check"
- fileManager.showLog = parsed isSet "--show-log"
fileManager.failed = parsed isSet "--failed"
- if (parsed isSet "--ansi") NestUI initialize NestUI.MANY
- if (parsed isSet "--timeout") fileManager.timeout = parsed("--timeout")
- if (parsed isSet "--debug") setProp("partest.debug", "true")
+ val partestTests = (
+ if (parsed isSet "--self-test") TestKinds.testsForPartest
+ else Nil
+ )
- def addTestFile(file: File) = {
- if (!file.exists)
- NestUI.failure("Test file '%s' not found, skipping.\n" format file)
- else {
- NestUI.verbose("adding test file " + file)
- testFiles +:= file
- }
- }
+ val grepExpr = parsed get "--grep" getOrElse ""
// If --grep is given we suck in every file it matches.
-
- val grepOption = parsed get "--grep"
- val grepPaths = grepOption.toList flatMap { expr =>
- val subjectDirs = testSetKinds map (srcDir / _ toDirectory)
- val testPaths = subjectDirs flatMap (_.list filter stdFilter)
- val paths = testPaths filter (p => pathMatchesExpr(p, expr))
-
+ var grepMessage = ""
+ val greppedTests = if (grepExpr == "") Nil else {
+ val paths = grepFor(grepExpr)
if (paths.isEmpty)
- NestUI.failure("--grep string '%s' matched no tests." format expr)
+ echoWarning(s"grep string '$grepExpr' matched no tests.\n")
- paths map (_.jfile)
+ paths.sortBy(_.toString)
}
- val grepMessage = grepOption map (x => "Argument '%s' matched %d test(s)".format(x, grepPaths.size)) getOrElse ""
-
- grepPaths foreach addTestFile
- args foreach (x => addTestFile(new File(x)))
- // If no file arguments were given, we assume --all
- val enabledTestSets: List[TestSet] = {
- val enabledArgs = testSetArgs filter parsed.isSet
-
- if (args.isEmpty && !(parsed isSet "--grep") && (enabledArgs.isEmpty || (parsed isSet "--all"))) testSets
- else enabledArgs map testSetArgMap
- }
+ val isRerun = parsed isSet "--failed"
+ val rerunTests = if (isRerun) TestKinds.failedTests else Nil
+ def miscTests = partestTests ++ individualTests ++ greppedTests ++ rerunTests
+ val givenKinds = standardArgs filter parsed.isSet
+ val kinds = (
+ if (parsed isSet "--all") standardKinds
+ else if (givenKinds.nonEmpty) givenKinds map (_ stripPrefix "--")
+ else if (invalid.isEmpty && miscTests.isEmpty && !isRerun) standardKinds // If no kinds, --grep, or individual tests were given, assume --all
+ else Nil
+ )
+ val kindsTests = kinds flatMap testsFor
val dir =
if (fileManager.testClasses.isDefined) fileManager.testClassesDir
else fileManager.testBuildFile getOrElse {
fileManager.latestCompFile.getParentFile.getParentFile.getAbsoluteFile
}
- val vmBin = javaHome + File.separator + "bin"
- val vmName = "%s (build %s, %s)".format(javaVmName, javaVmVersion, javaVmInfo)
- val vmOpts = fileManager.JAVA_OPTS
-
- NestUI.verbose("enabled test sets: " + (enabledTestSets map (_.kind) mkString " "))
-
- List(
- "Scala compiler classes in: " + dir,
- "Scala version is: " + versionMsg,
- "Scalac options are: " + fileManager.SCALAC_OPTS,
- "Java binaries in: " + vmBin,
- "Java runtime is: " + vmName,
- "Java options are: " + vmOpts,
- "Source directory is: " + srcDir,
- ""
- ) foreach (x => NestUI verbose (x + "\n"))
-
- NestUI.verbose("available processors: " + Runtime.getRuntime().availableProcessors())
-
- // Dragged down here so it isn't buried under the banner.
- if (grepMessage != "")
- NestUI.normal(grepMessage + "\n")
-
- val ((successes, failures), elapsedMillis) = timed(testCheckAll(enabledTestSets))
- val total = successes + failures
-
- val elapsedSecs = elapsedMillis/1000
- val elapsedMins = elapsedSecs/60
- val elapsedHrs = elapsedMins/60
- val dispMins = elapsedMins - elapsedHrs * 60
- val dispSecs = elapsedSecs - elapsedMins * 60
-
- val dispElapsed = {
- def form(num: Long) = if (num < 10) "0"+num else ""+num
- form(elapsedHrs)+":"+form(dispMins)+":"+form(dispSecs)
+ def testContributors = {
+ List(
+ if (partestTests.isEmpty) "" else "partest self-tests",
+ if (rerunTests.isEmpty) "" else "previously failed tests",
+ if (kindsTests.isEmpty) "" else s"${kinds.size} named test categories",
+ if (greppedTests.isEmpty) "" else s"${greppedTests.size} tests matching '$grepExpr'",
+ if (individualTests.isEmpty) "" else "specified tests"
+ ) filterNot (_ == "") mkString ", "
}
- if (failures == 0)
- NestUI.success("All of "+total+" tests were successful (elapsed time: "+dispElapsed+")\n")
- else
- NestUI.failure(failures+" of "+total+" tests failed (elapsed time: "+dispElapsed+")\n")
+ def banner = {
+ val vmBin = javaHome + fileSeparator + "bin"
+ val vmName = "%s (build %s, %s)".format(javaVmName, javaVmVersion, javaVmInfo)
+ val vmOpts = fileManager.JAVA_OPTS
+
+ s"""|Scala compiler classes in: $dir
+ |Scala version is: $versionMsg
+ |Scalac options are: ${fileManager.SCALAC_OPTS mkString " "}
+ |Java binaries in: $vmBin
+ |Java runtime is: $vmName
+ |Java options are: $vmOpts
+ |Source directory is: $srcDir
+ |Available processors: ${Runtime.getRuntime().availableProcessors()}
+ |Java Classpath: ${sys.props("java.class.path")}
+ """.stripMargin
+ }
- System exit ( if (failures == errors) 0 else 1 )
- }
+ chatty(banner)
- def runTests(testSet: TestSet): (Int, Int) = {
- val TestSet(kind, filter, msg) = testSet
+ val allTests = (miscTests ++ (kinds flatMap testsFor)).distinct
+ val grouped = (allTests groupBy kindOf).toList sortBy (x => standardKinds indexOf x._1)
- fileManager.getFiles(kind, filter) match {
- case Nil => NestUI.verbose("test dir empty\n") ; (0, 0)
- case files =>
- NestUI.verbose("test files: "+files)
- NestUI.outline("\n"+msg+"\n")
- resultsToStatistics(runTestsForFiles(files, kind))
+ totalTests = allTests.size
+ expectedFailures = propOrNone("partest.errors") match {
+ case Some(num) => num.toInt
+ case _ => 0
}
- }
-
- /**
- * @return (success count, failure count)
- */
- def testCheckAll(enabledSets: List[TestSet]): (Int, Int) = {
- def kindOf(f: File) = {
- (srcDir relativize Path(f).toCanonical).segments match {
- case (".." :: "scaladoc" :: xs) => xs.head
- case xs => xs.head
+ val expectedFailureMessage = if (expectedFailures == 0) "" else s" (expecting $expectedFailures to fail)"
+ echo(s"Selected $totalTests tests drawn from $testContributors$expectedFailureMessage\n")
+
+ val (_, millis) = timed {
+ for ((kind, paths) <- grouped) {
+ val num = paths.size
+ val ss = if (num == 1) "" else "s"
+ comment(s"starting $num test$ss in $kind")
+ val results = runTestsForFiles(paths map (_.jfile), kind)
+ val (passed, failed) = results partition (_.isOk)
+
+ passedTests ++= passed
+ failedTests ++= failed
+ if (failed.nonEmpty) {
+ comment(passFailString(passed.size, failed.size, 0) + " in " + kind)
+ }
+ echo("")
}
}
-
- val (valid, invalid) = testFiles partition (x => testSetKinds contains kindOf(x))
- invalid foreach (x => NestUI.failure(
- "Invalid test file '%s', skipping.\n".format(x) +
- "(Test kind '%s' not in known set '%s')".format(kindOf(x), testSetKinds))
- )
-
- val grouped = (valid groupBy kindOf).toList sortBy (x => testSetKinds indexOf x._1)
- val runTestsFileLists =
- for ((kind, files) <- grouped) yield {
- NestUI.outline("\nTesting individual files\n")
- resultsToStatistics(runTestsForFiles(files, kind))
- }
-
- if (enabledSets.nonEmpty)
- NestUI.verbose("Run sets: "+enabledSets)
-
- val results = runTestsFileLists ::: (enabledSets map runTests)
-
- (results map (_._1) sum, results map (_._2) sum)
+ this.elapsedMillis = millis
+ issueSummaryReport()
+ System exit ( if (isSuccess) 0 else 1 )
}
}
diff --git a/src/partest/scala/tools/partest/nest/DirectCompiler.scala b/src/partest/scala/tools/partest/nest/DirectCompiler.scala
new file mode 100644
index 0000000000..650b6c35c8
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/DirectCompiler.scala
@@ -0,0 +1,105 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2013 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+package scala.tools.partest
+package nest
+
+import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError }
+import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
+import scala.tools.nsc.util.{ FakePos, stackTraceString }
+import scala.tools.nsc.Properties.{ setProp, propOrEmpty }
+import scala.reflect.io.AbstractFile
+import scala.reflect.internal.util.Position
+import java.io.{ BufferedReader, PrintWriter, FileReader, Writer, FileWriter }
+
+class ExtConsoleReporter(settings: Settings, val writer: PrintWriter) extends ConsoleReporter(settings, Console.in, writer) {
+ shortname = true
+ // override def error(pos: Position, msg: String): Unit
+}
+
+class TestSettings(cp: String, error: String => Unit) extends Settings(error) {
+ def this(cp: String) = this(cp, _ => ())
+
+ nowarnings.value = false
+ encoding.value = "UTF-8"
+ classpath.value = cp
+}
+
+class PartestGlobal(settings: Settings, reporter: Reporter) extends Global(settings, reporter) {
+ // override def abort(msg: String): Nothing
+ // override def globalError(msg: String): Unit
+ // override def supplementErrorMessage(msg: String): String
+}
+class DirectCompiler(val fileManager: FileManager) {
+ def newGlobal(settings: Settings, reporter: Reporter): PartestGlobal =
+ new PartestGlobal(settings, reporter)
+
+ def newGlobal(settings: Settings, logWriter: FileWriter): Global =
+ newGlobal(settings, new ExtConsoleReporter(settings, new PrintWriter(logWriter)))
+
+ def newSettings(): TestSettings = new TestSettings(fileManager.LATEST_LIB)
+ def newSettings(outdir: String): TestSettings = {
+ val cp = ClassPath.join(fileManager.LATEST_LIB, outdir)
+ val s = new TestSettings(cp)
+ s.outdir.value = outdir
+ s
+ }
+
+ def compile(runner: Runner, opts0: List[String], sources: List[File]): TestState = {
+ import runner._
+
+ val testSettings = new TestSettings(ClassPath.join(fileManager.LATEST_LIB, outDir.getPath))
+ val logWriter = new FileWriter(logFile)
+ val srcDir = if (testFile.isDirectory) testFile else Path(testFile).parent.jfile
+ val opts = fileManager.updatePluginPath(opts0, AbstractFile getDirectory outDir, AbstractFile getDirectory srcDir)
+ val command = new CompilerCommand(opts, testSettings)
+ val global = newGlobal(testSettings, logWriter)
+ val reporter = global.reporter.asInstanceOf[ExtConsoleReporter]
+ def errorCount = reporter.ERROR.count
+
+ def defineSettings(s: Settings) = {
+ s.outputDirs setSingleOutput outDir.getPath
+ // adding codelib.jar to the classpath
+ // codelib provides the possibility to override standard reify
+ // this shields the massive amount of reification tests from changes in the API
+ prependToClasspaths(s, codelib)
+ s.classpath append fileManager.CLASSPATH // adding this why?
+
+ // add the instrumented library version to classpath
+ if (kind == "specialized")
+ prependToClasspaths(s, speclib)
+
+ // check that option processing succeeded
+ opts0.isEmpty || command.ok
+ }
+
+ if (!defineSettings(testSettings))
+ if (opts0.isEmpty)
+ reporter.error(null, s"bad settings: $testSettings")
+ else
+ reporter.error(null, opts0.mkString("bad options: ", space, ""))
+
+ def ids = sources.map(_.testIdent) mkString space
+ vlog(s"% scalac $ids")
+
+ def execCompile() =
+ if (command.shouldStopWithInfo) {
+ logWriter append (command getInfoMessage global)
+ runner genFail "compilation stopped with info"
+ } else {
+ new global.Run compile sources.map(_.getPath)
+ if (!reporter.hasErrors) runner.genPass()
+ else {
+ reporter.printSummary()
+ reporter.writer.close()
+ runner.genFail(s"compilation failed with $errorCount errors")
+ }
+ }
+
+ try { execCompile() }
+ catch { case t: Throwable => reporter.error(null, t.getMessage) ; runner.genCrash(t) }
+ finally { logWriter.close() }
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala
index 7e4c3b842c..49dd39c344 100644
--- a/src/partest/scala/tools/partest/nest/DirectRunner.scala
+++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala
@@ -3,14 +3,12 @@
* @author Philipp Haller
*/
-// $Id$
-
package scala.tools.partest
package nest
import java.io.File
import scala.util.Properties.setProp
-import scala.tools.nsc.util.ScalaClassLoader
+import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional }
import scala.tools.nsc.io.Path
import scala.collection.{ mutable, immutable }
import java.util.concurrent._
@@ -22,41 +20,33 @@ trait DirectRunner {
import PartestDefaults.numThreads
- def denotesTestFile(arg: String) = Path(arg).hasExtension("scala", "res", "xml")
- def denotesTestDir(arg: String) = Path(arg).ifDirectory(_.files.nonEmpty) exists (x => x)
- def denotesTestPath(arg: String) = denotesTestDir(arg) || denotesTestFile(arg)
-
- /** No duplicate, no empty directories, don't mess with this unless
- * you like partest hangs.
- */
- def onlyValidTestPaths[T](args: List[T]): List[T] = {
- args.distinct filter (arg => denotesTestPath("" + arg) || {
- NestUI.warning("Discarding invalid test path '%s'\n" format arg)
- false
- })
- }
- def runTestsForFiles(_kindFiles: List[File], kind: String): immutable.Map[String, TestState] = {
- System.setProperty("line.separator", "\n")
+ Thread.setDefaultUncaughtExceptionHandler(
+ new Thread.UncaughtExceptionHandler {
+ def uncaughtException(thread: Thread, t: Throwable) {
+ val t1 = Exceptional unwrap t
+ System.err.println(s"Uncaught exception on thread $thread: $t1")
+ t1.printStackTrace()
+ }
+ }
+ )
+ def runTestsForFiles(kindFiles: List[File], kind: String): List[TestState] = {
- val allUrls = PathSettings.scalaCheck.toURL :: fileManager.latestUrls
- val scalaCheckParentClassLoader = ScalaClassLoader.fromURLs(allUrls)
- val kindFiles = onlyValidTestPaths(_kindFiles)
- val pool = Executors.newFixedThreadPool(numThreads)
- val manager = new RunnerManager(kind, fileManager, TestRunParams(scalaCheckParentClassLoader))
- val futures = kindFiles map (f => (f, pool submit callable(manager runTest f))) toMap
+ NestUI.resetTestNumber()
- pool.shutdown()
+ val allUrls = PathSettings.scalaCheck.toURL :: fileManager.latestUrls
+ val parentClassLoader = ScalaClassLoader fromURLs allUrls
+ val pool = Executors newFixedThreadPool numThreads
+ val manager = new RunnerManager(kind, fileManager, TestRunParams(parentClassLoader))
+ val futures = kindFiles map (f => pool submit callable(manager runTest f))
+ pool.shutdown()
try if (!pool.awaitTermination(4, TimeUnit.HOURS))
- NestUI.warning("Thread pool timeout elapsed before all tests were complete!")
+ NestUI warning "Thread pool timeout elapsed before all tests were complete!"
catch { case t: InterruptedException =>
- NestUI.warning("Thread pool was interrupted")
+ NestUI warning "Thread pool was interrupted"
t.printStackTrace()
}
- for ((file, future) <- futures) yield {
- val state = if (future.isCancelled) TestState.Timeout else future.get
- (file.getAbsolutePath, state)
- }
+ futures map (_.get)
}
}
diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala
index 23546c6511..25371b7d54 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, File => SFile }
+import scala.reflect.io.AbstractFile
import scala.collection.mutable
trait FileUtil {
@@ -62,16 +62,19 @@ trait FileManager extends FileUtil {
var LATEST_ACTORS: String
protected def relativeToLibrary(what: String): String = {
- if (LATEST_LIB endsWith ".jar") {
- (SFile(LATEST_LIB).parent / s"scala-$what.jar").toAbsolute.path
- }
- else {
+ def jarname = if (what startsWith "scala") s"$what.jar" else s"scala-$what.jar"
+ if (LATEST_LIB endsWith ".jar")
+ (SFile(LATEST_LIB).parent / jarname).toAbsolute.path
+ else
(SFile(LATEST_LIB).parent.parent / "classes" / what).toAbsolute.path
- }
}
def latestScaladoc = relativeToLibrary("scaladoc")
def latestInteractive = relativeToLibrary("interactive")
- def latestPaths = List(LATEST_LIB, LATEST_REFLECT, LATEST_COMP, LATEST_PARTEST, LATEST_ACTORS, latestScaladoc, latestInteractive)
+ def latestScalapFile = relativeToLibrary("scalap")
+ def latestPaths = List(
+ LATEST_LIB, LATEST_REFLECT, LATEST_COMP, LATEST_PARTEST, LATEST_ACTORS,
+ latestScalapFile, latestScaladoc, latestInteractive
+ )
def latestFiles = latestPaths map (p => new java.io.File(p))
def latestUrls = latestFiles map (_.toURI.toURL)
@@ -128,4 +131,34 @@ trait FileManager extends FileUtil {
f.printlnAll(f.lines.toList map replace: _*)
}
+
+ /** Massage args to merge plugins and fix paths.
+ * Plugin path can be relative to test root, or cwd is out.
+ * While we're at it, mix in the baseline options, too.
+ * That's how ant passes in the plugins dir.
+ */
+ def updatePluginPath(args: List[String], out: AbstractFile, srcdir: AbstractFile): List[String] = {
+ val dir = testRootDir
+ // The given path, or the output dir if ".", or a temp dir if output is virtual (since plugin loading doesn't like virtual)
+ def pathOrCwd(p: String) =
+ if (p == ".") {
+ val plugxml = "scalac-plugin.xml"
+ val pout = if (out.isVirtual) Directory.makeTemp() else Path(out.path)
+ val srcpath = Path(srcdir.path)
+ val pd = (srcpath / plugxml).toFile
+ if (pd.exists) pd copyTo (pout / plugxml)
+ pout
+ } else Path(p)
+ def absolutize(path: String) = pathOrCwd(path) match {
+ case x if x.isAbsolute => x.path
+ case x => (dir / x).toAbsolute.path
+ }
+
+ val xprefix = "-Xplugin:"
+ val (xplugs, others) = args partition (_ startsWith xprefix)
+ val Xplugin = if (xplugs.isEmpty) Nil else List(xprefix +
+ (xplugs map (_ stripPrefix xprefix) flatMap (_ split pathSeparator) map absolutize mkString pathSeparator)
+ )
+ SCALAC_OPTS.toList ::: others ::: Xplugin
+ }
}
diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala
index df90b22448..2e203bfd91 100644
--- a/src/partest/scala/tools/partest/nest/NestUI.scala
+++ b/src/partest/scala/tools/partest/nest/NestUI.scala
@@ -3,14 +3,37 @@
* @author Philipp Haller
*/
-// $Id$
-
package scala.tools.partest
package nest
import java.io.PrintWriter
+class Colors(enabled: => Boolean) {
+ import Console._
+
+ val bold = colored(BOLD)
+ val yellow = colored(YELLOW)
+ val green = colored(GREEN)
+ val blue = colored(BLUE)
+ val red = colored(RED)
+ val red_b = colored(RED_B)
+ val green_b = colored(GREEN_B)
+ val cyan = colored(CYAN)
+ val magenta = colored(MAGENTA)
+
+ private def colored(code: String): String => String =
+ s => if (enabled) code + s + RESET else s
+}
+
object NestUI {
+ private val testNum = new java.util.concurrent.atomic.AtomicInteger(1)
+ // @volatile private var testNumber = 1
+ private def testNumber = "%3d" format testNum.getAndIncrement()
+ def resetTestNumber() = testNum set 1
+
+ var colorEnabled = sys.props contains "partest.colors"
+ val color = new Colors(colorEnabled)
+ import color._
val NONE = 0
val SOME = 1
@@ -22,11 +45,57 @@ object NestUI {
private var _warning = ""
private var _default = ""
+ private var dotCount = 0
+ private val DotWidth = 72
+
+ def leftFlush() {
+ if (dotCount != 0) {
+ normal("\n")
+ dotCount = 0
+ }
+ }
+
+ def statusLine(state: TestState) = {
+ import state._
+ val word = bold(
+ if (isSkipped) yellow("--")
+ else if (isOk) green("ok")
+ else red("!!")
+ )
+ word + f" $testNumber%3s - $testIdent%-40s$reasonString"
+ }
+
+ def reportTest(state: TestState) = {
+ if (isTerse && state.isOk) {
+ if (dotCount >= DotWidth) {
+ outline("\n.")
+ dotCount = 1
+ }
+ else {
+ outline(".")
+ dotCount += 1
+ }
+ }
+ else echo(statusLine(state))
+ }
+
+ def echo(message: String): Unit = synchronized {
+ leftFlush()
+ print(message + "\n")
+ }
+ def chatty(msg: String) = if (isVerbose) echo(msg)
+
+ def echoSkipped(msg: String) = echo(yellow(msg))
+ def echoPassed(msg: String) = echo(bold(green(msg)))
+ def echoFailed(msg: String) = echo(bold(red(msg)))
+ def echoMixed(msg: String) = echo(bold(yellow(msg)))
+ def echoWarning(msg: String) = echo(bold(red(msg)))
+
def initialize(number: Int) = number match {
case MANY =>
_outline = Console.BOLD + Console.BLACK
_success = Console.BOLD + Console.GREEN
- _failure = Console.BOLD + Console.RED
+ _failure = Console.BOLD + Console.RED
_warning = Console.BOLD + Console.YELLOW
_default = Console.RESET
case SOME =>
@@ -61,10 +130,7 @@ object NestUI {
}
def usage() {
- println("Usage: NestRunner [<options>] [<testfile> ..] [<resfile>]")
- println(" <testfile>: list of files ending in '.scala'")
- println(" <resfile>: a file not ending in '.scala'")
- println(" <options>:")
+ println("Usage: NestRunner [options] [test test ...]")
println
println(" Test categories:")
println(" --all run all tests")
@@ -74,16 +140,12 @@ object NestUI {
println(" --jvm run JVM backend tests")
println(" --res run resident compiler tests")
println(" --scalacheck run ScalaCheck tests")
- println(" --script run script runner tests")
- println(" --shootout run shootout tests")
println(" --instrumented run instrumented tests")
println(" --presentation run presentation compiler tests")
- println(" --grep <expr> run all tests whose source file contains <expr>")
println
println(" Other options:")
println(" --pack pick compiler/reflect/library in build/pack, and run all tests")
- println(" --show-log show log")
- println(" --show-diff show diff between log and check file")
+ println(" --grep <expr> run all tests whose source file contains <expr>")
println(" --failed run only those tests that failed during the last run")
println(" --update-check instead of failing tests with output change, update checkfile. (Use with care!)")
println(" --verbose show progress information")
@@ -100,11 +162,28 @@ object NestUI {
}
var _verbose = false
+ var _debug = false
+ var _terse = false
+ def isVerbose = _verbose
+ def isDebug = _debug
+ def isTerse = _terse
+
+ def setVerbose() {
+ _verbose = true
+ }
+ def setDebug() {
+ _debug = true
+ }
+ def setTerse() {
+ _terse = true
+ }
def verbose(msg: String) {
- if (_verbose) {
- outline("debug: ")
- println(msg)
- }
+ if (isVerbose)
+ System.err.println(msg)
+ }
+ def debug(msg: String) {
+ if (isDebug)
+ System.err.println(msg)
}
}
diff --git a/src/partest/scala/tools/partest/nest/Runner.scala b/src/partest/scala/tools/partest/nest/Runner.scala
new file mode 100644
index 0000000000..95b304a56d
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/Runner.scala
@@ -0,0 +1,584 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+package scala.tools.partest
+package nest
+
+import java.io.{ Console => _, _ }
+import java.net.URL
+import scala.tools.nsc.Properties.{ jdkHome, javaHome, propOrElse, propOrEmpty }
+import scala.util.Properties.{ envOrElse, isWin }
+import scala.tools.nsc.{ 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, stackTraceString }
+import ClassPath.{ join, split }
+import scala.tools.scalap.scalax.rules.scalasig.ByteCode
+import scala.collection.{ mutable, immutable }
+import scala.sys.process._
+import java.util.concurrent.{ Executors, TimeUnit, TimeoutException }
+import PartestDefaults.{ javaCmd, javacCmd }
+import scala.tools.scalap.Main.decompileScala
+
+trait PartestRunSettings {
+ def gitPath: Path
+ def reportPath: Path
+ def logPath: Path
+
+ def testPaths: List[Path]
+
+ def gitDiffOptions: List[String]
+ def extraScalacOptions: List[String]
+ def extraJavaOptions: List[String]
+}
+
+class TestTranscript {
+ import NestUI.color._
+ private val buf = mutable.ListBuffer[String]()
+ private def pass(s: String) = bold(green("% ")) + s
+ private def fail(s: String) = bold(red("% ")) + s
+
+ def add(action: String): this.type = { buf += action ; this }
+ def append(text: String) { val s = buf.last ; buf.trimEnd(1) ; buf += (s + text) }
+
+ // Colorize prompts according to pass/fail
+ def fail: List[String] = buf.toList match {
+ case Nil => Nil
+ case xs => (xs.init map pass) :+ fail(xs.last)
+ }
+}
+
+class Runner(val testFile: File, fileManager: FileManager) {
+ import fileManager._
+
+ // Override to true to have the outcome of this test displayed
+ // whether it passes or not; in general only failures are reported,
+ // except for a . per passing test to show progress.
+ def isEnumeratedTest = false
+
+ def testRunParams: TestRunParams = ???
+
+ private var _lastState: TestState = null
+ private var _transcript = new TestTranscript
+
+ def lastState = if (_lastState == null) TestState.Uninitialized(testFile) else _lastState
+ def setLastState(s: TestState) = _lastState = s
+ def transcript: List[String] = _transcript.fail ++ logFile.fileLines
+ def pushTranscript(msg: String) = _transcript add msg
+
+ val parentFile = testFile.getParentFile
+ val kind = parentFile.getName
+ val fileBase = basename(testFile.getName)
+ val logFile = new File(parentFile, s"$fileBase-$kind.log")
+ val outFile = logFile changeExtension "obj"
+ val checkFile = testFile changeExtension "check"
+ val flagsFile = testFile changeExtension "flags"
+ val testIdent = testFile.testIdent // e.g. pos/t1234
+
+ lazy val outDir = { outFile.mkdirs() ; outFile }
+
+ type RanOneTest = (Boolean, LogContext)
+
+ def showCrashInfo(t: Throwable) {
+ System.err.println("Crashed running test $testIdent: " + t)
+ if (!isPartestTerse)
+ System.err.println(stackTraceString(t))
+ }
+ protected def crashHandler: PartialFunction[Throwable, TestState] = {
+ case t: InterruptedException =>
+ genTimeout()
+ case t: Throwable =>
+ showCrashInfo(t)
+ logFile.appendAll(stackTraceString(t))
+ genCrash(t)
+ }
+
+ def genPass() = TestState.Pass(testFile)
+ def genFail(reason: String) = TestState.Fail(testFile, reason, _transcript.fail)
+ def genTimeout() = TestState.Fail(testFile, "timed out", _transcript.fail)
+ def genCrash(caught: Throwable) = TestState.Crash(testFile, caught, _transcript.fail)
+
+ def speclib = PathSettings.srcSpecLib.toString // specialization lib
+ def codelib = PathSettings.srcCodeLib.toString // reify lib
+
+ // Prepend to a classpath, but without incurring duplicate entries
+ def prependTo(classpath: String, path: String): String = {
+ val segments = ClassPath split classpath
+
+ if (segments startsWith path) classpath
+ else ClassPath.join(path :: segments distinct: _*)
+ }
+
+ def prependToJavaClasspath(path: String) {
+ val jcp = sys.props.getOrElse("java.class.path", "")
+ prependTo(jcp, path) match {
+ case `jcp` =>
+ case cp => sys.props("java.class.path") = cp
+ }
+ }
+ def prependToClasspaths(s: Settings, path: String) {
+ prependToJavaClasspath(path)
+ val scp = s.classpath.value
+ prependTo(scp, path) match {
+ case `scp` =>
+ case cp => s.classpath.value = cp
+ }
+ }
+
+ private def workerError(msg: String): Unit = System.err.println("Error: " + msg)
+
+ def javac(files: List[File]): TestState = {
+ // compile using command-line javac compiler
+ val args = Seq(
+ javacCmd,
+ "-d",
+ outDir.getAbsolutePath,
+ "-classpath",
+ join(outDir.toString, CLASSPATH)
+ ) ++ files.map("" + _)
+
+ pushTranscript(args mkString " ")
+ val captured = StreamCapture(runCommand(args, logFile))
+ if (captured.result) genPass() else {
+ logFile appendAll captured.stderr
+ genFail("java compilation failed")
+ }
+ }
+
+ def testPrompt = kind match {
+ case "res" => "nsc> "
+ case _ => "% "
+ }
+
+ def nextTestAction[T](body: => T)(failFn: PartialFunction[T, TestState]): T = {
+ val result = body
+ setLastState( if (failFn isDefinedAt result) failFn(result) else genPass() )
+ result
+ }
+ def nextTestActionExpectTrue[T](reason: String, body: => Boolean): Boolean = {
+ nextTestAction(body) { case false => genFail(reason) }
+ }
+
+ private def assembleTestCommand(outDir: File, logFile: File): List[String] = {
+ // check whether there is a ".javaopts" file
+ val argsFile = testFile changeExtension "javaopts"
+ val argString = file2String(argsFile)
+ if (argString != "")
+ NestUI.verbose("Found javaopts file '%s', using options: '%s'".format(argsFile, argString))
+
+ val testFullPath = testFile.getAbsolutePath
+
+ // Note! As this currently functions, JAVA_OPTS must precede argString
+ // because when an option is repeated to java only the last one wins.
+ // That means until now all the .javaopts files were being ignored because
+ // they all attempt to change options which are also defined in
+ // partest.java_opts, leading to debug output like:
+ //
+ // debug: Found javaopts file 'files/shootout/message.scala-2.javaopts', using options: '-Xss32k'
+ // debug: java -Xss32k -Xss2m -Xms256M -Xmx1024M -classpath [...]
+ val extras = if (isPartestDebug) List("-Dpartest.debug=true") else Nil
+ val propertyOptions = List(
+ "-Dfile.encoding=UTF-8",
+ "-Djava.library.path="+logFile.getParentFile.getAbsolutePath,
+ "-Dpartest.output="+outDir.getAbsolutePath,
+ "-Dpartest.lib="+LATEST_LIB,
+ "-Dpartest.reflect="+LATEST_REFLECT,
+ "-Dpartest.cwd="+outDir.getParent,
+ "-Dpartest.test-path="+testFullPath,
+ "-Dpartest.testname="+fileBase,
+ "-Djavacmd="+javaCmd,
+ "-Djavaccmd="+javacCmd,
+ "-Duser.language=en",
+ "-Duser.country=US"
+ ) ++ extras
+
+ val classpath = if (extraClasspath != "") join(extraClasspath, CLASSPATH) else CLASSPATH
+
+ javaCmd +: (
+ (JAVA_OPTS.split(' ') ++ extraJavaOptions.split(' ') ++ argString.split(' ')).map(_.trim).filter(_ != "").toList ++ Seq(
+ "-classpath",
+ join(outDir.toString, classpath)
+ ) ++ propertyOptions ++ Seq(
+ "scala.tools.nsc.MainGenericRunner",
+ "-usejavacp",
+ "Test",
+ "jvm"
+ )
+ )
+ }
+
+ /** Runs command redirecting standard out and
+ * error out to output file.
+ */
+ private def runCommand(args: Seq[String], outFile: File): Boolean = {
+ (Process(args) #> outFile !) == 0
+ }
+
+ private def execTest(outDir: File, logFile: File): Boolean = {
+ val cmd = assembleTestCommand(outDir, logFile)
+
+ pushTranscript(cmd.mkString(" \\\n ") + " > " + logFile.getName)
+ nextTestActionExpectTrue("non-zero exit code", runCommand(cmd, logFile)) || {
+ _transcript append logFile.fileContents
+ false
+ }
+ }
+
+ override def toString = s"""Test($testIdent, lastState = $lastState)"""
+
+ def newTestWriters() = {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr, true)
+ // diff = ""
+
+ ((swr, wr))
+ }
+
+ def fail(what: Any) = {
+ NestUI.verbose("scalac: compilation of "+what+" failed\n")
+ false
+ }
+
+ def currentDiff = (
+ if (checkFile.canRead) compareFiles(logFile, checkFile)
+ else compareContents(augmentString(file2String(logFile)).lines.toList, Nil)
+ )
+
+ val gitRunner = List("/usr/local/bin/git", "/usr/bin/git") map (f => new java.io.File(f)) find (_.canRead)
+ val gitDiffOptions = "--ignore-space-at-eol --no-index " + propOrEmpty("partest.git_diff_options")
+ // --color=always --word-diff
+
+ def gitDiff(f1: File, f2: File): Option[String] = {
+ try gitRunner map { git =>
+ val cmd = s"$git diff $gitDiffOptions $f1 $f2"
+ val diff = Process(cmd).lines_!.drop(4).map(_ + "\n").mkString
+
+ "\n" + diff
+ }
+ catch { case t: Exception => None }
+ }
+
+ /** This does something about absolute paths and file separator
+ * chars before diffing.
+ */
+ def normalizeLog() {
+ // squashing // in paths also munges line comments, so save this innovation for another time.
+ // (There are line comments in the "stub implementations" error output.)
+ //val slashes = """[/\\]+""".r
+ //def squashSlashes(s: String) = slashes replaceAllIn (s, "/")
+ def squashSlashes(s: String) = s replace ('\\', '/')
+ val base = squashSlashes(parentFile.getAbsolutePath + File.separator)
+ val quoted = """\Q%s\E""" format base
+ val baseless = (if (isWin) "(?i)" + quoted else quoted).r
+ def canonicalize(s: String) = baseless replaceAllIn (squashSlashes(s), "")
+ logFile mapInPlace canonicalize
+ }
+
+ def diffIsOk: Boolean = {
+ val diff = currentDiff
+ val ok: Boolean = (diff == "") || {
+ fileManager.updateCheck && {
+ NestUI.verbose("Updating checkfile " + checkFile)
+ checkFile writeAll file2String(logFile)
+ true
+ }
+ }
+ pushTranscript(s"diff $logFile $checkFile")
+ nextTestAction(ok) {
+ case false =>
+ // Get a word-highlighted diff from git if we can find it
+ val bestDiff = if (ok) "" else {
+ if (checkFile.canRead)
+ gitDiff(logFile, checkFile) getOrElse {
+ s"diff $logFile $checkFile\n$diff"
+ }
+ else diff
+ }
+ _transcript append bestDiff
+ genFail("output differs")
+ // TestState.fail("output differs", "output differs",
+ // genFail("output differs")
+ // TestState.Fail("output differs", bestDiff)
+ }
+ }
+
+ /** 1. Creates log file and output directory.
+ * 2. Runs script function, providing log file and output directory as arguments.
+ */
+ def runInContext(body: => Boolean): (Boolean, LogContext) = {
+ val (swr, wr) = newTestWriters()
+ val succeeded = body
+ (succeeded, LogContext(logFile, swr, wr))
+ }
+
+ /** Grouped files in group order, and lex order within each group. */
+ def groupedFiles(dir: File): List[List[File]] = {
+ val testFiles = dir.listFiles.toList filter (_.isJavaOrScala)
+ val grouped = testFiles groupBy (_.group)
+ grouped.keys.toList.sorted map (k => grouped(k) sortBy (_.getName))
+ }
+
+ def newCompiler = new DirectCompiler(fileManager)
+
+ def attemptCompile(sources: List[File]): TestState = {
+ val state = newCompiler.compile(this, flagsForCompilation(sources), sources)
+ if (!state.isOk)
+ _transcript append ("\n" + file2String(logFile))
+
+ state
+ }
+
+ // snort or scarf all the contributing flags files
+ def flagsForCompilation(sources: List[File]): List[String] = {
+ def argsplitter(s: String) = words(s) filter (_.nonEmpty)
+ val perTest = argsplitter(flagsFile.fileContents)
+ val perGroup = if (testFile.isDirectory) {
+ sources flatMap { f => SFile(Path(f) changeExtension "flags").safeSlurp map argsplitter getOrElse Nil }
+ } else Nil
+ perTest ++ perGroup
+ }
+
+ abstract class CompileRound {
+ def fs: List[File]
+ def result: TestState
+ def description: String
+
+ def fsString = fs map (_.toString stripPrefix parentFile.toString + "/") mkString " "
+ def isOk = result.isOk
+ def mkScalacString(): String = {
+ val flags = file2String(flagsFile) match {
+ case "" => ""
+ case s => " " + s
+ }
+ s"""scalac $fsString"""
+ }
+ override def toString = description + ( if (result.isOk) "" else "\n" + result.status )
+ }
+ case class OnlyJava(fs: List[File]) extends CompileRound {
+ def description = s"""javac $fsString"""
+ lazy val result = { pushTranscript(description) ; javac(fs) }
+ }
+ case class OnlyScala(fs: List[File]) extends CompileRound {
+ def description = mkScalacString()
+ lazy val result = { pushTranscript(description) ; attemptCompile(fs) }
+ }
+ case class ScalaAndJava(fs: List[File]) extends CompileRound {
+ def description = mkScalacString()
+ lazy val result = { pushTranscript(description) ; attemptCompile(fs) }
+ }
+
+ def compilationRounds(file: File): List[CompileRound] = {
+ val grouped = if (file.isDirectory) groupedFiles(file) else List(List(file))
+
+ (grouped map mixedCompileGroup).flatten
+ }
+ def mixedCompileGroup(allFiles: List[File]): List[CompileRound] = {
+ val (scalaFiles, javaFiles) = allFiles partition (_.isScala)
+ val isMixed = javaFiles.nonEmpty && scalaFiles.nonEmpty
+ val round1 = if (scalaFiles.isEmpty) None else Some(ScalaAndJava(allFiles))
+ val round2 = if (javaFiles.isEmpty) None else Some(OnlyJava(javaFiles))
+ val round3 = if (!isMixed) None else Some(OnlyScala(scalaFiles))
+
+ List(round1, round2, round3).flatten
+ }
+
+ def runNegTest() = runInContext {
+ val rounds = compilationRounds(testFile)
+
+ if (rounds forall (x => nextTestActionExpectTrue("compilation failed", x.isOk)))
+ nextTestActionExpectTrue("expected compilation failure", false)
+ else {
+ normalizeLog // put errors in a normal form
+ diffIsOk
+ }
+ }
+
+ def runTestCommon(andAlso: => Boolean): (Boolean, LogContext) = runInContext {
+ compilationRounds(testFile).forall(x => nextTestActionExpectTrue("compilation failed", x.isOk)) && andAlso
+ }
+
+ // Apache Ant 1.6 or newer
+ def ant(args: Seq[String], output: File): Boolean = {
+ val antDir = Directory(envOrElse("ANT_HOME", "/opt/ant/"))
+ val antLibDir = Directory(antDir / "lib")
+ val antLauncherPath = SFile(antLibDir / "ant-launcher.jar").path
+ val antOptions =
+ if (NestUI._verbose) List("-verbose", "-noinput")
+ else List("-noinput")
+ val cmd = javaCmd +: (
+ JAVA_OPTS.split(' ').map(_.trim).filter(_ != "") ++ Seq(
+ "-classpath",
+ antLauncherPath,
+ "org.apache.tools.ant.launch.Launcher"
+ ) ++ antOptions ++ args
+ )
+
+ runCommand(cmd, output)
+ }
+
+ def runAntTest(): (Boolean, LogContext) = {
+ val (swr, wr) = newTestWriters()
+
+ val succeeded = try {
+ val binary = "-Dbinary="+(
+ if (fileManager.LATEST_LIB endsWith "build/quick/classes/library") "quick"
+ else if (fileManager.LATEST_LIB endsWith "build/pack/lib/scala-library.jar") "pack"
+ else if (fileManager.LATEST_LIB endsWith "dists/latest/lib/scala-library.jar/") "latest"
+ else "installed"
+ )
+ val args = Array(binary, "-logfile", logFile.getPath, "-file", testFile.getPath)
+ NestUI.verbose("ant "+args.mkString(" "))
+
+ pushTranscript(s"ant ${args.mkString(" ")}")
+ nextTestActionExpectTrue("ant failed", ant(args, logFile)) && diffIsOk
+ }
+ catch { // *catch-all*
+ case e: Exception =>
+ NestUI.warning("caught "+e)
+ false
+ }
+
+ (succeeded, LogContext(logFile, swr, wr))
+ }
+
+ def extraClasspath = kind match {
+ case "specialized" => PathSettings.srcSpecLib.toString
+ case _ => ""
+ }
+ def extraJavaOptions = kind match {
+ case "instrumented" => "-javaagent:"+PathSettings.instrumentationAgentLib
+ case _ => ""
+ }
+
+ def runScalacheckTest() = runTestCommon {
+ NestUI.verbose("compilation of "+testFile+" succeeded\n")
+
+ val outURL = outDir.getAbsoluteFile.toURI.toURL
+ val logWriter = new PrintStream(new FileOutputStream(logFile), true)
+
+ Output.withRedirected(logWriter) {
+ // this classloader is test specific: its parent contains library classes and others
+ ScalaClassLoader.fromURLs(List(outURL), testRunParams.scalaCheckParentClassLoader).run("Test", Nil)
+ }
+
+ NestUI.verbose(file2String(logFile))
+ // obviously this must be improved upon
+ val lines = SFile(logFile).lines map (_.trim) filterNot (_ == "") toBuffer;
+ lines.forall(x => !x.startsWith("!")) || {
+ NestUI.normal("ScalaCheck test failed. Output:\n")
+ lines foreach (x => NestUI.normal(x + "\n"))
+ false
+ }
+ }
+
+ def runResidentTest() = {
+ // simulate resident compiler loop
+ val prompt = "\nnsc> "
+ val (swr, wr) = newTestWriters()
+
+ NestUI.verbose(this+" running test "+fileBase)
+ val dir = parentFile
+ val resFile = new File(dir, fileBase + ".res")
+
+ // run compiler in resident mode
+ // $SCALAC -d "$os_dstbase".obj -Xresident -sourcepath . "$@"
+ val sourcedir = logFile.getParentFile.getAbsoluteFile
+ val sourcepath = sourcedir.getAbsolutePath+File.separator
+ NestUI.verbose("sourcepath: "+sourcepath)
+
+ val argList = List(
+ "-d", outDir.getAbsoluteFile.getPath,
+ "-Xresident",
+ "-sourcepath", sourcepath)
+
+ // configure input/output files
+ val logOut = new FileOutputStream(logFile)
+ val logWriter = new PrintStream(logOut, true)
+ val resReader = new BufferedReader(new FileReader(resFile))
+ val logConsoleWriter = new PrintWriter(new OutputStreamWriter(logOut), true)
+
+ // create compiler
+ val settings = new Settings(workerError)
+ settings.sourcepath.value = sourcepath
+ settings.classpath.value = fileManager.CLASSPATH
+ val reporter = new ConsoleReporter(settings, scala.Console.in, logConsoleWriter)
+ val command = new CompilerCommand(argList, settings)
+ object compiler extends Global(command.settings, reporter)
+
+ def resCompile(line: String): Boolean = {
+ // NestUI.verbose("compiling "+line)
+ val cmdArgs = (line split ' ').toList map (fs => new File(dir, fs).getAbsolutePath)
+ // NestUI.verbose("cmdArgs: "+cmdArgs)
+ val sett = new Settings(workerError)
+ sett.sourcepath.value = sourcepath
+ val command = new CompilerCommand(cmdArgs, sett)
+ // "scalac " + command.files.mkString(" ")
+ pushTranscript("scalac " + command.files.mkString(" "))
+ nextTestActionExpectTrue(
+ "compilation failed",
+ command.ok && {
+ (new compiler.Run) compile command.files
+ !reporter.hasErrors
+ }
+ )
+ }
+ def loop(): Boolean = {
+ logWriter.print(prompt)
+ resReader.readLine() match {
+ case null | "" => logWriter.close() ; true
+ case line => resCompile(line) && loop()
+ }
+ }
+ // res/t687.res depends on ignoring its compilation failure
+ // and just looking at the diff, so I made them all do that
+ // because this is long enough.
+ if (!Output.withRedirected(logWriter)(try loop() finally resReader.close()))
+ setLastState(genPass())
+
+ normalizeLog // put errors in a normal form
+ (diffIsOk, LogContext(logFile, swr, wr))
+ }
+
+ def run(): TestState = {
+ if (kind == "neg" || (kind endsWith "-neg")) runNegTest()
+ else kind match {
+ case "pos" => runTestCommon(true)
+ case "ant" => runAntTest()
+ case "scalacheck" => runScalacheckTest()
+ case "res" => runResidentTest()
+ case "scalap" => runScalapTest()
+ case "script" => runScriptTest()
+ case _ => runTestCommon(execTest(outDir, logFile) && diffIsOk)
+ }
+
+ lastState
+ }
+
+ def runScalapTest() = runTestCommon {
+ val isPackageObject = testFile.getName startsWith "package"
+ val className = testFile.getName.stripSuffix(".scala").capitalize + (if (!isPackageObject) "" else ".package")
+ val loader = ScalaClassLoader.fromURLs(List(outDir.toURI.toURL), this.getClass.getClassLoader)
+ val byteCode = ByteCode forClass (loader loadClass className)
+ val result = decompileScala(byteCode.bytes, isPackageObject)
+
+ logFile writeAll result
+ diffIsOk
+ }
+ def runScriptTest() = {
+ val (swr, wr) = newTestWriters()
+
+ val args = file2String(testFile changeExtension "args")
+ val cmdFile = if (isWin) testFile changeExtension "bat" else testFile
+ val succeeded = (((cmdFile + " " + args) #> logFile !) == 0) && diffIsOk
+
+ (succeeded, LogContext(logFile, swr, wr))
+ }
+
+ def cleanup() {
+ if (lastState.isOk)
+ logFile.delete()
+ if (!isPartestDebug)
+ Directory(outDir).deleteRecursively()
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala
index a63a81c47b..1c689714c7 100644
--- a/src/partest/scala/tools/partest/nest/RunnerManager.scala
+++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala
@@ -8,8 +8,6 @@ package nest
import java.io._
import java.net.URL
-import java.util.{ Timer, TimerTask }
-
import scala.tools.nsc.Properties.{ jdkHome, javaHome, propOrElse }
import scala.util.Properties.{ envOrElse, isWin }
import scala.tools.nsc.{ Settings, CompilerCommand, Global }
@@ -22,6 +20,7 @@ import scala.collection.{ mutable, immutable }
import scala.sys.process._
import java.util.concurrent.{ Executors, TimeUnit, TimeoutException }
import PartestDefaults.{ javaCmd, javacCmd }
+import scala.tools.scalap.Main.decompileScala
class LogContext(val file: File, val writers: Option[(StringWriter, PrintWriter)])
@@ -75,690 +74,22 @@ object Output {
class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunParams) {
import fileManager._
-
- val compileMgr = new CompileManager(fileManager)
fileManager.CLASSPATH += File.pathSeparator + PathSettings.scalaCheck
fileManager.CLASSPATH += File.pathSeparator + PathSettings.diffUtils // needed to put diffutils on test/partest's classpath
- private def compareFiles(f1: File, f2: File): String =
- try fileManager.compareFiles(f1, f2)
- catch { case t: Exception => t.toString }
-
- /** This does something about absolute paths and file separator
- * chars before diffing.
- */
- private def replaceSlashes(dir: File, s: String): String = {
- val base = (dir.getAbsolutePath + File.separator).replace('\\', '/')
- var regex = """\Q%s\E""" format base
- if (isWin) regex = "(?i)" + regex
- s.replace('\\', '/').replaceAll(regex, "")
- }
-
- private def workerError(msg: String): Unit = System.err.println("Error: " + msg)
-
- private def printInfoStart(file: File, printer: PrintWriter) {
- NestUI.outline("testing: ", printer)
- val filesdir = file.getAbsoluteFile.getParentFile.getParentFile
- val testdir = filesdir.getParentFile
- val totalWidth = 56
- val name = {
- // 1. try with [...]/files/run/test.scala
- val name = file.getAbsolutePath drop testdir.getAbsolutePath.length
- if (name.length <= totalWidth) name
- // 2. try with [...]/run/test.scala
- else file.getAbsolutePath drop filesdir.getAbsolutePath.length
- }
- NestUI.normal("[...]%s%s".format(name, " " * (totalWidth - name.length)), printer)
- }
-
- private def printInfoEnd(success: Boolean, printer: PrintWriter) {
- NestUI.normal("[", printer)
- if (success) NestUI.success(" OK ", printer)
- else NestUI.failure("FAILED", printer)
- NestUI.normal("]\n", printer)
- }
-
- private def printInfoTimeout(printer: PrintWriter) {
- NestUI.normal("[", printer)
- NestUI.failure("TIMOUT", printer)
- NestUI.normal("]\n", printer)
- }
-
- private def javac(outDir: File, files: List[File], output: File): CompilationOutcome = {
- // compile using command-line javac compiler
- val args = Seq(
- javacCmd,
- "-d",
- outDir.getAbsolutePath,
- "-classpath",
- join(outDir.toString, CLASSPATH)
- ) ++ files.map("" + _)
-
- try if (runCommand(args, output)) CompileSuccess else CompileFailed
- catch exHandler(output, "javac command failed:\n" + args.map(" " + _ + "\n").mkString + "\n", CompilerCrashed)
- }
-
- /** Runs command redirecting standard out and error out to output file.
- * Overloaded to accept a sequence of arguments.
- */
- private def runCommand(args: Seq[String], outFile: File): Boolean = {
- NestUI.verbose("running command:\n"+args.map(" " + _ + "\n").mkString)
- runCommandImpl(Process(args), outFile)
- }
-
- /** Runs command redirecting standard out and error out to output file.
- * Overloaded to accept a single string = concatenated command + arguments.
- */
- private def runCommand(command: String, outFile: File): Boolean = {
- NestUI.verbose("running command:"+command)
- runCommandImpl(Process(command), outFile)
- }
-
- private def runCommandImpl(process: => ProcessBuilder, outFile: File): Boolean = {
- val exitCode = (process #> outFile !)
- // normalize line endings
- // System.getProperty("line.separator") should be "\n" here
- // so reading a file and writing it back should convert all CRLFs to LFs
- SFile(outFile).printlnAll(SFile(outFile).lines.toList: _*)
- exitCode == 0
- }
-
- @inline private def isJava(f: File) = SFile(f) hasExtension "java"
- @inline private def isScala(f: File) = SFile(f) hasExtension "scala"
- @inline private def isJavaOrScala(f: File) = isJava(f) || isScala(f)
-
- private def outputLogFile(logFile: File) {
- val lines = SFile(logFile).lines
- if (lines.nonEmpty) {
- NestUI.normal("Log file '" + logFile + "': \n")
- lines foreach (x => NestUI.normal(x + "\n"))
- }
- }
- private def logStackTrace(logFile: File, t: Throwable, msg: String): Boolean = {
- SFile(logFile).writeAll(msg, stackTraceString(t))
- outputLogFile(logFile) // if running the test threw an exception, output log file
- false
- }
-
- private def exHandler[T](logFile: File, msg: String, value: T): PartialFunction[Throwable, T] = {
- case e: Exception => logStackTrace(logFile, e, msg) ; value
- }
-
- class Runner(testFile: File) {
- var testDiff: String = ""
- var passed: Option[Boolean] = None
-
- val fileBase = basename(testFile.getName)
- val logFile = fileManager.getLogFile(testFile, kind)
- val parent = testFile.getParentFile
- val outDir = new File(parent, "%s-%s.obj".format(fileBase, kind))
- def toDelete = if (isPartestDebug) Nil else List(
- if (passed exists (x => x)) Some(logFile) else None,
- if (outDir.isDirectory) Some(outDir) else None
- ).flatten
-
- private def createOutputDir(): File = {
- outDir.mkdirs()
- outDir
- }
-
- private def execTest(outDir: File, logFile: File, classpathPrefix: String = "", javaOpts: String = ""): Boolean = {
- // check whether there is a ".javaopts" file
- 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))
-
- val testFullPath = {
- val d = new File(logFile.getParentFile, fileBase)
- if (d.isDirectory) d.getAbsolutePath
- else {
- val f = new File(logFile.getParentFile, fileBase + ".scala")
- if (f.isFile) f.getAbsolutePath
- else ""
- }
- }
-
- // Note! As this currently functions, JAVA_OPTS must precede argString
- // because when an option is repeated to java only the last one wins.
- // That means until now all the .javaopts files were being ignored because
- // they all attempt to change options which are also defined in
- // partest.java_opts, leading to debug output like:
- //
- // debug: Found javaopts file 'files/shootout/message.scala-2.javaopts', using options: '-Xss32k'
- // debug: java -Xss32k -Xss2m -Xms256M -Xmx1024M -classpath [...]
- val extras = if (isPartestDebug) List("-Dpartest.debug=true") else Nil
- val propertyOptions = List(
- "-Dfile.encoding=UTF-8",
- "-Djava.library.path="+logFile.getParentFile.getAbsolutePath,
- "-Dpartest.output="+outDir.getAbsolutePath,
- "-Dpartest.lib="+LATEST_LIB,
- "-Dpartest.reflect="+LATEST_REFLECT,
- "-Dpartest.comp="+LATEST_COMP,
- "-Dpartest.cwd="+outDir.getParent,
- "-Dpartest.test-path="+testFullPath,
- "-Dpartest.testname="+fileBase,
- "-Djavacmd="+javaCmd,
- "-Djavaccmd="+javacCmd,
- "-Duser.language=en",
- "-Duser.country=US"
- ) ++ extras
-
- val classpath = if (classpathPrefix != "") join(classpathPrefix, CLASSPATH) else CLASSPATH
- val cmd = javaCmd +: (
- (JAVA_OPTS.split(' ') ++ javaOpts.split(' ') ++ argString.split(' ')).map(_.trim).filter(_ != "") ++ Seq(
- "-classpath",
- join(outDir.toString, classpath)
- ) ++ propertyOptions ++ Seq(
- "scala.tools.nsc.MainGenericRunner",
- "-usejavacp",
- "Test",
- "jvm"
- )
- )
-
- runCommand(cmd, logFile)
- }
-
- private def getCheckFilePath(dir: File, suffix: String) = {
- def chkFile(s: String) = (Directory(dir) / "%s%s.check".format(fileBase, s)).toFile
-
- if (chkFile("").isFile || suffix == "") chkFile("")
- else chkFile("-" + suffix)
- }
-
- private def compareOutput(dir: File, logFile: File): String = {
- val checkFile = getCheckFilePath(dir, kind)
- val diff =
- if (checkFile.canRead) compareFiles(logFile, checkFile.jfile)
- else file2String(logFile)
-
- // if check file exists, compare with log file
- if (diff != "" && fileManager.updateCheck) {
- NestUI.verbose("Updating checkfile " + checkFile.jfile)
- val toWrite = if (checkFile.exists) checkFile else getCheckFilePath(dir, "")
- toWrite writeAll file2String(logFile)
- ""
- }
- else diff
- }
-
- def newTestWriters() = {
- val swr = new StringWriter
- val wr = new PrintWriter(swr, true)
-
- ((swr, wr))
- }
-
- def diffCheck(testFile: File, diff: String) = {
- testDiff = diff
- testDiff == ""
- }
-
- /** 1. Creates log file and output directory.
- * 2. Runs script function, providing log file and output directory as arguments.
- */
- def runInContext(file: File, script: (File, File) => Boolean): (Boolean, LogContext) = {
- val (swr, wr) = newTestWriters()
- printInfoStart(file, wr)
-
- NestUI.verbose(this+" running test "+fileBase)
- val outDir = createOutputDir()
- NestUI.verbose("output directory: "+outDir)
-
- // run test-specific code
- val succeeded = try {
- if (isPartestDebug) {
- val (result, millis) = timed(script(logFile, outDir))
- fileManager.recordTestTiming(file.getPath, millis)
- result
- }
- else script(logFile, outDir)
- }
- catch exHandler(logFile, "", false)
-
- (succeeded, LogContext(logFile, swr, wr))
- }
-
- def groupedFiles(dir: File): List[List[File]] = {
- val testFiles = dir.listFiles.toList filter isJavaOrScala
-
- def isInGroup(f: File, num: Int) = SFile(f).stripExtension endsWith ("_" + num)
- val groups = (0 to 9).toList map (num => (testFiles filter (f => isInGroup(f, num))).sorted)
- val noGroupSuffix = (testFiles filterNot (groups.flatten contains)).sorted
-
- noGroupSuffix :: groups filterNot (_.isEmpty)
- }
-
- def compileFilesIn(dir: File, logFile: File, outDir: File): CompilationOutcome = {
- def compileGroup(g: List[File]): CompilationOutcome = {
- val (scalaFiles, javaFiles) = g partition isScala
- val allFiles = javaFiles ++ scalaFiles
-
- /* The test can contain both java and scala files, each of which should be compiled with the corresponding
- * compiler. Since the source files can reference each other both ways (java referencing scala classes and
- * vice versa, the partest compilation routine attempts to reach a "bytecode fixpoint" between the two
- * compilers -- that's when bytecode generated by each compiler implements the signatures expected by the other.
- *
- * In theory this property can't be guaranteed, as neither compiler can know what signatures the other
- * compiler expects and how to implement them. (see SI-1240 for the full story)
- *
- * In practice, this happens in 3 steps:
- * STEP1: Feed all the files to scalac if there are also non-Scala sources.
- * It will parse java files and obtain their expected signatures and generate bytecode for scala files
- * STEP2: Feed the java files to javac if there are any.
- * It will generate the bytecode for the java files and link to the scalac-generated bytecode for scala
- * STEP3: (Re-)compile the scala sources so they link to the correct
- * java signatures, in case the signatures deduced by scalac from the source files were wrong. Since the
- * bytecode for java is already in place, we only feed the scala files to scalac so it will take the
- * java signatures from the existing javac-generated bytecode.
- * Note that no artifacts are deleted before this step.
- */
- List(1, 2, 3).foldLeft(CompileSuccess: CompilationOutcome) {
- case (CompileSuccess, 1) if scalaFiles.nonEmpty && javaFiles.nonEmpty =>
- compileMgr.attemptCompile(Some(outDir), allFiles, kind, logFile)
- case (CompileSuccess, 2) if javaFiles.nonEmpty =>
- javac(outDir, javaFiles, logFile)
- case (CompileSuccess, 3) if scalaFiles.nonEmpty =>
- // TODO: Do we actually need this? SI-1240 is known to require this, but we don't know if other tests
- // require it: https://groups.google.com/forum/?fromgroups#!topic/scala-internals/rFDKAcOKciU
- compileMgr.attemptCompile(Some(outDir), scalaFiles, kind, logFile)
-
- case (outcome, _) => outcome
- }
- }
- groupedFiles(dir).foldLeft(CompileSuccess: CompilationOutcome) {
- case (CompileSuccess, files) => compileGroup(files)
- case (outcome, _) => outcome
- }
- }
-
- def runTestCommon(file: File, expectFailure: Boolean)(
- onSuccess: (File, File) => Boolean,
- onFail: (File, File) => Unit = (_, _) => ()): (Boolean, LogContext) =
- {
- runInContext(file, (logFile: File, outDir: File) => {
- val outcome = (
- if (file.isDirectory) compileFilesIn(file, logFile, outDir)
- else compileMgr.attemptCompile(None, List(file), kind, logFile)
- )
- val result = (
- if (expectFailure) outcome.isNegative
- else outcome.isPositive
- )
-
- if (result) onSuccess(logFile, outDir)
- else { onFail(logFile, outDir) ; false }
- })
- }
-
- def runJvmTest(file: File): (Boolean, LogContext) =
- runTestCommon(file, expectFailure = false)((logFile, outDir) => {
- val dir = file.getParentFile
-
- // adding codelib.jar to the classpath
- // codelib provides the possibility to override standard reify
- // this shields the massive amount of reification tests from changes in the API
- execTest(outDir, logFile, PathSettings.srcCodeLib.toString) && {
- // cannot replace paths here since this also inverts slashes
- // which affects a bunch of tests
- //fileManager.mapFile(logFile, replaceSlashes(dir, _))
- diffCheck(file, compareOutput(dir, logFile))
- }
- })
-
- // Apache Ant 1.6 or newer
- def ant(args: Seq[String], output: File): Boolean = {
- val antDir = Directory(envOrElse("ANT_HOME", "/opt/ant/"))
- val antLibDir = Directory(antDir / "lib")
- val antLauncherPath = SFile(antLibDir / "ant-launcher.jar").path
- val antOptions =
- if (NestUI._verbose) List("-verbose", "-noinput")
- else List("-noinput")
- val cmd = javaCmd +: (
- JAVA_OPTS.split(' ').map(_.trim).filter(_ != "") ++ Seq(
- "-classpath",
- antLauncherPath,
- "org.apache.tools.ant.launch.Launcher"
- ) ++ antOptions ++ args
- )
-
- try runCommand(cmd, output)
- catch exHandler(output, "ant command '" + cmd + "' failed:\n", false)
- }
-
- def runAntTest(file: File): (Boolean, LogContext) = {
- val (swr, wr) = newTestWriters()
- printInfoStart(file, wr)
-
- NestUI.verbose(this+" running test "+fileBase)
-
- val succeeded = try {
- val binary = "-Dbinary="+(
- if (fileManager.LATEST_LIB endsWith "build/quick/classes/library") "quick"
- else if (fileManager.LATEST_LIB endsWith "build/pack/lib/scala-library.jar") "pack"
- else if (fileManager.LATEST_LIB endsWith "dists/latest/lib/scala-library.jar/") "latest"
- else "installed"
- )
- val args = Array(binary, "-logfile", logFile.path, "-file", file.path)
- NestUI.verbose("ant "+args.mkString(" "))
- ant(args, logFile) && diffCheck(file, compareOutput(file.getParentFile, logFile))
- }
- catch { // *catch-all*
- case e: Exception =>
- NestUI.verbose("caught "+e)
- false
- }
-
- (succeeded, LogContext(logFile, swr, wr))
- }
-
- def runSpecializedTest(file: File): (Boolean, LogContext) =
- runTestCommon(file, expectFailure = false)((logFile, outDir) => {
- val dir = file.getParentFile
-
- // adding the instrumented library to the classpath
- ( execTest(outDir, logFile, PathSettings.srcSpecLib.toString) &&
- diffCheck(file, compareOutput(dir, logFile))
- )
- })
-
- def runInstrumentedTest(file: File): (Boolean, LogContext) =
- runTestCommon(file, expectFailure = false)((logFile, outDir) => {
- val dir = file.getParentFile
-
- // adding the javagent option with path to instrumentation agent
- execTest(outDir, logFile, javaOpts = "-javaagent:"+PathSettings.instrumentationAgentLib) &&
- diffCheck(file, compareOutput(dir, logFile))
- })
-
- def processSingleFile(file: File): (Boolean, LogContext) = kind match {
- case "scalacheck" =>
- val succFn: (File, File) => Boolean = { (logFile, outDir) =>
- NestUI.verbose("compilation of "+file+" succeeded\n")
-
- val outURL = outDir.getAbsoluteFile.toURI.toURL
- val logWriter = new PrintStream(new FileOutputStream(logFile), true)
-
- Output.withRedirected(logWriter) {
- // this classloader is test specific: its parent contains library classes and others
- ScalaClassLoader.fromURLs(List(outURL), params.scalaCheckParentClassLoader).run("Test", Nil)
- }
-
- NestUI.verbose(file2String(logFile))
- // obviously this must be improved upon
- val lines = SFile(logFile).lines map (_.trim) filterNot (_ == "") toBuffer;
- lines.forall(x => !x.startsWith("!")) || {
- NestUI.normal("ScalaCheck test failed. Output:\n")
- lines foreach (x => NestUI.normal(x + "\n"))
- false
- }
- }
- runTestCommon(file, expectFailure = false)(
- succFn,
- (logFile, outDir) => outputLogFile(logFile)
- )
-
- case "pos" =>
- runTestCommon(file, expectFailure = false)(
- (logFile, outDir) => true,
- (_, _) => ()
- )
-
- case "neg" =>
- runTestCommon(file, expectFailure = true)((logFile, outDir) => {
- // compare log file to check file
- val dir = file.getParentFile
-
- // diff is contents of logFile
- fileManager.mapFile(logFile, replaceSlashes(dir, _))
- diffCheck(file, compareOutput(dir, logFile))
- })
-
- case "run" | "jvm" =>
- runJvmTest(file)
-
- case "specialized" =>
- runSpecializedTest(file)
-
- case "instrumented" =>
- runInstrumentedTest(file)
-
- case "presentation" =>
- runJvmTest(file) // for the moment, it's exactly the same as for a run test
-
- case "ant" =>
- runAntTest(file)
-
- case "res" => {
- // simulate resident compiler loop
- val prompt = "\nnsc> "
-
- val (swr, wr) = newTestWriters()
- printInfoStart(file, wr)
-
- NestUI.verbose(this+" running test "+fileBase)
- val dir = file.getParentFile
- val outDir = createOutputDir()
- val resFile = new File(dir, fileBase + ".res")
- NestUI.verbose("outDir: "+outDir)
- NestUI.verbose("logFile: "+logFile)
- //NestUI.verbose("logFileErr: "+logFileErr)
- NestUI.verbose("resFile: "+resFile)
-
- // run compiler in resident mode
- // $SCALAC -d "$os_dstbase".obj -Xresident -sourcepath . "$@"
- val sourcedir = logFile.getParentFile.getAbsoluteFile
- val sourcepath = sourcedir.getAbsolutePath+File.separator
- NestUI.verbose("sourcepath: "+sourcepath)
-
- val argList = List(
- "-d", outDir.getAbsoluteFile.getPath,
- "-Xresident",
- "-sourcepath", sourcepath)
-
- // configure input/output files
- val logOut = new FileOutputStream(logFile)
- val logWriter = new PrintStream(logOut, true)
- val resReader = new BufferedReader(new FileReader(resFile))
- val logConsoleWriter = new PrintWriter(new OutputStreamWriter(logOut), true)
-
- // create compiler
- val settings = new Settings(workerError)
- settings.sourcepath.value = sourcepath
- settings.classpath.value = fileManager.CLASSPATH
- val reporter = new ConsoleReporter(settings, scala.Console.in, logConsoleWriter)
- val command = new CompilerCommand(argList, settings)
- object compiler extends Global(command.settings, reporter)
-
- val resCompile = (line: String) => {
- NestUI.verbose("compiling "+line)
- val cmdArgs = (line split ' ').toList map (fs => new File(dir, fs).getAbsolutePath)
- NestUI.verbose("cmdArgs: "+cmdArgs)
- val sett = new Settings(workerError)
- sett.sourcepath.value = sourcepath
- val command = new CompilerCommand(cmdArgs, sett)
- command.ok && {
- (new compiler.Run) compile command.files
- !reporter.hasErrors
- }
- }
-
- def loop(action: String => Boolean): Boolean = {
- logWriter.print(prompt)
- resReader.readLine() match {
- case null | "" => logWriter.flush() ; true
- case line => action(line) && loop(action)
- }
- }
-
- Output.withRedirected(logWriter) {
- try loop(resCompile)
- finally resReader.close()
- }
- fileManager.mapFile(logFile, replaceSlashes(dir, _))
-
- (diffCheck(file, compareOutput(dir, logFile)), LogContext(logFile, swr, wr))
- }
-
- case "shootout" =>
- val (swr, wr) = newTestWriters()
- printInfoStart(file, wr)
-
- NestUI.verbose(this+" running test "+fileBase)
- val outDir = createOutputDir()
-
- // 2. define file {outDir}/test.scala that contains code to compile/run
- val testFile = new File(outDir, "test.scala")
- NestUI.verbose("outDir: "+outDir)
- NestUI.verbose("logFile: "+logFile)
- NestUI.verbose("testFile: "+testFile)
-
- // 3. cat {test}.scala.runner {test}.scala > testFile
- val runnerFile = new File(parent, fileBase+".scala.runner")
- val bodyFile = new File(parent, fileBase+".scala")
- SFile(testFile).writeAll(
- file2String(runnerFile),
- file2String(bodyFile)
- )
-
- // 4. compile testFile
- val ok = compileMgr.attemptCompile(None, List(testFile), kind, logFile) eq CompileSuccess
- NestUI.verbose("compilation of " + testFile + (if (ok) "succeeded" else "failed"))
- val result = ok && {
- execTest(outDir, logFile) && {
- NestUI.verbose(this+" finished running "+fileBase)
- diffCheck(file, compareOutput(parent, logFile))
- }
- }
-
- (result, LogContext(logFile, swr, wr))
-
- case "scalap" =>
- runInContext(file, (logFile: File, outDir: File) => {
- val sourceDir = Directory(if (file.isFile) file.getParent else file)
- val sources = sourceDir.files filter (_ hasExtension "scala") map (_.jfile) toList
- val results = sourceDir.files filter (_.name == "result.test") map (_.jfile) toList
-
- if (sources.length != 1 || results.length != 1) {
- NestUI.warning("Misconfigured scalap test directory: " + sourceDir + " \n")
- false
- }
- else {
- val resFile = results.head
- // 2. Compile source file
-
- if (!compileMgr.attemptCompile(Some(outDir), sources, kind, logFile).isPositive) {
- NestUI.normal("compilerMgr failed to compile %s to %s".format(sources mkString ", ", outDir))
- false
- }
- else {
- // 3. Decompile file and compare results
- val isPackageObject = sourceDir.name startsWith "package"
- val className = sourceDir.name.capitalize + (if (!isPackageObject) "" else ".package")
- val url = outDir.toURI.toURL
- val loader = ScalaClassLoader.fromURLs(List(url), this.getClass.getClassLoader)
- val clazz = loader.loadClass(className)
-
- val byteCode = ByteCode.forClass(clazz)
- val result = scala.tools.scalap.Main.decompileScala(byteCode.bytes, isPackageObject)
-
- SFile(logFile) writeAll result
- diffCheck(file, compareFiles(logFile, resFile))
- }
- }
- })
-
- case "script" =>
- val (swr, wr) = newTestWriters()
- printInfoStart(file, wr)
-
- NestUI.verbose(this+" running test "+fileBase)
-
- // check whether there is an args file
- val argsFile = new File(file.getParentFile, fileBase+".args")
- NestUI.verbose("argsFile: "+argsFile)
- val argString = file2String(argsFile)
- val succeeded = try {
- val cmdString =
- if (isWin) {
- val batchFile = new File(file.getParentFile, fileBase+".bat")
- NestUI.verbose("batchFile: "+batchFile)
- batchFile.getAbsolutePath
- }
- else file.getAbsolutePath
-
- val ok = runCommand(cmdString+argString, logFile)
- ( ok && diffCheck(file, compareOutput(file.getParentFile, logFile)) )
- }
- catch { case e: Exception => NestUI.verbose("caught "+e) ; false }
-
- (succeeded, LogContext(logFile, swr, wr))
- }
-
- private def crashContext(t: Throwable): LogContext = {
- try {
- logStackTrace(logFile, t, "Possible compiler crash during test of: " + testFile + "\n")
- LogContext(logFile)
- }
- catch { case t: Throwable => LogContext(null) }
- }
-
- def run(): (Boolean, LogContext) = {
- val result = try processSingleFile(testFile) catch { case t: Throwable => (false, crashContext(t)) }
- passed = Some(result._1)
- result
- }
-
- def reportResult(writers: Option[(StringWriter, PrintWriter)]) {
- writers foreach { case (swr, wr) =>
- if (passed.isEmpty) printInfoTimeout(wr)
- else printInfoEnd(passed.get, wr)
- wr.flush()
- swr.flush()
- NestUI.normal(swr.toString)
-
- if (passed exists (x => !x)) {
- if (fileManager.showDiff || isPartestDebug)
- NestUI.normal(testDiff)
- if (fileManager.showLog)
- showLog(logFile)
- }
- }
- toDelete foreach (_.deleteRecursively())
- }
- }
-
def runTest(testFile: File): TestState = {
- val runner = new Runner(testFile)
+ val runner = new Runner(testFile, fileManager) {
+ override def testRunParams = params
+ }
// when option "--failed" is provided execute test only if log
// is present (which means it failed before)
if (fileManager.failed && !runner.logFile.canRead)
- return TestState.Ok
-
- val (success, ctx) = runner.run()
- val state = if (success) TestState.Ok else TestState.Fail
-
- runner.reportResult(ctx.writers)
- state
- }
-
- private def filesToSet(pre: String, fs: List[String]): Set[AbstractFile] =
- fs flatMap (s => Option(AbstractFile getFile (pre + s))) toSet
-
- private def copyTestFiles(testDir: File, destDir: File) {
- val invalidExts = List("changes", "svn", "obj")
- testDir.listFiles.toList filter (
- f => (isJavaOrScala(f) && f.isFile) ||
- (f.isDirectory && !(invalidExts.contains(SFile(f).extension)))) foreach
- { f => fileManager.copyFile(f, destDir) }
- }
-
- private def showLog(logFile: File) {
- file2String(logFile) match {
- case "" if logFile.canRead => ()
- case "" => NestUI.failure("Couldn't open log file: " + logFile + "\n")
- case s => NestUI.normal(s)
+ runner.genPass()
+ else {
+ val (state, elapsed) = timed(runner.run())
+ NestUI.reportTest(state)
+ runner.cleanup()
+ state
}
}
}
diff --git a/src/partest/scala/tools/partest/nest/SBTRunner.scala b/src/partest/scala/tools/partest/nest/SBTRunner.scala
index 20f9c701d5..1cf3aa858f 100644
--- a/src/partest/scala/tools/partest/nest/SBTRunner.scala
+++ b/src/partest/scala/tools/partest/nest/SBTRunner.scala
@@ -1,3 +1,6 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2013 LAMP/EPFL
+ */
package scala.tools.partest
package nest
@@ -21,7 +24,7 @@ object SBTRunner extends DirectRunner {
val testRootDir: Directory = Directory(testRootPath)
}
- def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String):java.util.Map[String, TestState] = {
+ def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String): java.util.List[TestState] = {
def failedOnlyIfRequired(files:List[File]):List[File]={
if (fileManager.failed) files filter (x => fileManager.logFileExists(x, kind)) else files
}
@@ -33,7 +36,7 @@ object SBTRunner extends DirectRunner {
scalacOptions: Seq[String] = Seq(),
justFailedTests: Boolean = false)
- def mainReflect(args: Array[String]): java.util.Map[String, String] = {
+ def mainReflect(args: Array[String]): java.util.List[TestState] = {
setProp("partest.debug", "true")
val Argument = new scala.util.matching.Regex("-(.*)")
@@ -46,7 +49,7 @@ object SBTRunner extends DirectRunner {
case x => sys.error("Unknown command line options: " + x)
}
val config = parseArgs(args, CommandLineOptions())
- fileManager.SCALAC_OPTS ++= config.scalacOptions
+ fileManager.SCALAC_OPTS = config.scalacOptions
fileManager.CLASSPATH = config.classpath getOrElse sys.error("No classpath set")
def findClasspath(jar: String, name: String): Option[String] = {
@@ -67,22 +70,14 @@ object SBTRunner extends DirectRunner {
// TODO - Make this a flag?
//fileManager.updateCheck = true
// Now run and report...
- val runs = config.tests.filterNot(_._2.isEmpty)
- (for {
- (testType, files) <- runs
- (path, result) <- reflectiveRunTestsForFiles(files,testType).asScala
- } yield (path, fixResult(result))).seq.asJava
- }
- def fixResult(result: TestState): String = result match {
- case TestState.Ok => "OK"
- case TestState.Fail => "FAIL"
- case TestState.Timeout => "TIMEOUT"
+ val runs = config.tests.filterNot(_._2.isEmpty)
+ val result = runs.toList flatMap { case (kind, files) => reflectiveRunTestsForFiles(files, kind).asScala }
+
+ result.asJava
}
+
def main(args: Array[String]): Unit = {
- val failures = (
- for ((path, result) <- mainReflect(args).asScala ; if result != TestState.Ok) yield
- path + ( if (result == TestState.Fail) " [FAILED]" else " [TIMEOUT]" )
- )
+ val failures = mainReflect(args).asScala collect { case s if !s.isOk => s.longStatus }
// Re-list all failures so we can go figure out what went wrong.
failures foreach System.err.println
if(!failures.isEmpty) sys.exit(1)
diff --git a/src/partest/scala/tools/partest/nest/StreamCapture.scala b/src/partest/scala/tools/partest/nest/StreamCapture.scala
new file mode 100644
index 0000000000..dc155b1787
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/StreamCapture.scala
@@ -0,0 +1,53 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+package scala.tools.partest
+package nest
+
+import java.io.{ Console => _, _ }
+
+object StreamCapture {
+ case class Captured[T](stdout: String, stderr: String, result: T) {
+ override def toString = s"""
+ |result: $result
+ |[stdout]
+ |$stdout
+ |[stderr]
+ |$stderr""".stripMargin.trim
+ }
+
+ private def mkStream = {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr, true)
+ val ostream = new PrintStream(new OutputStream { def write(b: Int): Unit = wr write b }, true) // autoFlush = true
+
+ (ostream, () => { ostream.close() ; swr.toString })
+ }
+
+ def savingSystem[T](body: => T): T = {
+ val savedOut = System.out
+ val savedErr = System.err
+ try body
+ finally {
+ System setErr savedErr
+ System setOut savedOut
+ }
+ }
+
+ def apply[T](body: => T): Captured[T] = {
+ val (outstream, stdoutFn) = mkStream
+ val (errstream, stderrFn) = mkStream
+
+ val result = savingSystem {
+ System setOut outstream
+ System setErr errstream
+ Console.withOut(outstream) {
+ Console.withErr(errstream) {
+ body
+ }
+ }
+ }
+ Captured(stdoutFn(), stderrFn(), result)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala
deleted file mode 100644
index 880c6e431b..0000000000
--- a/src/partest/scala/tools/partest/nest/TestFile.scala
+++ /dev/null
@@ -1,80 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2013 LAMP/EPFL
- * @author Philipp Haller
- */
-
-// $Id$
-
-package scala.tools.partest
-package nest
-
-import java.io.{ File => JFile }
-import scala.tools.nsc.Settings
-import scala.tools.nsc.util.ClassPath
-import scala.tools.nsc.io._
-import scala.util.Properties.{ propIsSet, propOrElse, setProp }
-
-trait TestFileCommon {
- def file: JFile
- def kind: String
-
- val dir = file.toAbsolute.parent
- val fileBase = file.stripExtension
- val flags = dir / (fileBase + ".flags") ifFile (f => f.slurp().trim)
-
- lazy val objectDir = dir / (fileBase + "-" + kind + ".obj") createDirectory true
- def setOutDirTo = objectDir
-}
-
-abstract class TestFile(val kind: String) extends TestFileCommon {
- def file: JFile
- def fileManager: FileManager
-
- def defineSettings(settings: Settings, setOutDir: Boolean) = {
- settings.classpath append dir.path
- if (setOutDir)
- settings.outputDirs setSingleOutput setOutDirTo.path
-
- // adding codelib.jar to the classpath
- // codelib provides the possibility to override standard reify
- // this shields the massive amount of reification tests from changes in the API
- settings.classpath prepend PathSettings.srcCodeLib.toString
- if (propIsSet("java.class.path")) setProp("java.class.path", PathSettings.srcCodeLib.toString + ";" + propOrElse("java.class.path", ""))
-
- // have to catch bad flags somewhere
- (flags forall (f => settings.processArgumentString(f)._1)) && {
- settings.classpath append fileManager.CLASSPATH
- true
- }
- }
-
- override def toString(): String = "%s %s".format(kind, file)
-}
-
-case class PosTestFile(file: JFile, fileManager: FileManager) extends TestFile("pos")
-case class NegTestFile(file: JFile, fileManager: FileManager) extends TestFile("neg")
-case class RunTestFile(file: JFile, fileManager: FileManager) extends TestFile("run")
-case class ScalaCheckTestFile(file: JFile, fileManager: FileManager) extends TestFile("scalacheck")
-case class JvmTestFile(file: JFile, fileManager: FileManager) extends TestFile("jvm")
-case class ShootoutTestFile(file: JFile, fileManager: FileManager) extends TestFile("shootout") {
- override def setOutDirTo = file.parent
-}
-case class ScalapTestFile(file: JFile, fileManager: FileManager) extends TestFile("scalap") {
- override def setOutDirTo = file.parent
-}
-case class SpecializedTestFile(file: JFile, fileManager: FileManager) extends TestFile("specialized") {
- override def defineSettings(settings: Settings, setOutDir: Boolean): Boolean = {
- super.defineSettings(settings, setOutDir) && {
- // add the instrumented library version to classpath
- settings.classpath prepend PathSettings.srcSpecLib.toString
- // @partest maintainer: if we use a custom Scala build (specified via --classpath)
- // then the classes provided by it will come earlier than instrumented.jar in the resulting classpath
- // this entire classpath business needs a thorough solution
- if (propIsSet("java.class.path")) setProp("java.class.path", PathSettings.srcSpecLib.toString + ";" + propOrElse("java.class.path", ""))
- true
- }
- }
-}
-case class PresentationTestFile(file: JFile, fileManager: FileManager) extends TestFile("presentation")
-case class AntTestFile(file: JFile, fileManager: FileManager) extends TestFile("ant")
-case class InstrumentedTestFile(file: JFile, fileManager: FileManager) extends TestFile("instrumented")
diff --git a/src/partest/scala/tools/partest/package.scala b/src/partest/scala/tools/partest/package.scala
index 2b2ce2e435..9e21b0f6ba 100644
--- a/src/partest/scala/tools/partest/package.scala
+++ b/src/partest/scala/tools/partest/package.scala
@@ -4,31 +4,102 @@
package scala.tools
-import java.io.{ FileNotFoundException, File => JFile }
-import nsc.io.{ Path, Directory, File => SFile }
-import scala.tools.util.PathResolver
-import nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
import scala.sys.process.javaVmArguments
import java.util.concurrent.Callable
+import scala.tools.partest.nest.NestUI
+import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional }
-package partest {
- class TestState { }
- object TestState {
- val Ok = new TestState
- val Fail = new TestState
- val Timeout = new TestState
+package object partest {
+ type File = java.io.File
+ type SFile = scala.reflect.io.File
+ type Directory = scala.reflect.io.Directory
+ type Path = scala.reflect.io.Path
+ type PathResolver = scala.tools.util.PathResolver
+ type ClassPath[T] = scala.tools.nsc.util.ClassPath[T]
+ type StringWriter = java.io.StringWriter
+
+ val SFile = scala.reflect.io.File
+ val Directory = scala.reflect.io.Directory
+ val Path = scala.reflect.io.Path
+ val PathResolver = scala.tools.util.PathResolver
+ val ClassPath = scala.tools.nsc.util.ClassPath
+
+ val space = "\u0020"
+ val EOL = scala.compat.Platform.EOL
+ def onull(s: String) = if (s == null) "" else s
+ def oempty(xs: String*) = xs filterNot (x => x == null || x == "")
+ def ojoin(xs: String*): String = oempty(xs: _*) mkString space
+ def nljoin(xs: String*): String = oempty(xs: _*) mkString EOL
+
+ def setUncaughtHandler() = {
+ Thread.setDefaultUncaughtExceptionHandler(
+ new Thread.UncaughtExceptionHandler {
+ def uncaughtException(thread: Thread, t: Throwable) {
+ val t1 = Exceptional unwrap t
+ System.err.println(s"Uncaught exception on thread $thread: $t1")
+ t1.printStackTrace()
+ }
+ }
+ )
}
-}
-package object partest {
- import nest.NestUI
+ /** Sources have a numerical group, specified by name_7 and so on. */
+ private val GroupPattern = """.*_(\d+)""".r
+
+ implicit class FileOps(val f: File) {
+ private def sf = SFile(f)
+
+ def testIdent = {
+ f.toString split """[/\\]+""" takeRight 2 mkString "/" // e.g. pos/t1234
+ }
+
+ def mapInPlace(mapFn: String => String): Unit =
+ writeAll(fileLines.map(x => mapFn(x) + "\n"): _*)
+
+ def appendAll(strings: String*): Unit = sf.appendAll(strings: _*)
+ def writeAll(strings: String*): Unit = sf.writeAll(strings: _*)
+ def absolutePathSegments: List[String] = f.getAbsolutePath split """[/\\]+""" toList
+
+ def isJava = f.isFile && (sf hasExtension "java")
+ def isScala = f.isFile && (sf hasExtension "scala")
+ def isJavaOrScala = isJava || isScala
+
+ def extension = sf.extension
+ def hasExtension(ext: String) = sf hasExtension ext
+ def changeExtension(ext: String): File = (sf changeExtension ext).jfile
+
+ /** The group number for this source file, or -1 for no group. */
+ def group: Int =
+ sf.stripExtension match {
+ case GroupPattern(g) if g.toInt >= 0 => g.toInt
+ case _ => -1
+ }
+
+ def fileContents: String = try sf.slurp() catch { case _: java.io.FileNotFoundException => "" }
+ def fileLines: List[String] = augmentString(fileContents).lines.toList
+ }
+
+ implicit class PathOps(p: Path) extends FileOps(p.jfile) { }
+
+ implicit class Copier(val f: SFile) extends AnyVal {
+ def copyTo(dest: Path): Unit = dest.toFile writeAll f.slurp(scala.io.Codec.UTF8)
+ }
- implicit private[partest] def temporaryPath2File(x: Path): JFile = x.jfile
- implicit private[partest] def temporaryFile2Path(x: JFile): Path = Path(x)
+ implicit def temporaryPath2File(x: Path): File = x.jfile
+ implicit def stringPathToJavaFile(path: String): File = new File(path)
implicit lazy val postfixOps = scala.language.postfixOps
implicit lazy val implicitConversions = scala.language.implicitConversions
+ def fileSeparator = java.io.File.separator
+ def pathSeparator = java.io.File.pathSeparator
+
+ def pathToTestIdent(path: Path) = path.jfile.testIdent
+
+ def canonicalizeSlashes(line: String) = line.replaceAll("""[/\\]+""", "/")
+
+ def words(s: String): List[String] = (s.trim split "\\s+").toList
+
def timed[T](body: => T): (T, Long) = {
val t1 = System.currentTimeMillis
val result = body
@@ -39,15 +110,40 @@ package object partest {
def callable[T](body: => T): Callable[T] = new Callable[T] { override def call() = body }
- def file2String(f: JFile) =
- try SFile(f).slurp(scala.io.Codec.UTF8)
- catch { case _: FileNotFoundException => "" }
+ def file2String(f: File): String = f.fileContents
def basename(name: String): String = Path(name).stripExtension
- def resultsToStatistics(results: Iterable[(_, TestState)]): (Int, Int) = {
- val (files, failures) = results map (_._2 == TestState.Ok) partition (_ == true)
- (files.size, failures.size)
+ /** In order to allow for spaces in flags/options, this
+ * parses .flags, .javaopts, javacopts etc files as follows:
+ * If it is exactly one line, it is split (naively) on spaces.
+ * If it contains more than one line, each line is its own
+ * token, spaces and all.
+ */
+ def readOptionsFile(file: File): List[String] = {
+ file.fileLines match {
+ case x :: Nil => words(x)
+ case xs => xs map (_.trim)
+ }
+ }
+
+ def findProgram(name: String): Option[File] = {
+ val pathDirs = sys.env("PATH") match {
+ case null => List("/usr/local/bin", "/usr/bin", "/bin")
+ case path => path split "[:;]" filterNot (_ == "") toList
+ }
+ pathDirs.iterator map (d => new File(d, name)) find (_.canExecute)
+ }
+
+ def now = (new java.util.Date).toString
+ def elapsedString(millis: Long): String = {
+ val elapsedSecs = millis/1000
+ val elapsedMins = elapsedSecs/60
+ val elapsedHrs = elapsedMins/60
+ val dispMins = elapsedMins - elapsedHrs * 60
+ val dispSecs = elapsedSecs - elapsedMins * 60
+
+ "%02d:%02d:%02d".format(elapsedHrs, dispMins, dispSecs)
}
def vmArgString = javaVmArguments.mkString(
@@ -62,13 +158,10 @@ package object partest {
}
def showAllJVMInfo() {
- NestUI.verbose(vmArgString)
- NestUI.verbose(allPropertiesString)
+ vlog(vmArgString)
+ vlog(allPropertiesString)
}
- def isPartestDebug: Boolean =
- propOrEmpty("partest.debug") == "true"
-
import scala.language.experimental.macros
/**
@@ -117,4 +210,10 @@ package object partest {
a.tree))))),
a.tree))
}
+
+ def isPartestTerse = NestUI.isTerse
+ def isPartestDebug = NestUI.isDebug
+ def isPartestVerbose = NestUI.isVerbose
+
+ def vlog(msg: => String) = if (isPartestVerbose) System.err.println(msg)
}
diff --git a/test/build-partest.xml b/test/build-partest.xml
new file mode 100755
index 0000000000..44502ffa61
--- /dev/null
+++ b/test/build-partest.xml
@@ -0,0 +1,24 @@
+<project name="partest" basedir=".">
+ <dirname property="partest.basedir" file="${ant.file.partest}"/>
+ <property file="${partest.basedir}/included.properties"/>
+
+ <macrodef name="testSuite">
+ <attribute name="dir" default="${partest.basedir}/test"/>
+ <attribute name="srcdir" default="files"/> <!-- TODO: make targets for `pending` and other subdirs -->
+ <attribute name="colors" default="${partest.colors}"/>
+ <attribute name="scalacOpts" default="${scalac.args.optimise}"/>
+ <attribute name="kinds" default="pos neg run jvm res scalap scalacheck specialized instrumented presentation"/>
+ <sequential>
+ <property name="partest.dir" value="@{dir}" />
+ <partest srcdir="@{srcdir}"
+ kinds="@{kinds}"
+ colors="@{colors}"
+ scalacOpts="@{scalacOpts}"
+ compilationpathref="partest.classpath">
+ <compilationpath>
+ <fileset dir="${partest.dir}/files/lib" includes="*.jar" />
+ </compilationpath>
+ </partest>
+ </sequential>
+ </macrodef>
+</project>
diff --git a/test/files/neg/choices.check b/test/files/neg/choices.check
index 3e63f9999d..b114394e96 100644
--- a/test/files/neg/choices.check
+++ b/test/files/neg/choices.check
@@ -1,2 +1,2 @@
-partest error: bad flags: -Ylinearizer
+error: bad options: -Yresolve-term-conflict
one error found
diff --git a/test/files/neg/choices.flags b/test/files/neg/choices.flags
index 5464a18c5d..9718467d4c 100644
--- a/test/files/neg/choices.flags
+++ b/test/files/neg/choices.flags
@@ -1 +1 @@
--Ylinearizer \ No newline at end of file
+-Yresolve-term-conflict
diff --git a/test/files/run/reify_this.scala b/test/files/run/reify_this.scala
index ecbf394bba..c385da6360 100644
--- a/test/files/run/reify_this.scala
+++ b/test/files/run/reify_this.scala
@@ -1,11 +1,11 @@
import scala.reflect.runtime.universe._
import scala.tools.reflect.Eval
-trait Eval {
+trait Transvaal {
def eval(tree: Expr[_]) = tree.eval
}
-object Test extends App with Eval {
+object Test extends App with Transvaal {
// select a value from package
eval(reify{println("foo")})
eval(reify{println((new Object).toString == (new Object).toString)})
@@ -17,4 +17,4 @@ object Test extends App with Eval {
// select a value from module
val x = 2
eval(reify{println(x)})
-} \ No newline at end of file
+}
diff --git a/test/files/scalap/abstractClass/result.test b/test/files/scalap/abstractClass.check
index ef1daac23d..ef1daac23d 100644
--- a/test/files/scalap/abstractClass/result.test
+++ b/test/files/scalap/abstractClass.check
diff --git a/test/files/scalap/abstractClass/A.scala b/test/files/scalap/abstractClass.scala
index 19a528d5a1..19a528d5a1 100644
--- a/test/files/scalap/abstractClass/A.scala
+++ b/test/files/scalap/abstractClass.scala
diff --git a/test/files/scalap/abstractMethod/result.test b/test/files/scalap/abstractMethod.check
index 40fa02d408..40fa02d408 100644
--- a/test/files/scalap/abstractMethod/result.test
+++ b/test/files/scalap/abstractMethod.check
diff --git a/test/files/scalap/abstractMethod/A.scala b/test/files/scalap/abstractMethod.scala
index 4bedb377b3..4bedb377b3 100644
--- a/test/files/scalap/abstractMethod/A.scala
+++ b/test/files/scalap/abstractMethod.scala
diff --git a/test/files/scalap/caseClass/result.test b/test/files/scalap/caseClass.check
index 7d7aa4fd8f..7d7aa4fd8f 100644
--- a/test/files/scalap/caseClass/result.test
+++ b/test/files/scalap/caseClass.check
diff --git a/test/files/scalap/caseClass/A.scala b/test/files/scalap/caseClass.scala
index 95f9984519..95f9984519 100644
--- a/test/files/scalap/caseClass/A.scala
+++ b/test/files/scalap/caseClass.scala
diff --git a/test/files/scalap/caseObject/result.test b/test/files/scalap/caseObject.check
index 867a4b2162..867a4b2162 100644
--- a/test/files/scalap/caseObject/result.test
+++ b/test/files/scalap/caseObject.check
diff --git a/test/files/scalap/caseObject/A.scala b/test/files/scalap/caseObject.scala
index 6a3ff10d75..6a3ff10d75 100644
--- a/test/files/scalap/caseObject/A.scala
+++ b/test/files/scalap/caseObject.scala
diff --git a/test/files/scalap/cbnParam/result.test b/test/files/scalap/cbnParam.check
index 52ecb6ae66..52ecb6ae66 100644
--- a/test/files/scalap/cbnParam/result.test
+++ b/test/files/scalap/cbnParam.check
diff --git a/test/files/scalap/cbnParam/A.scala b/test/files/scalap/cbnParam.scala
index 2f366df64a..2f366df64a 100644
--- a/test/files/scalap/cbnParam/A.scala
+++ b/test/files/scalap/cbnParam.scala
diff --git a/test/files/scalap/classPrivate/result.test b/test/files/scalap/classPrivate.check
index ab2d40cdaf..ab2d40cdaf 100644
--- a/test/files/scalap/classPrivate/result.test
+++ b/test/files/scalap/classPrivate.check
diff --git a/test/files/scalap/classPrivate/A.scala b/test/files/scalap/classPrivate.scala
index 9f1bd34a6a..9f1bd34a6a 100644
--- a/test/files/scalap/classPrivate/A.scala
+++ b/test/files/scalap/classPrivate.scala
diff --git a/test/files/scalap/classWithExistential/result.test b/test/files/scalap/classWithExistential.check
index caee3fd6de..caee3fd6de 100644
--- a/test/files/scalap/classWithExistential/result.test
+++ b/test/files/scalap/classWithExistential.check
diff --git a/test/files/scalap/classWithExistential/A.scala b/test/files/scalap/classWithExistential.scala
index 4a5213f963..4a5213f963 100644
--- a/test/files/scalap/classWithExistential/A.scala
+++ b/test/files/scalap/classWithExistential.scala
diff --git a/test/files/scalap/classWithSelfAnnotation/result.test b/test/files/scalap/classWithSelfAnnotation.check
index 82bbd9e8df..82bbd9e8df 100644
--- a/test/files/scalap/classWithSelfAnnotation/result.test
+++ b/test/files/scalap/classWithSelfAnnotation.check
diff --git a/test/files/scalap/classWithSelfAnnotation/A.scala b/test/files/scalap/classWithSelfAnnotation.scala
index 9e0398622a..9e0398622a 100644
--- a/test/files/scalap/classWithSelfAnnotation/A.scala
+++ b/test/files/scalap/classWithSelfAnnotation.scala
diff --git a/test/files/scalap/covariantParam/result.test b/test/files/scalap/covariantParam.check
index f7a3c98966..f7a3c98966 100644
--- a/test/files/scalap/covariantParam/result.test
+++ b/test/files/scalap/covariantParam.check
diff --git a/test/files/scalap/covariantParam/A.scala b/test/files/scalap/covariantParam.scala
index 5b2c24d6fa..5b2c24d6fa 100644
--- a/test/files/scalap/covariantParam/A.scala
+++ b/test/files/scalap/covariantParam.scala
diff --git a/test/files/scalap/defaultParameter/result.test b/test/files/scalap/defaultParameter.check
index 0c775ea7b5..0c775ea7b5 100644
--- a/test/files/scalap/defaultParameter/result.test
+++ b/test/files/scalap/defaultParameter.check
diff --git a/test/files/scalap/defaultParameter/A.scala b/test/files/scalap/defaultParameter.scala
index d3514952f4..d3514952f4 100644
--- a/test/files/scalap/defaultParameter/A.scala
+++ b/test/files/scalap/defaultParameter.scala
diff --git a/test/files/scalap/implicitParam/result.test b/test/files/scalap/implicitParam.check
index a2cfd6092d..a2cfd6092d 100644
--- a/test/files/scalap/implicitParam/result.test
+++ b/test/files/scalap/implicitParam.check
diff --git a/test/files/scalap/implicitParam/A.scala b/test/files/scalap/implicitParam.scala
index 80657218d9..80657218d9 100644
--- a/test/files/scalap/implicitParam/A.scala
+++ b/test/files/scalap/implicitParam.scala
diff --git a/test/files/scalap/packageObject/result.test b/test/files/scalap/packageObject.check
index 5732d92958..5732d92958 100644
--- a/test/files/scalap/packageObject/result.test
+++ b/test/files/scalap/packageObject.check
diff --git a/test/files/scalap/packageObject/A.scala b/test/files/scalap/packageObject.scala
index 7e429c9935..7e429c9935 100644
--- a/test/files/scalap/packageObject/A.scala
+++ b/test/files/scalap/packageObject.scala
diff --git a/test/files/scalap/paramClauses/result.test b/test/files/scalap/paramClauses.check
index 3a141e8faf..3a141e8faf 100644
--- a/test/files/scalap/paramClauses/result.test
+++ b/test/files/scalap/paramClauses.check
diff --git a/test/files/scalap/paramClauses/A.scala b/test/files/scalap/paramClauses.scala
index f9d1917402..f9d1917402 100644
--- a/test/files/scalap/paramClauses/A.scala
+++ b/test/files/scalap/paramClauses.scala
diff --git a/test/files/scalap/paramNames/result.test b/test/files/scalap/paramNames.check
index 85e37f858d..85e37f858d 100644
--- a/test/files/scalap/paramNames/result.test
+++ b/test/files/scalap/paramNames.check
diff --git a/test/files/scalap/paramNames/A.scala b/test/files/scalap/paramNames.scala
index 7ba9ff0feb..7ba9ff0feb 100644
--- a/test/files/scalap/paramNames/A.scala
+++ b/test/files/scalap/paramNames.scala
diff --git a/test/files/scalap/sequenceParam/result.test b/test/files/scalap/sequenceParam.check
index 142d92fea3..142d92fea3 100644
--- a/test/files/scalap/sequenceParam/result.test
+++ b/test/files/scalap/sequenceParam.check
diff --git a/test/files/scalap/sequenceParam/A.scala b/test/files/scalap/sequenceParam.scala
index 86e13340b9..86e13340b9 100644
--- a/test/files/scalap/sequenceParam/A.scala
+++ b/test/files/scalap/sequenceParam.scala
diff --git a/test/files/scalap/simpleClass/result.test b/test/files/scalap/simpleClass.check
index 4fdf25d1cf..4fdf25d1cf 100644
--- a/test/files/scalap/simpleClass/result.test
+++ b/test/files/scalap/simpleClass.check
diff --git a/test/files/scalap/simpleClass/A.scala b/test/files/scalap/simpleClass.scala
index fa82e62680..fa82e62680 100644
--- a/test/files/scalap/simpleClass/A.scala
+++ b/test/files/scalap/simpleClass.scala
diff --git a/test/files/scalap/traitObject/result.test b/test/files/scalap/traitObject.check
index 104ba14f1a..104ba14f1a 100644
--- a/test/files/scalap/traitObject/result.test
+++ b/test/files/scalap/traitObject.check
diff --git a/test/files/scalap/traitObject/A.scala b/test/files/scalap/traitObject.scala
index d5f43181c1..d5f43181c1 100644
--- a/test/files/scalap/traitObject/A.scala
+++ b/test/files/scalap/traitObject.scala
diff --git a/test/files/scalap/typeAnnotations/result.test b/test/files/scalap/typeAnnotations.check
index 407b0235c6..407b0235c6 100644
--- a/test/files/scalap/typeAnnotations/result.test
+++ b/test/files/scalap/typeAnnotations.check
diff --git a/test/files/scalap/typeAnnotations/A.scala b/test/files/scalap/typeAnnotations.scala
index ff2445edc9..ff2445edc9 100644
--- a/test/files/scalap/typeAnnotations/A.scala
+++ b/test/files/scalap/typeAnnotations.scala
diff --git a/test/files/scalap/valAndVar/result.test b/test/files/scalap/valAndVar.check
index e940da9801..e940da9801 100644
--- a/test/files/scalap/valAndVar/result.test
+++ b/test/files/scalap/valAndVar.check
diff --git a/test/files/scalap/valAndVar/A.scala b/test/files/scalap/valAndVar.scala
index 2d89348401..2d89348401 100644
--- a/test/files/scalap/valAndVar/A.scala
+++ b/test/files/scalap/valAndVar.scala
diff --git a/test/files/scalap/wildcardType/result.test b/test/files/scalap/wildcardType.check
index e43261db32..e43261db32 100644
--- a/test/files/scalap/wildcardType/result.test
+++ b/test/files/scalap/wildcardType.check
diff --git a/test/files/scalap/wildcardType/A.scala b/test/files/scalap/wildcardType.scala
index 4bb0d14de5..4bb0d14de5 100644
--- a/test/files/scalap/wildcardType/A.scala
+++ b/test/files/scalap/wildcardType.scala
diff --git a/test/partest b/test/partest
index ec66f5c048..8243316cca 100755
--- a/test/partest
+++ b/test/partest
@@ -1,7 +1,8 @@
-#!/bin/sh
+#!/usr/bin/env bash
+#
##############################################################################
-# Scala test runner 2.8.0
+# Scala test runner 2.10.0
##############################################################################
# (c) 2002-2013 LAMP/EPFL
#
@@ -10,6 +11,16 @@
# PARTICULAR PURPOSE.
##############################################################################
+# Use tput to detect color-capable terminal.
+term_colors=$(tput colors 2>/dev/null)
+if [[ $? == 0 ]] && [[ $term_colors -gt 2 ]]; then
+ git_diff_options="--color=always --word-diff"
+ color_opts="-Dpartest.colors=$term_colors"
+else
+ unset color_opts
+ git_diff_options="--nocolor"
+fi
+
cygwin=false;
darwin=false;
case "`uname`" in
@@ -98,6 +109,7 @@ fi
"${JAVACMD:=java}" \
$JAVA_OPTS -cp "$EXT_CLASSPATH" \
${partestDebugStr} \
+ "$color_opts" \
-Dscala.home="${SCALA_HOME}" \
-Dpartest.javacmd="${JAVACMD}" \
-Dpartest.java_opts="${JAVA_OPTS}" \