summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-05-06 16:37:13 +0000
committerPaul Phillips <paulp@improving.org>2010-05-06 16:37:13 +0000
commitc55b106f503d5e712e69823cfeb1cab2460221eb (patch)
treea1af091d9a2eeb16ee4747930511db4996c47140
parentcb35c38f14f6a53c38966bde8e64dcfa9af17918 (diff)
downloadscala-c55b106f503d5e712e69823cfeb1cab2460221eb.tar.gz
scala-c55b106f503d5e712e69823cfeb1cab2460221eb.tar.bz2
scala-c55b106f503d5e712e69823cfeb1cab2460221eb.zip
Rolled partest back to r21328.
changes necessary to plug it back in while preserving everything which has happened since then in tests and such, but we should be the lookout for overreversion. Review by phaller (but as a formality, I don't think it requires direct review.)
-rw-r--r--build.xml122
-rw-r--r--src/compiler/scala/tools/nsc/util/CommandLineParser.scala145
-rw-r--r--src/partest-alternative/README50
-rw-r--r--src/partest-alternative/scala/tools/partest/Actions.scala (renamed from src/partest/scala/tools/partest/Actions.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Alarms.scala (renamed from src/partest/scala/tools/partest/Alarms.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/BuildContributors.scala (renamed from src/partest/scala/tools/partest/BuildContributors.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Categories.scala (renamed from src/partest/scala/tools/partest/Categories.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Compilable.scala (renamed from src/partest/scala/tools/partest/Compilable.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Config.scala (renamed from src/partest/scala/tools/partest/Config.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Dispatcher.scala (renamed from src/partest/scala/tools/partest/Dispatcher.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Entities.scala (renamed from src/partest/scala/tools/partest/Entities.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Housekeeping.scala (renamed from src/partest/scala/tools/partest/Housekeeping.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Partest.scala (renamed from src/partest/scala/tools/partest/Partest.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/PartestSpec.scala (renamed from src/partest/scala/tools/partest/PartestSpec.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Properties.scala (renamed from src/partest/scala/tools/partest/Properties.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Results.scala (renamed from src/partest/scala/tools/partest/Results.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Runner.scala (renamed from src/partest/scala/tools/partest/Runner.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Statistics.scala (renamed from src/partest/scala/tools/partest/Statistics.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/Universe.scala (renamed from src/partest/scala/tools/partest/Universe.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/ant/JavaTask.scala (renamed from src/partest/scala/tools/partest/ant/JavaTask.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/antlib.xml3
-rw-r--r--src/partest-alternative/scala/tools/partest/category/AllCategories.scala (renamed from src/partest/scala/tools/partest/category/AllCategories.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/category/Analysis.scala (renamed from src/partest/scala/tools/partest/category/Analysis.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/category/Compiler.scala (renamed from src/partest/scala/tools/partest/category/Compiler.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/category/Runner.scala (renamed from src/partest/scala/tools/partest/category/Runner.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/io/ANSIWriter.scala (renamed from src/partest/scala/tools/partest/io/ANSIWriter.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/io/Diff.java (renamed from src/partest/scala/tools/partest/io/Diff.java)0
-rw-r--r--src/partest-alternative/scala/tools/partest/io/DiffPrint.java (renamed from src/partest/scala/tools/partest/io/DiffPrint.java)0
-rw-r--r--src/partest-alternative/scala/tools/partest/io/JUnitReport.scala (renamed from src/partest/scala/tools/partest/io/JUnitReport.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/io/Logging.scala (renamed from src/partest/scala/tools/partest/io/Logging.scala)0
-rw-r--r--src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala94
-rw-r--r--src/partest-alternative/scala/tools/partest/package.scala45
-rw-r--r--src/partest-alternative/scala/tools/partest/util/package.scala (renamed from src/partest/scala/tools/partest/util/package.scala)0
-rw-r--r--src/partest/README76
-rw-r--r--src/partest/scala/tools/partest/PartestDefaults.scala30
-rw-r--r--src/partest/scala/tools/partest/PartestTask.scala287
-rw-r--r--src/partest/scala/tools/partest/antlib.xml3
-rw-r--r--src/partest/scala/tools/partest/nest/AntRunner.scala30
-rw-r--r--src/partest/scala/tools/partest/nest/CompileManager.scala197
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleFileManager.scala190
-rw-r--r--src/partest/scala/tools/partest/nest/ConsoleRunner.scala209
-rw-r--r--src/partest/scala/tools/partest/nest/Diff.java874
-rw-r--r--src/partest/scala/tools/partest/nest/DiffPrint.java607
-rw-r--r--src/partest/scala/tools/partest/nest/DirectRunner.scala78
-rw-r--r--src/partest/scala/tools/partest/nest/FileManager.scala110
-rw-r--r--src/partest/scala/tools/partest/nest/NestRunner.scala16
-rw-r--r--src/partest/scala/tools/partest/nest/NestUI.scala118
-rw-r--r--src/partest/scala/tools/partest/nest/PathSettings.scala41
-rw-r--r--src/partest/scala/tools/partest/nest/ReflectiveRunner.scala88
-rw-r--r--src/partest/scala/tools/partest/nest/RunnerUtils.scala29
-rw-r--r--src/partest/scala/tools/partest/nest/TestFile.scala49
-rw-r--r--src/partest/scala/tools/partest/nest/Worker.scala1071
-rw-r--r--src/partest/scala/tools/partest/package.scala59
-rw-r--r--src/partest/scala/tools/partest/utils/PrintMgr.scala52
-rw-r--r--src/partest/scala/tools/partest/utils/Properties.scala18
-rw-r--r--test/disabled/pos/spec-traits.scala (renamed from test/files/pos/spec-traits.scala)0
-rw-r--r--test/disabled/pos/t1254/t1254.java (renamed from test/files/pos/t1254/t1254.java)0
-rw-r--r--test/disabled/run/stream_length.check1
-rw-r--r--test/disabled/run/stream_length.scala (renamed from test/files/run/stream_length.scala)0
-rw-r--r--test/disabled/run/t2946/Parsers.scala (renamed from test/files/run/t2946/Parsers.scala)0
-rw-r--r--test/disabled/run/t2946/ResponseCommon.scala (renamed from test/files/run/t2946/ResponseCommon.scala)0
-rw-r--r--test/disabled/run/t2946/Test.scala (renamed from test/files/run/t2946/Test.scala)0
-rw-r--r--test/disabled/scalacheck/redblack.scala (renamed from test/files/scalacheck/redblack.scala)0
-rw-r--r--test/files/continuations-neg/function0.check (renamed from test/continuations/neg/function0.check)0
-rw-r--r--test/files/continuations-neg/function0.scala (renamed from test/continuations/neg/function0.scala)0
-rw-r--r--test/files/continuations-neg/function2.check (renamed from test/continuations/neg/function2.check)0
-rw-r--r--test/files/continuations-neg/function2.scala (renamed from test/continuations/neg/function2.scala)0
-rw-r--r--test/files/continuations-neg/function3.check (renamed from test/continuations/neg/function3.check)0
-rw-r--r--test/files/continuations-neg/function3.scala (renamed from test/continuations/neg/function3.scala)0
-rw-r--r--test/files/continuations-neg/infer0.check (renamed from test/continuations/neg/infer0.check)0
-rw-r--r--test/files/continuations-neg/infer0.scala (renamed from test/continuations/neg/infer0.scala)0
-rw-r--r--test/files/continuations-neg/infer2.check (renamed from test/continuations/neg/infer2.check)0
-rw-r--r--test/files/continuations-neg/infer2.scala (renamed from test/continuations/neg/infer2.scala)0
-rw-r--r--test/files/continuations-neg/lazy.check (renamed from test/continuations/neg/lazy.check)0
-rw-r--r--test/files/continuations-neg/lazy.scala (renamed from test/continuations/neg/lazy.scala)0
-rw-r--r--test/files/continuations-neg/t1929.check (renamed from test/continuations/neg/t1929.check)0
-rw-r--r--test/files/continuations-neg/t1929.scala (renamed from test/continuations/neg/t1929.scala)0
-rw-r--r--test/files/continuations-neg/t2285.check (renamed from test/continuations/neg/t2285.check)0
-rw-r--r--test/files/continuations-neg/t2285.scala (renamed from test/continuations/neg/t2285.scala)0
-rw-r--r--test/files/continuations-neg/t2949.check (renamed from test/continuations/neg/t2949.check)0
-rw-r--r--test/files/continuations-neg/t2949.scala (renamed from test/continuations/neg/t2949.scala)0
-rw-r--r--test/files/continuations-neg/trycatch2.check (renamed from test/continuations/neg/trycatch2.check)0
-rw-r--r--test/files/continuations-neg/trycatch2.scala (renamed from test/continuations/neg/trycatch2.scala)0
-rwxr-xr-xtest/files/continuations-run/basics.check (renamed from test/continuations/run/basics.check)0
-rwxr-xr-xtest/files/continuations-run/basics.scala (renamed from test/continuations/run/basics.scala)0
-rw-r--r--test/files/continuations-run/function1.check (renamed from test/continuations/run/function1.check)0
-rw-r--r--test/files/continuations-run/function1.scala (renamed from test/continuations/run/function1.scala)0
-rw-r--r--test/files/continuations-run/function4.check (renamed from test/continuations/run/function4.check)0
-rw-r--r--test/files/continuations-run/function4.scala (renamed from test/continuations/run/function4.scala)0
-rw-r--r--test/files/continuations-run/function5.check (renamed from test/continuations/run/function5.check)0
-rw-r--r--test/files/continuations-run/function5.scala (renamed from test/continuations/run/function5.scala)0
-rw-r--r--test/files/continuations-run/function6.check (renamed from test/continuations/run/function6.check)0
-rw-r--r--test/files/continuations-run/function6.scala (renamed from test/continuations/run/function6.scala)0
-rw-r--r--test/files/continuations-run/ifelse0.check (renamed from test/continuations/run/ifelse0.check)0
-rw-r--r--test/files/continuations-run/ifelse0.scala (renamed from test/continuations/run/ifelse0.scala)0
-rw-r--r--test/files/continuations-run/ifelse1.check (renamed from test/continuations/run/ifelse1.check)0
-rw-r--r--test/files/continuations-run/ifelse1.scala (renamed from test/continuations/run/ifelse1.scala)0
-rw-r--r--test/files/continuations-run/ifelse2.check (renamed from test/continuations/run/ifelse2.check)0
-rw-r--r--test/files/continuations-run/ifelse2.scala (renamed from test/continuations/run/ifelse2.scala)0
-rw-r--r--test/files/continuations-run/ifelse3.check (renamed from test/continuations/run/ifelse3.check)0
-rw-r--r--test/files/continuations-run/ifelse3.scala (renamed from test/continuations/run/ifelse3.scala)0
-rw-r--r--test/files/continuations-run/infer1.scala (renamed from test/continuations/run/infer1.scala)0
-rw-r--r--test/files/continuations-run/match0.check (renamed from test/continuations/run/match0.check)0
-rw-r--r--test/files/continuations-run/match0.scala (renamed from test/continuations/run/match0.scala)0
-rw-r--r--test/files/continuations-run/match1.check (renamed from test/continuations/run/match1.check)0
-rw-r--r--test/files/continuations-run/match1.scala (renamed from test/continuations/run/match1.scala)0
-rw-r--r--test/files/continuations-run/match2.check (renamed from test/continuations/run/match2.check)0
-rw-r--r--test/files/continuations-run/match2.scala (renamed from test/continuations/run/match2.scala)0
-rw-r--r--test/files/continuations-run/t1807.check (renamed from test/continuations/run/t1807.check)0
-rw-r--r--test/files/continuations-run/t1807.scala (renamed from test/continuations/run/t1807.scala)0
-rw-r--r--test/files/continuations-run/t1808.scala (renamed from test/continuations/run/t1808.scala)0
-rw-r--r--test/files/continuations-run/t1820.scala (renamed from test/continuations/run/t1820.scala)0
-rw-r--r--test/files/continuations-run/t1821.check (renamed from test/continuations/run/t1821.check)0
-rw-r--r--test/files/continuations-run/t1821.scala (renamed from test/continuations/run/t1821.scala)0
-rw-r--r--test/files/continuations-run/t2864.check (renamed from test/continuations/run/t2864.check)0
-rw-r--r--test/files/continuations-run/t2864.scala (renamed from test/continuations/run/t2864.scala)0
-rw-r--r--test/files/continuations-run/t2934.check (renamed from test/continuations/run/t2934.check)0
-rw-r--r--test/files/continuations-run/t2934.scala (renamed from test/continuations/run/t2934.scala)0
-rw-r--r--test/files/continuations-run/t3199.check (renamed from test/continuations/run/t3199.check)0
-rw-r--r--test/files/continuations-run/t3199.scala (renamed from test/continuations/run/t3199.scala)0
-rw-r--r--test/files/continuations-run/t3199b.check (renamed from test/continuations/run/t3199b.check)0
-rw-r--r--test/files/continuations-run/t3199b.scala (renamed from test/continuations/run/t3199b.scala)0
-rw-r--r--test/files/continuations-run/t3223.check (renamed from test/continuations/run/t3223.check)0
-rw-r--r--test/files/continuations-run/t3223.scala (renamed from test/continuations/run/t3223.scala)0
-rw-r--r--test/files/continuations-run/t3225.check (renamed from test/continuations/run/t3225.check)0
-rw-r--r--test/files/continuations-run/t3225.scala (renamed from test/continuations/run/t3225.scala)0
-rw-r--r--test/files/continuations-run/trycatch0.check (renamed from test/continuations/run/trycatch0.check)0
-rw-r--r--test/files/continuations-run/trycatch0.scala (renamed from test/continuations/run/trycatch0.scala)0
-rw-r--r--test/files/continuations-run/trycatch1.check (renamed from test/continuations/run/trycatch1.check)0
-rw-r--r--test/files/continuations-run/trycatch1.scala (renamed from test/continuations/run/trycatch1.scala)0
-rw-r--r--test/files/continuations-run/while0.check (renamed from test/continuations/run/while0.check)0
-rw-r--r--test/files/continuations-run/while0.scala (renamed from test/continuations/run/while0.scala)0
-rw-r--r--test/files/continuations-run/while1.check (renamed from test/continuations/run/while1.check)0
-rw-r--r--test/files/continuations-run/while1.scala (renamed from test/continuations/run/while1.scala)0
-rw-r--r--test/files/continuations-run/while2.check (renamed from test/continuations/run/while2.check)0
-rw-r--r--test/files/continuations-run/while2.scala (renamed from test/continuations/run/while2.scala)0
-rw-r--r--test/files/jvm/genericNest.scala (renamed from test/files/jvm/genericNest/genericNest.scala)0
-rw-r--r--test/files/jvm/methvsfield.java11
-rw-r--r--test/files/jvm/methvsfield.scala4
-rw-r--r--test/files/jvm/nest.java38
-rw-r--r--test/files/jvm/nest.scala21
-rw-r--r--test/files/jvm/outerEnum.scala (renamed from test/files/jvm/outerEnum/outerEnum.scala)0
-rw-r--r--test/files/jvm/t1652.check2
-rw-r--r--test/files/lib/annotations.jar.desired.sha1 (renamed from test/files/jvm/lib/annotations.jar.desired.sha1)0
-rw-r--r--test/files/lib/enums.jar.desired.sha1 (renamed from test/files/jvm/outerEnum/enums.jar.desired.sha1)0
-rw-r--r--test/files/lib/genericNest.jar.desired.sha1 (renamed from test/files/jvm/genericNest/genericNest.jar.desired.sha1)0
-rw-r--r--test/files/lib/methvsfield.jar.desired.sha11
-rw-r--r--test/files/lib/nest.jar.desired.sha1 (renamed from test/files/jvm/lib/nest.jar.desired.sha1)0
-rw-r--r--test/files/lib/scalacheck.jar.desired.sha1 (renamed from lib/scalacheck.jar.desired.sha1)0
-rw-r--r--test/files/neg/bug414.scala2
-rw-r--r--test/files/neg/migration28.check3
-rw-r--r--test/files/res/bug687.check5
-rw-r--r--test/files/run/numbereq.scala2
-rw-r--r--test/files/run/programmatic-main.check2
-rwxr-xr-xtest/partest25
-rwxr-xr-xtest/partest.bat4
-rw-r--r--test/pending/jvm/t1464.check1
-rw-r--r--test/pending/pos/t0644.scala11
-rw-r--r--test/pending/run/bug2365/Test.scala35
-rw-r--r--test/pending/run/bug2365/bug2365.javaopts1
-rwxr-xr-xtest/pending/run/bug2365/run13
-rw-r--r--test/pending/run/subarray.check2
162 files changed, 4712 insertions, 163 deletions
diff --git a/build.xml b/build.xml
index 4df52769ec..5c2c8f0add 100644
--- a/build.xml
+++ b/build.xml
@@ -147,9 +147,7 @@ PROPERTIES
<property name="lib.dir" value="${basedir}/lib"/>
<property name="lib-ant.dir" value="${lib.dir}/ant"/>
<property name="src.dir" value="${basedir}/src"/>
- <property name="partest.rootdir" location="test" />
- <property name="partest.srcdir.default" value="files" />
- <property name="partest.options" value="" />
+ <property name="partest.dir" value="${basedir}/test"/>
<!-- Loads custom properties definitions -->
<property file="${basedir}/build.properties"/>
@@ -178,7 +176,7 @@ PROPERTIES
<property name="dists.dir" value="${basedir}/dists"/>
<property name="copyright.string" value="Copyright 2002-2010, LAMP/EPFL"/>
- <property name="partest.version.number" value="0.9.3"/>
+ <property name="partest.version.number" value="0.9.2"/>
<!-- These are NOT the flags used to run SuperSabbus, but the ones written
into the script runners created with scala.tools.ant.ScalaTool -->
@@ -186,11 +184,13 @@ PROPERTIES
<!-- if ANT_OPTS is already set by the environment, it will be unaltered,
but if it is unset it will take this default value. -->
- <property name="env.ANT_OPTS" value="-Xms128M -Xmx1024M -Xss1M -XX:MaxPermSize=128M" />
+ <property name="env.ANT_OPTS" value="-Xms512M -Xmx1536M -Xss1M -XX:MaxPermSize=128M" />
<!-- to find max heap usage: -Xaprof ; currently at 980M for locker.comp -->
+ <echo message="Using ANT_OPTS: ${env.ANT_OPTS}" />
- <property name="scalacfork.jvmargs" value="${env.ANT_OPTS}" />
- <echo message="Using scalacfork.jvmargs: ${scalacfork.jvmargs}" />
+ <property
+ name="scalacfork.jvmargs"
+ value="${env.ANT_OPTS}"/>
<!-- ===========================================================================
INITIALISATION
@@ -204,9 +204,7 @@ INITIALISATION
<property name="scalac.args.quickonly" value=""/>
<property name="scalac.args.all" value="${scalac.args} ${scalac.args.optimise}"/>
- <echo message="Using scalac.args.all: ${scalac.args.all}"/>
- <echo message="Using javac.args: ${javac.args}"/>
- <property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/>
+ <property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/>
<!-- Setting-up Ant contrib tasks -->
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib.dir}/ant/ant-contrib.jar"/>
<!-- This is the start time for the distribution -->
@@ -1498,54 +1496,68 @@ BOOTRAPING TEST AND TEST SUITE
<exclude name="misc/scala-devel/plugins/*.jar"/>
</same>
</target>
+
+ <!-- this target will run only those tests found in test/debug -->
+ <target name="test.debug">
+ <antcall target="test.suite">
+ <param name="partest.srcdir" value="debug" />
+ </antcall>
+ </target>
- <target name="test.suite" depends="pack.done">
- <partest classpathref="pack.classpath">
- <env key="PATH" path="${build-pack.dir}/bin:${env.PATH}" />
- <sysproperty key="partest.timeout" value="36000" />
- <sysproperty key="partest.test-warning" value="600" />
- <sysproperty key="partest.test-timeout" value="5400" />
- <sysproperty key="partest.srcdir" value="files" />
- <sysproperty key="partest.scalacopts" value="${scalac.args.all}" />
- <sysproperty key="partest.javacopts" value="${javac.args}" />
- <syspropertyset>
- <propertyref prefix="partest"/>
- </syspropertyset>
+ <target name="test.run" depends="pack.done">
+ <partest showlog="yes" erroronfailed="yes" javacmd="${java.home}/bin/java"
+ timeout="1200000"
+ scalacopts="${scalac.args.optimise}">
+ <compilationpath>
+ <path refid="pack.classpath"/>
+ <fileset dir="${partest.dir}/files/lib" includes="*.jar" />
+ </compilationpath>
+ <runtests dir="${partest.dir}/files">
+ <include name="run/**/*.scala"/>
+ <include name="jvm/**/*.scala"/>
+ </runtests>
</partest>
</target>
- <target name="test.continuations.suite" depends="pack.done">
- <partest classpathref="pack.classpath">
- <env key="PATH" path="${build-pack.dir}/bin:${env.PATH}" />
- <sysproperty key="partest.srcdir" value="continuations" />
- <sysproperty key="partest.scalacopts" value="${scalac.args.optimise} -Xpluginsdir ${build-quick.dir}/misc/scala-devel/plugins -Xplugin-require:continuations -P:continuations:enable" />
- <sysproperty key="partest.runsets" value="neg run" />
- <syspropertyset>
- <propertyref prefix="partest"/>
- </syspropertyset>
+ <target name="test.suite" depends="pack.done">
+ <property name="partest.srcdir" value="files" />
+ <partest showlog="yes" erroronfailed="yes" javacmd="${java.home}/bin/java"
+ timeout="2400000"
+ srcdir="${partest.srcdir}"
+ scalacopts="${scalac.args.optimise}">
+ <compilationpath>
+ <path refid="pack.classpath"/>
+ <pathelement location="${pack.dir}/lib/scala-swing.jar"/>
+ <fileset dir="${partest.dir}/files/lib" includes="*.jar" />
+ </compilationpath>
+ <postests dir="${partest.dir}/${partest.srcdir}/pos" includes="*.scala"/>
+ <negtests dir="${partest.dir}/${partest.srcdir}/neg" includes="*.scala"/>
+ <runtests dir="${partest.dir}/${partest.srcdir}">
+ <include name="run/**/*.scala"/>
+ </runtests>
+ <jvmtests dir="${partest.dir}/${partest.srcdir}/jvm" includes="*.scala"/>
+ <scalachecktests dir="${partest.dir}/${partest.srcdir}/scalacheck" includes="**/*.scala"/>
+ <residenttests dir="${partest.dir}/${partest.srcdir}/res" includes="*.res"/>
+ <buildmanagertests dir="${partest.dir}/${partest.srcdir}/buildmanager" includes="*"/>
+ <scalaptests dir="${partest.dir}/${partest.srcdir}/scalap" includes="**/*.scala"/>
+ <!-- <scripttests dir="${partest.dir}/${partest.srcdir}/script" includes="*.scala"/> -->
</partest>
</target>
-
- <target name="test.partest-opt" depends="pack.done">
- <antcall target="test.partest">
- <param name="scalac.args.optimise" value="-optimise"/>
- </antcall>
- </target>
- <target name="test.partest" depends="pack.done">
- <partest classpathref="pack.classpath">
- <env key="PATH" path="${build-pack.dir}/bin:${env.PATH}" />
- <sysproperty key="partest.srcdir" value="partest-tests" />
- <sysproperty key="partest.scalacopts" value="${scalac.args.all}" />
- <sysproperty key="partest.javacopts" value="${javac.args}" />
- <sysproperty key="partest.verbose" value="true" />
- <sysproperty key="partest.trace" value="true" />
- <sysproperty key="partest.debug" value="true" />
- <sysproperty key="partest.test-timeout" value="25" />
- <sysproperty key="partest.scalacopts" value="${scalac.args.optimise}" />
- <syspropertyset>
- <propertyref prefix="partest"/>
- </syspropertyset>
+ <target name="test.continuations.suite" depends="pack.done">
+ <property name="partest.srcdir" value="files" />
+ <partest showlog="yes" erroronfailed="yes" javacmd="${java.home}/bin/java"
+ timeout="2400000"
+ srcdir="${partest.srcdir}"
+ scalacopts="${scalac.args.optimise} -Xpluginsdir ${build-quick.dir}/misc/scala-devel/plugins -Xplugin-require:continuations -P:continuations:enable">
+ <compilationpath>
+ <path refid="pack.classpath"/>
+ <fileset dir="${partest.dir}/files/lib" includes="*.jar" />
+ </compilationpath>
+ <negtests dir="${partest.dir}/${partest.srcdir}/continuations-neg" includes="*.scala"/>
+ <runtests dir="${partest.dir}/${partest.srcdir}">
+ <include name="continuations-run/**/*.scala"/>
+ </runtests>
</partest>
</target>
@@ -1767,7 +1779,7 @@ POSITIONS
<target name="test.positions" depends="quick.comp">
<antcall target="test.positions.tests.sub" inheritRefs="true">
- <param name="test.tests.srcs" value="${partest.rootdir}/${partest.srcdir.default}/positions"/>
+ <param name="test.tests.srcs" value="${partest.dir}/files/positions"/>
</antcall>
<antcall target="test.positions.sub" inheritRefs="true">
<param name="test.srcs" value="${src.dir}/compiler"/>
@@ -1791,13 +1803,13 @@ POSITIONS
<param name="test.srcs" value="${src.dir}/scalap"/>
</antcall>
<antcall target="test.positions.tests.sub" inheritRefs="true">
- <param name="test.tests.srcs" value="${partest.rootdir}/${partest.srcdir.default}/pos"/>
+ <param name="test.tests.srcs" value="${partest.dir}/files/pos"/>
</antcall>
<antcall target="test.positions.tests.sub" inheritRefs="true">
- <param name="test.tests.srcs" value="${partest.rootdir}/${partest.srcdir.default}/run"/>
+ <param name="test.tests.srcs" value="${partest.dir}/files/run"/>
</antcall>
<antcall target="test.positions.tests.sub" inheritRefs="true">
- <param name="test.tests.srcs" value="${partest.rootdir}/${partest.srcdir.default}/neg"/>
+ <param name="test.tests.srcs" value="${partest.dir}/files/neg"/>
</antcall>
</target>
diff --git a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala b/src/compiler/scala/tools/nsc/util/CommandLineParser.scala
new file mode 100644
index 0000000000..16d79d5776
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/CommandLineParser.scala
@@ -0,0 +1,145 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package util
+
+import scala.util.parsing.combinator._
+import scala.util.parsing.input.{ Reader }
+import scala.util.parsing.input.CharArrayReader.EofCh
+import scala.collection.mutable.ListBuffer
+
+/** A simple command line parser to replace the several different
+ * simple ones spread around trunk.
+ *
+ * XXX Note this has been completely obsolesced by scala.tools.cmd.
+ * I checked it back in as part of rolling partest back a month
+ * rather than go down the rabbit hole of unravelling dependencies.
+ */
+
+trait ParserUtil extends Parsers {
+ class ParserPlus[+T](underlying: Parser[T]) {
+ def !~>[U](p: => Parser[U]): Parser[U] = (underlying ~! p) ^^ { case a~b => b }
+ def <~![U](p: => Parser[U]): Parser[T] = (underlying ~! p) ^^ { case a~b => a }
+ }
+ protected implicit def parser2parserPlus[T](p: Parser[T]): ParserPlus[T] = new ParserPlus(p)
+}
+
+case class CommandLine(
+ args: List[String],
+ unaryArguments: List[String],
+ binaryArguments: List[String]
+) {
+ def this(args: List[String]) = this(args, Nil, Nil)
+ def this(args: Array[String]) = this(args.toList, Nil, Nil)
+ def this(line: String) = this(CommandLineParser tokenize line, Nil, Nil)
+
+ def withUnaryArgs(xs: List[String]) = copy(unaryArguments = xs)
+ def withBinaryArgs(xs: List[String]) = copy(binaryArguments = xs)
+
+ def originalArgs = args
+ def assumeBinary = true
+ def enforceArity = true
+ def onlyKnownOptions = false
+
+ val Terminator = "--"
+ val ValueForUnaryOption = "true" // so if --opt is given, x(--opt) = true
+
+ def mapForUnary(opt: String) = Map(opt -> ValueForUnaryOption)
+ def errorFn(msg: String) = println(msg)
+
+ /** argMap is option -> argument (or "" if it is a unary argument)
+ * residualArgs are what is left after removing the options and their args.
+ */
+ lazy val (argMap, residualArgs) = {
+ val residualBuffer = new ListBuffer[String]
+
+ def stripQuotes(s: String) = {
+ def isQuotedBy(c: Char) = s.length > 0 && s.head == c && s.last == c
+ if (List('"', '\'') exists isQuotedBy) s.tail.init else s
+ }
+
+ def isValidOption(s: String) = !onlyKnownOptions || (unaryArguments contains s) || (binaryArguments contains s)
+ def isOption(s: String) = (s startsWith "-") && (isValidOption(s) || { unknownOption(s) ; false })
+ def isUnary(s: String) = isOption(s) && (unaryArguments contains s)
+ def isBinary(s: String) = isOption(s) && !isUnary(s) && (assumeBinary || (binaryArguments contains s))
+
+ def unknownOption(opt: String) =
+ errorFn("Option '%s' not recognized.".format(opt))
+ def missingArg(opt: String, what: String) =
+ errorFn("Option '%s' requires argument, found %s instead.".format(opt, what))
+
+ def loop(args: List[String]): Map[String, String] = {
+ def residual(xs: List[String]) = { residualBuffer ++= xs ; Map[String, String]() }
+ if (args.isEmpty) return Map()
+ val hd :: rest = args
+ if (rest.isEmpty) {
+ if (isBinary(hd) && enforceArity)
+ missingArg(hd, "EOF")
+
+ if (isOption(hd)) mapForUnary(hd) else residual(args)
+ }
+ else
+ if (hd == Terminator) residual(rest)
+ else {
+ val hd1 :: hd2 :: rest = args
+
+ if (hd2 == Terminator) mapForUnary(hd1) ++ residual(rest)
+ else if (isUnary(hd1)) mapForUnary(hd1) ++ loop(hd2 :: rest)
+ else if (isBinary(hd1)) {
+ // Disabling this check so
+ // --scalacopts "-verbose" works. We can't tell if it's quoted,
+ // the shell does us in.
+ //
+ // if (isOption(hd2) && enforceArity)
+ // missingArg(hd1, hd2)
+
+ Map(hd1 -> hd2) ++ loop(rest)
+ }
+ else { residual(List(hd1)) ++ loop(hd2 :: rest) }
+ }
+ }
+
+ (loop(args), residualBuffer map stripQuotes toList)
+ }
+
+ def isSet(arg: String) = args contains arg
+ def get(arg: String) = argMap get arg
+ def getOrElse(arg: String, orElse: => String) = if (isSet(arg)) apply(arg) else orElse
+ def apply(arg: String) = argMap(arg)
+
+ override def toString() = "CommandLine(\n%s)\n" format (args map (" " + _ + "\n") mkString)
+}
+
+object CommandLineParser extends RegexParsers with ParserUtil {
+ override def skipWhitespace = false
+
+ def elemExcept(xs: Elem*): Parser[Elem] = elem("elemExcept", x => x != EofCh && !(xs contains x))
+ def elemOf(xs: Elem*): Parser[Elem] = elem("elemOf", xs contains _)
+ def escaped(ch: Char): Parser[String] = "\\" + ch
+ def mkQuoted(ch: Char): Parser[String] = (
+ elem(ch) !~> rep(escaped(ch) | elemExcept(ch)) <~ ch ^^ (_.mkString)
+ | failure("Unmatched %s in input." format ch)
+ )
+
+ /** Apparently windows can't deal with the quotes sticking around. */
+ lazy val squoted: Parser[String] = mkQuoted('\'') // ^^ (x => "'%s'" format x)
+ lazy val dquoted: Parser[String] = mkQuoted('"') // ^^ (x => "\"" + x + "\"")
+ lazy val token: Parser[String] = """\S+""".r
+
+ lazy val argument: Parser[String] = squoted | dquoted | token
+ lazy val commandLine: Parser[List[String]] = phrase(repsep(argument, whiteSpace))
+
+ class ParseException(msg: String) extends RuntimeException(msg)
+
+ def tokenize(line: String): List[String] = tokenize(line, x => throw new ParseException(x))
+ def tokenize(line: String, errorFn: String => Unit): List[String] = {
+ parse(commandLine, line.trim) match {
+ case Success(args, _) => args
+ case NoSuccess(msg, rest) => errorFn(msg) ; Nil
+ }
+ }
+ def apply(line: String) = new CommandLine(tokenize(line))
+}
diff --git a/src/partest-alternative/README b/src/partest-alternative/README
new file mode 100644
index 0000000000..c7673fe2f8
--- /dev/null
+++ b/src/partest-alternative/README
@@ -0,0 +1,50 @@
+If you're looking for something to read, I suggest running ../test/partest
+with no arguments, which at this moment prints this:
+
+Usage: partest [<options>] [<test> <test> ...]
+ <test>: a path to a test designator, typically a .scala file or a directory.
+ Examples: files/pos/test1.scala, files/res/bug785
+
+ Test categories:
+ --all run all tests (default, unless no options given)
+ --pos Compile files that are expected to build
+ --neg Compile files that are expected to fail
+ --run Test JVM backend
+ --jvm Test JVM backend
+ --res Run resident compiler scenarii
+ --buildmanager Run Build Manager scenarii
+ --scalacheck Run Scalacheck tests
+ --script Run script files
+ --shootout Run shootout tests
+ --scalap Run scalap tests
+
+ Test "smart" categories:
+ --grep run all tests with a source file containing <expr>
+ --failed run all tests which failed on the last run
+
+ Specifying paths and additional flags, ~ means repository root:
+ --rootdir path from ~ to partest (default: test)
+ --builddir path from ~ to test build (default: build/pack)
+ --srcdir path from --rootdir to sources (default: files)
+ --javaopts flags to java on all runs (overrides JAVA_OPTS)
+ --scalacopts flags to scalac on all tests (overrides SCALAC_OPTS)
+ --pack alias for --builddir build/pack
+ --quick alias for --builddir build/quick
+
+ Options influencing output:
+ --trace show the individual steps taken by each test
+ --show-diff show diff between log and check file
+ --show-log show log on failures
+ --dry-run do not run tests, only show their traces.
+ --terse be less verbose (almost silent except for failures)
+ --verbose be more verbose (additive with --trace)
+ --debug maximum debugging output
+ --ansi print output in color
+
+ Other options:
+ --timeout Timeout in seconds
+ --cleanup delete all stale files and dirs before run
+ --nocleanup do not delete any logfiles or object dirs
+ --stats collect and print statistics about the tests
+ --validate examine test filesystem for inconsistencies
+ --version print version
diff --git a/src/partest/scala/tools/partest/Actions.scala b/src/partest-alternative/scala/tools/partest/Actions.scala
index cb60152b71..cb60152b71 100644
--- a/src/partest/scala/tools/partest/Actions.scala
+++ b/src/partest-alternative/scala/tools/partest/Actions.scala
diff --git a/src/partest/scala/tools/partest/Alarms.scala b/src/partest-alternative/scala/tools/partest/Alarms.scala
index f38d8d6268..f38d8d6268 100644
--- a/src/partest/scala/tools/partest/Alarms.scala
+++ b/src/partest-alternative/scala/tools/partest/Alarms.scala
diff --git a/src/partest/scala/tools/partest/BuildContributors.scala b/src/partest-alternative/scala/tools/partest/BuildContributors.scala
index 64c7e07bc3..64c7e07bc3 100644
--- a/src/partest/scala/tools/partest/BuildContributors.scala
+++ b/src/partest-alternative/scala/tools/partest/BuildContributors.scala
diff --git a/src/partest/scala/tools/partest/Categories.scala b/src/partest-alternative/scala/tools/partest/Categories.scala
index 172cca74b4..172cca74b4 100644
--- a/src/partest/scala/tools/partest/Categories.scala
+++ b/src/partest-alternative/scala/tools/partest/Categories.scala
diff --git a/src/partest/scala/tools/partest/Compilable.scala b/src/partest-alternative/scala/tools/partest/Compilable.scala
index ddaa277842..ddaa277842 100644
--- a/src/partest/scala/tools/partest/Compilable.scala
+++ b/src/partest-alternative/scala/tools/partest/Compilable.scala
diff --git a/src/partest/scala/tools/partest/Config.scala b/src/partest-alternative/scala/tools/partest/Config.scala
index 288a3034e9..288a3034e9 100644
--- a/src/partest/scala/tools/partest/Config.scala
+++ b/src/partest-alternative/scala/tools/partest/Config.scala
diff --git a/src/partest/scala/tools/partest/Dispatcher.scala b/src/partest-alternative/scala/tools/partest/Dispatcher.scala
index 2a9d99ab60..2a9d99ab60 100644
--- a/src/partest/scala/tools/partest/Dispatcher.scala
+++ b/src/partest-alternative/scala/tools/partest/Dispatcher.scala
diff --git a/src/partest/scala/tools/partest/Entities.scala b/src/partest-alternative/scala/tools/partest/Entities.scala
index bea505b594..bea505b594 100644
--- a/src/partest/scala/tools/partest/Entities.scala
+++ b/src/partest-alternative/scala/tools/partest/Entities.scala
diff --git a/src/partest/scala/tools/partest/Housekeeping.scala b/src/partest-alternative/scala/tools/partest/Housekeeping.scala
index a624ca8adb..a624ca8adb 100644
--- a/src/partest/scala/tools/partest/Housekeeping.scala
+++ b/src/partest-alternative/scala/tools/partest/Housekeeping.scala
diff --git a/src/partest/scala/tools/partest/Partest.scala b/src/partest-alternative/scala/tools/partest/Partest.scala
index b3fe9a98ef..b3fe9a98ef 100644
--- a/src/partest/scala/tools/partest/Partest.scala
+++ b/src/partest-alternative/scala/tools/partest/Partest.scala
diff --git a/src/partest/scala/tools/partest/PartestSpec.scala b/src/partest-alternative/scala/tools/partest/PartestSpec.scala
index c25119b3af..c25119b3af 100644
--- a/src/partest/scala/tools/partest/PartestSpec.scala
+++ b/src/partest-alternative/scala/tools/partest/PartestSpec.scala
diff --git a/src/partest/scala/tools/partest/Properties.scala b/src/partest-alternative/scala/tools/partest/Properties.scala
index 4eeb0359ec..4eeb0359ec 100644
--- a/src/partest/scala/tools/partest/Properties.scala
+++ b/src/partest-alternative/scala/tools/partest/Properties.scala
diff --git a/src/partest/scala/tools/partest/Results.scala b/src/partest-alternative/scala/tools/partest/Results.scala
index 5d0e300136..5d0e300136 100644
--- a/src/partest/scala/tools/partest/Results.scala
+++ b/src/partest-alternative/scala/tools/partest/Results.scala
diff --git a/src/partest/scala/tools/partest/Runner.scala b/src/partest-alternative/scala/tools/partest/Runner.scala
index 1a28e60896..1a28e60896 100644
--- a/src/partest/scala/tools/partest/Runner.scala
+++ b/src/partest-alternative/scala/tools/partest/Runner.scala
diff --git a/src/partest/scala/tools/partest/Statistics.scala b/src/partest-alternative/scala/tools/partest/Statistics.scala
index 2ea3c6e8f0..2ea3c6e8f0 100644
--- a/src/partest/scala/tools/partest/Statistics.scala
+++ b/src/partest-alternative/scala/tools/partest/Statistics.scala
diff --git a/src/partest/scala/tools/partest/Universe.scala b/src/partest-alternative/scala/tools/partest/Universe.scala
index 942fc1a8be..942fc1a8be 100644
--- a/src/partest/scala/tools/partest/Universe.scala
+++ b/src/partest-alternative/scala/tools/partest/Universe.scala
diff --git a/src/partest/scala/tools/partest/ant/JavaTask.scala b/src/partest-alternative/scala/tools/partest/ant/JavaTask.scala
index 6740554dd8..6740554dd8 100644
--- a/src/partest/scala/tools/partest/ant/JavaTask.scala
+++ b/src/partest-alternative/scala/tools/partest/ant/JavaTask.scala
diff --git a/src/partest-alternative/scala/tools/partest/antlib.xml b/src/partest-alternative/scala/tools/partest/antlib.xml
new file mode 100644
index 0000000000..af36f11368
--- /dev/null
+++ b/src/partest-alternative/scala/tools/partest/antlib.xml
@@ -0,0 +1,3 @@
+<antlib>
+ <taskdef name="partest" classname="scala.tools.partest.ant.JavaTask"/>
+</antlib>
diff --git a/src/partest/scala/tools/partest/category/AllCategories.scala b/src/partest-alternative/scala/tools/partest/category/AllCategories.scala
index 953f80324b..953f80324b 100644
--- a/src/partest/scala/tools/partest/category/AllCategories.scala
+++ b/src/partest-alternative/scala/tools/partest/category/AllCategories.scala
diff --git a/src/partest/scala/tools/partest/category/Analysis.scala b/src/partest-alternative/scala/tools/partest/category/Analysis.scala
index 2c6c208ee5..2c6c208ee5 100644
--- a/src/partest/scala/tools/partest/category/Analysis.scala
+++ b/src/partest-alternative/scala/tools/partest/category/Analysis.scala
diff --git a/src/partest/scala/tools/partest/category/Compiler.scala b/src/partest-alternative/scala/tools/partest/category/Compiler.scala
index 49775d5031..49775d5031 100644
--- a/src/partest/scala/tools/partest/category/Compiler.scala
+++ b/src/partest-alternative/scala/tools/partest/category/Compiler.scala
diff --git a/src/partest/scala/tools/partest/category/Runner.scala b/src/partest-alternative/scala/tools/partest/category/Runner.scala
index 10bf5794a9..10bf5794a9 100644
--- a/src/partest/scala/tools/partest/category/Runner.scala
+++ b/src/partest-alternative/scala/tools/partest/category/Runner.scala
diff --git a/src/partest/scala/tools/partest/io/ANSIWriter.scala b/src/partest-alternative/scala/tools/partest/io/ANSIWriter.scala
index 0ddcd97a5f..0ddcd97a5f 100644
--- a/src/partest/scala/tools/partest/io/ANSIWriter.scala
+++ b/src/partest-alternative/scala/tools/partest/io/ANSIWriter.scala
diff --git a/src/partest/scala/tools/partest/io/Diff.java b/src/partest-alternative/scala/tools/partest/io/Diff.java
index c7a3d42f30..c7a3d42f30 100644
--- a/src/partest/scala/tools/partest/io/Diff.java
+++ b/src/partest-alternative/scala/tools/partest/io/Diff.java
diff --git a/src/partest/scala/tools/partest/io/DiffPrint.java b/src/partest-alternative/scala/tools/partest/io/DiffPrint.java
index 2b2ad93ec7..2b2ad93ec7 100644
--- a/src/partest/scala/tools/partest/io/DiffPrint.java
+++ b/src/partest-alternative/scala/tools/partest/io/DiffPrint.java
diff --git a/src/partest/scala/tools/partest/io/JUnitReport.scala b/src/partest-alternative/scala/tools/partest/io/JUnitReport.scala
index 63ae200020..63ae200020 100644
--- a/src/partest/scala/tools/partest/io/JUnitReport.scala
+++ b/src/partest-alternative/scala/tools/partest/io/JUnitReport.scala
diff --git a/src/partest/scala/tools/partest/io/Logging.scala b/src/partest-alternative/scala/tools/partest/io/Logging.scala
index 52239ffb2c..52239ffb2c 100644
--- a/src/partest/scala/tools/partest/io/Logging.scala
+++ b/src/partest-alternative/scala/tools/partest/io/Logging.scala
diff --git a/src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala b/src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala
new file mode 100644
index 0000000000..8cebcf1685
--- /dev/null
+++ b/src/partest-alternative/scala/tools/partest/nest/StreamAppender.scala
@@ -0,0 +1,94 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io._
+
+object StreamAppender {
+ def wrapIn(in: InputStream): BufferedReader = new BufferedReader(new InputStreamReader(in))
+ def wrapIn(reader: Reader): BufferedReader = new BufferedReader(reader)
+ def wrapIn(str: String): BufferedReader = new BufferedReader(new StringReader(str))
+
+ def wrapOut(out: OutputStream): PrintWriter = new PrintWriter(new OutputStreamWriter(out), true)
+ def wrapOut(writer: Writer): PrintWriter = new PrintWriter(writer, true)
+ def wrapOut(): PrintWriter = wrapOut(new StringWriter)
+
+ def apply(reader: BufferedReader, writer: Writer): StreamAppender =
+ new StreamAppender(reader, wrapOut(writer))
+
+ def apply(reader: Reader, writer: Writer): StreamAppender =
+ apply(wrapIn(reader), writer)
+
+ def apply(in: InputStream, writer: Writer): StreamAppender =
+ apply(wrapIn(in), writer)
+
+ def apply(str: String, writer: Writer): StreamAppender =
+ apply(wrapIn(str), writer)
+
+ def apply(in: File, out: File): StreamAppender =
+ apply(new FileReader(in), new FileWriter(out))
+
+ def appendToString(in1: InputStream, in2: InputStream): String = {
+ val swriter1 = new StringWriter
+ val swriter2 = new StringWriter
+ val app1 = StreamAppender(wrapIn(in1), swriter1)
+ val app2 = StreamAppender(wrapIn(in2), swriter2)
+
+ val async = new Thread(app2)
+ async.start()
+ app1.run()
+ async.join()
+ swriter1.toString + swriter2.toString
+ }
+/*
+ private def inParallel(t1: Runnable, t2: Runnable, t3: Runnable) {
+ val thr1 = new Thread(t1)
+ val thr2 = new Thread(t2)
+ thr1.start()
+ thr2.start()
+ t3.run()
+ thr1.join()
+ thr2.join()
+ }
+*/
+ private def inParallel(t1: Runnable, t2: Runnable) {
+ val thr = new Thread(t2)
+ thr.start()
+ t1.run()
+ thr.join()
+ }
+
+ def concat(in: InputStream, err: InputStream, out: OutputStream) = new Runnable {
+ override def run() {
+ val outWriter = wrapOut(out)
+ val inApp = StreamAppender(in, outWriter)
+
+ val errStringWriter = new StringWriter
+ val errApp = StreamAppender(wrapIn(err), errStringWriter)
+
+ inParallel(inApp, errApp)
+
+ // append error string to out
+ StreamAppender(errStringWriter.toString, outWriter).run()
+ }
+ }
+}
+
+class StreamAppender(reader: BufferedReader, writer: PrintWriter) extends Runnable {
+ override def run() = runAndMap(identity)
+ private def lines() = Iterator continually reader.readLine() takeWhile (_ != null)
+ def closeAll() = {
+ reader.close()
+ writer.close()
+ }
+
+ def runAndMap(f: String => String) =
+ try lines() map f foreach (writer println _)
+ catch { case e: IOException => e.printStackTrace() }
+}
diff --git a/src/partest-alternative/scala/tools/partest/package.scala b/src/partest-alternative/scala/tools/partest/package.scala
new file mode 100644
index 0000000000..f6d216e379
--- /dev/null
+++ b/src/partest-alternative/scala/tools/partest/package.scala
@@ -0,0 +1,45 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ */
+
+package scala.tools
+
+import nsc.io.{ File, Path, Process, Directory }
+import java.nio.charset.CharacterCodingException
+
+package object partest {
+ /** The CharacterCodingExceptions are thrown at least on windows trying
+ * to read a file like script/utf-8.scala
+ */
+ private[partest] def safeSlurp(f: File) =
+ try if (f.exists) f.slurp() else ""
+ catch { case _: CharacterCodingException => "" }
+
+ private[partest] def safeLines(f: File) = safeSlurp(f) split """\r\n|\r|\n""" toList
+ private[partest] def safeArgs(f: File) = toArgs(safeSlurp(f))
+ private[partest] def isJava(f: Path) = f.isFile && (f hasExtension "java")
+ private[partest] def isScala(f: Path) = f.isFile && (f hasExtension "scala")
+ private[partest] def isJavaOrScala(f: Path) = isJava(f) || isScala(f)
+
+ private[partest] def toArgs(line: String) = cmd toArgs line
+ private[partest] def fromArgs(args: List[String]) = cmd fromArgs args
+
+ /** Strings, argument lists, etc. */
+
+ private[partest] def fromAnyArgs(args: List[Any]) = args mkString " " // separate to avoid accidents
+ private[partest] def toStringTrunc(x: Any, max: Int = 240) = {
+ val s = x.toString
+ if (s.length < max) s
+ else (s take max) + " [...]"
+ }
+ private[partest] def setProp(k: String, v: String) = scala.util.Properties.setProp(k, v)
+
+ /** Pretty self explanatory. */
+ def printAndExit(msg: String): Unit = {
+ println(msg)
+ exit(1)
+ }
+
+ /** Apply a function and return the passed value */
+ def returning[T](x: T)(f: T => Unit): T = { f(x) ; x }
+} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/util/package.scala b/src/partest-alternative/scala/tools/partest/util/package.scala
index bc5470ba5d..bc5470ba5d 100644
--- a/src/partest/scala/tools/partest/util/package.scala
+++ b/src/partest-alternative/scala/tools/partest/util/package.scala
diff --git a/src/partest/README b/src/partest/README
index c7673fe2f8..81876fc810 100644
--- a/src/partest/README
+++ b/src/partest/README
@@ -1,50 +1,32 @@
-If you're looking for something to read, I suggest running ../test/partest
-with no arguments, which at this moment prints this:
+How partest choses the compiler / library:
-Usage: partest [<options>] [<test> <test> ...]
- <test>: a path to a test designator, typically a .scala file or a directory.
- Examples: files/pos/test1.scala, files/res/bug785
+ * ''-Dpartest.build=build/four-pack'' -> will search for libraries in
+ ''lib'' directory of given path
+ * ''--pack'' -> will set ''partest.build=build/pack'', and run all tests.
+ add ''--[kind]'' to run a selected set of tests.
+ * auto detection:
+ - partest.build property -> ''bin'' / ''lib'' directories
+ - distribution (''dists/latest'')
+ - supersabbus pack (''build/pack'')
+ - sabbus quick (''build/quick'')
+ - installed dist (test files in ''misc/scala-test/files'')
- Test categories:
- --all run all tests (default, unless no options given)
- --pos Compile files that are expected to build
- --neg Compile files that are expected to fail
- --run Test JVM backend
- --jvm Test JVM backend
- --res Run resident compiler scenarii
- --buildmanager Run Build Manager scenarii
- --scalacheck Run Scalacheck tests
- --script Run script files
- --shootout Run shootout tests
- --scalap Run scalap tests
+How partest choses test files: the test files must be accessible from
+the directory on which partest is run. So the test files must be either
+at:
+ * ./test/files
+ * ./files (cwd is "test")
+ * ./misc/scala-test/files (installed scala distribution)
- Test "smart" categories:
- --grep run all tests with a source file containing <expr>
- --failed run all tests which failed on the last run
-
- Specifying paths and additional flags, ~ means repository root:
- --rootdir path from ~ to partest (default: test)
- --builddir path from ~ to test build (default: build/pack)
- --srcdir path from --rootdir to sources (default: files)
- --javaopts flags to java on all runs (overrides JAVA_OPTS)
- --scalacopts flags to scalac on all tests (overrides SCALAC_OPTS)
- --pack alias for --builddir build/pack
- --quick alias for --builddir build/quick
-
- Options influencing output:
- --trace show the individual steps taken by each test
- --show-diff show diff between log and check file
- --show-log show log on failures
- --dry-run do not run tests, only show their traces.
- --terse be less verbose (almost silent except for failures)
- --verbose be more verbose (additive with --trace)
- --debug maximum debugging output
- --ansi print output in color
-
- Other options:
- --timeout Timeout in seconds
- --cleanup delete all stale files and dirs before run
- --nocleanup do not delete any logfiles or object dirs
- --stats collect and print statistics about the tests
- --validate examine test filesystem for inconsistencies
- --version print version
+Other arguments:
+ * --pos next files test a compilation success
+ * --neg next files test a compilation failure
+ * --run next files test the interpreter and all backends
+ * --jvm next files test the JVM backend
+ * --res next files test the resident compiler
+ * --buildmanager next files test the build manager
+ * --shootout next files are shootout tests
+ * --script next files test the script runner
+ * ''-Dpartest.scalac_opts=...'' -> add compiler options
+ * ''--verbose'' -> print verbose messages
+ * ''-Dpartest.debug=true'' -> print debug messages
diff --git a/src/partest/scala/tools/partest/PartestDefaults.scala b/src/partest/scala/tools/partest/PartestDefaults.scala
new file mode 100644
index 0000000000..139c54dedd
--- /dev/null
+++ b/src/partest/scala/tools/partest/PartestDefaults.scala
@@ -0,0 +1,30 @@
+package scala.tools
+package partest
+
+import nsc.io.{ File, Path, Process, Directory }
+import util.{ PathResolver }
+import nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
+
+object PartestDefaults {
+ import nsc.Properties._
+ private def wrapAccessControl[T](body: => Option[T]): Option[T] =
+ try body catch { case _: java.security.AccessControlException => None }
+
+ def testRootName = propOrNone("partest.root")
+ def srcDirName = propOrElse("partest.srcdir", "files")
+ def testRootDir = testRootName map (x => Directory(x))
+
+ def classPath = PathResolver.Environment.javaUserClassPath // XXX
+
+ def javaCmd = propOrElse("partest.javacmd", "java")
+ def javacCmd = propOrElse("partest.javac_cmd", "javac")
+ def javaOpts = propOrElse("partest.java_opts", "")
+ def scalacOpts = propOrElse("partest.scalac_opts", "-deprecation")
+
+ def testBuild = propOrNone("partest.build")
+ def errorCount = propOrElse("partest.errors", "0").toInt
+ def numActors = propOrElse("partest.actors", "8").toInt
+ def poolSize = wrapAccessControl(propOrNone("actors.corePoolSize"))
+
+ def timeout = "1200000"
+}
diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala
new file mode 100644
index 0000000000..230a6f73ec
--- /dev/null
+++ b/src/partest/scala/tools/partest/PartestTask.scala
@@ -0,0 +1,287 @@
+/* __ *\
+** ________ ___ / / ___ Scala Parallel Testing **
+** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+package scala.tools
+package partest
+
+import scala.actors.Actor._
+import scala.util.Properties.setProp
+import scala.tools.nsc.io.{ Directory, Path => SPath }
+import nsc.Settings
+import nsc.util.ClassPath
+import util.PathResolver
+import scala.tools.ant.sabbus.CompilationPathProperty
+
+import java.io.File
+import java.net.URLClassLoader
+import java.lang.reflect.Method
+
+import org.apache.tools.ant.Task
+import org.apache.tools.ant.types.{Path, Reference, FileSet}
+
+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 addConfiguredBuildManagerTests(input: FileSet) {
+ buildManagerFiles = 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 setSrcDir(input: String) {
+ srcDir = Some(input)
+ }
+
+ def setClasspath(input: Path) {
+ if (classpath.isEmpty)
+ classpath = Some(input)
+ else
+ classpath.get.append(input)
+ }
+
+ def createClasspath(): Path = {
+ if (classpath.isEmpty) classpath = Some(new Path(getProject()))
+ classpath.get.createPath()
+ }
+
+ 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
+ }
+
+ def setJavaCmd(input: File) {
+ javacmd = Some(input)
+ }
+
+ def setJavacCmd(input: File) {
+ javaccmd = Some(input)
+ }
+
+ def setScalacOpts(opts: String) {
+ scalacOpts = Some(opts)
+ }
+
+ def setTimeout(delay: String) {
+ timeout = Some(delay)
+ }
+
+ def setDebug(input: Boolean) {
+ debug = input
+ }
+
+ def setJUnitReportDir(input: File) {
+ 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 runFailed: 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 buildManagerFiles: 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 errorOnFailed: Boolean = false
+ private var scalacOpts: Option[String] = 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 ".")
+
+ val fileTests = getFiles(Some(fs)) filterNot (x => shouldExclude(x.getName))
+ val dirTests: Iterator[SPath] = fileSetToDir(fs).dirs filterNot (x => shouldExclude(x.name))
+ val dirResult = dirTests.toList.toArray map (_.jfile)
+
+ dirResult ++ fileTests
+ }
+
+ private def getPosFiles = getFilesAndDirs(posFiles)
+ private def getNegFiles = getFilesAndDirs(negFiles)
+ private def getRunFiles = getFiles(runFiles)
+ private def getJvmFiles = getFilesAndDirs(jvmFiles)
+ private def getResidentFiles = getFiles(residentFiles)
+ private def getBuildManagerFiles = getFilesAndDirs(buildManagerFiles)
+ private def getScalacheckFiles = getFiles(scalacheckFiles)
+ private def getScriptFiles = getFiles(scriptFiles)
+ private def getShootoutFiles = getFiles(shootoutFiles)
+ private def getScalapFiles = getFiles(scalapFiles)
+
+ override def execute() {
+ if (isPartestDebug)
+ setProp("partest.debug", "true")
+
+ srcDir foreach (x => setProp("partest.srcdir", x))
+
+ val classpath = this.compilationPath getOrElse 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 error("Provided classpath does not contain a Scala library.")
+
+ val antRunner = new scala.tools.partest.nest.AntRunner
+ val antFileManager = antRunner.fileManager
+
+ antFileManager.showDiff = showDiff
+ antFileManager.showLog = showLog
+ antFileManager.failed = runFailed
+ antFileManager.CLASSPATH = ClassPath.join(classpath.list: _*)
+ antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath
+
+ javacmd foreach (x => antFileManager.JAVACMD = x.getAbsolutePath)
+ javaccmd foreach (x => antFileManager.JAVAC_CMD = x.getAbsolutePath)
+ scalacOpts 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"),
+ (getBuildManagerFiles, "buildmanager", "Running Build Manager scenarii"),
+ (getScalacheckFiles, "scalacheck", "Running scalacheck tests"),
+ (getScriptFiles, "script", "Running script files"),
+ (getShootoutFiles, "shootout", "Running shootout tests"),
+ (getScalapFiles, "scalap", "Running scalap tests")
+ )
+
+ def runSet(set: TFSet): (Int, Int, Iterable[String]) = {
+ val (files, name, msg) = set
+ if (files.isEmpty) (0, 0, List())
+ else {
+ log(msg)
+ val results: Iterable[(String, Int)] = antRunner.reflectiveRunTestsForFiles(files, name)
+ val (succs, fails) = resultsToStatistics(results)
+
+ val failed: Iterable[String] = results collect {
+ case (path, 1) => path + " [FAILED]"
+ case (path, 2) => path + " [TIMOUT]"
+ }
+
+ // 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)
+ }
+
+ (succs, fails, failed)
+ }
+ }
+
+ val _results = testFileSets map runSet
+ val allSuccesses = _results map (_._1) sum
+ val allFailures = _results map (_._2) sum
+ val allFailedPaths = _results flatMap (_._3)
+
+ def f = if (errorOnFailed && allFailures > 0) error(_) else log(_: String)
+ def s = if (allFailures > 1) "s" else ""
+ val msg =
+ if (allFailures > 0)
+ "Test suite finished with %d case%s failing:\n".format(allFailures, s)+
+ allFailedPaths.mkString("\n")
+ else if (allSuccesses == 0) "There were no tests to run."
+ else "Test suite finished with no failures."
+
+ f(msg)
+ }
+ def oneResult(res: (String, Int)) =
+ <testcase name={res._1}>{
+ res._2 match {
+ case 0 => scala.xml.NodeSeq.Empty
+ case 1 => <failure message="Test failed"/>
+ case 2 => <failure message="Test timed out"/>
+ }
+ }</testcase>
+
+ def testReport(kind: String, results: Iterable[(String, Int)], succs: Int, fails: Int) =
+ <testsuite name={kind} tests={(succs + fails).toString} failures={fails.toString}>
+ <properties/>
+ {
+ results.map(oneResult(_))
+ }
+ </testsuite>
+}
diff --git a/src/partest/scala/tools/partest/antlib.xml b/src/partest/scala/tools/partest/antlib.xml
index af36f11368..b3b98e853f 100644
--- a/src/partest/scala/tools/partest/antlib.xml
+++ b/src/partest/scala/tools/partest/antlib.xml
@@ -1,3 +1,4 @@
<antlib>
- <taskdef name="partest" classname="scala.tools.partest.ant.JavaTask"/>
+ <taskdef name="partest"
+ classname="scala.tools.partest.PartestTask"/>
</antlib>
diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala
new file mode 100644
index 0000000000..cb819720fc
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/AntRunner.scala
@@ -0,0 +1,30 @@
+/* __ *\
+** ________ ___ / / ___ Scala Parallel Testing **
+** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+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 = _
+ val testRootPath: String = "test"
+ val testRootDir: Directory = Directory(testRootPath)
+ }
+
+ def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String) =
+ runTestsForFiles(kindFiles.toList, kind)
+}
diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala
new file mode 100644
index 0000000000..22568ad2d0
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/CompileManager.scala
@@ -0,0 +1,197 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io }
+import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
+import scala.tools.nsc.util.ClassPath
+import scala.tools.util.PathResolver
+import io.Path
+
+import java.io.{ File, BufferedReader, PrintWriter, FileReader, Writer, FileWriter, StringWriter }
+import File.pathSeparator
+
+class ExtConsoleReporter(override val settings: Settings, reader: BufferedReader, var writer: PrintWriter)
+extends ConsoleReporter(settings, reader, writer) {
+ def this(settings: Settings) = this(settings, Console.in, new PrintWriter(new FileWriter("/dev/null")))
+}
+
+abstract class SimpleCompiler {
+ def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean
+}
+
+class TestSettings(fileMan: FileManager) extends Settings(_ => ()) { }
+
+class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler {
+ def newGlobal(settings: Settings, reporter: Reporter): Global =
+ new Global(settings, reporter)
+
+ def newGlobal(settings: Settings, logWriter: FileWriter): Global = {
+ val rep = newReporter(settings, logWriter)
+ rep.shortname = true
+ newGlobal(settings, rep)
+ }
+
+ def newSettings(out: Option[String]) = {
+ val settings = new TestSettings(fileManager)
+ settings.usejavacp.value = true
+ settings.deprecation.value = true
+ settings.nowarnings.value = false
+ settings.encoding.value = "ISO-8859-1" // XXX why?
+
+ val classpathElements = settings.classpath.value :: fileManager.LATEST_LIB :: out.toList
+ settings.classpath.value = ClassPath.join(classpathElements: _*)
+ out foreach (settings.outdir.value = _)
+
+ settings
+ }
+
+ def newReporter(sett: Settings, writer: Writer = new StringWriter) =
+ new ExtConsoleReporter(sett, Console.in, new PrintWriter(writer))
+
+ private def updatePluginPath(options: String): String = {
+ val dir = fileManager.testRootDir
+ def absolutize(path: String) = Path(path) match {
+ case x if x.isAbsolute => x.path
+ case x => (fileManager.testRootDir / 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): Boolean = {
+ val testSettings = newSettings(out map (_.getAbsolutePath))
+ val logWriter = new FileWriter(log)
+
+ // check whether there is a ".flags" file
+ val flagsFileName = "%s.flags" format (basename(log.getName) dropRight 4) // 4 is "-run" or similar
+ val argString = (io.File(log).parent / flagsFileName) ifFile (x => updatePluginPath(x.slurp())) getOrElse ""
+ val allOpts = fileManager.SCALAC_OPTS+" "+argString
+ val args = (allOpts split "\\s").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
+ }
+ val test: TestFile = testFileFn(files.head, fileManager)
+ test.defineSettings(command.settings, out.isEmpty)
+ val toCompile = files map (_.getPath)
+
+ try {
+ NestUI.verbose("compiling "+toCompile)
+ try new global.Run compile toCompile
+ catch {
+ case FatalError(msg) =>
+ testRep.error(null, "fatal error: " + msg)
+ }
+
+ testRep.printSummary
+ testRep.writer.flush
+ testRep.writer.close
+ }
+ catch {
+ case e =>
+ e.printStackTrace()
+ return false
+ }
+ finally logWriter.close()
+
+ !testRep.hasErrors
+ }
+}
+
+// class ReflectiveCompiler(val fileManager: ConsoleFileManager) extends SimpleCompiler {
+// import fileManager.{latestCompFile, latestPartestFile}
+//
+// val sepUrls = Array(latestCompFile.toURI.toURL, latestPartestFile.toURI.toURL)
+// //NestUI.verbose("constructing URLClassLoader from URLs "+latestCompFile+" and "+latestPartestFile)
+//
+// val sepLoader = new java.net.URLClassLoader(sepUrls, null)
+//
+// val sepCompilerClass =
+// sepLoader.loadClass("scala.tools.partest.nest.DirectCompiler")
+// val sepCompiler = sepCompilerClass.newInstance()
+//
+// // needed for reflective invocation
+// val fileClass = Class.forName("java.io.File")
+// val stringClass = Class.forName("java.lang.String")
+// val sepCompileMethod =
+// sepCompilerClass.getMethod("compile", fileClass, stringClass)
+// val sepCompileMethod2 =
+// sepCompilerClass.getMethod("compile", fileClass, stringClass, fileClass)
+//
+// /* This method throws java.lang.reflect.InvocationTargetException
+// * if the compiler crashes.
+// * This exception is handled in the shouldCompile and shouldFailCompile
+// * methods of class CompileManager.
+// */
+// def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean = {
+// val res = sepCompileMethod2.invoke(sepCompiler, out, files, kind, log).asInstanceOf[java.lang.Boolean]
+// res.booleanValue()
+// }
+// }
+
+class CompileManager(val fileManager: FileManager) {
+ var compiler: SimpleCompiler = new /*ReflectiveCompiler*/ DirectCompiler(fileManager)
+
+ var numSeparateCompilers = 1
+ def createSeparateCompiler() = {
+ numSeparateCompilers += 1
+ compiler = new /*ReflectiveCompiler*/ DirectCompiler(fileManager)
+ }
+
+ /* This method returns true iff compilation succeeds.
+ */
+ def shouldCompile(files: List[File], kind: String, log: File): Boolean = {
+ createSeparateCompiler()
+ compiler.compile(None, files, kind, log)
+ }
+
+ /* This method returns true iff compilation succeeds.
+ */
+ def shouldCompile(out: File, files: List[File], kind: String, log: File): Boolean = {
+ createSeparateCompiler()
+ compiler.compile(Some(out), files, kind, log)
+ }
+
+ /* This method returns true iff compilation fails
+ * _and_ the compiler does _not_ crash or loop.
+ *
+ * If the compiler crashes, this method returns false.
+ */
+ def shouldFailCompile(files: List[File], kind: String, log: File): Boolean = {
+ createSeparateCompiler()
+ !compiler.compile(None, files, kind, log)
+ }
+
+ /* This method returns true iff compilation fails
+ * _and_ the compiler does _not_ crash or loop.
+ *
+ * If the compiler crashes, this method returns false.
+ */
+ def shouldFailCompile(out: File, files: List[File], kind: String, log: File): Boolean = {
+ createSeparateCompiler()
+ !compiler.compile(Some(out), files, kind, log)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
new file mode 100644
index 0000000000..58d16a3f45
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala
@@ -0,0 +1,190 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{ File, FilenameFilter, IOException, StringWriter }
+import java.net.URI
+import scala.util.Properties.{ propOrElse, scalaCmd, scalacCmd }
+import scala.tools.util.PathResolver
+import scala.tools.nsc.{ Settings }
+import scala.tools.nsc.{ io, util }
+import util.{ ClassPath }
+import io.{ Path, Directory }
+import File.pathSeparator
+import ClassPath.{ join }
+import PathResolver.{ Environment, Defaults }
+import RunnerUtils._
+
+
+class ConsoleFileManager extends FileManager {
+ var testBuild: Option[String] = PartestDefaults.testBuild
+ def testBuildFile = testBuild map (testParent / _)
+
+ var testClasses: Option[String] = None
+
+ def this(buildPath: String, rawClasses: Boolean) = {
+ this()
+ if (rawClasses)
+ testClasses = Some(buildPath)
+ else
+ testBuild = Some(buildPath)
+ // re-run because initialization of default
+ // constructor must be updated
+ findLatest()
+ }
+
+ def this(buildPath: String) = {
+ this(buildPath, false)
+ }
+
+ def this(buildPath: String, rawClasses: Boolean, moreOpts: String) = {
+ this(buildPath, rawClasses)
+ SCALAC_OPTS = SCALAC_OPTS+" "+moreOpts
+ }
+
+ lazy val srcDir = PathSettings.srcDir
+ lazy val testRootDir = PathSettings.testRoot
+ lazy val testRootPath = testRootDir.toAbsolute.path
+ def testParent = testRootDir.parent
+
+ var CLASSPATH = PartestDefaults.classPath
+ var JAVACMD = PartestDefaults.javaCmd
+ var JAVAC_CMD = PartestDefaults.javacCmd
+
+
+ NestUI.verbose("CLASSPATH: "+CLASSPATH)
+
+ if (!srcDir.isDirectory) {
+ NestUI.failure("Source directory \"" + srcDir.path + "\" not found")
+ exit(1)
+ }
+
+ CLASSPATH = {
+ val libs = (srcDir / Directory("lib")).files filter (_ hasExtension "jar") map (_.normalize.path)
+
+ // add all jars in libs
+ (CLASSPATH :: libs.toList) mkString pathSeparator
+ }
+
+ def findLatest() {
+ NestUI.verbose("test parent: "+testParent)
+
+ def prefixFileWith(parent: File, relPath: String) = (io.File(parent) / relPath).normalize
+ def prefixFile(relPath: String) = (testParent / relPath).normalize
+
+ if (!testClasses.isEmpty) {
+ testClassesDir = Path(testClasses.get).normalize.toDirectory
+ NestUI.verbose("Running with classes in "+testClassesDir)
+
+ latestFile = testClassesDir.parent / "bin"
+ latestLibFile = testClassesDir / "library"
+ latestCompFile = testClassesDir / "compiler"
+ latestPartestFile = testClassesDir / "partest"
+ latestFjbgFile = testParent / "lib" / "fjbg.jar"
+ }
+ else if (testBuild.isDefined) {
+ val dir = Path(testBuild.get)
+ NestUI.verbose("Running on "+dir)
+ latestFile = dir / "bin"
+ latestLibFile = dir / "lib/scala-library.jar"
+ latestCompFile = dir / "lib/scala-compiler.jar"
+ latestPartestFile = dir / "lib/scala-partest.jar"
+ }
+ else {
+ def setupQuick() {
+ NestUI.verbose("Running build/quick")
+ latestFile = prefixFile("build/quick/bin")
+ latestLibFile = prefixFile("build/quick/classes/library")
+ latestCompFile = prefixFile("build/quick/classes/compiler")
+ latestPartestFile = prefixFile("build/quick/classes/partest")
+ }
+
+ def setupInst() {
+ NestUI.verbose("Running dist (installed)")
+ val p = testParent.getParentFile
+ latestFile = prefixFileWith(p, "bin")
+ latestLibFile = prefixFileWith(p, "lib/scala-library.jar")
+ latestCompFile = prefixFileWith(p, "lib/scala-compiler.jar")
+ latestPartestFile = prefixFileWith(p, "lib/scala-partest.jar")
+ }
+
+ def setupDist() {
+ NestUI.verbose("Running dists/latest")
+ latestFile = prefixFile("dists/latest/bin")
+ latestLibFile = prefixFile("dists/latest/lib/scala-library.jar")
+ latestCompFile = prefixFile("dists/latest/lib/scala-compiler.jar")
+ latestPartestFile = prefixFile("dists/latest/lib/scala-partest.jar")
+ }
+
+ def setupPack() {
+ NestUI.verbose("Running build/pack")
+ latestFile = prefixFile("build/pack/bin")
+ latestLibFile = prefixFile("build/pack/lib/scala-library.jar")
+ latestCompFile = prefixFile("build/pack/lib/scala-compiler.jar")
+ latestPartestFile = prefixFile("build/pack/lib/scala-partest.jar")
+ }
+
+ val dists = testParent / "dists"
+ val build = testParent / "build"
+ // in case of an installed dist, testRootDir is one level deeper
+ val bin = testParent.parent / "bin"
+
+ def mostRecentOf(base: String, names: String*) =
+ names map (x => prefixFile(base + "/" + x).lastModified) reduceLeft (_ max _)
+
+ // detect most recent build
+ val quickTime = mostRecentOf("build/quick/classes", "compiler/compiler.properties", "library/library.properties")
+ val packTime = mostRecentOf("build/pack/lib", "scala-compiler.jar", "scala-library.jar")
+ val distTime = mostRecentOf("dists/latest/lib", "scala-compiler.jar", "scala-library.jar")
+ val instTime = mostRecentOf("lib", "scala-compiler.jar", "scala-library.jar")
+
+ val pairs = Map(
+ (quickTime, () => setupQuick()),
+ (packTime, () => setupPack()),
+ (distTime, () => setupDist()),
+ (instTime, () => setupInst())
+ )
+
+ // run setup based on most recent time
+ pairs(pairs.keys max)()
+
+ latestFjbgFile = prefixFile("lib/fjbg.jar")
+ }
+
+ LATEST_LIB = latestLibFile.getAbsolutePath
+ }
+
+ var LATEST_LIB: String = ""
+
+ var latestFile: File = _
+ var latestLibFile: File = _
+ var latestCompFile: File = _
+ var latestPartestFile: File = _
+ var latestFjbgFile: File = _
+ var testClassesDir: Directory = _
+ // initialize above fields
+ findLatest()
+
+ var testFiles: List[io.Path] = Nil
+
+ def getFiles(kind: String, cond: Path => Boolean): List[File] = {
+ def ignoreDir(p: Path) = List("svn", "obj") exists (p hasExtension _)
+
+ val dir = Directory(srcDir / kind)
+
+ if (dir.isDirectory) NestUI.verbose("look in %s for tests" format dir)
+ else NestUI.failure("Directory '%s' not found" format dir)
+
+ val files =
+ if (testFiles.nonEmpty) testFiles filter (_.parent isSame dir)
+ else dir.list filterNot ignoreDir filter cond toList
+
+ ( if (failed) files filter (x => logFileExists(x, kind)) else files ) map (_.jfile)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
new file mode 100644
index 0000000000..eae79f23af
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala
@@ -0,0 +1,209 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{File, PrintStream, FileOutputStream, BufferedReader,
+ InputStreamReader, StringWriter, PrintWriter}
+import utils.Properties._
+import RunnerUtils._
+import scala.tools.nsc.Properties.{ versionMsg, setProp }
+import scala.tools.nsc.util.CommandLineParser
+import scala.tools.nsc.io
+import scala.tools.nsc.interpreter.returning
+import io.{ Path, Process }
+
+class ConsoleRunner extends DirectRunner {
+ import PathSettings.{ srcDir, testRoot }
+
+ case class TestSet(kind: String, filter: Path => Boolean, msg: String)
+
+ val testSets = {
+ val pathFilter: Path => Boolean = _ hasExtension "scala"
+
+ List(
+ TestSet("pos", pathFilter, "Testing compiler (on files whose compilation should succeed)"),
+ TestSet("neg", pathFilter, "Testing compiler (on files whose compilation should fail)"),
+ TestSet("run", pathFilter, "Testing JVM backend"),
+ TestSet("jvm", pathFilter, "Testing JVM backend"),
+ TestSet("res", x => x.isFile && (x hasExtension "res"), "Testing resident compiler"),
+ TestSet("buildmanager", _.isDirectory, "Testing Build Manager"),
+ TestSet("shootout", pathFilter, "Testing shootout tests"),
+ TestSet("script", pathFilter, "Testing script tests"),
+ TestSet("scalacheck", pathFilter, "Testing ScalaCheck tests"),
+ TestSet("scalap", _.isDirectory, "Run scalap decompiler tests")
+ )
+ }
+
+ 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
+
+ def denotesTestSet(arg: String) = testSetArgs contains arg
+ def denotesTestFile(arg: String) = (arg endsWith ".scala") || (arg endsWith ".res")
+ def denotesTestDir(arg: String) = Path(arg).isDirectory
+ def denotesTestPath(arg: String) = denotesTestDir(arg) || denotesTestFile(arg)
+
+ private def printVersion { NestUI outline (versionMsg + "\n") }
+
+ private val unaryArgs = List(
+ "--pack", "--all", "--verbose", "--show-diff", "--show-log",
+ "--failed", "--version", "--ansi", "--debug"
+ ) ::: testSetArgs
+
+ private val binaryArgs = List(
+ "--grep", "--srcpath", "--buildpath", "--classpath"
+ )
+
+ def main(argstr: String) {
+ val parsed = CommandLineParser(argstr) withUnaryArgs unaryArgs withBinaryArgs binaryArgs
+ val args = parsed.residualArgs
+
+ /** Early return on no args, version, or invalid args */
+ if (argstr == "") return NestUI.usage()
+ if (parsed isSet "--version") return printVersion
+ if (args exists (x => !denotesTestPath(x))) {
+ val invalid = (args filterNot denotesTestPath).head
+ NestUI.failure("Invalid argument '%s'\n" format invalid)
+ return NestUI.usage()
+ }
+
+ parsed get "--srcpath" foreach (x => setProp("partest.srcdir", x))
+
+ fileManager =
+ if (parsed isSet "--buildpath") new ConsoleFileManager(parsed("--buildpath"))
+ else if (parsed isSet "--classpath") new ConsoleFileManager(parsed("--classpath"), true)
+ else if (parsed isSet "--pack") new ConsoleFileManager("build/pack")
+ else new ConsoleFileManager // auto detection, see ConsoleFileManager.findLatest
+
+ def argNarrowsTests(x: String) = denotesTestSet(x) || denotesTestFile(x) || denotesTestDir(x)
+
+ NestUI._verbose = parsed isSet "--verbose"
+ fileManager.showDiff = parsed isSet "--show-diff"
+ 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")
+
+ 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
+ }
+ }
+
+ // If --grep is given we suck in every file it matches.
+ parsed get "--grep" foreach { expr =>
+ val allFiles = srcDir.deepList() filter (_ hasExtension "scala") map (_.toFile) toList
+ val files = allFiles filter (_.slurp() contains expr)
+
+ if (files.isEmpty) NestUI.failure("--grep string '%s' matched no files." format expr)
+ else NestUI.verbose("--grep string '%s' matched %d file(s)".format(expr, files.size))
+
+ files foreach (x => addTestFile(x.jfile))
+ }
+ 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 dir =
+ if (fileManager.testClasses.isDefined) fileManager.testClassesDir
+ else fileManager.testBuildFile getOrElse {
+ fileManager.latestCompFile.getParentFile.getParentFile.getCanonicalFile
+ }
+
+ 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 outline (x + "\n"))
+
+ val start = System.currentTimeMillis
+ val (successes, failures) = testCheckAll(enabledTestSets)
+ val end = System.currentTimeMillis
+
+ val total = successes + failures
+
+ val elapsedSecs = (end - start)/1000
+ val elapsedMins = elapsedSecs/60
+ val elapsedHrs = elapsedMins/60
+ val dispMins = elapsedMins - elapsedHrs * 60
+ val dispSecs = elapsedSecs - elapsedMins * 60
+
+ val dispElapsed = {
+ def form(num: Long) = if (num < 10) "0"+num else ""+num
+ form(elapsedHrs)+":"+form(dispMins)+":"+form(dispSecs)
+ }
+
+ println
+ if (failures == 0)
+ NestUI.success("All of "+total+" tests were successful (elapsed time: "+dispElapsed+")\n")
+ else
+ NestUI.failure(failures+" of "+total+" tests failed (elapsed time: "+dispElapsed+")\n")
+
+ System exit ( if (failures == errors) 0 else 1 )
+ }
+
+ def runTests(testSet: TestSet): (Int, Int) = {
+ val TestSet(kind, filter, msg) = testSet
+
+ 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))
+ }
+ }
+
+ /**
+ * @return (success count, failure count)
+ */
+ def testCheckAll(enabledSets: List[TestSet]): (Int, Int) = {
+ def kindOf(f: File) = (srcDir relativize Path(f).normalize).segments.head
+
+ val (valid, invalid) = testFiles partition (x => testSetKinds contains kindOf(x))
+ invalid foreach (x => NestUI.failure("Invalid test file '%s', skipping.\n" format x))
+
+ val runTestsFileLists =
+ for ((kind, files) <- valid groupBy kindOf toList) yield {
+ NestUI.outline("\nTesting individual files\n")
+ resultsToStatistics(runTestsForFiles(files, kind))
+ }
+
+ NestUI.verbose("Run sets: "+enabledSets)
+ val results = runTestsFileLists ::: (enabledSets map runTests)
+
+ (results map (_._1) sum, results map (_._2) sum)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/Diff.java b/src/partest/scala/tools/partest/nest/Diff.java
new file mode 100644
index 0000000000..abd09d0293
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/Diff.java
@@ -0,0 +1,874 @@
+// $Id$
+
+package scala.tools.partest.nest;
+
+import java.util.Hashtable;
+
+/** A class to compare IndexedSeqs of objects. The result of comparison
+ is a list of <code>change</code> objects which form an
+ edit script. The objects compared are traditionally lines
+ of text from two files. Comparison options such as "ignore
+ whitespace" are implemented by modifying the <code>equals</code>
+ and <code>hashcode</code> methods for the objects compared.
+<p>
+ The basic algorithm is described in: </br>
+ "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
+ Algorithmica Vol. 1 No. 2, 1986, p 251.
+<p>
+ This class outputs different results from GNU diff 1.15 on some
+ inputs. Our results are actually better (smaller change list, smaller
+ total size of changes), but it would be nice to know why. Perhaps
+ there is a memory overwrite bug in GNU diff 1.15.
+
+ @author Stuart D. Gathman, translated from GNU diff 1.15
+ Copyright (C) 2000 Business Management Systems, Inc.
+<p>
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+<p>
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+<p>
+ You should have received a copy of the <a href=COPYING.txt>
+ GNU General Public License</a>
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+public class Diff {
+
+ /** Prepare to find differences between two arrays. Each element of
+ the arrays is translated to an "equivalence number" based on
+ the result of <code>equals</code>. The original Object arrays
+ are no longer needed for computing the differences. They will
+ be needed again later to print the results of the comparison as
+ an edit script, if desired.
+ */
+ public Diff(Object[] a,Object[] b) {
+ Hashtable h = new Hashtable(a.length + b.length);
+ filevec[0] = new file_data(a,h);
+ filevec[1] = new file_data(b,h);
+ }
+
+ /** 1 more than the maximum equivalence value used for this or its
+ sibling file. */
+ private int equiv_max = 1;
+
+ /** When set to true, the comparison uses a heuristic to speed it up.
+ With this heuristic, for files with a constant small density
+ of changes, the algorithm is linear in the file size. */
+ public boolean heuristic = false;
+
+ /** When set to true, the algorithm returns a guarranteed minimal
+ set of changes. This makes things slower, sometimes much slower. */
+ public boolean no_discards = false;
+
+ private int[] xvec, yvec; /* IndexedSeqs being compared. */
+ private int[] fdiag; /* IndexedSeq, indexed by diagonal, containing
+ the X coordinate of the point furthest
+ along the given diagonal in the forward
+ search of the edit matrix. */
+ private int[] bdiag; /* IndexedSeq, indexed by diagonal, containing
+ the X coordinate of the point furthest
+ along the given diagonal in the backward
+ search of the edit matrix. */
+ private int fdiagoff, bdiagoff;
+ private final file_data[] filevec = new file_data[2];
+ private int cost;
+
+ /** Find the midpoint of the shortest edit script for a specified
+ portion of the two files.
+
+ We scan from the beginnings of the files, and simultaneously from the ends,
+ doing a breadth-first search through the space of edit-sequence.
+ When the two searches meet, we have found the midpoint of the shortest
+ edit sequence.
+
+ The value returned is the number of the diagonal on which the midpoint lies.
+ The diagonal number equals the number of inserted lines minus the number
+ of deleted lines (counting only lines before the midpoint).
+ The edit cost is stored into COST; this is the total number of
+ lines inserted or deleted (counting only lines before the midpoint).
+
+ This function assumes that the first lines of the specified portions
+ of the two files do not match, and likewise that the last lines do not
+ match. The caller must trim matching lines from the beginning and end
+ of the portions it is going to specify.
+
+ Note that if we return the "wrong" diagonal value, or if
+ the value of bdiag at that diagonal is "wrong",
+ the worst this can do is cause suboptimal diff output.
+ It cannot cause incorrect diff output. */
+
+ private int diag (int xoff, int xlim, int yoff, int ylim) {
+ final int[] fd = fdiag; // Give the compiler a chance.
+ final int[] bd = bdiag; // Additional help for the compiler.
+ final int[] xv = xvec; // Still more help for the compiler.
+ final int[] yv = yvec; // And more and more . . .
+ final int dmin = xoff - ylim; // Minimum valid diagonal.
+ final int dmax = xlim - yoff; // Maximum valid diagonal.
+ final int fmid = xoff - yoff; // Center diagonal of top-down search.
+ final int bmid = xlim - ylim; // Center diagonal of bottom-up search.
+ int fmin = fmid, fmax = fmid; // Limits of top-down search.
+ int bmin = bmid, bmax = bmid; // Limits of bottom-up search.
+ /* True if southeast corner is on an odd
+ diagonal with respect to the northwest. */
+ final boolean odd = (fmid - bmid & 1) != 0;
+
+ fd[fdiagoff + fmid] = xoff;
+ bd[bdiagoff + bmid] = xlim;
+
+ for (int c = 1;; ++c)
+ {
+ int d; /* Active diagonal. */
+ boolean big_snake = false;
+
+ /* Extend the top-down search by an edit step in each diagonal. */
+ if (fmin > dmin)
+ fd[fdiagoff + --fmin - 1] = -1;
+ else
+ ++fmin;
+ if (fmax < dmax)
+ fd[fdiagoff + ++fmax + 1] = -1;
+ else
+ --fmax;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1];
+
+ if (tlo >= thi)
+ x = tlo + 1;
+ else
+ x = thi;
+ oldx = x;
+ y = x - d;
+ while (x < xlim && y < ylim && xv[x] == yv[y]) {
+ ++x; ++y;
+ }
+ if (x - oldx > 20)
+ big_snake = true;
+ fd[fdiagoff + d] = x;
+ if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d])
+ {
+ cost = 2 * c - 1;
+ return d;
+ }
+ }
+
+ /* Similar extend the bottom-up search. */
+ if (bmin > dmin)
+ bd[bdiagoff + --bmin - 1] = Integer.MAX_VALUE;
+ else
+ ++bmin;
+ if (bmax < dmax)
+ bd[bdiagoff + ++bmax + 1] = Integer.MAX_VALUE;
+ else
+ --bmax;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1];
+
+ if (tlo < thi)
+ x = tlo;
+ else
+ x = thi - 1;
+ oldx = x;
+ y = x - d;
+ while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) {
+ --x; --y;
+ }
+ if (oldx - x > 20)
+ big_snake = true;
+ bd[bdiagoff + d] = x;
+ if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d])
+ {
+ cost = 2 * c;
+ return d;
+ }
+ }
+
+ /* Heuristic: check occasionally for a diagonal that has made
+ lots of progress compared with the edit distance.
+ If we have any such, find the one that has made the most
+ progress and return it as if it had succeeded.
+
+ With this heuristic, for files with a constant small density
+ of changes, the algorithm is linear in the file size. */
+
+ if (c > 200 && big_snake && heuristic)
+ {
+ int best = 0;
+ int bestpos = -1;
+
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int dd = d - fmid;
+ if ((fd[fdiagoff + d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd)))
+ {
+ if (fd[fdiagoff + d] * 2 - dd > best
+ && fd[fdiagoff + d] - xoff > 20
+ && fd[fdiagoff + d] - d - yoff > 20)
+ {
+ int k;
+ int x = fd[fdiagoff + d];
+
+ /* We have a good enough best diagonal;
+ now insist that it end with a significant snake. */
+ for (k = 1; k <= 20; k++)
+ if (xvec[x - k] != yvec[x - d - k])
+ break;
+
+ if (k == 21)
+ {
+ best = fd[fdiagoff + d] * 2 - dd;
+ bestpos = d;
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ cost = 2 * c - 1;
+ return bestpos;
+ }
+
+ best = 0;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int dd = d - bmid;
+ if ((xlim - bd[bdiagoff + d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd)))
+ {
+ if ((xlim - bd[bdiagoff + d]) * 2 + dd > best
+ && xlim - bd[bdiagoff + d] > 20
+ && ylim - (bd[bdiagoff + d] - d) > 20)
+ {
+ /* We have a good enough best diagonal;
+ now insist that it end with a significant snake. */
+ int k;
+ int x = bd[bdiagoff + d];
+
+ for (k = 0; k < 20; k++)
+ if (xvec[x + k] != yvec[x - d + k])
+ break;
+ if (k == 20)
+ {
+ best = (xlim - bd[bdiagoff + d]) * 2 + dd;
+ bestpos = d;
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ cost = 2 * c - 1;
+ return bestpos;
+ }
+ }
+ }
+ }
+
+ /** Compare in detail contiguous subsequences of the two files
+ which are known, as a whole, to match each other.
+
+ The results are recorded in the IndexedSeqs filevec[N].changed_flag, by
+ storing a 1 in the element for each line that is an insertion or deletion.
+
+ The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
+
+ Note that XLIM, YLIM are exclusive bounds.
+ All line numbers are origin-0 and discarded lines are not counted. */
+
+ private void compareseq (int xoff, int xlim, int yoff, int ylim) {
+ /* Slide down the bottom initial diagonal. */
+ while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) {
+ ++xoff; ++yoff;
+ }
+ /* Slide up the top initial diagonal. */
+ while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) {
+ --xlim; --ylim;
+ }
+
+ /* Handle simple cases. */
+ if (xoff == xlim)
+ while (yoff < ylim)
+ filevec[1].changed_flag[1+filevec[1].realindexes[yoff++]] = true;
+ else if (yoff == ylim)
+ while (xoff < xlim)
+ filevec[0].changed_flag[1+filevec[0].realindexes[xoff++]] = true;
+ else
+ {
+ /* Find a point of correspondence in the middle of the files. */
+
+ int d = diag (xoff, xlim, yoff, ylim);
+ int c = cost;
+ int f = fdiag[fdiagoff + d];
+ int b = bdiag[bdiagoff + d];
+
+ if (c == 1)
+ {
+ /* This should be impossible, because it implies that
+ one of the two subsequences is empty,
+ and that case was handled above without calling `diag'.
+ Let's verify that this is true. */
+ throw new IllegalArgumentException("Empty subsequence");
+ }
+ else
+ {
+ /* Use that point to split this problem into two subproblems. */
+ compareseq (xoff, b, yoff, b - d);
+ /* This used to use f instead of b,
+ but that is incorrect!
+ It is not necessarily the case that diagonal d
+ has a snake from b to f. */
+ compareseq (b, xlim, b - d, ylim);
+ }
+ }
+ }
+
+ /** Discard lines from one file that have no matches in the other file.
+ */
+
+ private void discard_confusing_lines() {
+ filevec[0].discard_confusing_lines(filevec[1]);
+ filevec[1].discard_confusing_lines(filevec[0]);
+ }
+
+ private boolean inhibit = false;
+
+ /** Adjust inserts/deletes of blank lines to join changes
+ as much as possible.
+ */
+
+ private void shift_boundaries() {
+ if (inhibit)
+ return;
+ filevec[0].shift_boundaries(filevec[1]);
+ filevec[1].shift_boundaries(filevec[0]);
+ }
+
+ public interface ScriptBuilder {
+ /** Scan the tables of which lines are inserted and deleted,
+ producing an edit script.
+ @param changed0 true for lines in first file which do not match 2nd
+ @param len0 number of lines in first file
+ @param changed1 true for lines in 2nd file which do not match 1st
+ @param len1 number of lines in 2nd file
+ @return a linked list of changes - or null
+ */
+ public change build_script(
+ boolean[] changed0,int len0,
+ boolean[] changed1,int len1
+ );
+ }
+
+ /** Scan the tables of which lines are inserted and deleted,
+ producing an edit script in reverse order. */
+
+ static class ReverseScript implements ScriptBuilder {
+ public change build_script(
+ final boolean[] changed0,int len0,
+ final boolean[] changed1,int len1)
+ {
+ change script = null;
+ int i0 = 0, i1 = 0;
+ while (i0 < len0 || i1 < len1) {
+ if (changed0[1+i0] || changed1[1+i1]) {
+ int line0 = i0, line1 = i1;
+
+ /* Find # lines changed here in each file. */
+ while (changed0[1+i0]) ++i0;
+ while (changed1[1+i1]) ++i1;
+
+ /* Record this change. */
+ script = new change(line0, line1, i0 - line0, i1 - line1, script);
+ }
+
+ /* We have reached lines in the two files that match each other. */
+ i0++; i1++;
+ }
+
+ return script;
+ }
+ }
+
+ static class ForwardScript implements ScriptBuilder {
+ /** Scan the tables of which lines are inserted and deleted,
+ producing an edit script in forward order. */
+ public change build_script(
+ final boolean[] changed0,int len0,
+ final boolean[] changed1,int len1)
+ {
+ change script = null;
+ int i0 = len0, i1 = len1;
+
+ while (i0 >= 0 || i1 >= 0)
+ {
+ if (changed0[i0] || changed1[i1])
+ {
+ int line0 = i0, line1 = i1;
+
+ /* Find # lines changed here in each file. */
+ while (changed0[i0]) --i0;
+ while (changed1[i1]) --i1;
+
+ /* Record this change. */
+ script = new change(i0, i1, line0 - i0, line1 - i1, script);
+ }
+
+ /* We have reached lines in the two files that match each other. */
+ i0--; i1--;
+ }
+
+ return script;
+ }
+ }
+
+ /** Standard ScriptBuilders. */
+ public final static ScriptBuilder
+ forwardScript = new ForwardScript(),
+ reverseScript = new ReverseScript();
+
+ /* Report the differences of two files. DEPTH is the current directory
+ depth. */
+ public final change diff_2(final boolean reverse) {
+ return diff(reverse ? reverseScript : forwardScript);
+ }
+
+ /** Get the results of comparison as an edit script. The script
+ is described by a list of changes. The standard ScriptBuilder
+ implementations provide for forward and reverse edit scripts.
+ Alternate implementations could, for instance, list common elements
+ instead of differences.
+ @param bld an object to build the script from change flags
+ @return the head of a list of changes
+ */
+ public change diff(final ScriptBuilder bld) {
+
+ /* Some lines are obviously insertions or deletions
+ because they don't match anything. Detect them now,
+ and avoid even thinking about them in the main comparison algorithm. */
+
+ discard_confusing_lines ();
+
+ /* Now do the main comparison algorithm, considering just the
+ undiscarded lines. */
+
+ xvec = filevec[0].undiscarded;
+ yvec = filevec[1].undiscarded;
+
+ int diags =
+ filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3;
+ fdiag = new int[diags];
+ fdiagoff = filevec[1].nondiscarded_lines + 1;
+ bdiag = new int[diags];
+ bdiagoff = filevec[1].nondiscarded_lines + 1;
+
+ compareseq (0, filevec[0].nondiscarded_lines,
+ 0, filevec[1].nondiscarded_lines);
+ fdiag = null;
+ bdiag = null;
+
+ /* Modify the results slightly to make them prettier
+ in cases where that can validly be done. */
+
+ shift_boundaries ();
+
+ /* Get the results of comparison in the form of a chain
+ of `struct change's -- an edit script. */
+ return bld.build_script(
+ filevec[0].changed_flag,
+ filevec[0].buffered_lines,
+ filevec[1].changed_flag,
+ filevec[1].buffered_lines
+ );
+
+ }
+
+ /** The result of comparison is an "edit script": a chain of change objects.
+ Each change represents one place where some lines are deleted
+ and some are inserted.
+
+ LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+ DELETED is the number of lines deleted here from file 0.
+ INSERTED is the number of lines inserted here in file 1.
+
+ If DELETED is 0 then LINE0 is the number of the line before
+ which the insertion was done; vice versa for INSERTED and LINE1. */
+
+ public static class change {
+ /** Previous or next edit command. */
+ public change link;
+ /** # lines of file 1 changed here. */
+ public final int inserted;
+ /** # lines of file 0 changed here. */
+ public final int deleted;
+ /** Line number of 1st deleted line. */
+ public final int line0;
+ /** Line number of 1st inserted line. */
+ public final int line1;
+
+ /** Cons an additional entry onto the front of an edit script OLD.
+ LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+ DELETED is the number of lines deleted here from file 0.
+ INSERTED is the number of lines inserted here in file 1.
+
+ If DELETED is 0 then LINE0 is the number of the line before
+ which the insertion was done; vice versa for INSERTED and LINE1. */
+ public change(int line0, int line1, int deleted, int inserted, change old) {
+ this.line0 = line0;
+ this.line1 = line1;
+ this.inserted = inserted;
+ this.deleted = deleted;
+ this.link = old;
+ //System.err.println(line0+","+line1+","+inserted+","+deleted);
+ }
+ }
+
+ /** Data on one input file being compared.
+ */
+
+ class file_data {
+
+ /** Allocate changed array for the results of comparison. */
+ void clear() {
+ /* Allocate a flag for each line of each file, saying whether that line
+ is an insertion or deletion.
+ Allocate an extra element, always zero, at each end of each IndexedSeq.
+ */
+ changed_flag = new boolean[buffered_lines + 2];
+ }
+
+ /** Return equiv_count[I] as the number of lines in this file
+ that fall in equivalence class I.
+ @return the array of equivalence class counts.
+ */
+ int[] equivCount() {
+ int[] equiv_count = new int[equiv_max];
+ for (int i = 0; i < buffered_lines; ++i)
+ ++equiv_count[equivs[i]];
+ return equiv_count;
+ }
+
+ /** Discard lines that have no matches in another file.
+
+ A line which is discarded will not be considered by the actual
+ comparison algorithm; it will be as if that line were not in the file.
+ The file's `realindexes' table maps virtual line numbers
+ (which don't count the discarded lines) into real line numbers;
+ this is how the actual comparison algorithm produces results
+ that are comprehensible when the discarded lines are counted.
+<p>
+ When we discard a line, we also mark it as a deletion or insertion
+ so that it will be printed in the output.
+ @param f the other file
+ */
+ void discard_confusing_lines(file_data f) {
+ clear();
+ /* Set up table of which lines are going to be discarded. */
+ final byte[] discarded = discardable(f.equivCount());
+
+ /* Don't really discard the provisional lines except when they occur
+ in a run of discardables, with nonprovisionals at the beginning
+ and end. */
+ filterDiscards(discarded);
+
+ /* Actually discard the lines. */
+ discard(discarded);
+ }
+
+ /** Mark to be discarded each line that matches no line of another file.
+ If a line matches many lines, mark it as provisionally discardable.
+ @see equivCount()
+ @param counts The count of each equivalence number for the other file.
+ @return 0=nondiscardable, 1=discardable or 2=provisionally discardable
+ for each line
+ */
+
+ private byte[] discardable(final int[] counts) {
+ final int end = buffered_lines;
+ final byte[] discards = new byte[end];
+ final int[] equivs = this.equivs;
+ int many = 5;
+ int tem = end / 64;
+
+ /* Multiply MANY by approximate square root of number of lines.
+ That is the threshold for provisionally discardable lines. */
+ while ((tem = tem >> 2) > 0)
+ many *= 2;
+
+ for (int i = 0; i < end; i++)
+ {
+ int nmatch;
+ if (equivs[i] == 0)
+ continue;
+ nmatch = counts[equivs[i]];
+ if (nmatch == 0)
+ discards[i] = 1;
+ else if (nmatch > many)
+ discards[i] = 2;
+ }
+ return discards;
+ }
+
+ /** Don't really discard the provisional lines except when they occur
+ in a run of discardables, with nonprovisionals at the beginning
+ and end. */
+
+ private void filterDiscards(final byte[] discards) {
+ final int end = buffered_lines;
+
+ for (int i = 0; i < end; i++)
+ {
+ /* Cancel provisional discards not in middle of run of discards. */
+ if (discards[i] == 2)
+ discards[i] = 0;
+ else if (discards[i] != 0)
+ {
+ /* We have found a nonprovisional discard. */
+ int j;
+ int length;
+ int provisional = 0;
+
+ /* Find end of this run of discardable lines.
+ Count how many are provisionally discardable. */
+ for (j = i; j < end; j++)
+ {
+ if (discards[j] == 0)
+ break;
+ if (discards[j] == 2)
+ ++provisional;
+ }
+
+ /* Cancel provisional discards at end, and shrink the run. */
+ while (j > i && discards[j - 1] == 2) {
+ discards[--j] = 0; --provisional;
+ }
+
+ /* Now we have the length of a run of discardable lines
+ whose first and last are not provisional. */
+ length = j - i;
+
+ /* If 1/4 of the lines in the run are provisional,
+ cancel discarding of all provisional lines in the run. */
+ if (provisional * 4 > length)
+ {
+ while (j > i)
+ if (discards[--j] == 2)
+ discards[j] = 0;
+ }
+ else
+ {
+ int consec;
+ int minimum = 1;
+ int tem = length / 4;
+
+ /* MINIMUM is approximate square root of LENGTH/4.
+ A subrun of two or more provisionals can stand
+ when LENGTH is at least 16.
+ A subrun of 4 or more can stand when LENGTH >= 64. */
+ while ((tem = tem >> 2) > 0)
+ minimum *= 2;
+ minimum++;
+
+ /* Cancel any subrun of MINIMUM or more provisionals
+ within the larger run. */
+ for (j = 0, consec = 0; j < length; j++)
+ if (discards[i + j] != 2)
+ consec = 0;
+ else if (minimum == ++consec)
+ /* Back up to start of subrun, to cancel it all. */
+ j -= consec;
+ else if (minimum < consec)
+ discards[i + j] = 0;
+
+ /* Scan from beginning of run
+ until we find 3 or more nonprovisionals in a row
+ or until the first nonprovisional at least 8 lines in.
+ Until that point, cancel any provisionals. */
+ for (j = 0, consec = 0; j < length; j++)
+ {
+ if (j >= 8 && discards[i + j] == 1)
+ break;
+ if (discards[i + j] == 2) {
+ consec = 0; discards[i + j] = 0;
+ }
+ else if (discards[i + j] == 0)
+ consec = 0;
+ else
+ consec++;
+ if (consec == 3)
+ break;
+ }
+
+ /* I advances to the last line of the run. */
+ i += length - 1;
+
+ /* Same thing, from end. */
+ for (j = 0, consec = 0; j < length; j++)
+ {
+ if (j >= 8 && discards[i - j] == 1)
+ break;
+ if (discards[i - j] == 2) {
+ consec = 0; discards[i - j] = 0;
+ }
+ else if (discards[i - j] == 0)
+ consec = 0;
+ else
+ consec++;
+ if (consec == 3)
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /** Actually discard the lines.
+ @param discards flags lines to be discarded
+ */
+ private void discard(final byte[] discards) {
+ final int end = buffered_lines;
+ int j = 0;
+ for (int i = 0; i < end; ++i)
+ if (no_discards || discards[i] == 0)
+ {
+ undiscarded[j] = equivs[i];
+ realindexes[j++] = i;
+ }
+ else
+ changed_flag[1+i] = true;
+ nondiscarded_lines = j;
+ }
+
+ file_data(Object[] data,Hashtable h) {
+ buffered_lines = data.length;
+
+ equivs = new int[buffered_lines];
+ undiscarded = new int[buffered_lines];
+ realindexes = new int[buffered_lines];
+
+ for (int i = 0; i < data.length; ++i) {
+ Integer ir = (Integer)h.get(data[i]);
+ if (ir == null)
+ h.put(data[i],new Integer(equivs[i] = equiv_max++));
+ else
+ equivs[i] = ir.intValue();
+ }
+ }
+
+ /** Adjust inserts/deletes of blank lines to join changes
+ as much as possible.
+
+ We do something when a run of changed lines include a blank
+ line at one end and have an excluded blank line at the other.
+ We are free to choose which blank line is included.
+ `compareseq' always chooses the one at the beginning,
+ but usually it is cleaner to consider the following blank line
+ to be the "change". The only exception is if the preceding blank line
+ would join this change to other changes.
+ @param f the file being compared against
+ */
+
+ void shift_boundaries(file_data f) {
+ final boolean[] changed = changed_flag;
+ final boolean[] other_changed = f.changed_flag;
+ int i = 0;
+ int j = 0;
+ int i_end = buffered_lines;
+ int preceding = -1;
+ int other_preceding = -1;
+
+ for (;;)
+ {
+ int start, end, other_start;
+
+ /* Scan forwards to find beginning of another run of changes.
+ Also keep track of the corresponding point in the other file. */
+
+ while (i < i_end && !changed[1+i])
+ {
+ while (other_changed[1+j++])
+ /* Non-corresponding lines in the other file
+ will count as the preceding batch of changes. */
+ other_preceding = j;
+ i++;
+ }
+
+ if (i == i_end)
+ break;
+
+ start = i;
+ other_start = j;
+
+ for (;;)
+ {
+ /* Now find the end of this run of changes. */
+
+ while (i < i_end && changed[1+i]) i++;
+ end = i;
+
+ /* If the first changed line matches the following unchanged one,
+ and this run does not follow right after a previous run,
+ and there are no lines deleted from the other file here,
+ then classify the first changed line as unchanged
+ and the following line as changed in its place. */
+
+ /* You might ask, how could this run follow right after another?
+ Only because the previous run was shifted here. */
+
+ if (end != i_end
+ && equivs[start] == equivs[end]
+ && !other_changed[1+j]
+ && end != i_end
+ && !((preceding >= 0 && start == preceding)
+ || (other_preceding >= 0
+ && other_start == other_preceding)))
+ {
+ changed[1+end++] = true;
+ changed[1+start++] = false;
+ ++i;
+ /* Since one line-that-matches is now before this run
+ instead of after, we must advance in the other file
+ to keep in synch. */
+ ++j;
+ }
+ else
+ break;
+ }
+
+ preceding = i;
+ other_preceding = j;
+ }
+ }
+
+ /** Number of elements (lines) in this file. */
+ final int buffered_lines;
+
+ /** IndexedSeq, indexed by line number, containing an equivalence code for
+ each line. It is this IndexedSeq that is actually compared with that
+ of another file to generate differences. */
+ private final int[] equivs;
+
+ /** IndexedSeq, like the previous one except that
+ the elements for discarded lines have been squeezed out. */
+ final int[] undiscarded;
+
+ /** IndexedSeq mapping virtual line numbers (not counting discarded lines)
+ to real ones (counting those lines). Both are origin-0. */
+ final int[] realindexes;
+
+ /** Total number of nondiscarded lines. */
+ int nondiscarded_lines;
+
+ /** Array, indexed by real origin-1 line number,
+ containing true for a line that is an insertion or a deletion.
+ The results of comparison are stored here. */
+ boolean[] changed_flag;
+
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/DiffPrint.java b/src/partest/scala/tools/partest/nest/DiffPrint.java
new file mode 100644
index 0000000000..494bc06e4a
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/DiffPrint.java
@@ -0,0 +1,607 @@
+// $Id$
+
+package scala.tools.partest.nest;
+
+import java.io.*;
+import java.util.Vector;
+import java.util.Date;
+//import com.objectspace.jgl.predicates.UnaryPredicate;
+
+interface UnaryPredicate {
+ boolean execute(Object obj);
+}
+
+/** A simple framework for printing change lists produced by <code>Diff</code>.
+ @see bmsi.util.Diff
+ @author Stuart D. Gathman
+ Copyright (C) 2000 Business Management Systems, Inc.
+<p>
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+<p>
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+<p>
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+public class DiffPrint {
+ /** A Base class for printing edit scripts produced by Diff.
+ This class divides the change list into "hunks", and calls
+ <code>print_hunk</code> for each hunk. Various utility methods
+ are provided as well.
+ */
+ public static abstract class Base {
+ protected Base(Object[] a,Object[] b, Writer w) {
+ outfile = new PrintWriter(w);
+ file0 = a;
+ file1 = b;
+ }
+ /** Set to ignore certain kinds of lines when printing
+ an edit script. For example, ignoring blank lines or comments.
+ */
+ protected UnaryPredicate ignore = null;
+
+ /** Set to the lines of the files being compared.
+ */
+ protected Object[] file0, file1;
+
+ /** Divide SCRIPT into pieces by calling HUNKFUN and
+ print each piece with PRINTFUN.
+ Both functions take one arg, an edit script.
+
+ PRINTFUN takes a subscript which belongs together (with a null
+ link at the end) and prints it. */
+ public void print_script(Diff.change script) {
+ Diff.change next = script;
+
+ while (next != null)
+ {
+ Diff.change t, end;
+
+ /* Find a set of changes that belong together. */
+ t = next;
+ end = hunkfun(next);
+
+ /* Disconnect them from the rest of the changes,
+ making them a hunk, and remember the rest for next iteration. */
+ next = end.link;
+ end.link = null;
+ //if (DEBUG)
+ // debug_script(t);
+
+ /* Print this hunk. */
+ print_hunk(t);
+
+ /* Reconnect the script so it will all be freed properly. */
+ end.link = next;
+ }
+ outfile.flush();
+ }
+
+ /** Called with the tail of the script
+ and returns the last link that belongs together with the start
+ of the tail. */
+
+ protected Diff.change hunkfun(Diff.change hunk) {
+ return hunk;
+ }
+
+ protected int first0, last0, first1, last1, deletes, inserts;
+ protected PrintWriter outfile;
+
+ /** Look at a hunk of edit script and report the range of lines in each file
+ that it applies to. HUNK is the start of the hunk, which is a chain
+ of `struct change'. The first and last line numbers of file 0 are stored
+ in *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
+ Note that these are internal line numbers that count from 0.
+
+ If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
+
+ Also set *DELETES nonzero if any lines of file 0 are deleted
+ and set *INSERTS nonzero if any lines of file 1 are inserted.
+ If only ignorable lines are inserted or deleted, both are
+ set to 0. */
+
+ protected void analyze_hunk(Diff.change hunk) {
+ int f0, l0 = 0, f1, l1 = 0, show_from = 0, show_to = 0;
+ int i;
+ Diff.change next;
+ boolean nontrivial = (ignore == null);
+
+ show_from = show_to = 0;
+
+ f0 = hunk.line0;
+ f1 = hunk.line1;
+
+ for (next = hunk; next != null; next = next.link)
+ {
+ l0 = next.line0 + next.deleted - 1;
+ l1 = next.line1 + next.inserted - 1;
+ show_from += next.deleted;
+ show_to += next.inserted;
+ for (i = next.line0; i <= l0 && ! nontrivial; i++)
+ if (!ignore.execute(file0[i]))
+ nontrivial = true;
+ for (i = next.line1; i <= l1 && ! nontrivial; i++)
+ if (!ignore.execute(file1[i]))
+ nontrivial = true;
+ }
+
+ first0 = f0;
+ last0 = l0;
+ first1 = f1;
+ last1 = l1;
+
+ /* If all inserted or deleted lines are ignorable,
+ tell the caller to ignore this hunk. */
+
+ if (!nontrivial)
+ show_from = show_to = 0;
+
+ deletes = show_from;
+ inserts = show_to;
+ }
+
+ /** Print the script header which identifies the files compared. */
+ protected void print_header(String filea, String fileb) { }
+
+ protected abstract void print_hunk(Diff.change hunk);
+
+ protected void print_1_line(String pre,Object linbuf) {
+ outfile.println(pre + linbuf.toString());
+ }
+
+ /** Print a pair of line numbers with SEPCHAR, translated for file FILE.
+ If the two numbers are identical, print just one number.
+
+ Args A and B are internal line numbers.
+ We print the translated (real) line numbers. */
+
+ protected void print_number_range (char sepchar, int a, int b) {
+ /* Note: we can have B < A in the case of a range of no lines.
+ In this case, we should print the line number before the range,
+ which is B. */
+ if (++b > ++a)
+ outfile.print("" + a + sepchar + b);
+ else
+ outfile.print(b);
+ }
+
+ public static char change_letter(int inserts, int deletes) {
+ if (inserts == 0)
+ return 'd';
+ else if (deletes == 0)
+ return 'a';
+ else
+ return 'c';
+ }
+ }
+
+ /** Print a change list in the standard diff format.
+ */
+ public static class NormalPrint extends Base {
+
+ public NormalPrint(Object[] a,Object[] b, Writer w) {
+ super(a,b,w);
+ }
+
+ /** Print a hunk of a normal diff.
+ This is a contiguous portion of a complete edit script,
+ describing changes in consecutive lines. */
+
+ protected void print_hunk (Diff.change hunk) {
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk(hunk);
+ if (deletes == 0 && inserts == 0)
+ return;
+
+ /* Print out the line number header for this hunk */
+ print_number_range (',', first0, last0);
+ outfile.print(change_letter(inserts, deletes));
+ print_number_range (',', first1, last1);
+ outfile.println();
+
+ /* Print the lines that the first file has. */
+ if (deletes != 0)
+ for (int i = first0; i <= last0; i++)
+ print_1_line ("< ", file0[i]);
+
+ if (inserts != 0 && deletes != 0)
+ outfile.println("---");
+
+ /* Print the lines that the second file has. */
+ if (inserts != 0)
+ for (int i = first1; i <= last1; i++)
+ print_1_line ("> ", file1[i]);
+ }
+ }
+
+ /** Prints an edit script in a format suitable for input to <code>ed</code>.
+ The edit script must be generated with the reverse option to
+ be useful as actual <code>ed</code> input.
+ */
+ public static class EdPrint extends Base {
+
+ public EdPrint(Object[] a,Object[] b, Writer w) {
+ super(a,b,w);
+ }
+
+ /** Print a hunk of an ed diff */
+ protected void print_hunk(Diff.change hunk) {
+
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk);
+ if (deletes == 0 && inserts == 0)
+ return;
+
+ /* Print out the line number header for this hunk */
+ print_number_range (',', first0, last0);
+ outfile.println(change_letter(inserts, deletes));
+
+ /* Print new/changed lines from second file, if needed */
+ if (inserts != 0)
+ {
+ boolean inserting = true;
+ for (int i = first1; i <= last1; i++)
+ {
+ /* Resume the insert, if we stopped. */
+ if (! inserting)
+ outfile.println(i - first1 + first0 + "a");
+ inserting = true;
+
+ /* If the file's line is just a dot, it would confuse `ed'.
+ So output it with a double dot, and set the flag LEADING_DOT
+ so that we will output another ed-command later
+ to change the double dot into a single dot. */
+
+ if (".".equals(file1[i]))
+ {
+ outfile.println("..");
+ outfile.println(".");
+ /* Now change that double dot to the desired single dot. */
+ outfile.println(i - first1 + first0 + 1 + "s/^\\.\\././");
+ inserting = false;
+ }
+ else
+ /* Line is not `.', so output it unmodified. */
+ print_1_line ("", file1[i]);
+ }
+
+ /* End insert mode, if we are still in it. */
+ if (inserting)
+ outfile.println(".");
+ }
+ }
+ }
+
+ /** Prints an edit script in context diff format. This and its
+ 'unified' variation is used for source code patches.
+ */
+ public static class ContextPrint extends Base {
+
+ protected int context = 3;
+
+ public ContextPrint(Object[] a,Object[] b, Writer w) {
+ super(a,b,w);
+ }
+
+ protected void print_context_label (String mark, File inf, String label) {
+ if (label != null)
+ outfile.println(mark + ' ' + label);
+ else if (inf.lastModified() > 0)
+ // FIXME: use DateFormat to get precise format needed.
+ outfile.println(
+ mark + ' ' + inf.getPath() + '\t' + new Date(inf.lastModified())
+ );
+ else
+ /* Don't pretend that standard input is ancient. */
+ outfile.println(mark + ' ' + inf.getPath());
+ }
+
+ public void print_header(String filea,String fileb) {
+ print_context_label ("***", new File(filea), filea);
+ print_context_label ("---", new File(fileb), fileb);
+ }
+
+ /** If function_regexp defined, search for start of function. */
+ private String find_function(Object[] lines, int start) {
+ return null;
+ }
+
+ protected void print_function(Object[] file,int start) {
+ String function = find_function (file0, first0);
+ if (function != null) {
+ outfile.print(" ");
+ outfile.print(
+ (function.length() < 40) ? function : function.substring(0,40)
+ );
+ }
+ }
+
+ protected void print_hunk(Diff.change hunk) {
+
+ /* Determine range of line numbers involved in each file. */
+
+ analyze_hunk (hunk);
+
+ if (deletes == 0 && inserts == 0)
+ return;
+
+ /* Include a context's width before and after. */
+
+ first0 = Math.max(first0 - context, 0);
+ first1 = Math.max(first1 - context, 0);
+ last0 = Math.min(last0 + context, file0.length - 1);
+ last1 = Math.min(last1 + context, file1.length - 1);
+
+
+ outfile.print("***************");
+
+ /* If we looked for and found a function this is part of,
+ include its name in the header of the diff section. */
+ print_function (file0, first0);
+
+ outfile.println();
+ outfile.print("*** ");
+ print_number_range (',', first0, last0);
+ outfile.println(" ****");
+
+ if (deletes != 0) {
+ Diff.change next = hunk;
+
+ for (int i = first0; i <= last0; i++) {
+ /* Skip past changes that apply (in file 0)
+ only to lines before line I. */
+
+ while (next != null && next.line0 + next.deleted <= i)
+ next = next.link;
+
+ /* Compute the marking for line I. */
+
+ String prefix = " ";
+ if (next != null && next.line0 <= i)
+ /* The change NEXT covers this line.
+ If lines were inserted here in file 1, this is "changed".
+ Otherwise it is "deleted". */
+ prefix = (next.inserted > 0) ? "!" : "-";
+
+ print_1_line (prefix, file0[i]);
+ }
+ }
+
+ outfile.print("--- ");
+ print_number_range (',', first1, last1);
+ outfile.println(" ----");
+
+ if (inserts != 0) {
+ Diff.change next = hunk;
+
+ for (int i = first1; i <= last1; i++) {
+ /* Skip past changes that apply (in file 1)
+ only to lines before line I. */
+
+ while (next != null && next.line1 + next.inserted <= i)
+ next = next.link;
+
+ /* Compute the marking for line I. */
+
+ String prefix = " ";
+ if (next != null && next.line1 <= i)
+ /* The change NEXT covers this line.
+ If lines were deleted here in file 0, this is "changed".
+ Otherwise it is "inserted". */
+ prefix = (next.deleted > 0) ? "!" : "+";
+
+ print_1_line (prefix, file1[i]);
+ }
+ }
+ }
+ }
+
+ /** Prints an edit script in context diff format. This and its
+ 'unified' variation is used for source code patches.
+ */
+ public static class UnifiedPrint extends ContextPrint {
+
+ public UnifiedPrint(Object[] a,Object[] b, Writer w) {
+ super(a,b,w);
+ }
+
+ public void print_header(String filea,String fileb) {
+ print_context_label ("---", new File(filea), filea);
+ print_context_label ("+++", new File(fileb), fileb);
+ }
+
+ private void print_number_range (int a, int b) {
+ //translate_range (file, a, b, &trans_a, &trans_b);
+
+ /* Note: we can have B < A in the case of a range of no lines.
+ In this case, we should print the line number before the range,
+ which is B. */
+ if (b < a)
+ outfile.print(b + ",0");
+ else
+ super.print_number_range(',',a,b);
+ }
+
+ protected void print_hunk(Diff.change hunk) {
+ /* Determine range of line numbers involved in each file. */
+ analyze_hunk (hunk);
+
+ if (deletes == 0 && inserts == 0)
+ return;
+
+ /* Include a context's width before and after. */
+
+ first0 = Math.max(first0 - context, 0);
+ first1 = Math.max(first1 - context, 0);
+ last0 = Math.min(last0 + context, file0.length - 1);
+ last1 = Math.min(last1 + context, file1.length - 1);
+
+
+
+ outfile.print("@@ -");
+ print_number_range (first0, last0);
+ outfile.print(" +");
+ print_number_range (first1, last1);
+ outfile.print(" @@");
+
+ /* If we looked for and found a function this is part of,
+ include its name in the header of the diff section. */
+ print_function(file0,first0);
+
+ outfile.println();
+
+ Diff.change next = hunk;
+ int i = first0;
+ int j = first1;
+
+ while (i <= last0 || j <= last1) {
+
+ /* If the line isn't a difference, output the context from file 0. */
+
+ if (next == null || i < next.line0) {
+ outfile.print(' ');
+ print_1_line ("", file0[i++]);
+ j++;
+ }
+ else {
+ /* For each difference, first output the deleted part. */
+
+ int k = next.deleted;
+ while (k-- > 0) {
+ outfile.print('-');
+ print_1_line ("", file0[i++]);
+ }
+
+ /* Then output the inserted part. */
+
+ k = next.inserted;
+ while (k-- > 0) {
+ outfile.print('+');
+ print_1_line ("", file1[j++]);
+ }
+
+ /* We're done with this hunk, so on to the next! */
+
+ next = next.link;
+ }
+ }
+ }
+ }
+
+
+ /** Read a text file into an array of String. This provides basic diff
+ functionality. A more advanced diff utility will use specialized
+ objects to represent the text lines, with options to, for example,
+ convert sequences of whitespace to a single space for comparison
+ purposes.
+ */
+ static String[] slurp(String file) throws IOException {
+ BufferedReader rdr = new BufferedReader(new FileReader(file));
+ Vector s = new Vector();
+ for (;;) {
+ String line = rdr.readLine();
+ if (line == null) break;
+ s.addElement(line);
+ }
+ String[] a = new String[s.size()];
+ s.copyInto(a);
+ return a;
+ }
+
+ public static void main(String[] argv) throws IOException {
+ String filea = argv[argv.length - 2];
+ String fileb = argv[argv.length - 1];
+ String[] a = slurp(filea);
+ String[] b = slurp(fileb);
+ Diff d = new Diff(a,b);
+ char style = 'n';
+ for (int i = 0; i < argv.length - 2; ++i) {
+ String f = argv[i];
+ if (f.startsWith("-")) {
+ for (int j = 1; j < f.length(); ++j) {
+ switch (f.charAt(j)) {
+ case 'e': // Ed style
+ style = 'e'; break;
+ case 'c': // Context diff
+ style = 'c'; break;
+ case 'u':
+ style = 'u'; break;
+ }
+ }
+ }
+ }
+ boolean reverse = style == 'e';
+ Diff.change script = d.diff_2(reverse);
+ if (script == null)
+ System.err.println("No differences");
+ else {
+ Base p;
+ Writer w = new OutputStreamWriter(System.out);
+ switch (style) {
+ case 'e':
+ p = new EdPrint(a,b,w); break;
+ case 'c':
+ p = new ContextPrint(a,b,w); break;
+ case 'u':
+ p = new UnifiedPrint(a,b,w); break;
+ default:
+ p = new NormalPrint(a,b,w);
+ }
+ p.print_header(filea,fileb);
+ p.print_script(script);
+ }
+ }
+
+ public static void doDiff(String[] argv, Writer w) throws IOException {
+ String filea = argv[argv.length - 2];
+ String fileb = argv[argv.length - 1];
+ String[] a = slurp(filea);
+ String[] b = slurp(fileb);
+ Diff d = new Diff(a,b);
+ char style = 'n';
+ for (int i = 0; i < argv.length - 2; ++i) {
+ String f = argv[i];
+ if (f.startsWith("-")) {
+ for (int j = 1; j < f.length(); ++j) {
+ switch (f.charAt(j)) {
+ case 'e': // Ed style
+ style = 'e'; break;
+ case 'c': // Context diff
+ style = 'c'; break;
+ case 'u':
+ style = 'u'; break;
+ }
+ }
+ }
+ }
+ boolean reverse = style == 'e';
+ Diff.change script = d.diff_2(reverse);
+ if (script == null)
+ w.write("No differences\n");
+ else {
+ Base p;
+ switch (style) {
+ case 'e':
+ p = new EdPrint(a,b,w); break;
+ case 'c':
+ p = new ContextPrint(a,b,w); break;
+ case 'u':
+ p = new UnifiedPrint(a,b,w); break;
+ default:
+ p = new NormalPrint(a,b,w);
+ }
+ p.print_header(filea,fileb);
+ p.print_script(script);
+ }
+ }
+
+}
diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala
new file mode 100644
index 0000000000..f774320f4e
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala
@@ -0,0 +1,78 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{File, PrintStream, FileOutputStream, BufferedReader,
+ InputStreamReader, StringWriter, PrintWriter}
+import java.util.StringTokenizer
+import scala.util.Properties.{ setProp }
+import scala.tools.nsc.io.Directory
+
+import scala.actors.Actor._
+import scala.actors.TIMEOUT
+
+trait DirectRunner {
+
+ def fileManager: FileManager
+
+ import PartestDefaults.numActors
+
+ if (isPartestDebug)
+ scala.actors.Debug.level = 3
+
+ if (PartestDefaults.poolSize.isEmpty) {
+ scala.actors.Debug.info("actors.corePoolSize not defined")
+ setProp("actors.corePoolSize", "16")
+ }
+
+ def runTestsForFiles(kindFiles: List[File], kind: String): scala.collection.immutable.Map[String, Int] = {
+ val len = kindFiles.length
+ val (testsEach, lastFrag) = (len/numActors, len%numActors)
+ val last = numActors-1
+ val workers = for (i <- List.range(0, numActors)) yield {
+ val toTest = kindFiles.slice(i*testsEach, (i+1)*testsEach)
+ val worker = new Worker(fileManager)
+ worker.start()
+ if (i == last)
+ worker ! RunTests(kind, (kindFiles splitAt (last*testsEach))._2)
+ else
+ worker ! RunTests(kind, toTest)
+ worker
+ }
+
+ var logsToDelete: List[File] = List()
+ var outdirsToDelete: List[File] = List()
+ var results = new scala.collection.immutable.HashMap[String, Int]
+ workers foreach { w =>
+ receiveWithin(3600 * 1000) {
+ case Results(res, logs, outdirs) =>
+ logsToDelete :::= logs filter (_.toDelete)
+ outdirsToDelete :::= outdirs
+ results ++= res
+ case TIMEOUT =>
+ // add at least one failure
+ NestUI.verbose("worker timed out; adding failed test")
+ results += ("worker timed out; adding failed test" -> 2)
+ }
+ }
+
+ if (isPartestDebug)
+ fileManager.showTestTimings()
+
+ if (!isPartestDebug) {
+ for (x <- logsToDelete ::: outdirsToDelete) {
+ NestUI.verbose("deleting "+x)
+ Directory(x).deleteRecursively()
+ }
+ }
+
+ results
+ }
+
+}
diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala
new file mode 100644
index 0000000000..bdbb34b3c4
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/FileManager.scala
@@ -0,0 +1,110 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.{File, FilenameFilter, IOException, StringWriter,
+ FileInputStream, FileOutputStream, BufferedReader,
+ FileReader, PrintWriter, FileWriter}
+import java.net.URI
+import scala.tools.nsc.io.{ Path, Directory }
+import scala.collection.mutable.HashMap
+
+trait FileManager {
+ /**
+ * Compares two files using a Java implementation of the GNU diff
+ * available at http://www.bmsi.com/java/#diff.
+ *
+ * @param f1 the first file to be compared
+ * @param f2 the second file to be compared
+ * @return the text difference between the compared files
+ */
+ def compareFiles(f1: File, f2: File): String = {
+ val diffWriter = new StringWriter
+ val args = Array(f1.getCanonicalPath(), f2.getCanonicalPath())
+
+ DiffPrint.doDiff(args, diffWriter)
+ val res = diffWriter.toString
+ if (res startsWith "No") "" else res
+ }
+
+ def testRootDir: Directory
+ def testRootPath: String
+
+ var JAVACMD: String
+ var JAVAC_CMD: String
+
+ var CLASSPATH: String
+ var LATEST_LIB: String
+
+ var showDiff = false
+ var showLog = false
+ var failed = false
+
+ var SCALAC_OPTS = PartestDefaults.scalacOpts
+ var JAVA_OPTS = PartestDefaults.javaOpts
+ var timeout = PartestDefaults.timeout
+
+ /** Only when --debug is given. */
+ lazy val testTimings = new HashMap[String, Long]
+ def recordTestTiming(name: String, milliseconds: Long) =
+ synchronized { testTimings(name) = milliseconds }
+ def showTestTimings() {
+ testTimings.toList sortBy (-_._2) foreach { case (k, v) => println("%s: %s".format(k, v)) }
+ }
+
+ def getLogFile(dir: File, fileBase: String, kind: String): LogFile =
+ new LogFile(dir, fileBase + "-" + kind + ".log")
+
+ def getLogFile(file: File, kind: String): LogFile = {
+ val dir = file.getParentFile
+ val fileBase = basename(file.getName)
+ getLogFile(dir, fileBase, kind)
+ }
+
+ def logFileExists(file: File, kind: String) =
+ getLogFile(file, kind).canRead
+
+ def overwriteFileWith(dest: File, file: File) =
+ dest.isFile && copyFile(file, dest)
+
+
+ def copyFile(from: File, dest: File): Boolean = {
+ def copyFile0(from: File, to: File): Boolean =
+ try {
+ val appender = StreamAppender(from, to)
+ appender.run()
+ appender.closeAll()
+ true
+ } catch {
+ case _: IOException => false
+ }
+
+ if (from.isDirectory) {
+ assert(dest.isDirectory, "cannot copy directory to file")
+ val subDir:Directory = Path(dest) / Directory(from.getName)
+ subDir.createDirectory()
+ from.listFiles.toList.forall(copyFile(_, subDir))
+ } else
+ copyFile0(from, if (dest.isDirectory) new File(dest, from.getName) else dest)
+ }
+
+ def mapFile(file: File, suffix: String, dir: File, replace: String => String) {
+ val tmpFile = File.createTempFile("tmp", suffix, dir) // prefix required by API
+
+ val appender = StreamAppender(file, tmpFile)
+ appender.runAndMap(replace)
+ appender.closeAll()
+
+ val appender2 = StreamAppender(tmpFile, file)
+ appender2.run()
+ appender2.closeAll()
+
+ tmpFile.delete()
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/NestRunner.scala b/src/partest/scala/tools/partest/nest/NestRunner.scala
new file mode 100644
index 0000000000..158521875e
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/NestRunner.scala
@@ -0,0 +1,16 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+object NestRunner {
+ def main(args: Array[String]) {
+ val argstr = args.mkString(" ")
+ (new ReflectiveRunner).main(argstr)
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala
new file mode 100644
index 0000000000..efff4e8375
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/NestUI.scala
@@ -0,0 +1,118 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io.PrintWriter
+
+object NestUI {
+
+ val NONE = 0
+ val SOME = 1
+ val MANY = 2
+
+ private var _outline = ""
+ private var _success = ""
+ private var _failure = ""
+ private var _warning = ""
+ private var _default = ""
+
+ def initialize(number: Int) = number match {
+ case MANY =>
+ _outline = Console.BOLD + Console.BLACK
+ _success = Console.BOLD + Console.GREEN
+ _failure = Console.BOLD + Console.RED
+ _warning = Console.BOLD + Console.YELLOW
+ _default = Console.RESET
+ case SOME =>
+ _outline = Console.BOLD + Console.BLACK
+ _success = Console.RESET
+ _failure = Console.BOLD + Console.BLACK
+ _warning = Console.BOLD + Console.BLACK
+ _default = Console.RESET
+ case _ =>
+ }
+
+ def outline(msg: String) = print(_outline + msg + _default)
+ def outline(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_outline + msg + _default)
+ }
+
+ def success(msg: String) = print(_success + msg + _default)
+ def success(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_success + msg + _default)
+ }
+
+ def failure(msg: String) = print(_failure + msg + _default)
+ def failure(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_failure + msg + _default)
+ }
+
+ def warning(msg: String) = print(_warning + msg + _default)
+ def warning(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_warning + msg + _default)
+ }
+
+ def normal(msg: String) = print(_default + msg)
+ def normal(msg: String, wr: PrintWriter) = synchronized {
+ wr.print(_default + msg)
+ }
+
+ def usage() {
+ println("Usage: NestRunner [<options>] [<testfile> ..] [<resfile>]")
+ println(" <testfile>: list of files ending in '.scala'")
+ println(" <resfile>: a file not ending in '.scala'")
+ println(" <options>:")
+ println
+ println(" Test categories:")
+ println(" --all run all tests")
+ println(" --pos run compilation tests (success)")
+ println(" --neg run compilation tests (failure)")
+ println(" --run run interpreter and backend tests")
+ println(" --jvm run JVM backend tests")
+ println(" --res run resident compiler tests")
+ println(" --buildmanager run Build Manager tests")
+ println(" --scalacheck run ScalaCheck tests")
+ println(" --script run script runner tests")
+ println(" --shootout run shootout tests")
+ println(" --grep <expr> run all tests whose source file contains <expr>")
+ println
+ println(" Other options:")
+ println(" --pack pick compiler/library in build/pack, and run all tests")
+ println(" --show-log show log")
+ println(" --show-diff show diff between log and check file")
+ println(" --failed run only those tests that failed during the last run")
+ println(" --verbose show progress information")
+ println(" --buildpath set (relative) path to build jars")
+ println(" ex.: --buildpath build/pack")
+ println(" --classpath set (absolute) path to build classes")
+ println(" --srcpath set (relative) path to test source files")
+ println(" ex.: --srcpath pending")
+ println(" --debug enable debugging output")
+ println
+ println(utils.Properties.versionString)
+ println("maintained by Philipp Haller (EPFL)")
+ exit(1)
+ }
+
+ var _verbose = false
+ var _debug = false
+
+ def verbose(msg: String) {
+ if (_verbose) {
+ outline("debug: ")
+ println(msg)
+ }
+ }
+ def debug(msg: String) {
+ if (isPartestDebug) {
+ outline("debug: ")
+ println(msg)
+ }
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala
new file mode 100644
index 0000000000..41bba5782e
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/PathSettings.scala
@@ -0,0 +1,41 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ */
+
+package scala.tools.partest
+package nest
+
+import scala.tools.nsc.Properties.{ setProp, propOrEmpty, propOrNone, propOrElse }
+import scala.tools.nsc.util.ClassPath
+import scala.tools.nsc.io
+import io.{ Path, File, Directory }
+import RunnerUtils._
+import java.net.URLClassLoader
+
+object PathSettings {
+ import PartestDefaults.{ testRootDir, srcDirName }
+
+ private def cwd = Directory.Current getOrElse error("user.dir property not set")
+ private def isPartestDir(d: Directory) = (d.name == "test") && (d / srcDirName isDirectory)
+
+ // Directory <root>/test
+ lazy val testRoot: Directory = testRootDir getOrElse {
+ val candidates: List[Directory] = (cwd :: cwd.parents) flatMap (d => List(d, Directory(d / "test")))
+
+ candidates find isPartestDir getOrElse error("Directory 'test' not found.")
+ }
+
+ // Directory <root>/test/files
+ lazy val srcDir = Directory(testRoot / srcDirName normalize)
+
+ // Directory <root>/test/files/lib
+ lazy val srcLibDir = Directory(srcDir / "lib")
+
+ lazy val scalaCheck = srcLibDir.files find (_.name startsWith "scalacheck") getOrElse {
+ error("No scalacheck jar found in '%s'" format srcLibDir)
+ }
+}
+
+class PathSettings() {
+ // def classpathAsURLs: List[URL]
+}
diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
new file mode 100644
index 0000000000..b3f199a3d6
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
@@ -0,0 +1,88 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import scala.tools.nsc.Properties.{ setProp, propOrEmpty }
+import scala.tools.nsc.util.ClassPath
+import scala.tools.nsc.io
+import io.Path
+import RunnerUtils._
+import java.net.URLClassLoader
+
+/* This class is used to load an instance of DirectRunner using
+ * a custom class loader.
+ * The purpose is to "auto-detect" a good classpath for the
+ * rest of the classes (Worker, CompileManager etc.), so that
+ * the main NestRunner can be started merely by putting its
+ * class on the classpath (ideally).
+ */
+class ReflectiveRunner {
+ // TODO: we might also use fileManager.CLASSPATH
+ // to use the same classes as used by `scala` that
+ // was used to start the runner.
+ val sepRunnerClassName = "scala.tools.partest.nest.ConsoleRunner"
+
+ def main(args: String) {
+ val argList = (args.split("\\s")).toList
+
+ if (isPartestDebug)
+ showAllJVMInfo
+
+ // find out which build to test
+ val buildPath = searchPath("--buildpath", argList)
+ val classPath = searchPath("--classpath", argList)
+ val fileManager =
+ if (!buildPath.isEmpty)
+ new ConsoleFileManager(buildPath.get)
+ else if (!classPath.isEmpty)
+ new ConsoleFileManager(classPath.get, true)
+ else if (argList contains "--pack")
+ new ConsoleFileManager("build/pack")
+ else // auto detection
+ new ConsoleFileManager
+
+ import fileManager.
+ { latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile }
+ val files =
+ Array(latestCompFile, latestLibFile, latestPartestFile, latestFjbgFile) map (x => io.File(x))
+
+ val sepUrls = files map (_.toURL)
+ val sepLoader = new URLClassLoader(sepUrls, null)
+
+ if (isPartestDebug)
+ println("Loading classes from:\n" + sepUrls.mkString("\n"))
+
+ val paths = classPath match {
+ case Some(cp) => Nil
+ case _ => files.toList map (_.path)
+ }
+ val newClasspath = ClassPath.join(paths: _*)
+
+ setProp("java.class.path", newClasspath)
+ setProp("scala.home", "")
+
+ if (isPartestDebug)
+ for (prop <- List("java.class.path", "sun.boot.class.path", "java.ext.dirs"))
+ println(prop + ": " + propOrEmpty(prop))
+
+ try {
+ val sepRunnerClass = sepLoader loadClass sepRunnerClassName
+ val sepRunner = sepRunnerClass.newInstance()
+ val sepMainMethod = sepRunnerClass.getMethod("main", Array(classOf[String]): _*)
+ val cargs: Array[AnyRef] = Array(args)
+ sepMainMethod.invoke(sepRunner, cargs: _*)
+ }
+ catch {
+ case cnfe: ClassNotFoundException =>
+ cnfe.printStackTrace()
+ NestUI.failure(sepRunnerClassName +" could not be loaded from:\n")
+ sepUrls foreach (x => NestUI.failure(x + "\n"))
+ }
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/RunnerUtils.scala b/src/partest/scala/tools/partest/nest/RunnerUtils.scala
new file mode 100644
index 0000000000..24445bb545
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/RunnerUtils.scala
@@ -0,0 +1,29 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+object RunnerUtils {
+ def splitArgs(str: String) = str split "\\s" filterNot (_ == "") toList
+
+ def searchPath(option: String, as: List[String]): Option[String] = as match {
+ case `option` :: r :: _ => Some(r)
+ case _ :: rest => searchPath(option, rest)
+ case Nil => None
+ }
+
+ def searchAndRemovePath(option: String, as: List[String]) = (as indexOf option) match {
+ case -1 => (None, as)
+ case idx => (Some(as(idx + 1)), (as take idx) ::: (as drop (idx + 2)))
+ }
+
+ def searchAndRemoveOption(option: String, as: List[String]) = (as indexOf option) match {
+ case -1 => (false, as)
+ case idx => (true, (as take idx) ::: (as drop (idx + 1)))
+ }
+}
diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala
new file mode 100644
index 0000000000..741556fdd5
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/TestFile.scala
@@ -0,0 +1,49 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 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.io._
+
+abstract class TestFile(kind: String) {
+ def file: JFile
+ def fileManager: FileManager
+
+ val dir = file.toAbsolute.parent
+ val fileBase = file.stripExtension
+ lazy val objectDir = dir / "%s-%s.obj".format(fileBase, kind) createDirectory true
+ val flags: Option[String] = dir / "%s.flags".format(fileBase) ifFile { _.slurp().trim }
+
+ def setOutDirTo = objectDir
+
+ def defineSettings(settings: Settings, setOutDir: Boolean) = {
+ settings.classpath append dir.path
+ if (setOutDir)
+ settings.outdir.value = setOutDirTo.path
+
+ flags foreach (settings processArgumentString _)
+ settings.classpath append fileManager.CLASSPATH
+ }
+
+ 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 BuildManagerTestFile(file: JFile, fileManager: FileManager) extends TestFile("bm")
+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
+}
diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala
new file mode 100644
index 0000000000..2f81dfd0f7
--- /dev/null
+++ b/src/partest/scala/tools/partest/nest/Worker.scala
@@ -0,0 +1,1071 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Philipp Haller
+ */
+
+// $Id$
+
+package scala.tools.partest
+package nest
+
+import java.io._
+import java.net.{ URLClassLoader, URL }
+import java.util.{ Timer, TimerTask }
+
+import scala.util.Properties.{ isWin }
+import scala.tools.nsc.{ ObjectRunner, Settings, CompilerCommand, Global }
+import scala.tools.nsc.io.{ AbstractFile, PlainFile, Path, Directory, File => SFile }
+import scala.tools.nsc.reporters.ConsoleReporter
+import scala.tools.nsc.util.{ ClassPath, FakePos }
+import ClassPath.{ join, split }
+
+import scala.actors.{ Actor, Exit, TIMEOUT }
+import scala.actors.Actor._
+import scala.tools.scalap.scalax.rules.scalasig.{ByteCode, ClassFileParser, ScalaSigAttributeParsers}
+
+import scala.collection.immutable.{ HashMap, Map => ImmMap }
+import scala.collection.Map
+
+import scala.tools.nsc.interactive.{BuildManager, RefinedBuildManager}
+
+case class RunTests(kind: String, files: List[File])
+case class Results(results: ImmMap[String, Int], logs: List[LogFile], outdirs: List[File])
+
+case class LogContext(file: LogFile, writers: Option[(StringWriter, PrintWriter)])
+
+abstract class TestResult {
+ def file: File
+}
+case class Result(override val file: File, context: LogContext) extends TestResult
+case class Timeout(override val file: File) extends TestResult
+
+class LogFile(parent: File, child: String) extends File(parent, child) {
+ var toDelete = false
+}
+
+class Worker(val fileManager: FileManager) extends Actor {
+ import fileManager._
+
+ var reporter: ConsoleReporter = _
+ val timer = new Timer
+
+ def error(msg: String): Unit = reporter.error(
+ FakePos("scalac"),
+ msg + "\n scalac -help gives more information"
+ )
+
+ def act() {
+ react {
+ case RunTests(kind, files) =>
+ // NestUI.verbose("received "+files.length+" to test")
+ val master = sender
+ runTests(kind, files) { results =>
+ master ! Results(results, createdLogFiles, createdOutputDirs)
+ }
+ }
+ }
+
+ def printInfoStart(file: File, printer: PrintWriter) {
+ NestUI.outline("testing: ", printer)
+ val filesdir = file.getAbsoluteFile.getParentFile.getParentFile
+ val testdir = filesdir.getParentFile
+ val totalWidth = 56
+ val name = {
+ // 1. try with [...]/files/run/test.scala
+ val testPathLen = testdir.getAbsolutePath.length
+ val name = file.getAbsolutePath.substring(testPathLen)
+ if (name.length <= totalWidth)
+ name
+ // 2. try with [...]/run/test.scala
+ else {
+ val filesPathLen = filesdir.getAbsolutePath.length
+ file.getAbsolutePath.substring(filesPathLen)
+ }
+ }
+ NestUI.normal("[...]%s%s".format(name, " " * (totalWidth - name.length)), printer)
+ }
+
+ def printInfoEnd(success: Boolean, printer: PrintWriter) {
+ NestUI.normal("[", printer)
+ if (success) NestUI.success(" OK ", printer)
+ else NestUI.failure("FAILED", printer)
+ NestUI.normal("]\n", printer)
+ }
+
+ def printInfoTimeout(printer: PrintWriter) {
+ NestUI.normal("[", printer)
+ NestUI.failure("TIMOUT", printer)
+ NestUI.normal("]\n", printer)
+ }
+
+ var log = ""
+ var createdLogFiles: List[LogFile] = Nil
+ var createdOutputDirs: List[File] = Nil
+
+ def createLogFile(file: File, kind: String): LogFile = {
+ val logFile = fileManager.getLogFile(file, kind)
+ createdLogFiles ::= logFile
+ logFile
+ }
+
+ def createOutputDir(dir: File, fileBase: String, kind: String): File = {
+ val outDir = Path(dir) / Directory("%s-%s.obj".format(fileBase, kind))
+ outDir.createDirectory()
+ createdOutputDirs ::= outDir.jfile
+ outDir.jfile
+ }
+
+ /* Note: not yet used/tested. */
+ // def execTestObjectRunner(file: File, outDir: File, logFile: File) {
+ // val consFM = new ConsoleFileManager
+ //
+ // val classpath: List[URL] = {
+ // import consFM.{ latestCompFile, latestLibFile, latestPartestFile }
+ // val units = (
+ // List(outDir, latestCompFile, latestLibFile, latestPartestFile) :::
+ // ((CLASSPATH split File.pathSeparatorChar).toList map (x => new File(x)))
+ // )
+ // units map (_.toURI.toURL)
+ // }
+ //
+ // NestUI.verbose("ObjectRunner classpath: "+classpath)
+ //
+ // try {
+ // // configure input/output files
+ // val logOut = new FileOutputStream(logFile)
+ // val logWriter = new PrintStream(logOut)
+ //
+ // // grab global lock
+ // fileManager.synchronized {
+ // withOutputRedirected(logWriter) {
+ // System.setProperty("java.library.path", logFile.getParentFile.getCanonicalFile.getAbsolutePath)
+ // System.setProperty("partest.output", outDir.getCanonicalFile.getAbsolutePath)
+ // System.setProperty("partest.lib", LATEST_LIB)
+ // System.setProperty("partest.cwd", outDir.getParent)
+ // ObjectRunner.run(classpath, "Test", List("jvm"))
+ // }
+ // }
+ //
+ // /*val out = new FileOutputStream(logFile, true)
+ // Console.withOut(new PrintStream(out)) {
+ // ObjectRunner.run(classpath, "Test", List("jvm"))
+ // }
+ // out.flush
+ // out.close*/
+ // } catch {
+ // case e: Exception =>
+ // NestUI.verbose(e+" ("+file.getPath+")")
+ // e.printStackTrace()
+ // }
+ // }
+
+ def javac(outDir: File, files: List[File], output: File): Boolean = {
+ // compile using command-line javac compiler
+ val javacCmd = if ((fileManager.JAVAC_CMD.indexOf("${env.JAVA_HOME}") != -1) ||
+ fileManager.JAVAC_CMD.equals("/bin/javac") ||
+ fileManager.JAVAC_CMD.equals("\\bin\\javac"))
+ "javac"
+ else
+ fileManager.JAVAC_CMD
+
+ val cmd = javacCmd+
+ " -d "+outDir.getAbsolutePath+
+ " -classpath "+ join(outDir.toString, CLASSPATH) +
+ " "+files.mkString(" ")
+
+ val (success, msg) = try {
+ val exitCode = runCommand(cmd, output)
+ NestUI.verbose("javac returned exit code: "+exitCode)
+ if (exitCode != 0)
+ (false, "Running \"javac\" failed with exit code: "+exitCode+"\n"+cmd+"\n")
+ else
+ (true, "")
+ } catch {
+ case e: Exception =>
+ val swriter = new StringWriter
+ e.printStackTrace(new PrintWriter(swriter))
+ (false, "Running \"javac\" failed:\n"+cmd+"\n"+swriter.toString+"\n")
+ }
+ if (!success) {
+ val writer = new PrintWriter(new FileWriter(output, true), true)
+ writer.print(msg)
+ writer.close()
+ }
+ success
+ }
+
+ /** Runs <code>command</code> redirecting standard out and
+ * error out to <code>output</code> file.
+ */
+ def runCommand(command: String, output: File): Int = {
+ NestUI.verbose("running command:\n"+command)
+ val proc = Runtime.getRuntime.exec(command)
+ val in = proc.getInputStream
+ val err = proc.getErrorStream
+ val writer = new PrintWriter(new FileWriter(output), true)
+ val inApp = StreamAppender(in, writer)
+ val errApp = StreamAppender(err, writer)
+ val async = new Thread(errApp)
+ async.start()
+ inApp.run()
+ async.join()
+ writer.close()
+
+ try proc.exitValue()
+ catch { case _: IllegalThreadStateException => 0 }
+ }
+
+ def execTest(outDir: File, logFile: File, fileBase: String) {
+ // check whether there is a ".javaopts" file
+ val argsFile = new File(logFile.getParentFile, fileBase+".javaopts")
+ val argString = if (argsFile.exists) {
+ NestUI.verbose("Found javaopts file: "+argsFile)
+ val fileReader = new FileReader(argsFile)
+ val reader = new BufferedReader(fileReader)
+ val options = reader.readLine()
+ reader.close()
+ NestUI.verbose("Found javaopts file '%s', using options: '%s'".format(argsFile, options))
+ options
+ } else ""
+
+ def quote(path: String) = "\""+path+"\""
+
+ // 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 propertyOptions = List(
+ "-Djava.library.path="+logFile.getParentFile.getAbsolutePath,
+ "-Dpartest.output="+outDir.getAbsolutePath,
+ "-Dpartest.lib="+LATEST_LIB,
+ "-Dpartest.cwd="+outDir.getParent,
+ "-Djavacmd="+JAVACMD,
+ "-Duser.language=en -Duser.country=US"
+ ) ::: (
+ if (isPartestDebug) List("-Dpartest.debug=true") else Nil
+ )
+
+ val cmd = (
+ List(
+ JAVACMD,
+ JAVA_OPTS,
+ argString,
+ "-classpath " + join(outDir.toString, CLASSPATH)
+ ) ::: propertyOptions ::: List(
+ "scala.tools.nsc.MainGenericRunner",
+ "-usejavacp",
+ "Test",
+ "jvm"
+ )
+ ) mkString " "
+
+ runCommand(cmd, logFile)
+
+ if (fileManager.showLog) {
+ // produce log as string in `log`
+ val reader = new BufferedReader(new FileReader(logFile))
+ val swriter = new StringWriter
+ val pwriter = new PrintWriter(swriter, true)
+ val appender = new StreamAppender(reader, pwriter)
+ appender.run()
+ log = swriter.toString
+ }
+ }
+
+ def getCheckFile(dir: File, fileBase: String, kind: String) = {
+ def chkFile(s: String) = Directory(dir) / "%s%s.check".format(fileBase, s)
+ val checkFile = if (chkFile("").isFile) chkFile("") else chkFile("-" + kind)
+
+ if (checkFile.canRead) Some(checkFile) else None
+ }
+
+ def existsCheckFile(dir: File, fileBase: String, kind: String) =
+ getCheckFile(dir, fileBase, kind).isDefined
+
+ def compareOutput(dir: File, fileBase: String, kind: String, logFile: File): String =
+ // if check file exists, compare with log file
+ getCheckFile(dir, fileBase, kind) match {
+ case Some(f) => fileManager.compareFiles(logFile, f.jfile)
+ case _ => file2String(logFile)
+ }
+
+ def file2String(logFile: File) = SFile(logFile).slurp()
+ def isJava(f: File) = SFile(f) hasExtension "java"
+ def isScala(f: File) = SFile(f) hasExtension "scala"
+ def isJavaOrScala(f: File) = isJava(f) || isScala(f)
+
+ /** Runs a list of tests.
+ *
+ * @param kind The test kind (pos, neg, run, etc.)
+ * @param files The list of test files
+ */
+ def runTests(kind: String, files: List[File])(topcont: ImmMap[String, Int] => Unit) {
+ val compileMgr = new CompileManager(fileManager)
+ var errors = 0
+ var succeeded = true
+ var diff = ""
+ var log = ""
+
+ def fail(what: Any) {
+ NestUI.verbose("scalac: compilation of "+what+" failed\n")
+ succeeded = false
+ }
+ def diffCheck(latestDiff: String) = {
+ diff = latestDiff
+ if (latestDiff != "") {
+ NestUI.verbose("output differs from log file\n")
+ succeeded = false
+ }
+ }
+
+ /** 1. Creates log file and output directory.
+ * 2. Runs <code>script</code> function, providing log file and
+ * output directory as arguments.
+ */
+ def runInContext(file: File, kind: String, script: (File, File) => Unit): LogContext = {
+ // when option "--failed" is provided
+ // execute test only if log file is present
+ // (which means it failed before)
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true
+ diff = ""
+ log = ""
+ printInfoStart(file, wr)
+
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+ val dir = file.getParentFile
+ val outDir = createOutputDir(dir, fileBase, kind)
+ NestUI.verbose("output directory: "+outDir)
+
+ // run test-specific code
+ try {
+ if (isPartestDebug) {
+ val t1 = System.currentTimeMillis
+ script(logFile, outDir)
+ val t2 = System.currentTimeMillis
+ fileManager.recordTestTiming(file.getPath, t2 - t1)
+ }
+ else {
+ script(logFile, outDir)
+ }
+ } catch {
+ case e: Exception =>
+ val writer = new PrintWriter(new FileWriter(logFile), true)
+ e.printStackTrace(writer)
+ writer.close()
+ succeeded = false
+ }
+
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ }
+
+ def compileFilesIn(dir: File, kind: String, logFile: File, outDir: 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)))
+ val noGroupSuffix = testFiles -- groups.flatten
+
+ def compileGroup(g: List[File]) {
+ val (scalaFiles, javaFiles) = g partition isScala
+
+ if (scalaFiles.nonEmpty) {
+ if (!compileMgr.shouldCompile(outDir, javaFiles ::: scalaFiles, kind, logFile))
+ fail(g)
+ }
+
+ if (succeeded && javaFiles.nonEmpty) {
+ succeeded = javac(outDir, javaFiles, logFile)
+ if (succeeded && scalaFiles.nonEmpty && !compileMgr.shouldCompile(outDir, scalaFiles, kind, logFile))
+ fail(scalaFiles)
+ }
+ }
+
+ if (noGroupSuffix.nonEmpty)
+ compileGroup(noGroupSuffix)
+
+ groups foreach (grp => if (succeeded) compileGroup(grp))
+ }
+
+ def failCompileFilesIn(dir: File, kind: String, logFile: File, outDir: File) {
+ val testFiles = dir.listFiles.toList
+ val sourceFiles = testFiles filter isJavaOrScala
+
+ if (sourceFiles.nonEmpty) {
+ if (!compileMgr.shouldFailCompile(outDir, sourceFiles, kind, logFile))
+ fail(testFiles filter isScala)
+ }
+ }
+
+ def runTestCommon(file: File, kind: String, expectFailure: Boolean)(onSuccess: (File, File) => Unit): LogContext =
+ runInContext(file, kind, (logFile: File, outDir: File) => {
+
+ if (file.isDirectory) {
+ val f = if (expectFailure) failCompileFilesIn _ else compileFilesIn _
+ f(file, kind, logFile, outDir)
+ }
+ else {
+ val f: (List[File], String, File) => Boolean =
+ if (expectFailure) compileMgr.shouldFailCompile _
+ else compileMgr.shouldCompile _
+
+ if (!f(List(file), kind, logFile))
+ fail(file)
+ }
+
+ if (succeeded) // run test
+ onSuccess(logFile, outDir)
+ })
+
+ def runJvmTest(file: File, kind: String): LogContext =
+ runTestCommon(file, kind, expectFailure = false)((logFile, outDir) => {
+ val fileBase = basename(file.getName)
+ val dir = file.getParentFile
+
+ //TODO: detect whether we have to use Runtime.exec
+ // val useRuntime = true
+ //
+ // if (useRuntime)
+ // execTest(outDir, logFile, fileBase)
+ // else
+ // execTestObjectRunner(file, outDir, logFile)
+ // // NestUI.verbose(this+" finished running "+fileBase)
+ execTest(outDir, logFile, fileBase)
+
+ diffCheck(compareOutput(dir, fileBase, kind, logFile))
+ })
+
+ def processSingleFile(file: File): LogContext = kind match {
+ case "scalacheck" =>
+ runTestCommon(file, kind, expectFailure = false)((logFile, outDir) => {
+ val consFM = new ConsoleFileManager
+ import consFM.{ latestCompFile, latestLibFile, latestPartestFile }
+
+ NestUI.verbose("compilation of "+file+" succeeded\n")
+
+ val scalacheckURL = PathSettings.scalaCheck.toURL
+ val outURL = outDir.getCanonicalFile.toURI.toURL
+ val classpath: List[URL] =
+ List(outURL, scalacheckURL, latestCompFile.toURI.toURL, latestLibFile.toURI.toURL, latestPartestFile.toURI.toURL).distinct
+
+ NestUI.debug("scalacheck urls")
+ classpath foreach (x => NestUI.debug(x.toString))
+
+ val logWriter = new PrintStream(new FileOutputStream(logFile))
+
+ withOutputRedirected(logWriter) {
+ ObjectRunner.run(classpath, "Test", Nil)
+ }
+
+ NestUI.verbose(SFile(logFile).slurp())
+ // obviously this must be improved upon
+ succeeded = SFile(logFile).lines() forall (_ contains " OK")
+ })
+
+ case "pos" =>
+ runTestCommon(file, kind, expectFailure = false)((_, _) => ())
+
+ case "neg" =>
+ runTestCommon(file, kind, expectFailure = true)((logFile, outDir) => {
+ // compare log file to check file
+ val fileBase = basename(file.getName)
+ val dir = file.getParentFile
+
+ diffCheck(
+ // diff is contents of logFile
+ if (!existsCheckFile(dir, fileBase, kind)) file2String(logFile)
+ else compareOutput(dir, fileBase, kind, logFile)
+ )
+ })
+
+ case "run" | "jvm" =>
+ runJvmTest(file, kind)
+
+ case "buildmanager" =>
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true; diff = ""
+ printInfoStart(file, wr)
+ val (outDir, testFile, changesDir, fileBase) =
+
+ if (!file.isDirectory) {
+ succeeded = false
+ (null, null, null, null)
+ } else {
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+ val outDir = createOutputDir(file, fileBase, kind)
+ if (!outDir.exists) outDir.mkdir()
+ val testFile = new File(file, fileBase + ".test")
+ val changesDir = new File(file, fileBase + ".changes")
+ if (changesDir.isFile || !testFile.isFile) {
+ // if changes exists then it has to be a dir
+ if (!testFile.isFile) NestUI.verbose("invalid build manager test file")
+ if (changesDir.isFile) NestUI.verbose("invalid build manager changes directory")
+ succeeded = false
+ (null, null, null, null)
+ } else {
+ copyTestFiles(file, outDir)
+ NestUI.verbose("outDir: "+outDir)
+ NestUI.verbose("logFile: "+logFile)
+ (outDir, testFile, changesDir, fileBase)
+ }
+ }
+
+ if (succeeded) {
+ // Pre-conditions satisfied
+
+ try {
+ val sourcepath = outDir.getAbsolutePath+File.separator
+
+ // configure input/output files
+ val logWriter = new PrintStream(new FileOutputStream(logFile))
+ val testReader = new BufferedReader(new FileReader(testFile))
+ val logConsoleWriter = new PrintWriter(logWriter)
+
+ // create proper settings for the compiler
+ val settings = new Settings(error)
+ settings.outdir.value = outDir.getCanonicalFile.getAbsolutePath
+ settings.sourcepath.value = sourcepath
+ settings.classpath.value = fileManager.CLASSPATH
+ settings.Ybuildmanagerdebug.value = true
+
+ // simulate Build Manager loop
+ val prompt = "builder > "
+ reporter = new ConsoleReporter(settings, scala.Console.in, logConsoleWriter)
+ val bM: BuildManager =
+ new RefinedBuildManager(settings) {
+ override protected def newCompiler(settings: Settings) =
+ new BuilderGlobal(settings, reporter)
+ }
+
+ val testCompile = (line: String) => {
+ NestUI.verbose("compiling " + line)
+ val args = (line split ' ').toList
+ val command = new CompilerCommand(args, settings)
+ bM.update(filesToSet(settings.sourcepath.value, command.files), Set.empty)
+ !reporter.hasErrors
+ }
+
+ val updateFiles = (line: String) => {
+ NestUI.verbose("updating " + line)
+ val res =
+ ((line split ' ').toList).forall(u => {
+ (u split "=>").toList match {
+ case origFileName::(newFileName::Nil) =>
+ val newFile = new File(changesDir, newFileName)
+ if (newFile.isFile) {
+ val v = overwriteFileWith(new File(outDir, origFileName), newFile)
+ if (!v)
+ NestUI.verbose("'update' operation on " + u + " failed")
+ v
+ } else {
+ NestUI.verbose("File " + newFile + " is invalid")
+ false
+ }
+ case a =>
+ NestUI.verbose("Other =: " + a)
+ false
+ }
+ })
+ if (!res)
+ NestUI.verbose("updating failed")
+ else
+ NestUI.verbose("updating succeeded")
+ res
+ }
+
+ def loop() {
+ val command = testReader.readLine()
+ if ((command ne null) && command.length() > 0) {
+ val commandResult = command match {
+ case s if (s.startsWith(">>update ")) =>
+ updateFiles(s.stripPrefix(">>update "))
+ case s if (s.startsWith(">>compile ")) =>
+ val files = s.stripPrefix(">>compile ")
+ logWriter.println(prompt + files)
+ testCompile(files) // In the end, it can finish with an error
+ case _ =>
+ NestUI.verbose("wrong command in test file: " + command)
+ false
+ }
+
+ if (commandResult) loop()
+
+ } else {
+ NestUI.verbose("finished")
+ succeeded = true
+ }
+ }
+
+ withOutputRedirected(logWriter) {
+ loop()
+ testReader.close()
+ }
+
+ fileManager.mapFile(logFile, "tmp", file, _.replace(sourcepath, ""))
+
+ diffCheck(compareOutput(file, fileBase, kind, logFile))
+ }
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ } else
+ LogContext(logFile, None)
+
+ case "res" => {
+ // when option "--failed" is provided
+ // execute test only if log file is present
+ // (which means it failed before)
+
+ //val (logFileOut, logFileErr) = createLogFiles(file, kind)
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true; diff = ""; log = ""
+ printInfoStart(file, wr)
+
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+ val dir = file.getParentFile
+ val outDir = createOutputDir(dir, fileBase, kind)
+ if (!outDir.exists) outDir.mkdir()
+ 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 . "$@"
+
+ try {
+
+ val sourcedir = logFile.getParentFile.getCanonicalFile
+ val sourcepath = sourcedir.getAbsolutePath+File.separator
+ NestUI.verbose("sourcepath: "+sourcepath)
+
+ val argString =
+ "-d "+outDir.getCanonicalFile.getAbsolutePath+
+ " -Xresident"+
+ " -sourcepath "+sourcepath
+ val argList = argString split ' ' toList
+
+ // configure input/output files
+ val logOut = new FileOutputStream(logFile)
+ val logWriter = new PrintStream(logOut)
+ val resReader = new BufferedReader(new FileReader(resFile))
+ val logConsoleWriter = new PrintWriter(new OutputStreamWriter(logOut))
+
+ // create compiler
+ val settings = new Settings(error)
+ settings.sourcepath.value = sourcepath
+ settings.classpath.value = fileManager.CLASSPATH
+ reporter = new ConsoleReporter(settings, scala.Console.in, logConsoleWriter)
+ val command = new CompilerCommand(argList, settings)
+ object compiler extends Global(command.settings, reporter)
+
+ // simulate resident compiler loop
+ val prompt = "\nnsc> "
+
+ val resCompile = (line: String) => {
+ NestUI.verbose("compiling "+line)
+ val cmdArgs = (line split ' ').toList map (fs => new File(dir, fs).getAbsolutePath)
+ NestUI.verbose("cmdArgs: "+cmdArgs)
+ val sett = new Settings(error)
+ sett.sourcepath.value = sourcepath
+ val command = new CompilerCommand(cmdArgs, sett)
+ (new compiler.Run) compile command.files
+ }
+
+ def loop(action: (String) => Unit) {
+ logWriter.print(prompt)
+ val line = resReader.readLine()
+ if ((line ne null) && line.length() > 0) {
+/*
+ val parent = self
+ self.trapExit = true
+ val child = link {
+ action(line)
+ }
+
+ receiveWithin(fileManager.timeout.toLong) {
+ case TIMEOUT =>
+ NestUI.verbose("action timed out")
+ false
+ case Exit(from, reason) if from == child => reason match {
+ case 'normal => // do nothing
+ case t: Throwable =>
+ NestUI.verbose("while invoking compiler:")
+ NestUI.verbose("caught "+t)
+ t.printStackTrace
+ if (t.getCause != null)
+ t.getCause.printStackTrace
+ false
+ }
+ }
+*/
+ action(line)
+ loop(action)
+ }
+ }
+
+ withOutputRedirected(logWriter) {
+ loop(resCompile)
+ resReader.close()
+ }
+
+ def replaceSlashes(s: String): String = {
+ val path = dir.getAbsolutePath+File.separator
+ // find `path` in `line`
+ val index = s.indexOf(path)
+ val line =
+ if (index != -1)
+ s.substring(0, index) + s.substring(index + path.length, s.length)
+ else s
+ line.replace('\\', '/')
+ }
+
+ fileManager.mapFile(logFile, "tmp", dir, replaceSlashes)
+ diffCheck(compareOutput(dir, fileBase, kind, logFile))
+
+ } catch {
+ case e: Exception =>
+ e.printStackTrace()
+ succeeded = false
+ }
+
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ }
+
+ case "shootout" => {
+ // when option "--failed" is provided
+ // execute test only if log file is present
+ // (which means it failed before)
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true; diff = ""; log = ""
+ printInfoStart(file, wr)
+
+ val fileBase: String = basename(file.getName)
+ NestUI.verbose(this+" running test "+fileBase)
+ val dir = file.getParentFile
+ val outDir = createOutputDir(dir, fileBase, kind)
+ if (!outDir.exists) outDir.mkdir()
+
+ // 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(dir, fileBase+".scala.runner")
+ val bodyFile = new File(dir, fileBase+".scala")
+ val appender = StreamAppender.concat(new FileInputStream(runnerFile),
+ new FileInputStream(bodyFile),
+ new FileOutputStream(testFile))
+ appender.run()
+
+ try { // *catch-all*
+ // 4. compile testFile
+ if (!compileMgr.shouldCompile(List(testFile), kind, logFile)) {
+ NestUI.verbose("compilation of "+file+" failed\n")
+ succeeded = false
+ } else {
+ NestUI.verbose("compilation of "+testFile+"succeeded")
+ // -------- run test --------
+
+ //TODO: detect whether we have to use Runtime.exec
+ // val useRuntime = true
+ //
+ // if (useRuntime)
+ // execTest(outDir, logFile, fileBase)
+ // else
+ // execTestObjectRunner(file, outDir, logFile)
+
+ execTest(outDir, logFile, fileBase)
+
+ NestUI.verbose(this+" finished running "+fileBase)
+ } // successful compile
+ } catch { // *catch-all*
+ case e: Exception =>
+ NestUI.verbose("caught "+e)
+ succeeded = false
+ }
+
+ diffCheck(compareOutput(dir, fileBase, kind, logFile))
+
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ }
+
+ case "scalap" => {
+
+ runInContext(file, kind, (logFile: File, outDir: File) => {
+ val sourceDir = file.getParentFile
+ val sourceDirName = sourceDir.getName
+
+ // 1. Find file with result text
+ val results = sourceDir.listFiles(new FilenameFilter {
+ def accept(dir: File, name: String) = name == "result.test"
+ })
+
+ if (results.length != 1) {
+ NestUI.verbose("Result file not found in directory " + sourceDirName + " \n")
+ } else {
+ val resFile = results(0)
+ // 2. Compile source file
+ if (!compileMgr.shouldCompile(outDir, List(file), kind, logFile)) {
+ NestUI.verbose("compilerMgr failed to compile %s to %s".format(file, outDir))
+ succeeded = false
+ } else {
+
+ // 3. Decompile file and compare results
+ val isPackageObject = sourceDir.getName.startsWith("package")
+ val className = sourceDirName.capitalize + (if (!isPackageObject) "" else ".package")
+ val url = outDir.toURI.toURL
+ val loader = new URLClassLoader(Array(url), getClass.getClassLoader)
+ val clazz = loader.loadClass(className)
+
+ val byteCode = ByteCode.forClass(clazz)
+ val result = scala.tools.scalap.Main.decompileScala(byteCode.bytes, isPackageObject)
+
+ try {
+ val fstream = new FileWriter(logFile);
+ val out = new BufferedWriter(fstream);
+ out.write(result)
+ out.close();
+ } catch {
+ case e: IOException => NestUI.verbose(e.getMessage()); succeeded = false
+ }
+
+ diffCheck(fileManager.compareFiles(logFile, resFile))
+ }
+ }
+ })
+ }
+
+ case "script" => {
+ // when option "--failed" is provided
+ // execute test only if log file is present
+ // (which means it failed before)
+ val logFile = createLogFile(file, kind)
+ if (!fileManager.failed || logFile.canRead) {
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ succeeded = true; diff = ""; log = ""
+ printInfoStart(file, wr)
+
+ val fileBase: String = basename(file.getName)
+ 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 = if (argsFile.exists) {
+ val swriter = new StringWriter
+ val app = StreamAppender(new BufferedReader(new FileReader(argsFile)),
+ swriter)
+ app.run()
+ " "+swriter.toString
+ } else ""
+
+ try {
+ val cmdString =
+ if (isWin) {
+ val batchFile = new File(file.getParentFile, fileBase+".bat")
+ NestUI.verbose("batchFile: "+batchFile)
+ batchFile.getAbsolutePath
+ }
+ else file.getAbsolutePath
+ val proc = Runtime.getRuntime.exec(cmdString+argString)
+ val in = proc.getInputStream
+ val err = proc.getErrorStream
+ val writer = new PrintWriter(new FileWriter(logFile), true)
+ val inApp = new StreamAppender(new BufferedReader(new InputStreamReader(in)),
+ writer)
+ val errApp = new StreamAppender(new BufferedReader(new InputStreamReader(err)),
+ writer)
+ val async = new Thread(errApp)
+ async.start()
+ inApp.run()
+ async.join()
+
+ writer.close()
+
+ diffCheck(compareOutput(file.getParentFile, fileBase, kind, logFile))
+ } catch { // *catch-all*
+ case e: Exception =>
+ NestUI.verbose("caught "+e)
+ succeeded = false
+ }
+
+ LogContext(logFile, Some((swr, wr)))
+ } else
+ LogContext(logFile, None)
+ }
+ }
+
+ def reportAll(results: ImmMap[String, Int], cont: ImmMap[String, Int] => Unit) {
+ // NestUI.verbose("finished testing "+kind+" with "+errors+" errors")
+ // NestUI.verbose("created "+compileMgr.numSeparateCompilers+" separate compilers")
+ timer.cancel()
+ cont(results)
+ }
+
+ def reportResult(state: Int, logFile: Option[LogFile], writers: Option[(StringWriter, PrintWriter)]) {
+ val good = (state == 0)
+ if (!good) {
+ errors += 1
+ NestUI.verbose("incremented errors: "+errors)
+ }
+
+ try {
+ // delete log file only if test was successful
+ if (good && !logFile.isEmpty && !isPartestDebug)
+ logFile.get.toDelete = true
+
+ writers match {
+ case Some((swr, wr)) =>
+ if (state == 2)
+ printInfoTimeout(wr)
+ else
+ printInfoEnd(good, wr)
+ wr.flush()
+ swr.flush()
+ NestUI.normal(swr.toString)
+ if (state == 1 && fileManager.showDiff && diff != "")
+ NestUI.normal(diff)
+ if (state == 1 && fileManager.showLog)
+ showLog(logFile.get)
+ case None =>
+ }
+ } catch {
+ case npe: NullPointerException =>
+ }
+ }
+
+ val numFiles = files.size
+ if (numFiles == 0)
+ reportAll(ImmMap(), topcont)
+
+ // maps canonical file names to the test result (0: OK, 1: FAILED, 2: TIMOUT)
+ var status = new HashMap[String, Int]
+
+ var fileCnt = 1
+ Actor.loopWhile(fileCnt <= numFiles) {
+ val parent = self
+
+ actor {
+ val testFile = files(fileCnt-1)
+
+ val ontimeout = new TimerTask {
+ def run() = parent ! Timeout(testFile)
+ }
+ timer.schedule(ontimeout, fileManager.timeout.toLong)
+
+ val context = try {
+ processSingleFile(testFile)
+ } catch {
+ case t: Throwable =>
+ NestUI.verbose("while invoking compiler ("+files+"):")
+ NestUI.verbose("caught "+t)
+ t.printStackTrace
+ if (t.getCause != null)
+ t.getCause.printStackTrace
+ LogContext(null, None)
+ }
+ parent ! Result(testFile, context)
+ }
+
+ react {
+ case res: TestResult =>
+ val path = res.file.getCanonicalPath
+ status.get(path) match {
+ case Some(stat) => // ignore message
+ case None =>
+ res match {
+ case Timeout(_) =>
+ status = status + (path -> 2)
+ val swr = new StringWriter
+ val wr = new PrintWriter(swr)
+ printInfoStart(res.file, wr)
+ succeeded = false
+ reportResult(2, None, Some((swr, wr)))
+ case Result(_, logs) =>
+ status = status + (path -> (if (succeeded) 0 else 1))
+ reportResult(
+ if (succeeded) 0 else 1,
+ if (logs != null) Some(logs.file) else None,
+ if (logs != null) logs.writers else None)
+ }
+ if (fileCnt == numFiles)
+ reportAll(status, topcont)
+ fileCnt += 1
+ }
+ }
+ }
+ }
+
+ private def withOutputRedirected(out: PrintStream)(func: => Unit) {
+ val oldStdOut = System.out
+ val oldStdErr = System.err
+
+ try {
+ System.setOut(out)
+ System.setErr(out)
+ func
+ out.flush()
+ out.close()
+ } finally {
+ System.setOut(oldStdOut)
+ System.setErr(oldStdErr)
+ }
+ }
+
+ 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) }
+ }
+
+ def showLog(logFile: File) {
+ try {
+ val logReader = new BufferedReader(new FileReader(logFile))
+ val strWriter = new StringWriter
+ val logWriter = new PrintWriter(strWriter, true)
+ val logAppender = new StreamAppender(logReader, logWriter)
+ logAppender.run()
+ logReader.close()
+ val log = strWriter.toString
+ NestUI.normal(log)
+ } catch {
+ case fnfe: java.io.FileNotFoundException =>
+ NestUI.failure("Couldn't open log file \""+logFile+"\".")
+ }
+ }
+}
diff --git a/src/partest/scala/tools/partest/package.scala b/src/partest/scala/tools/partest/package.scala
index f6d216e379..e9eda6fb75 100644
--- a/src/partest/scala/tools/partest/package.scala
+++ b/src/partest/scala/tools/partest/package.scala
@@ -4,42 +4,37 @@
package scala.tools
-import nsc.io.{ File, Path, Process, Directory }
-import java.nio.charset.CharacterCodingException
+import java.io.{ File => JFile }
+import nsc.io.{ Path, Process, Directory }
+import util.{ PathResolver }
+import nsc.Properties.{ propOrElse, propOrNone, propOrEmpty }
package object partest {
- /** The CharacterCodingExceptions are thrown at least on windows trying
- * to read a file like script/utf-8.scala
- */
- private[partest] def safeSlurp(f: File) =
- try if (f.exists) f.slurp() else ""
- catch { case _: CharacterCodingException => "" }
-
- private[partest] def safeLines(f: File) = safeSlurp(f) split """\r\n|\r|\n""" toList
- private[partest] def safeArgs(f: File) = toArgs(safeSlurp(f))
- private[partest] def isJava(f: Path) = f.isFile && (f hasExtension "java")
- private[partest] def isScala(f: Path) = f.isFile && (f hasExtension "scala")
- private[partest] def isJavaOrScala(f: Path) = isJava(f) || isScala(f)
-
- private[partest] def toArgs(line: String) = cmd toArgs line
- private[partest] def fromArgs(args: List[String]) = cmd fromArgs args
-
- /** Strings, argument lists, etc. */
-
- private[partest] def fromAnyArgs(args: List[Any]) = args mkString " " // separate to avoid accidents
- private[partest] def toStringTrunc(x: Any, max: Int = 240) = {
- val s = x.toString
- if (s.length < max) s
- else (s take max) + " [...]"
+ import nest.NestUI
+
+ implicit private[partest] def temporaryPath2File(x: Path): JFile = x.jfile
+ implicit private[partest] def temporaryFile2Path(x: JFile): Path = Path(x)
+
+ def basename(name: String): String = Path(name).stripExtension
+ def resultsToStatistics(results: Iterable[(_, Int)]): (Int, Int) = {
+ val (files, failures) = results map (_._2 == 0) partition (_ == true)
+ (files.size, failures.size)
+ }
+
+ def vmArgString = {
+ val str = Process.javaVmArguments mkString " "
+ "Java VM started with arguments: '%s'" format str
+ }
+
+ def allPropertiesString = {
+ import collection.JavaConversions._
+ System.getProperties.toList.sorted map { case (k, v) => "%s -> %s\n".format(k, v) } mkString
}
- private[partest] def setProp(k: String, v: String) = scala.util.Properties.setProp(k, v)
- /** Pretty self explanatory. */
- def printAndExit(msg: String): Unit = {
- println(msg)
- exit(1)
+ def showAllJVMInfo {
+ NestUI.verbose(vmArgString)
+ NestUI.verbose(allPropertiesString)
}
- /** Apply a function and return the passed value */
- def returning[T](x: T)(f: T => Unit): T = { f(x) ; x }
+ def isPartestDebug = propOrEmpty("partest.debug") == "true"
} \ No newline at end of file
diff --git a/src/partest/scala/tools/partest/utils/PrintMgr.scala b/src/partest/scala/tools/partest/utils/PrintMgr.scala
new file mode 100644
index 0000000000..10533130f1
--- /dev/null
+++ b/src/partest/scala/tools/partest/utils/PrintMgr.scala
@@ -0,0 +1,52 @@
+/* __ *\
+** ________ ___ / / ___ Scala Parallel Testing **
+** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+package scala.tools.partest
+package utils
+
+/**
+ * @author Thomas Hofer
+ */
+object PrintMgr {
+
+ val NONE = 0
+ val SOME = 1
+ val MANY = 2
+
+ var outline = ""
+ var success = ""
+ var failure = ""
+ var warning = ""
+ var default = ""
+
+ def initialization(number: Int) = number match {
+ case MANY =>
+ outline = Console.BOLD + Console.BLACK
+ success = Console.BOLD + Console.GREEN
+ failure = Console.BOLD + Console.RED
+ warning = Console.BOLD + Console.YELLOW
+ default = Console.RESET
+ case SOME =>
+ outline = Console.BOLD + Console.BLACK
+ success = Console.RESET
+ failure = Console.BOLD + Console.BLACK
+ warning = Console.BOLD + Console.BLACK
+ default = Console.RESET
+ case _ =>
+ }
+
+ def printOutline(msg: String) = print(outline + msg + default)
+
+ def printSuccess(msg: String) = print(success + msg + default)
+
+ def printFailure(msg: String) = print(failure + msg + default)
+
+ def printWarning(msg: String) = print(warning + msg + default)
+}
diff --git a/src/partest/scala/tools/partest/utils/Properties.scala b/src/partest/scala/tools/partest/utils/Properties.scala
new file mode 100644
index 0000000000..237ddea14e
--- /dev/null
+++ b/src/partest/scala/tools/partest/utils/Properties.scala
@@ -0,0 +1,18 @@
+/* __ *\
+** ________ ___ / / ___ Scala Parallel Testing **
+** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+package scala.tools.partest
+package utils
+
+/** Loads partest.properties from the jar. */
+object Properties extends scala.util.PropertiesTrait {
+ protected def propCategory = "partest"
+ protected def pickJarBasedOn = classOf[Application]
+}
diff --git a/test/files/pos/spec-traits.scala b/test/disabled/pos/spec-traits.scala
index 9e339a14ad..9e339a14ad 100644
--- a/test/files/pos/spec-traits.scala
+++ b/test/disabled/pos/spec-traits.scala
diff --git a/test/files/pos/t1254/t1254.java b/test/disabled/pos/t1254/t1254.java
index 25b733cf28..25b733cf28 100644
--- a/test/files/pos/t1254/t1254.java
+++ b/test/disabled/pos/t1254/t1254.java
diff --git a/test/disabled/run/stream_length.check b/test/disabled/run/stream_length.check
new file mode 100644
index 0000000000..9906de773c
--- /dev/null
+++ b/test/disabled/run/stream_length.check
@@ -0,0 +1 @@
+Length: 970299
diff --git a/test/files/run/stream_length.scala b/test/disabled/run/stream_length.scala
index 68e9cad5ac..68e9cad5ac 100644
--- a/test/files/run/stream_length.scala
+++ b/test/disabled/run/stream_length.scala
diff --git a/test/files/run/t2946/Parsers.scala b/test/disabled/run/t2946/Parsers.scala
index c0961034c4..c0961034c4 100644
--- a/test/files/run/t2946/Parsers.scala
+++ b/test/disabled/run/t2946/Parsers.scala
diff --git a/test/files/run/t2946/ResponseCommon.scala b/test/disabled/run/t2946/ResponseCommon.scala
index fa9d8acccb..fa9d8acccb 100644
--- a/test/files/run/t2946/ResponseCommon.scala
+++ b/test/disabled/run/t2946/ResponseCommon.scala
diff --git a/test/files/run/t2946/Test.scala b/test/disabled/run/t2946/Test.scala
index e9d9896a0e..e9d9896a0e 100644
--- a/test/files/run/t2946/Test.scala
+++ b/test/disabled/run/t2946/Test.scala
diff --git a/test/files/scalacheck/redblack.scala b/test/disabled/scalacheck/redblack.scala
index 0334c1218d..0334c1218d 100644
--- a/test/files/scalacheck/redblack.scala
+++ b/test/disabled/scalacheck/redblack.scala
diff --git a/test/continuations/neg/function0.check b/test/files/continuations-neg/function0.check
index 0a66763a0f..0a66763a0f 100644
--- a/test/continuations/neg/function0.check
+++ b/test/files/continuations-neg/function0.check
diff --git a/test/continuations/neg/function0.scala b/test/files/continuations-neg/function0.scala
index 4112ee3835..4112ee3835 100644
--- a/test/continuations/neg/function0.scala
+++ b/test/files/continuations-neg/function0.scala
diff --git a/test/continuations/neg/function2.check b/test/files/continuations-neg/function2.check
index 4833057652..4833057652 100644
--- a/test/continuations/neg/function2.check
+++ b/test/files/continuations-neg/function2.check
diff --git a/test/continuations/neg/function2.scala b/test/files/continuations-neg/function2.scala
index ae0fda509d..ae0fda509d 100644
--- a/test/continuations/neg/function2.scala
+++ b/test/files/continuations-neg/function2.scala
diff --git a/test/continuations/neg/function3.check b/test/files/continuations-neg/function3.check
index 4705ad9ed9..4705ad9ed9 100644
--- a/test/continuations/neg/function3.check
+++ b/test/files/continuations-neg/function3.check
diff --git a/test/continuations/neg/function3.scala b/test/files/continuations-neg/function3.scala
index 0c3f1667e5..0c3f1667e5 100644
--- a/test/continuations/neg/function3.scala
+++ b/test/files/continuations-neg/function3.scala
diff --git a/test/continuations/neg/infer0.check b/test/files/continuations-neg/infer0.check
index 1dd072ef09..1dd072ef09 100644
--- a/test/continuations/neg/infer0.check
+++ b/test/files/continuations-neg/infer0.check
diff --git a/test/continuations/neg/infer0.scala b/test/files/continuations-neg/infer0.scala
index 894d5228b1..894d5228b1 100644
--- a/test/continuations/neg/infer0.scala
+++ b/test/files/continuations-neg/infer0.scala
diff --git a/test/continuations/neg/infer2.check b/test/files/continuations-neg/infer2.check
index 59eb670bc3..59eb670bc3 100644
--- a/test/continuations/neg/infer2.check
+++ b/test/files/continuations-neg/infer2.check
diff --git a/test/continuations/neg/infer2.scala b/test/files/continuations-neg/infer2.scala
index a890ac1fc4..a890ac1fc4 100644
--- a/test/continuations/neg/infer2.scala
+++ b/test/files/continuations-neg/infer2.scala
diff --git a/test/continuations/neg/lazy.check b/test/files/continuations-neg/lazy.check
index bfa44c59a4..bfa44c59a4 100644
--- a/test/continuations/neg/lazy.check
+++ b/test/files/continuations-neg/lazy.check
diff --git a/test/continuations/neg/lazy.scala b/test/files/continuations-neg/lazy.scala
index dffc57ffa0..dffc57ffa0 100644
--- a/test/continuations/neg/lazy.scala
+++ b/test/files/continuations-neg/lazy.scala
diff --git a/test/continuations/neg/t1929.check b/test/files/continuations-neg/t1929.check
index f42c3a1e15..f42c3a1e15 100644
--- a/test/continuations/neg/t1929.check
+++ b/test/files/continuations-neg/t1929.check
diff --git a/test/continuations/neg/t1929.scala b/test/files/continuations-neg/t1929.scala
index 02eda9170d..02eda9170d 100644
--- a/test/continuations/neg/t1929.scala
+++ b/test/files/continuations-neg/t1929.scala
diff --git a/test/continuations/neg/t2285.check b/test/files/continuations-neg/t2285.check
index d5dff6a4f2..d5dff6a4f2 100644
--- a/test/continuations/neg/t2285.check
+++ b/test/files/continuations-neg/t2285.check
diff --git a/test/continuations/neg/t2285.scala b/test/files/continuations-neg/t2285.scala
index f3c7f4c89c..f3c7f4c89c 100644
--- a/test/continuations/neg/t2285.scala
+++ b/test/files/continuations-neg/t2285.scala
diff --git a/test/continuations/neg/t2949.check b/test/files/continuations-neg/t2949.check
index dd9768807c..dd9768807c 100644
--- a/test/continuations/neg/t2949.check
+++ b/test/files/continuations-neg/t2949.check
diff --git a/test/continuations/neg/t2949.scala b/test/files/continuations-neg/t2949.scala
index ce27c7c0e8..ce27c7c0e8 100644
--- a/test/continuations/neg/t2949.scala
+++ b/test/files/continuations-neg/t2949.scala
diff --git a/test/continuations/neg/trycatch2.check b/test/files/continuations-neg/trycatch2.check
index 5ff2838bad..5ff2838bad 100644
--- a/test/continuations/neg/trycatch2.check
+++ b/test/files/continuations-neg/trycatch2.check
diff --git a/test/continuations/neg/trycatch2.scala b/test/files/continuations-neg/trycatch2.scala
index 761cee52ac..761cee52ac 100644
--- a/test/continuations/neg/trycatch2.scala
+++ b/test/files/continuations-neg/trycatch2.scala
diff --git a/test/continuations/run/basics.check b/test/files/continuations-run/basics.check
index 54c059fdcb..54c059fdcb 100755
--- a/test/continuations/run/basics.check
+++ b/test/files/continuations-run/basics.check
diff --git a/test/continuations/run/basics.scala b/test/files/continuations-run/basics.scala
index 9df209b11c..9df209b11c 100755
--- a/test/continuations/run/basics.scala
+++ b/test/files/continuations-run/basics.scala
diff --git a/test/continuations/run/function1.check b/test/files/continuations-run/function1.check
index 7f8f011eb7..7f8f011eb7 100644
--- a/test/continuations/run/function1.check
+++ b/test/files/continuations-run/function1.check
diff --git a/test/continuations/run/function1.scala b/test/files/continuations-run/function1.scala
index 3b39722e3a..3b39722e3a 100644
--- a/test/continuations/run/function1.scala
+++ b/test/files/continuations-run/function1.scala
diff --git a/test/continuations/run/function4.check b/test/files/continuations-run/function4.check
index c7930257df..c7930257df 100644
--- a/test/continuations/run/function4.check
+++ b/test/files/continuations-run/function4.check
diff --git a/test/continuations/run/function4.scala b/test/files/continuations-run/function4.scala
index b73eedb02c..b73eedb02c 100644
--- a/test/continuations/run/function4.scala
+++ b/test/files/continuations-run/function4.scala
diff --git a/test/continuations/run/function5.check b/test/files/continuations-run/function5.check
index c7930257df..c7930257df 100644
--- a/test/continuations/run/function5.check
+++ b/test/files/continuations-run/function5.check
diff --git a/test/continuations/run/function5.scala b/test/files/continuations-run/function5.scala
index a689ccf243..a689ccf243 100644
--- a/test/continuations/run/function5.scala
+++ b/test/files/continuations-run/function5.scala
diff --git a/test/continuations/run/function6.check b/test/files/continuations-run/function6.check
index c7930257df..c7930257df 100644
--- a/test/continuations/run/function6.check
+++ b/test/files/continuations-run/function6.check
diff --git a/test/continuations/run/function6.scala b/test/files/continuations-run/function6.scala
index 1a2792370a..1a2792370a 100644
--- a/test/continuations/run/function6.scala
+++ b/test/files/continuations-run/function6.scala
diff --git a/test/continuations/run/ifelse0.check b/test/files/continuations-run/ifelse0.check
index f8bc79860d..f8bc79860d 100644
--- a/test/continuations/run/ifelse0.check
+++ b/test/files/continuations-run/ifelse0.check
diff --git a/test/continuations/run/ifelse0.scala b/test/files/continuations-run/ifelse0.scala
index e34b86ee84..e34b86ee84 100644
--- a/test/continuations/run/ifelse0.scala
+++ b/test/files/continuations-run/ifelse0.scala
diff --git a/test/continuations/run/ifelse1.check b/test/files/continuations-run/ifelse1.check
index 86a3fbc0c1..86a3fbc0c1 100644
--- a/test/continuations/run/ifelse1.check
+++ b/test/files/continuations-run/ifelse1.check
diff --git a/test/continuations/run/ifelse1.scala b/test/files/continuations-run/ifelse1.scala
index 2ccc1ed730..2ccc1ed730 100644
--- a/test/continuations/run/ifelse1.scala
+++ b/test/files/continuations-run/ifelse1.scala
diff --git a/test/continuations/run/ifelse2.check b/test/files/continuations-run/ifelse2.check
index f97a95b08d..f97a95b08d 100644
--- a/test/continuations/run/ifelse2.check
+++ b/test/files/continuations-run/ifelse2.check
diff --git a/test/continuations/run/ifelse2.scala b/test/files/continuations-run/ifelse2.scala
index 536e350190..536e350190 100644
--- a/test/continuations/run/ifelse2.scala
+++ b/test/files/continuations-run/ifelse2.scala
diff --git a/test/continuations/run/ifelse3.check b/test/files/continuations-run/ifelse3.check
index 95b562c8e6..95b562c8e6 100644
--- a/test/continuations/run/ifelse3.check
+++ b/test/files/continuations-run/ifelse3.check
diff --git a/test/continuations/run/ifelse3.scala b/test/files/continuations-run/ifelse3.scala
index 5dbd079d1c..5dbd079d1c 100644
--- a/test/continuations/run/ifelse3.scala
+++ b/test/files/continuations-run/ifelse3.scala
diff --git a/test/continuations/run/infer1.scala b/test/files/continuations-run/infer1.scala
index a6c6c07215..a6c6c07215 100644
--- a/test/continuations/run/infer1.scala
+++ b/test/files/continuations-run/infer1.scala
diff --git a/test/continuations/run/match0.check b/test/files/continuations-run/match0.check
index f8bc79860d..f8bc79860d 100644
--- a/test/continuations/run/match0.check
+++ b/test/files/continuations-run/match0.check
diff --git a/test/continuations/run/match0.scala b/test/files/continuations-run/match0.scala
index bd36238d7f..bd36238d7f 100644
--- a/test/continuations/run/match0.scala
+++ b/test/files/continuations-run/match0.scala
diff --git a/test/continuations/run/match1.check b/test/files/continuations-run/match1.check
index 73053d3f4f..73053d3f4f 100644
--- a/test/continuations/run/match1.check
+++ b/test/files/continuations-run/match1.check
diff --git a/test/continuations/run/match1.scala b/test/files/continuations-run/match1.scala
index ea4e219666..ea4e219666 100644
--- a/test/continuations/run/match1.scala
+++ b/test/files/continuations-run/match1.scala
diff --git a/test/continuations/run/match2.check b/test/files/continuations-run/match2.check
index cbf91349cc..cbf91349cc 100644
--- a/test/continuations/run/match2.check
+++ b/test/files/continuations-run/match2.check
diff --git a/test/continuations/run/match2.scala b/test/files/continuations-run/match2.scala
index 8d4f04870f..8d4f04870f 100644
--- a/test/continuations/run/match2.scala
+++ b/test/files/continuations-run/match2.scala
diff --git a/test/continuations/run/t1807.check b/test/files/continuations-run/t1807.check
index 56a6051ca2..56a6051ca2 100644
--- a/test/continuations/run/t1807.check
+++ b/test/files/continuations-run/t1807.check
diff --git a/test/continuations/run/t1807.scala b/test/files/continuations-run/t1807.scala
index 278b3a9936..278b3a9936 100644
--- a/test/continuations/run/t1807.scala
+++ b/test/files/continuations-run/t1807.scala
diff --git a/test/continuations/run/t1808.scala b/test/files/continuations-run/t1808.scala
index 125c7c1cdf..125c7c1cdf 100644
--- a/test/continuations/run/t1808.scala
+++ b/test/files/continuations-run/t1808.scala
diff --git a/test/continuations/run/t1820.scala b/test/files/continuations-run/t1820.scala
index 893ddab6d1..893ddab6d1 100644
--- a/test/continuations/run/t1820.scala
+++ b/test/files/continuations-run/t1820.scala
diff --git a/test/continuations/run/t1821.check b/test/files/continuations-run/t1821.check
index f7b76115db..f7b76115db 100644
--- a/test/continuations/run/t1821.check
+++ b/test/files/continuations-run/t1821.check
diff --git a/test/continuations/run/t1821.scala b/test/files/continuations-run/t1821.scala
index 0d5fb553be..0d5fb553be 100644
--- a/test/continuations/run/t1821.scala
+++ b/test/files/continuations-run/t1821.scala
diff --git a/test/continuations/run/t2864.check b/test/files/continuations-run/t2864.check
index d411bb7c1a..d411bb7c1a 100644
--- a/test/continuations/run/t2864.check
+++ b/test/files/continuations-run/t2864.check
diff --git a/test/continuations/run/t2864.scala b/test/files/continuations-run/t2864.scala
index 7a2579e45c..7a2579e45c 100644
--- a/test/continuations/run/t2864.scala
+++ b/test/files/continuations-run/t2864.scala
diff --git a/test/continuations/run/t2934.check b/test/files/continuations-run/t2934.check
index a92586538e..a92586538e 100644
--- a/test/continuations/run/t2934.check
+++ b/test/files/continuations-run/t2934.check
diff --git a/test/continuations/run/t2934.scala b/test/files/continuations-run/t2934.scala
index a1b8ca9e04..a1b8ca9e04 100644
--- a/test/continuations/run/t2934.scala
+++ b/test/files/continuations-run/t2934.scala
diff --git a/test/continuations/run/t3199.check b/test/files/continuations-run/t3199.check
index a065247b8c..a065247b8c 100644
--- a/test/continuations/run/t3199.check
+++ b/test/files/continuations-run/t3199.check
diff --git a/test/continuations/run/t3199.scala b/test/files/continuations-run/t3199.scala
index 3fd2f1959a..3fd2f1959a 100644
--- a/test/continuations/run/t3199.scala
+++ b/test/files/continuations-run/t3199.scala
diff --git a/test/continuations/run/t3199b.check b/test/files/continuations-run/t3199b.check
index b5d8bb58d9..b5d8bb58d9 100644
--- a/test/continuations/run/t3199b.check
+++ b/test/files/continuations-run/t3199b.check
diff --git a/test/continuations/run/t3199b.scala b/test/files/continuations-run/t3199b.scala
index 950c584153..950c584153 100644
--- a/test/continuations/run/t3199b.scala
+++ b/test/files/continuations-run/t3199b.scala
diff --git a/test/continuations/run/t3223.check b/test/files/continuations-run/t3223.check
index ec635144f6..ec635144f6 100644
--- a/test/continuations/run/t3223.check
+++ b/test/files/continuations-run/t3223.check
diff --git a/test/continuations/run/t3223.scala b/test/files/continuations-run/t3223.scala
index 4e510178e6..4e510178e6 100644
--- a/test/continuations/run/t3223.scala
+++ b/test/files/continuations-run/t3223.scala
diff --git a/test/continuations/run/t3225.check b/test/files/continuations-run/t3225.check
index df1a8a9ce4..df1a8a9ce4 100644
--- a/test/continuations/run/t3225.check
+++ b/test/files/continuations-run/t3225.check
diff --git a/test/continuations/run/t3225.scala b/test/files/continuations-run/t3225.scala
index ecfde279cf..ecfde279cf 100644
--- a/test/continuations/run/t3225.scala
+++ b/test/files/continuations-run/t3225.scala
diff --git a/test/continuations/run/trycatch0.check b/test/files/continuations-run/trycatch0.check
index 36806909d0..36806909d0 100644
--- a/test/continuations/run/trycatch0.check
+++ b/test/files/continuations-run/trycatch0.check
diff --git a/test/continuations/run/trycatch0.scala b/test/files/continuations-run/trycatch0.scala
index 74a078b5ef..74a078b5ef 100644
--- a/test/continuations/run/trycatch0.scala
+++ b/test/files/continuations-run/trycatch0.scala
diff --git a/test/continuations/run/trycatch1.check b/test/files/continuations-run/trycatch1.check
index a028d2b1e1..a028d2b1e1 100644
--- a/test/continuations/run/trycatch1.check
+++ b/test/files/continuations-run/trycatch1.check
diff --git a/test/continuations/run/trycatch1.scala b/test/files/continuations-run/trycatch1.scala
index ade13794e3..ade13794e3 100644
--- a/test/continuations/run/trycatch1.scala
+++ b/test/files/continuations-run/trycatch1.scala
diff --git a/test/continuations/run/while0.check b/test/files/continuations-run/while0.check
index d58c55a31d..d58c55a31d 100644
--- a/test/continuations/run/while0.check
+++ b/test/files/continuations-run/while0.check
diff --git a/test/continuations/run/while0.scala b/test/files/continuations-run/while0.scala
index 9735f9d2c3..9735f9d2c3 100644
--- a/test/continuations/run/while0.scala
+++ b/test/files/continuations-run/while0.scala
diff --git a/test/continuations/run/while1.check b/test/files/continuations-run/while1.check
index 3d5f0b9a46..3d5f0b9a46 100644
--- a/test/continuations/run/while1.check
+++ b/test/files/continuations-run/while1.check
diff --git a/test/continuations/run/while1.scala b/test/files/continuations-run/while1.scala
index fb5dc0079a..fb5dc0079a 100644
--- a/test/continuations/run/while1.scala
+++ b/test/files/continuations-run/while1.scala
diff --git a/test/continuations/run/while2.check b/test/files/continuations-run/while2.check
index 9fe515181b..9fe515181b 100644
--- a/test/continuations/run/while2.check
+++ b/test/files/continuations-run/while2.check
diff --git a/test/continuations/run/while2.scala b/test/files/continuations-run/while2.scala
index f36288929e..f36288929e 100644
--- a/test/continuations/run/while2.scala
+++ b/test/files/continuations-run/while2.scala
diff --git a/test/files/jvm/genericNest/genericNest.scala b/test/files/jvm/genericNest.scala
index c1b0210117..c1b0210117 100644
--- a/test/files/jvm/genericNest/genericNest.scala
+++ b/test/files/jvm/genericNest.scala
diff --git a/test/files/jvm/methvsfield.java b/test/files/jvm/methvsfield.java
new file mode 100644
index 0000000000..dadc98669a
--- /dev/null
+++ b/test/files/jvm/methvsfield.java
@@ -0,0 +1,11 @@
+// This should be compiled with javac and saved
+// in ../lib/methvsfield.jar .
+class MethVsField
+{
+ int three = 3;
+
+ int three()
+ {
+ return 3;
+ }
+}
diff --git a/test/files/jvm/methvsfield.scala b/test/files/jvm/methvsfield.scala
new file mode 100644
index 0000000000..e9795ec6a8
--- /dev/null
+++ b/test/files/jvm/methvsfield.scala
@@ -0,0 +1,4 @@
+// bug #1062
+object Test extends Application {
+ println((new MethVsField).three)
+}
diff --git a/test/files/jvm/nest.java b/test/files/jvm/nest.java
new file mode 100644
index 0000000000..3f6f0bebbd
--- /dev/null
+++ b/test/files/jvm/nest.java
@@ -0,0 +1,38 @@
+package nestpkg;
+
+
+/** This file is needed for test 'nest.scala'. It should
+ * be compiled with javac and packaged into lib/nest.jar
+ */
+public class nest {
+ public static class best {
+ public static class rest {
+ public static rest test = new rest();
+ public static int x = 10;
+ public int inc(int i) {
+ return i + 1;
+ }
+ }
+ }
+
+
+ String name = "Outer name";
+
+ public class Inn {
+ int x;
+
+ public Inn(int x) {
+ this.x = x;
+ }
+
+ public void doSomething() {
+ System.out.println("Inn " + name + " x: " + x);
+ }
+ }
+
+ protected class ProtInn {
+ public void doSomething() {
+ System.out.println("ProtInn " + name);
+ }
+ }
+}
diff --git a/test/files/jvm/nest.scala b/test/files/jvm/nest.scala
new file mode 100644
index 0000000000..3ab62484fa
--- /dev/null
+++ b/test/files/jvm/nest.scala
@@ -0,0 +1,21 @@
+//############################################################################
+// Test Scala interaction with Java nested classes and static members.
+//############################################################################
+
+/** found in nest.jar, compiled from nest.java */
+import nestpkg._;
+
+object Test extends Application {
+ val x = nest.best.rest.test
+ Console.println(x.inc(1))
+
+ val o = new nest.best;
+ val r = new nest.best.rest;
+ Console.println(nest.best.rest.test.inc(2))
+ Console.println(nest.best.rest.x)
+
+ print("Instantiating public inner class: ")
+ val outer = new nest
+ val inn = new outer.Inn(42)
+ inn.doSomething
+}
diff --git a/test/files/jvm/outerEnum/outerEnum.scala b/test/files/jvm/outerEnum.scala
index 18794b7dbe..18794b7dbe 100644
--- a/test/files/jvm/outerEnum/outerEnum.scala
+++ b/test/files/jvm/outerEnum.scala
diff --git a/test/files/jvm/t1652.check b/test/files/jvm/t1652.check
new file mode 100644
index 0000000000..dfa480ce6e
--- /dev/null
+++ b/test/files/jvm/t1652.check
@@ -0,0 +1,2 @@
+OK1
+OK2
diff --git a/test/files/jvm/lib/annotations.jar.desired.sha1 b/test/files/lib/annotations.jar.desired.sha1
index 2b4292d796..2b4292d796 100644
--- a/test/files/jvm/lib/annotations.jar.desired.sha1
+++ b/test/files/lib/annotations.jar.desired.sha1
diff --git a/test/files/jvm/outerEnum/enums.jar.desired.sha1 b/test/files/lib/enums.jar.desired.sha1
index 46cd8e92cf..46cd8e92cf 100644
--- a/test/files/jvm/outerEnum/enums.jar.desired.sha1
+++ b/test/files/lib/enums.jar.desired.sha1
diff --git a/test/files/jvm/genericNest/genericNest.jar.desired.sha1 b/test/files/lib/genericNest.jar.desired.sha1
index e9321262f2..e9321262f2 100644
--- a/test/files/jvm/genericNest/genericNest.jar.desired.sha1
+++ b/test/files/lib/genericNest.jar.desired.sha1
diff --git a/test/files/lib/methvsfield.jar.desired.sha1 b/test/files/lib/methvsfield.jar.desired.sha1
new file mode 100644
index 0000000000..8c01532b88
--- /dev/null
+++ b/test/files/lib/methvsfield.jar.desired.sha1
@@ -0,0 +1 @@
+be8454d5e7751b063ade201c225dcedefd252775 ?methvsfield.jar
diff --git a/test/files/jvm/lib/nest.jar.desired.sha1 b/test/files/lib/nest.jar.desired.sha1
index 674ca79a5b..674ca79a5b 100644
--- a/test/files/jvm/lib/nest.jar.desired.sha1
+++ b/test/files/lib/nest.jar.desired.sha1
diff --git a/lib/scalacheck.jar.desired.sha1 b/test/files/lib/scalacheck.jar.desired.sha1
index ed9c46c3db..ed9c46c3db 100644
--- a/lib/scalacheck.jar.desired.sha1
+++ b/test/files/lib/scalacheck.jar.desired.sha1
diff --git a/test/files/neg/bug414.scala b/test/files/neg/bug414.scala
index 7983fe88b9..2bc83eedcb 100644
--- a/test/files/neg/bug414.scala
+++ b/test/files/neg/bug414.scala
@@ -1,4 +1,4 @@
-case class Empty[a] extends IntMap[a];
+case class Empty[a]() extends IntMap[a];
case class Node[a](left: IntMap[a], keyVal: Pair[Int, a], right: IntMap[a]) extends IntMap[a];
abstract class IntMap[a] {
def lookup(key: Int): a = this match {
diff --git a/test/files/neg/migration28.check b/test/files/neg/migration28.check
index 9e042a0f0b..4c8c58e0fd 100644
--- a/test/files/neg/migration28.check
+++ b/test/files/neg/migration28.check
@@ -1,5 +1,4 @@
-migration28.scala:5: error: method ++= in class Stack has changed semantics:
-Stack ++= now pushes arguments on the stack from left to right.
+migration28.scala:5: error: method ++= in class Stack is deprecated: use pushAll
s ++= List(1,2,3)
^
migration28.scala:7: error: method foreach in class Stack has changed semantics:
diff --git a/test/files/res/bug687.check b/test/files/res/bug687.check
index 353101c38b..ee9520d1ea 100644
--- a/test/files/res/bug687.check
+++ b/test/files/res/bug687.check
@@ -1,10 +1,11 @@
+
nsc>
-nsc>
-bug687/QueryB.scala:3: error: name clash between defined and inherited member:
+nsc> bug687/QueryB.scala:3: error: name clash between defined and inherited member:
method equals:(o: java.lang.Object)Boolean and
method equals:(x$1: Any)Boolean in class Any
have same type after erasure: (o: java.lang.Object)Boolean
override def equals(o : Object) = false;
^
+
nsc>
nsc>
diff --git a/test/files/run/numbereq.scala b/test/files/run/numbereq.scala
index 52f32cc52a..b07c83dc3e 100644
--- a/test/files/run/numbereq.scala
+++ b/test/files/run/numbereq.scala
@@ -33,7 +33,7 @@ object Test {
val sets = setneg1 ++ setneg2 ++ List(zero) ++ setpos1 ++ setpos2
for (set <- sets ; x <- set ; y <- set) {
- println("'%s' == '%s' (%s == %s) (%s == %s)".format(x, y, x.hashCode, y.hashCode, x.##, y.##))
+ // println("'%s' == '%s' (%s == %s) (%s == %s)".format(x, y, x.hashCode, y.hashCode, x.##, y.##))
assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass))
assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass))
}
diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check
index 3429195265..e6c83a6f48 100644
--- a/test/files/run/programmatic-main.check
+++ b/test/files/run/programmatic-main.check
@@ -5,9 +5,7 @@ typer
superaccessors
pickler
refchecks
-selectiveanf
liftcode
-selectivecps
uncurry
tailcalls
specialize
diff --git a/test/partest b/test/partest
index 87c7961689..1e7da8bd4a 100755
--- a/test/partest
+++ b/test/partest
@@ -75,23 +75,12 @@ if $cygwin; then
fi
# Reminder: substitution ${JAVA_OPTS:=-Xmx256M -Xms16M} DO NOT work on Solaris
-[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xms64M -Xmx1024M -Xss768K -XX:MaxPermSize=96M"
-[ -n "$SCALAC_OPTS" ] || SCALAC_OPTS=""
+[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xmx512M -Xms16M"
+[ -n "$SCALAC_OPTS" ] || SCALAC_OPTS="-deprecation"
-# export SCALAC_OPTS
-# export JAVA_OPTS
-export JAVACMD
-
-${JAVACMD:=java} $JAVA_OPTS \
- -cp "$EXT_CLASSPATH" \
- -Dscala.home="${SCALA_HOME}" \
- scala.tools.partest.Runner "$@"
+partestDebugStr=""
+if [ ! -z "${PARTEST_DEBUG}" ] ; then
+ partestDebugStr="-Dpartest.debug=${PARTEST_DEBUG}"
+fi
-# ${JAVACMD:=java} $JAVA_OPTS \
-# -cp "$EXT_CLASSPATH" \
-# -Dscala.home="${SCALA_HOME}" \
-# -Dpartest.scalac_opts="${SCALAC_OPTS}" \
-# -Dpartest.javacmd="${JAVACMD}" \
-# -Dpartest.java_opts="${JAVA_OPTS}" \
-# -Dpartest.javac_cmd="${JAVA_HOME}/bin/javac" \
-# scala.tools.partest.Runner "$@"
+${JAVACMD:=java} $JAVA_OPTS -cp "$EXT_CLASSPATH" ${partestDebugStr} -Dscala.home="${SCALA_HOME}" -Dpartest.javacmd="${JAVACMD}" -Dpartest.java_opts="${JAVA_OPTS}" -Dpartest.scalac_opts="${SCALAC_OPTS}" -Dpartest.javac_cmd="${JAVA_HOME}/bin/javac" scala.tools.partest.nest.NestRunner "$@"
diff --git a/test/partest.bat b/test/partest.bat
index 0b5618a164..39fe830082 100755
--- a/test/partest.bat
+++ b/test/partest.bat
@@ -55,8 +55,8 @@ if "%_EXTENSION_CLASSPATH%"=="" (
set _PROPS=-Dscala.home="%_SCALA_HOME%" -Dpartest.javacmd="%_JAVACMD%" -Dpartest.java_options="%_JAVA_OPTS%" -Dpartest.scalac_options="%_SCALAC_OPTS%" -Dpartest.javac_cmd="%JAVA_HOME%\bin\javac"
-rem echo %_JAVACMD% %_JAVA_OPTS% %_PROPS% -cp "%_EXTENSION_CLASSPATH%" scala.tools.partest.Runner %_ARGS%
-%_JAVACMD% %_JAVA_OPTS% %_PROPS% -cp "%_EXTENSION_CLASSPATH%" scala.tools.partest.Runner %_ARGS%
+rem echo %_JAVACMD% %_JAVA_OPTS% %_PROPS% -cp "%_EXTENSION_CLASSPATH%" scala.tools.partest.nest.NestRunner %_ARGS%
+%_JAVACMD% %_JAVA_OPTS% %_PROPS% -cp "%_EXTENSION_CLASSPATH%" scala.tools.partest.nest.NestRunner %_ARGS%
goto end
rem ##########################################################################
diff --git a/test/pending/jvm/t1464.check b/test/pending/jvm/t1464.check
new file mode 100644
index 0000000000..c508d5366f
--- /dev/null
+++ b/test/pending/jvm/t1464.check
@@ -0,0 +1 @@
+false
diff --git a/test/pending/pos/t0644.scala b/test/pending/pos/t0644.scala
new file mode 100644
index 0000000000..5ad12c3632
--- /dev/null
+++ b/test/pending/pos/t0644.scala
@@ -0,0 +1,11 @@
+class A {
+ def appply(): Int = 0
+ def update(n: Int) {}
+}
+
+class B extends A {
+ this()
+ this()=1
+ super()
+ super()=1
+}
diff --git a/test/pending/run/bug2365/Test.scala b/test/pending/run/bug2365/Test.scala
new file mode 100644
index 0000000000..92b58f4a25
--- /dev/null
+++ b/test/pending/run/bug2365/Test.scala
@@ -0,0 +1,35 @@
+import scala.tools.nsc.io._
+import java.net.URL
+
+object A { def apply(d: { def apply(): Int}) = d.apply() }
+object A2 { def apply(d: { def apply(): Int}) = d.apply() }
+object A3 { def apply(d: { def apply(): Int}) = d.apply() }
+object A4 { def apply(d: { def apply(): Int}) = d.apply() }
+
+class B extends Function0[Int] {
+ def apply() = 3
+}
+
+object Test
+{
+ type StructF0 = { def apply(): Int }
+ def main(args: Array[String]) {
+ for(i <- 0 until 150)
+ println(i + " " + test(A.apply) + " " + test(A2.apply) + " " + test(A3.apply) + " " + test(A3.apply))
+ }
+
+ def test(withF0: StructF0 => Int): Int = {
+ // Some large jar
+ val ivyJar = File("/local/lib/java/ivy.jar").toURL
+ // load a class in a separate loader that will be passed to A
+ val loader = new java.net.URLClassLoader(Array(File(".").toURL, ivyJar))
+ // load a real class to fill perm gen space
+ Class.forName("org.apache.ivy.Ivy", true, loader).newInstance
+ // create a class from another class loader with an apply: Int method
+ val b = Class.forName("B", true, loader).newInstance
+
+ // pass instance to a, which will call apply using structural type reflection.
+ // This should hold on to the class for B, which means bLoader will not get collected
+ withF0(b.asInstanceOf[StructF0])
+ }
+}
diff --git a/test/pending/run/bug2365/bug2365.javaopts b/test/pending/run/bug2365/bug2365.javaopts
new file mode 100644
index 0000000000..357e033c1c
--- /dev/null
+++ b/test/pending/run/bug2365/bug2365.javaopts
@@ -0,0 +1 @@
+-XX:MaxPermSize=25M
diff --git a/test/pending/run/bug2365/run b/test/pending/run/bug2365/run
new file mode 100755
index 0000000000..f3c44ad086
--- /dev/null
+++ b/test/pending/run/bug2365/run
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+# This script should fail with any build of scala where #2365
+# is not fixed, and otherwise succeed. Failure means running out
+# of PermGen space.
+
+CP=.:/local/lib/java/ivy.jar
+# SCALAC=/scala/inst/28/bin/scalac
+SCALAC=scalac
+RUN_OPTS="-XX:MaxPermSize=25M -verbose:gc"
+
+$SCALAC -cp $CP *.scala
+JAVA_OPTS="${RUN_OPTS}" scala -cp $CP Test
diff --git a/test/pending/run/subarray.check b/test/pending/run/subarray.check
new file mode 100644
index 0000000000..814f4a4229
--- /dev/null
+++ b/test/pending/run/subarray.check
@@ -0,0 +1,2 @@
+one
+two