@@ -242,10 +242,20 @@ trait ParallelTesting extends RunnerOrchestration { self =>
242242 _errorCount += errors
243243 }
244244
245- private [this ] var _failed = false
245+ sealed trait Failure
246+ case class JavaCompilationFailure (reason : String ) extends Failure
247+ case class TimeoutFailure (title : String ) extends Failure
248+ case object Generic extends Failure
249+
250+ private [this ] var _failures = Set .empty[Failure ]
246251 /** Fail the current test */
247- protected [this ] final def fail (): Unit = synchronized { _failed = true }
248- def didFail : Boolean = _failed
252+ protected [this ] final def fail (failure : Failure = Generic ): Unit = synchronized {
253+ _failures = _failures + failure
254+ }
255+ def didFail : Boolean = _failures.nonEmpty
256+
257+ /** A set of the different failures */
258+ def failureReasons : Set [Failure ] = _failures
249259
250260 protected def logBuildInstructions (reporter : TestReporter , testSource : TestSource , err : Int , war : Int ) = {
251261 val errorMsg = testSource.buildInstructions(reporter.errorCount, reporter.warningCount)
@@ -260,10 +270,14 @@ trait ParallelTesting extends RunnerOrchestration { self =>
260270
261271 /** The test sources that failed according to the implementing subclass */
262272 private [this ] val failedTestSources = mutable.ArrayBuffer .empty[String ]
263- protected final def failTestSource (testSource : TestSource , reason : Option [String ] = None ) = synchronized {
264- val extra = reason.map(" with reason: " + _).getOrElse(" " )
273+ protected final def failTestSource (testSource : TestSource , reason : Failure = Generic ) = synchronized {
274+ val extra = reason match {
275+ case TimeoutFailure (title) => s " , test ' $title' timed out "
276+ case JavaCompilationFailure (msg) => s " , java test sources failed to compile with: \n $msg"
277+ case Generic => " "
278+ }
265279 failedTestSources.append(testSource.title + s " failed " + extra)
266- fail()
280+ fail(reason )
267281 }
268282
269283 /** Prints to `System.err` if we're not suppressing all output */
@@ -342,12 +356,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
342356 def compileWithJavac (fs : Array [String ]) = if (fs.nonEmpty) {
343357 val fullArgs = Array (
344358 " javac" ,
359+ " -encoding" , " UTF-8" ,
345360 " -classpath" ,
346361 s " .: ${Jars .scalaLibrary}: ${targetDir.getAbsolutePath}"
347362 ) ++ flags.takeRight(2 ) ++ fs
348363
349- Runtime .getRuntime.exec(fullArgs).waitFor() == 0
350- } else true
364+ val process = Runtime .getRuntime.exec(fullArgs)
365+ val output = Source .fromInputStream(process.getErrorStream).mkString
366+
367+ if (process.waitFor() != 0 ) Some (output)
368+ else None
369+ } else None
351370
352371 val reporter =
353372 TestReporter .reporter(realStdout, logLevel =
@@ -377,7 +396,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
377396 driver.process(allArgs ++ files.map(_.getAbsolutePath), reporter = reporter)
378397
379398 val javaFiles = files.filter(_.getName.endsWith(" .java" )).map(_.getAbsolutePath)
380- assert(compileWithJavac(javaFiles), s " java compilation failed for ${javaFiles.mkString(" , " )}" )
399+ val javaErrors = compileWithJavac(javaFiles)
400+
401+ if (javaErrors.isDefined) {
402+ echo(s " \n java compilation failed: \n ${ javaErrors.get }" )
403+ fail(failure = JavaCompilationFailure (javaErrors.get))
404+ }
381405 }
382406 catch {
383407 case NonFatal (ex) => reporter.logStackTrace(ex)
@@ -522,7 +546,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
522546
523547 case Timeout =>
524548 echo(" failed because test " + testSource.title + " timed out" )
525- failTestSource(testSource, Some ( " test timed out " ))
549+ failTestSource(testSource, TimeoutFailure (testSource.title ))
526550 }
527551 }
528552
@@ -803,15 +827,16 @@ trait ParallelTesting extends RunnerOrchestration { self =>
803827 private [ParallelTesting ] val times : Int ,
804828 private [ParallelTesting ] val shouldDelete : Boolean ,
805829 private [ParallelTesting ] val threadLimit : Option [Int ],
806- private [ParallelTesting ] val shouldFail : Boolean
830+ private [ParallelTesting ] val shouldFail : Boolean ,
831+ private [ParallelTesting ] val shouldSuppressOutput : Boolean
807832 ) {
808833 import org .junit .Assert .fail
809834
810835 private [ParallelTesting ] def this (target : TestSource ) =
811- this (List (target), 1 , true , None , false )
836+ this (List (target), 1 , true , None , false , false )
812837
813838 private [ParallelTesting ] def this (targets : List [TestSource ]) =
814- this (targets, 1 , true , None , false )
839+ this (targets, 1 , true , None , false , false )
815840
816841 /** Compose test targets from `this` with `other`
817842 *
@@ -831,18 +856,19 @@ trait ParallelTesting extends RunnerOrchestration { self =>
831856 require(other.times == times, " can't combine tests that are meant to be benchmark compiled" )
832857 require(other.shouldDelete == shouldDelete, " can't combine tests that differ on deleting output" )
833858 require(other.shouldFail == shouldFail, " can't combine tests that have different expectations on outcome" )
834- new CompilationTest (targets ++ other.targets, times, shouldDelete, threadLimit, shouldFail)
859+ require(other.shouldSuppressOutput == shouldSuppressOutput, " can't combine tests that both suppress and don't suppress output" )
860+ new CompilationTest (targets ++ other.targets, times, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput)
835861 }
836862
837863 /** Creates a "pos" test run, which makes sure that all tests pass
838864 * compilation without generating errors and that they do not crash the
839865 * compiler
840866 */
841867 def checkCompile ()(implicit summaryReport : SummaryReporting ): this .type = {
842- val test = new PosTest (targets, times, threadLimit, shouldFail).executeTestSuite()
868+ val test = new PosTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput ).executeTestSuite()
843869
844870 if (! shouldFail && test.didFail) {
845- fail(s " Expected no errors when compiling, but found: ${ test.errorCount }" )
871+ fail(s " Expected no errors when compiling, failed for the following reason(s): \n ${ reasonsForFailure( test) }" )
846872 }
847873 else if (shouldFail && ! test.didFail) {
848874 fail(" Pos test should have failed, but didn't" )
@@ -856,10 +882,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
856882 * that none of these tests crash the compiler
857883 */
858884 def checkExpectedErrors ()(implicit summaryReport : SummaryReporting ): this .type = {
859- val test = new NegTest (targets, times, threadLimit, shouldFail).executeTestSuite()
885+ val test = new NegTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput ).executeTestSuite()
860886
861887 if (! shouldFail && test.didFail) {
862- fail(" Neg test shouldn't have failed, but did" )
888+ fail(s " Neg test shouldn't have failed, but did. Reasons: \n ${ reasonsForFailure(test) } " )
863889 }
864890 else if (shouldFail && ! test.didFail) {
865891 fail(" Neg test should have failed, but did not" )
@@ -874,10 +900,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
874900 * expected output
875901 */
876902 def checkRuns ()(implicit summaryReport : SummaryReporting ): this .type = {
877- val test = new RunTest (targets, times, threadLimit, shouldFail).executeTestSuite()
903+ val test = new RunTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput ).executeTestSuite()
878904
879905 if (! shouldFail && test.didFail) {
880- fail(" Run test failed, but should not" )
906+ fail(s " Run test failed, but should not, reasons: \n ${ reasonsForFailure(test) } " )
881907 }
882908 else if (shouldFail && ! test.didFail) {
883909 fail(" Run test should have failed, but did not" )
@@ -892,6 +918,20 @@ trait ParallelTesting extends RunnerOrchestration { self =>
892918 this
893919 }
894920
921+ /** Extract `Failure` set and render from `Test` */
922+ private [this ] def reasonsForFailure (test : Test ): String = {
923+ val errors =
924+ if (test.errorCount == 0 ) " "
925+ else s " \n - encountered ${test.errorCount} error(s) "
926+
927+ errors + test.failureReasons.collect {
928+ case test.TimeoutFailure (title) =>
929+ s " - test ' $title' timed out "
930+ case test.JavaCompilationFailure (msg) =>
931+ s " - java compilation failed with: \n ${ msg.lines.map(" " + _).mkString(" \n " ) }"
932+ }.mkString(" \n " )
933+ }
934+
895935 /** Copies `file` to `dir` - taking into account if `file` is a directory,
896936 * and if so copying recursively
897937 */
@@ -913,21 +953,21 @@ trait ParallelTesting extends RunnerOrchestration { self =>
913953 case target @ SeparateCompilationSource (_, dir, _, outDir) =>
914954 target.copy(dir = copyToDir(outDir, dir))
915955 },
916- times, shouldDelete, threadLimit, shouldFail
956+ times, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput
917957 )
918958
919959 /** Builds a `CompilationTest` which performs the compilation `i` times on
920960 * each target
921961 */
922962 def times (i : Int ): CompilationTest =
923- new CompilationTest (targets, i, shouldDelete, threadLimit, shouldFail)
963+ new CompilationTest (targets, i, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput )
924964
925965 /** Builds a `Compilationtest` which passes the verbose flag and logs the
926966 * classpath
927967 */
928968 def verbose : CompilationTest = new CompilationTest (
929969 targets.map(t => t.withFlags(" -verbose" , " -Ylog-classpath" )),
930- times, shouldDelete, threadLimit, shouldFail
970+ times, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput
931971 )
932972
933973 /** Builds a `CompilationTest` which keeps the generated output files
@@ -937,20 +977,27 @@ trait ParallelTesting extends RunnerOrchestration { self =>
937977 * part which depends on the first
938978 */
939979 def keepOutput : CompilationTest =
940- new CompilationTest (targets, times, false , threadLimit, shouldFail)
980+ new CompilationTest (targets, times, false , threadLimit, shouldFail, shouldSuppressOutput )
941981
942982 /** Builds a `CompilationTest` with a limited level of concurrency with
943983 * maximum `i` threads
944984 */
945985 def limitThreads (i : Int ): CompilationTest =
946- new CompilationTest (targets, times, shouldDelete, Some (i), shouldFail)
986+ new CompilationTest (targets, times, shouldDelete, Some (i), shouldFail, shouldSuppressOutput )
947987
948988 /** Builds a `CompilationTest` where the executed test is expected to fail
949989 *
950990 * This behaviour is mainly needed for the tests that test the test suite.
951991 */
952992 def expectFailure : CompilationTest =
953- new CompilationTest (targets, times, shouldDelete, threadLimit, true )
993+ new CompilationTest (targets, times, shouldDelete, threadLimit, true , shouldSuppressOutput)
994+
995+ /** Builds a `CompilationTest` where all output is suppressed
996+ *
997+ * This behaviour is mainly needed for the tests that test the test suite.
998+ */
999+ def suppressAllOutput : CompilationTest =
1000+ new CompilationTest (targets, times, shouldDelete, threadLimit, shouldFail, true )
9541001
9551002 /** Delete all output files generated by this `CompilationTest` */
9561003 def delete (): Unit = targets.foreach(t => delete(t.outDir))
0 commit comments