@@ -183,12 +183,39 @@ trait ParallelTesting extends RunnerOrchestration { self =>
183
183
/** Each `Test` takes the `testSources` and performs the compilation and assertions
184
184
* according to the implementing class "neg", "run" or "pos".
185
185
*/
186
- private abstract class Test (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean ) {
186
+ private abstract class Test (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean ) { test =>
187
187
protected final val realStdout = System .out
188
188
protected final val realStderr = System .err
189
189
190
+ /** A runnable that logs its contents in a buffer */
191
+ trait LoggedRunnable extends Runnable {
192
+ import TestReporter .logWriter
193
+
194
+ /** Instances of `LoggedRunnable` implement this method instead of the
195
+ * `run` method
196
+ */
197
+ def checkTestSource (): Unit
198
+
199
+ private [this ] val logBuffer = mutable.ArrayBuffer .empty[String ]
200
+ def log (msg : String ): Unit = logBuffer.append(msg)
201
+
202
+ def logReporterContents (reporter : TestReporter ): Unit =
203
+ reporter.messages.foreach(log)
204
+
205
+ def echo (msg : String ): Unit = {
206
+ log(msg)
207
+ test.echo(msg)
208
+ }
209
+
210
+ final def run (): Unit = {
211
+ checkTestSource()
212
+ logBuffer.iterator.foreach(logWriter.println)
213
+ logWriter.flush()
214
+ }
215
+ }
216
+
190
217
/** Actual compilation run logic, the test behaviour is defined here */
191
- protected def compilationRunnable (testSource : TestSource ): Runnable
218
+ protected def encapsulatedCompilation (testSource : TestSource ): LoggedRunnable
192
219
193
220
/** All testSources left after filtering out */
194
221
private val filteredSources =
@@ -220,7 +247,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
220
247
protected [this ] final def fail (): Unit = synchronized { _failed = true }
221
248
def didFail : Boolean = _failed
222
249
223
- protected def echoBuildInstructions (reporter : TestReporter , testSource : TestSource , err : Int , war : Int ) = {
250
+ protected def logBuildInstructions (reporter : TestReporter , testSource : TestSource , err : Int , war : Int ) = {
224
251
val errorMsg = testSource.buildInstructions(reporter.errorCount, reporter.warningCount)
225
252
addFailureInstruction(errorMsg)
226
253
failTestSource(testSource)
@@ -278,7 +305,9 @@ trait ParallelTesting extends RunnerOrchestration { self =>
278
305
*/
279
306
protected def tryCompile (testSource : TestSource )(op : => Unit ): Unit =
280
307
try {
281
- if (! isInteractive) realStdout.println(s " Testing ${testSource.title}" )
308
+ val testing = s " Testing ${testSource.title}"
309
+ TestReporter .logWriter.println(testing)
310
+ if (! isInteractive) realStdout.println(testing)
282
311
op
283
312
} catch {
284
313
case NonFatal (e) => {
@@ -342,10 +371,17 @@ trait ParallelTesting extends RunnerOrchestration { self =>
342
371
}
343
372
344
373
val allArgs = addOutDir(flags)
345
- driver.process(allArgs ++ files.map(_.getAbsolutePath), reporter = reporter)
346
374
347
- val javaFiles = files.filter(_.getName.endsWith(" .java" )).map(_.getAbsolutePath)
348
- assert(compileWithJavac(javaFiles), s " java compilation failed for ${javaFiles.mkString(" , " )}" )
375
+ // Compile with a try to catch any StackTrace generated by the compiler:
376
+ try {
377
+ driver.process(allArgs ++ files.map(_.getAbsolutePath), reporter = reporter)
378
+
379
+ val javaFiles = files.filter(_.getName.endsWith(" .java" )).map(_.getAbsolutePath)
380
+ assert(compileWithJavac(javaFiles), s " java compilation failed for ${javaFiles.mkString(" , " )}" )
381
+ }
382
+ catch {
383
+ case NonFatal (ex) => reporter.logStackTrace(ex)
384
+ }
349
385
350
386
reporter
351
387
}
@@ -362,7 +398,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
362
398
if (isInteractive && ! suppressAllOutput) pool.submit(createProgressMonitor)
363
399
364
400
filteredSources.foreach { target =>
365
- pool.submit(compilationRunnable (target))
401
+ pool.submit(encapsulatedCompilation (target))
366
402
}
367
403
368
404
pool.shutdown()
@@ -392,22 +428,25 @@ trait ParallelTesting extends RunnerOrchestration { self =>
392
428
393
429
private final class PosTest (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean )
394
430
extends Test (testSources, times, threadLimit, suppressAllOutput) {
395
- protected def compilationRunnable (testSource : TestSource ): Runnable = new Runnable {
396
- def run (): Unit = tryCompile(testSource) {
431
+ protected def encapsulatedCompilation (testSource : TestSource ) = new LoggedRunnable {
432
+ def checkTestSource (): Unit = tryCompile(testSource) {
397
433
testSource match {
398
434
case testSource @ JointCompilationSource (_, files, flags, outDir) => {
399
435
val reporter = compile(testSource.sourceFiles, flags, false , outDir)
400
436
registerCompletion(reporter.errorCount)
401
437
402
- if (reporter.errorCount > 0 )
403
- echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
438
+ if (reporter.compilerCrashed || reporter.errorCount > 0 ) {
439
+ logReporterContents(reporter)
440
+ logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
441
+ }
404
442
}
405
443
406
444
case testSource @ SeparateCompilationSource (_, dir, flags, outDir) => {
407
445
val reporters = testSource.compilationGroups.map(files => compile(files, flags, false , outDir))
446
+ val compilerCrashed = reporters.exists(_.compilerCrashed)
408
447
val errorCount = reporters.foldLeft(0 ) { (acc, reporter) =>
409
448
if (reporter.errorCount > 0 )
410
- echoBuildInstructions (reporter, testSource, reporter.errorCount, reporter.warningCount)
449
+ logBuildInstructions (reporter, testSource, reporter.errorCount, reporter.warningCount)
411
450
412
451
acc + reporter.errorCount
413
452
}
@@ -416,8 +455,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
416
455
417
456
registerCompletion(errorCount)
418
457
419
- if (errorCount > 0 )
420
- echoBuildInstructions(reporters.head, testSource, errorCount, warningCount)
458
+ if (compilerCrashed || errorCount > 0 ) {
459
+ reporters.foreach(logReporterContents)
460
+ logBuildInstructions(reporters.head, testSource, errorCount, warningCount)
461
+ }
421
462
}
422
463
}
423
464
}
@@ -483,9 +524,9 @@ trait ParallelTesting extends RunnerOrchestration { self =>
483
524
}
484
525
}
485
526
486
- protected def compilationRunnable (testSource : TestSource ): Runnable = new Runnable {
487
- def run (): Unit = tryCompile(testSource) {
488
- val (errorCount, warningCount, hasCheckFile, verifier : Function0 [Unit ]) = testSource match {
527
+ protected def encapsulatedCompilation (testSource : TestSource ) = new LoggedRunnable {
528
+ def checkTestSource (): Unit = tryCompile(testSource) {
529
+ val (compilerCrashed, errorCount, warningCount, hasCheckFile, verifier : Function0 [Unit ]) = testSource match {
489
530
case testSource @ JointCompilationSource (_, files, flags, outDir) => {
490
531
val checkFile = files.flatMap { file =>
491
532
if (file.isDirectory) Nil
@@ -498,33 +539,37 @@ trait ParallelTesting extends RunnerOrchestration { self =>
498
539
}.headOption
499
540
val reporter = compile(testSource.sourceFiles, flags, false , outDir)
500
541
501
- if (reporter.errorCount > 0 )
502
- echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
542
+ if (reporter.compilerCrashed || reporter.errorCount > 0 ) {
543
+ logReporterContents(reporter)
544
+ logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
545
+ }
503
546
504
- (reporter.errorCount, reporter.warningCount, checkFile.isDefined, () => verifyOutput(checkFile.get, outDir, testSource, reporter.warningCount))
547
+ (reporter.compilerCrashed, reporter. errorCount, reporter.warningCount, checkFile.isDefined, () => verifyOutput(checkFile.get, outDir, testSource, reporter.warningCount))
505
548
}
506
549
507
550
case testSource @ SeparateCompilationSource (_, dir, flags, outDir) => {
508
551
val checkFile = new JFile (dir.getAbsolutePath.reverse.dropWhile(_ == '/' ).reverse + " .check" )
552
+ val reporters = testSource.compilationGroups.map(compile(_, flags, false , outDir))
553
+ val compilerCrashed = reporters.exists(_.compilerCrashed)
509
554
val (errorCount, warningCount) =
510
- testSource
511
- .compilationGroups
512
- .map(compile(_, flags, false , outDir))
513
- .foldLeft((0 ,0 )) { case ((errors, warnings), reporter) =>
514
- if (reporter.errorCount > 0 )
515
- echoBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
555
+ reporters.foldLeft((0 ,0 )) { case ((errors, warnings), reporter) =>
556
+ if (reporter.errorCount > 0 )
557
+ logBuildInstructions(reporter, testSource, reporter.errorCount, reporter.warningCount)
516
558
517
- (errors + reporter.errorCount, warnings + reporter.warningCount)
518
- }
559
+ (errors + reporter.errorCount, warnings + reporter.warningCount)
560
+ }
519
561
520
- if (errorCount > 0 ) fail()
562
+ if (errorCount > 0 ) {
563
+ reporters.foreach(logReporterContents)
564
+ logBuildInstructions(reporters.head, testSource, errorCount, warningCount)
565
+ }
521
566
522
- (errorCount, warningCount, checkFile.exists, () => verifyOutput(checkFile, outDir, testSource, warningCount))
567
+ (compilerCrashed, errorCount, warningCount, checkFile.exists, () => verifyOutput(checkFile, outDir, testSource, warningCount))
523
568
}
524
569
}
525
570
526
- if (errorCount == 0 && hasCheckFile) verifier()
527
- else if (errorCount == 0 ) {
571
+ if (! compilerCrashed && errorCount == 0 && hasCheckFile) verifier()
572
+ else if (! compilerCrashed && errorCount == 0 ) {
528
573
if (Properties .testsNoRun) addNoRunWarning()
529
574
else runMain(testSource.classPath) match {
530
575
case Success (_) => // success!
@@ -537,26 +582,21 @@ trait ParallelTesting extends RunnerOrchestration { self =>
537
582
failTestSource(testSource, Some (" test timed out" ))
538
583
}
539
584
}
540
- else if (errorCount > 0 ) {
585
+ else {
541
586
echo(s " \n Compilation failed for: ' $testSource' " )
542
587
val buildInstr = testSource.buildInstructions(errorCount, warningCount)
543
588
addFailureInstruction(buildInstr)
544
589
failTestSource(testSource)
545
590
}
546
- else {
547
- realStdout.println(" Got a super weird error that I haven't handled yet" )
548
- realStdout.println(" errorCount: " + errorCount)
549
- realStdout.println(" test: " + testSource.title + " " + testSource.name)
550
- }
551
591
registerCompletion(errorCount)
552
592
}
553
593
}
554
594
}
555
595
556
596
private final class NegTest (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean )
557
597
extends Test (testSources, times, threadLimit, suppressAllOutput) {
558
- protected def compilationRunnable (testSource : TestSource ): Runnable = new Runnable {
559
- def run (): Unit = tryCompile(testSource) {
598
+ protected def encapsulatedCompilation (testSource : TestSource ) = new LoggedRunnable {
599
+ def checkTestSource (): Unit = tryCompile(testSource) {
560
600
// In neg-tests we allow two types of error annotations,
561
601
// "nopos-error" which doesn't care about position and "error" which
562
602
// has to be annotated on the correct line number.
@@ -608,27 +648,39 @@ trait ParallelTesting extends RunnerOrchestration { self =>
608
648
}
609
649
}
610
650
611
- val (expectedErrors, actualErrors, hasMissingAnnotations, errorMap) = testSource match {
651
+ val (compilerCrashed, expectedErrors, actualErrors, hasMissingAnnotations, errorMap) = testSource match {
612
652
case testSource @ JointCompilationSource (_, files, flags, outDir) => {
613
653
val sourceFiles = testSource.sourceFiles
614
654
val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(sourceFiles)
615
655
val reporter = compile(sourceFiles, flags, true , outDir)
616
656
val actualErrors = reporter.errorCount
617
657
618
- (expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, reporter.errors), errorMap)
658
+ if (reporter.compilerCrashed || actualErrors > 0 )
659
+ logReporterContents(reporter)
660
+
661
+ (reporter.compilerCrashed, expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, reporter.errors), errorMap)
619
662
}
620
663
621
664
case testSource @ SeparateCompilationSource (_, dir, flags, outDir) => {
622
665
val compilationGroups = testSource.compilationGroups
623
666
val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(compilationGroups.toArray.flatten)
624
667
val reporters = compilationGroups.map(compile(_, flags, true , outDir))
668
+ val compilerCrashed = reporters.exists(_.compilerCrashed)
625
669
val actualErrors = reporters.foldLeft(0 )(_ + _.errorCount)
626
670
val errors = reporters.iterator.flatMap(_.errors)
627
- (expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, errors), errorMap)
671
+
672
+ if (actualErrors > 0 )
673
+ reporters.foreach(logReporterContents)
674
+
675
+ (compilerCrashed, expectedErrors, actualErrors, () => getMissingExpectedErrors(errorMap, errors), errorMap)
628
676
}
629
677
}
630
678
631
- if (expectedErrors != actualErrors) {
679
+ if (compilerCrashed) {
680
+ echo(s " Compiler crashed when compiling: ${testSource.title}" )
681
+ failTestSource(testSource)
682
+ }
683
+ else if (expectedErrors != actualErrors) {
632
684
echo {
633
685
s " \n Wrong number of errors encountered when compiling $testSource, expected: $expectedErrors, actual: $actualErrors\n "
634
686
}
0 commit comments