@@ -242,10 +242,20 @@ trait ParallelTesting extends RunnerOrchestration { self =>
242
242
_errorCount += errors
243
243
}
244
244
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 ]
246
251
/** 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
249
259
250
260
protected def logBuildInstructions (reporter : TestReporter , testSource : TestSource , err : Int , war : Int ) = {
251
261
val errorMsg = testSource.buildInstructions(reporter.errorCount, reporter.warningCount)
@@ -260,10 +270,14 @@ trait ParallelTesting extends RunnerOrchestration { self =>
260
270
261
271
/** The test sources that failed according to the implementing subclass */
262
272
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
+ }
265
279
failedTestSources.append(testSource.title + s " failed " + extra)
266
- fail()
280
+ fail(reason )
267
281
}
268
282
269
283
/** Prints to `System.err` if we're not suppressing all output */
@@ -342,12 +356,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
342
356
def compileWithJavac (fs : Array [String ]) = if (fs.nonEmpty) {
343
357
val fullArgs = Array (
344
358
" javac" ,
359
+ " -encoding" , " UTF-8" ,
345
360
" -classpath" ,
346
361
s " .: ${Jars .scalaLibrary}: ${targetDir.getAbsolutePath}"
347
362
) ++ flags.takeRight(2 ) ++ fs
348
363
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
351
370
352
371
val reporter =
353
372
TestReporter .reporter(realStdout, logLevel =
@@ -377,7 +396,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
377
396
driver.process(allArgs ++ files.map(_.getAbsolutePath), reporter = reporter)
378
397
379
398
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
+ }
381
405
}
382
406
catch {
383
407
case NonFatal (ex) => reporter.logStackTrace(ex)
@@ -522,7 +546,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
522
546
523
547
case Timeout =>
524
548
echo(" failed because test " + testSource.title + " timed out" )
525
- failTestSource(testSource, Some ( " test timed out " ))
549
+ failTestSource(testSource, TimeoutFailure (testSource.title ))
526
550
}
527
551
}
528
552
@@ -803,15 +827,16 @@ trait ParallelTesting extends RunnerOrchestration { self =>
803
827
private [ParallelTesting ] val times : Int ,
804
828
private [ParallelTesting ] val shouldDelete : Boolean ,
805
829
private [ParallelTesting ] val threadLimit : Option [Int ],
806
- private [ParallelTesting ] val shouldFail : Boolean
830
+ private [ParallelTesting ] val shouldFail : Boolean ,
831
+ private [ParallelTesting ] val shouldSuppressOutput : Boolean
807
832
) {
808
833
import org .junit .Assert .fail
809
834
810
835
private [ParallelTesting ] def this (target : TestSource ) =
811
- this (List (target), 1 , true , None , false )
836
+ this (List (target), 1 , true , None , false , false )
812
837
813
838
private [ParallelTesting ] def this (targets : List [TestSource ]) =
814
- this (targets, 1 , true , None , false )
839
+ this (targets, 1 , true , None , false , false )
815
840
816
841
/** Compose test targets from `this` with `other`
817
842
*
@@ -831,18 +856,19 @@ trait ParallelTesting extends RunnerOrchestration { self =>
831
856
require(other.times == times, " can't combine tests that are meant to be benchmark compiled" )
832
857
require(other.shouldDelete == shouldDelete, " can't combine tests that differ on deleting output" )
833
858
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)
835
861
}
836
862
837
863
/** Creates a "pos" test run, which makes sure that all tests pass
838
864
* compilation without generating errors and that they do not crash the
839
865
* compiler
840
866
*/
841
867
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()
843
869
844
870
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) }" )
846
872
}
847
873
else if (shouldFail && ! test.didFail) {
848
874
fail(" Pos test should have failed, but didn't" )
@@ -856,10 +882,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
856
882
* that none of these tests crash the compiler
857
883
*/
858
884
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()
860
886
861
887
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) } " )
863
889
}
864
890
else if (shouldFail && ! test.didFail) {
865
891
fail(" Neg test should have failed, but did not" )
@@ -874,10 +900,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
874
900
* expected output
875
901
*/
876
902
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()
878
904
879
905
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) } " )
881
907
}
882
908
else if (shouldFail && ! test.didFail) {
883
909
fail(" Run test should have failed, but did not" )
@@ -892,6 +918,20 @@ trait ParallelTesting extends RunnerOrchestration { self =>
892
918
this
893
919
}
894
920
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
+
895
935
/** Copies `file` to `dir` - taking into account if `file` is a directory,
896
936
* and if so copying recursively
897
937
*/
@@ -913,21 +953,21 @@ trait ParallelTesting extends RunnerOrchestration { self =>
913
953
case target @ SeparateCompilationSource (_, dir, _, outDir) =>
914
954
target.copy(dir = copyToDir(outDir, dir))
915
955
},
916
- times, shouldDelete, threadLimit, shouldFail
956
+ times, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput
917
957
)
918
958
919
959
/** Builds a `CompilationTest` which performs the compilation `i` times on
920
960
* each target
921
961
*/
922
962
def times (i : Int ): CompilationTest =
923
- new CompilationTest (targets, i, shouldDelete, threadLimit, shouldFail)
963
+ new CompilationTest (targets, i, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput )
924
964
925
965
/** Builds a `Compilationtest` which passes the verbose flag and logs the
926
966
* classpath
927
967
*/
928
968
def verbose : CompilationTest = new CompilationTest (
929
969
targets.map(t => t.withFlags(" -verbose" , " -Ylog-classpath" )),
930
- times, shouldDelete, threadLimit, shouldFail
970
+ times, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput
931
971
)
932
972
933
973
/** Builds a `CompilationTest` which keeps the generated output files
@@ -937,20 +977,27 @@ trait ParallelTesting extends RunnerOrchestration { self =>
937
977
* part which depends on the first
938
978
*/
939
979
def keepOutput : CompilationTest =
940
- new CompilationTest (targets, times, false , threadLimit, shouldFail)
980
+ new CompilationTest (targets, times, false , threadLimit, shouldFail, shouldSuppressOutput )
941
981
942
982
/** Builds a `CompilationTest` with a limited level of concurrency with
943
983
* maximum `i` threads
944
984
*/
945
985
def limitThreads (i : Int ): CompilationTest =
946
- new CompilationTest (targets, times, shouldDelete, Some (i), shouldFail)
986
+ new CompilationTest (targets, times, shouldDelete, Some (i), shouldFail, shouldSuppressOutput )
947
987
948
988
/** Builds a `CompilationTest` where the executed test is expected to fail
949
989
*
950
990
* This behaviour is mainly needed for the tests that test the test suite.
951
991
*/
952
992
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 )
954
1001
955
1002
/** Delete all output files generated by this `CompilationTest` */
956
1003
def delete (): Unit = targets.foreach(t => delete(t.outDir))
0 commit comments