summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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