@@ -6,22 +6,21 @@ import java.io.{ File => JFile }
66import java .text .SimpleDateFormat
77import java .util .HashMap
88import java .nio .file .StandardCopyOption .REPLACE_EXISTING
9- import java .nio .file .{ Files , Path , Paths , NoSuchFileException }
10- import java .util .concurrent .{ Executors => JExecutors , TimeUnit , TimeoutException }
9+ import java .nio .file .{ Files , NoSuchFileException , Path , Paths }
10+ import java .util .concurrent .{ TimeUnit , TimeoutException , Executors => JExecutors }
1111
1212import scala .io .Source
1313import scala .util .control .NonFatal
1414import scala .util .Try
1515import scala .collection .mutable
1616import scala .util .matching .Regex
1717import scala .util .Random
18-
1918import dotc .core .Contexts ._
20- import dotc .reporting .{ Reporter , TestReporter }
19+ import dotc .reporting .{ Reporter , StoredTestReporter , TestReporter }
2120import dotc .reporting .diagnostic .MessageContainer
2221import dotc .interfaces .Diagnostic .ERROR
2322import dotc .util .DiffUtil
24- import dotc .{ Driver , Compiler }
23+ import dotc .{ Compiler , Driver }
2524
2625/** A parallel testing suite whose goal is to integrate nicely with JUnit
2726 *
@@ -47,7 +46,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
4746 /** A test source whose files or directory of files is to be compiled
4847 * in a specific way defined by the `Test`
4948 */
50- private sealed trait TestSource { self =>
49+ sealed trait TestSource { self =>
5150 def name : String
5251 def outDir : JFile
5352 def flags : TestFlags
@@ -128,7 +127,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
128127 /** A group of files that may all be compiled together, with the same flags
129128 * and output directory
130129 */
131- private final case class JointCompilationSource (
130+ final case class JointCompilationSource (
132131 name : String ,
133132 files : Array [JFile ],
134133 flags : TestFlags ,
@@ -143,7 +142,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
143142 /** A test source whose files will be compiled separately according to their
144143 * suffix `_X`
145144 */
146- private final case class SeparateCompilationSource (
145+ final case class SeparateCompilationSource (
147146 name : String ,
148147 dir : JFile ,
149148 flags : TestFlags ,
@@ -176,7 +175,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
176175 /** Each `Test` takes the `testSources` and performs the compilation and assertions
177176 * according to the implementing class "neg", "run" or "pos".
178177 */
179- private abstract class Test (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean )(implicit val summaryReport : SummaryReporting ) { test =>
178+ private abstract class Test (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean , checkCompileOutput : Boolean = false )(implicit val summaryReport : SummaryReporting ) { test =>
180179
181180 import summaryReport ._
182181
@@ -352,9 +351,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
352351 else None
353352 } else None
354353
354+ val logLevel = if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR
355355 val reporter =
356- TestReporter .reporter(realStdout, logLevel =
357- if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR )
356+ if (checkCompileOutput)
357+ TestReporter .storedReporter(realStdout, logLevel = logLevel)
358+ else
359+ TestReporter .reporter(realStdout, logLevel = logLevel)
358360
359361 val driver =
360362 if (times == 1 ) new Driver
@@ -463,10 +465,28 @@ trait ParallelTesting extends RunnerOrchestration { self =>
463465 private def flattenFiles (f : JFile ): Array [JFile ] =
464466 if (f.isDirectory) f.listFiles.flatMap(flattenFiles)
465467 else Array (f)
468+
469+ protected def verifyCompileOutput (source : TestSource , checkFile : JFile , reporter : StoredTestReporter ): Unit = {
470+ reporter.writer.flush()
471+ val checkLines = Source .fromFile(checkFile).getLines().mkString(" \n " )
472+ val outputLines = reporter.writer.toString.trim.replaceAll(" \\ s+\n " , " \n " )
473+
474+ if (outputLines != checkLines) {
475+ val msg = s " Output from ' ${source.title}' did not match check file ' ${checkFile.getName}'. "
476+ println(" ===============================" )
477+ println(" expected: \n " + checkLines)
478+ println(" actual: \n " + outputLines)
479+ println(" ===============================" )
480+
481+ echo(msg)
482+ addFailureInstruction(msg)
483+ failTestSource(source)
484+ }
485+ }
466486 }
467487
468- private final class PosTest (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean )(implicit summaryReport : SummaryReporting )
469- extends Test (testSources, times, threadLimit, suppressAllOutput) {
488+ private final class PosTest (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean , checkCompileOutput : Boolean = false )(implicit summaryReport : SummaryReporting )
489+ extends Test (testSources, times, threadLimit, suppressAllOutput, checkCompileOutput ) {
470490 protected def encapsulatedCompilation (testSource : TestSource ) = new LoggedRunnable {
471491 def checkTestSource (): Unit = tryCompile(testSource) {
472492 testSource match {
@@ -499,6 +519,15 @@ trait ParallelTesting extends RunnerOrchestration { self =>
499519 reporters.foreach(logReporterContents)
500520 logBuildInstructions(reporters.head, testSource, errorCount, warningCount)
501521 }
522+
523+ // verify compilation check file
524+ (1 to testSource.compilationGroups.length).foreach { index =>
525+ val checkFile = new JFile (dir.getAbsolutePath.reverse.dropWhile(_ == '/' ).reverse + " /" + index + " .check" )
526+
527+ if (checkFile.exists && checkCompileOutput)
528+ verifyCompileOutput(testSource, checkFile, reporters(index).asInstanceOf [StoredTestReporter ])
529+ }
530+ }
502531 }
503532 }
504533 }
@@ -622,8 +651,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>
622651 }
623652 }
624653
625- private final class NegTest (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean )(implicit summaryReport : SummaryReporting )
626- extends Test (testSources, times, threadLimit, suppressAllOutput) {
654+ private final class NegTest (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean , checkCompileOutput : Boolean = false )(implicit summaryReport : SummaryReporting )
655+ extends Test (testSources, times, threadLimit, suppressAllOutput, checkCompileOutput ) {
627656 protected def encapsulatedCompilation (testSource : TestSource ) = new LoggedRunnable {
628657 def checkTestSource (): Unit = tryCompile(testSource) {
629658 // In neg-tests we allow two types of error annotations,
@@ -700,6 +729,14 @@ trait ParallelTesting extends RunnerOrchestration { self =>
700729 if (actualErrors > 0 )
701730 reporters.foreach(logReporterContents)
702731
732+ // Compilation check file: for testing plugins
733+ (1 to testSource.compilationGroups.length).foreach { index =>
734+ val checkFile = new JFile (dir.getAbsolutePath.reverse.dropWhile(_ == '/' ).reverse + " /" + index + " .check" )
735+
736+ if (checkFile.exists && checkCompileOutput)
737+ verifyCompileOutput(testSource, checkFile, reporters(index).asInstanceOf [StoredTestReporter ])
738+ }
739+
703740 (compilerCrashed, expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, errors), errorMap)
704741 }
705742 }
@@ -847,10 +884,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
847884 ) {
848885 import org .junit .Assert .fail
849886
850- private [ ParallelTesting ] def this (target : TestSource ) =
887+ def this (target : TestSource ) =
851888 this (List (target), 1 , true , None , false , false )
852889
853- private [ ParallelTesting ] def this (targets : List [TestSource ]) =
890+ def this (targets : List [TestSource ]) =
854891 this (targets, 1 , true , None , false , false )
855892
856893 /** Compose test targets from `this` with `other`
@@ -879,8 +916,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
879916 * compilation without generating errors and that they do not crash the
880917 * compiler
881918 */
882- def checkCompile ()(implicit summaryReport : SummaryReporting ): this .type = {
883- val test = new PosTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput).executeTestSuite()
919+ def checkCompile (checkCompileOutput : Boolean = false )(implicit summaryReport : SummaryReporting ): this .type = {
920+ val test = new PosTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput, checkCompileOutput).executeTestSuite()
921+
922+ cleanup()
884923
885924 if (! shouldFail && test.didFail) {
886925 fail(s " Expected no errors when compiling, failed for the following reason(s): \n ${ reasonsForFailure(test) }" )
@@ -889,15 +928,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
889928 fail(" Pos test should have failed, but didn't" )
890929 }
891930
892- cleanup()
931+ this
893932 }
894933
895934 /** Creates a "neg" test run, which makes sure that each test generates the
896935 * correct amount of errors at the correct positions. It also makes sure
897936 * that none of these tests crash the compiler
898937 */
899- def checkExpectedErrors ()(implicit summaryReport : SummaryReporting ): this .type = {
900- val test = new NegTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput).executeTestSuite()
938+ def checkExpectedErrors (checkCompileOutput : Boolean = false )(implicit summaryReport : SummaryReporting ): this .type = {
939+ val test = new NegTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput, checkCompileOutput).executeTestSuite()
940+
941+ cleanup()
901942
902943 if (! shouldFail && test.didFail) {
903944 fail(s " Neg test shouldn't have failed, but did. Reasons: \n ${ reasonsForFailure(test) }" )
@@ -906,7 +947,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
906947 fail(" Neg test should have failed, but did not" )
907948 }
908949
909- cleanup()
950+ this
910951 }
911952
912953 /** Creates a "run" test run, which is a superset of "pos". In addition to
@@ -917,14 +958,16 @@ trait ParallelTesting extends RunnerOrchestration { self =>
917958 def checkRuns ()(implicit summaryReport : SummaryReporting ): this .type = {
918959 val test = new RunTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput).executeTestSuite()
919960
961+ cleanup()
962+
920963 if (! shouldFail && test.didFail) {
921964 fail(s " Run test failed, but should not, reasons: \n ${ reasonsForFailure(test) }" )
922965 }
923966 else if (shouldFail && ! test.didFail) {
924967 fail(" Run test should have failed, but did not" )
925968 }
926969
927- cleanup()
970+ this
928971 }
929972
930973 /** Deletes output directories and files */
@@ -1027,7 +1070,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
10271070 }
10281071
10291072 /** Create out directory for directory `d` */
1030- private def createOutputDirsForDir (d : JFile , sourceDir : JFile , outDir : String ): JFile = {
1073+ def createOutputDirsForDir (d : JFile , sourceDir : JFile , outDir : String ): JFile = {
10311074 val targetDir = new JFile (outDir + s " ${sourceDir.getName}/ ${d.getName}" )
10321075 targetDir.mkdirs()
10331076 targetDir
0 commit comments