@@ -6,7 +6,6 @@ package vulpix
6
6
import java .io .{ File => JFile }
7
7
import java .text .SimpleDateFormat
8
8
import java .util .HashMap
9
- import java .lang .reflect .InvocationTargetException
10
9
import java .nio .file .StandardCopyOption .REPLACE_EXISTING
11
10
import java .nio .file .{ Files , Path , Paths , NoSuchFileException }
12
11
import java .util .concurrent .{ Executors => JExecutors , TimeUnit , TimeoutException }
@@ -24,13 +23,15 @@ import reporting.diagnostic.MessageContainer
24
23
import interfaces .Diagnostic .ERROR
25
24
import dotc .util .DiffUtil
26
25
26
+ import vulpix .Statuses ._
27
+
27
28
/** A parallel testing suite whose goal is to integrate nicely with JUnit
28
29
*
29
30
* This trait can be mixed in to offer parallel testing to compile runs. When
30
31
* using this, you should be running your JUnit tests **sequentially**, as the
31
32
* test suite itself runs with a high level of concurrency.
32
33
*/
33
- trait ParallelTesting { self =>
34
+ trait ParallelTesting extends RunnerOrchestration { self =>
34
35
35
36
import ParallelTesting ._
36
37
import SummaryReport ._
@@ -225,14 +226,18 @@ trait ParallelTesting { self =>
225
226
226
227
/** The test sources that failed according to the implementing subclass */
227
228
private [this ] val failedTestSources = mutable.ArrayBuffer .empty[String ]
228
- protected final def failTestSource (testSource : TestSource ) = synchronized {
229
- failedTestSources.append(testSource.name + " failed" )
229
+ protected final def failTestSource (testSource : TestSource , reason : Option [String ] = None ) = synchronized {
230
+ val extra = reason.map(" with reason: " + _).getOrElse(" " )
231
+ failedTestSources.append(testSource.name + " failed" + extra)
230
232
fail()
231
233
}
232
234
233
235
/** Prints to `System.err` if we're not suppressing all output */
234
- protected def echo (msg : String ): Unit =
235
- if (! suppressAllOutput) realStderr.println(msg)
236
+ protected def echo (msg : String ): Unit = if (! suppressAllOutput) {
237
+ // pad right so that output is at least as large as progress bar line
238
+ val paddingRight = " " * math.max(0 , 80 - msg.length)
239
+ realStderr.println(msg + paddingRight)
240
+ }
236
241
237
242
/** A single `Runnable` that prints a progress bar for the curent `Test` */
238
243
private def createProgressMonitor : Runnable = new Runnable {
@@ -418,97 +423,58 @@ trait ParallelTesting { self =>
418
423
echoBuildInstructions(reporters.head, testSource, errorCount, warningCount)
419
424
}
420
425
}
421
-
422
426
}
423
427
}
424
428
}
425
429
426
430
private final class RunTest (testSources : List [TestSource ], times : Int , threadLimit : Option [Int ], suppressAllOutput : Boolean )
427
431
extends Test (testSources, times, threadLimit, suppressAllOutput) {
428
- private def runMain (dir : JFile , testSource : TestSource ): Array [String ] = {
429
- def renderStackTrace (ex : Throwable ): String =
430
- ex.getStackTrace
431
- .takeWhile(_.getMethodName != " invoke0" )
432
- .mkString(" " , " \n " , " " )
433
-
434
- import java .io .{ ByteArrayOutputStream , PrintStream }
435
- import java .net .{ URL , URLClassLoader }
436
-
437
- val printStream = new ByteArrayOutputStream
438
-
439
- try {
440
- // Do classloading magic and running here:
441
- val ucl = new URLClassLoader (Array (dir.toURI.toURL))
442
- val cls = ucl.loadClass(" Test" )
443
- val meth = cls.getMethod(" main" , classOf [Array [String ]])
444
-
445
- synchronized {
446
- try {
447
- val ps = new PrintStream (printStream)
448
- System .setOut(ps)
449
- System .setErr(ps)
450
- Console .withOut(printStream) {
451
- Console .withErr(printStream) {
452
- meth.invoke(null , Array (" jvm" )) // partest passes at least "jvm" as an arg
453
- }
454
- }
455
- System .setOut(realStdout)
456
- System .setErr(realStderr)
457
- } catch {
458
- case t : Throwable =>
459
- System .setOut(realStdout)
460
- System .setErr(realStderr)
461
- throw t
432
+ private def verifyOutput (checkFile : JFile , dir : JFile , testSource : TestSource , warnings : Int ) = {
433
+ runMain(dir) match {
434
+ case success : Success => {
435
+ val outputLines = success.output.lines.toArray
436
+ val checkLines : Array [String ] = Source .fromFile(checkFile).getLines.toArray
437
+ val sourceTitle = testSource.title
438
+
439
+ def linesMatch =
440
+ outputLines
441
+ .zip(checkLines)
442
+ .forall { case (x, y) => x == y }
443
+
444
+ if (outputLines.length != checkLines.length || ! linesMatch) {
445
+ // Print diff to files and summary:
446
+ val diff = outputLines.zip(checkLines).map { case (act, exp) =>
447
+ DiffUtil .mkColoredLineDiff(exp, act)
448
+ }.mkString(" \n " )
449
+
450
+ val msg =
451
+ s """ |Output from ' $sourceTitle' did not match check file.
452
+ |Diff ('e' is expected, 'a' is actual):
453
+ | """ .stripMargin + diff + " \n "
454
+ echo(msg)
455
+ addFailureInstruction(msg)
456
+
457
+ // Print build instructions to file and summary:
458
+ val buildInstr = testSource.buildInstructions(0 , warnings)
459
+ addFailureInstruction(buildInstr)
460
+
461
+ // Fail target:
462
+ failTestSource(testSource)
462
463
}
463
464
}
464
- }
465
- catch {
466
- case ex : NoSuchMethodException =>
467
- echo(s " test in ' $dir' did not contain method: ${ex.getMessage}\n ${renderStackTrace(ex.getCause)}" )
468
- failTestSource(testSource)
469
465
470
- case ex : ClassNotFoundException =>
471
- echo(s " test in ' $dir ' did not contain class: ${ex.getMessage} \n ${renderStackTrace(ex.getCause)} " )
466
+ case failure : Failure =>
467
+ echo(renderFailure(failure) )
472
468
failTestSource(testSource)
473
469
474
- case ex : InvocationTargetException =>
475
- echo(s " An exception ocurred when running main: ${ex.getCause} \n ${renderStackTrace(ex.getCause)} " )
476
- failTestSource(testSource)
470
+ case _ : Timeout =>
471
+ echo(" failed because test " + testSource.title + " timed out " )
472
+ failTestSource(testSource, Some ( " test timed out " ) )
477
473
}
478
- printStream.toString(" utf-8" ).lines.toArray
479
474
}
480
475
481
- private def verifyOutput (checkFile : JFile , dir : JFile , testSource : TestSource , warnings : Int ) = {
482
- val outputLines = runMain(dir, testSource)
483
- val checkLines = Source .fromFile(checkFile).getLines.toArray
484
- val sourceTitle = testSource.title
485
-
486
- def linesMatch =
487
- outputLines
488
- .zip(checkLines)
489
- .forall { case (x, y) => x == y }
490
-
491
- if (outputLines.length != checkLines.length || ! linesMatch) {
492
- // Print diff to files and summary:
493
- val diff = outputLines.zip(checkLines).map { case (act, exp) =>
494
- DiffUtil .mkColoredLineDiff(exp, act)
495
- }.mkString(" \n " )
496
-
497
- val msg =
498
- s """ |Output from ' $sourceTitle' did not match check file.
499
- |Diff ('e' is expected, 'a' is actual):
500
- | """ .stripMargin + diff + " \n "
501
- echo(msg)
502
- addFailureInstruction(msg)
503
-
504
- // Print build instructions to file and summary:
505
- val buildInstr = testSource.buildInstructions(0 , warnings)
506
- addFailureInstruction(buildInstr)
507
-
508
- // Fail target:
509
- failTestSource(testSource)
510
- }
511
- }
476
+ private def renderFailure (failure : Failure ): String =
477
+ failure.message + " \n " + failure.stacktrace
512
478
513
479
protected def compilationRunnable (testSource : TestSource ): Runnable = new Runnable {
514
480
def run (): Unit = tryCompile(testSource) {
@@ -553,7 +519,15 @@ trait ParallelTesting { self =>
553
519
}
554
520
555
521
if (errorCount == 0 && hasCheckFile) verifier()
556
- else if (errorCount == 0 ) runMain(testSource.outDir, testSource)
522
+ else if (errorCount == 0 ) runMain(testSource.outDir) match {
523
+ case status : Failure =>
524
+ echo(renderFailure(status))
525
+ failTestSource(testSource)
526
+ case _ : Timeout =>
527
+ echo(" failed because test " + testSource.title + " timed out" )
528
+ failTestSource(testSource, Some (" test timed out" ))
529
+ case _ : Success => // success!
530
+ }
557
531
else if (errorCount > 0 ) {
558
532
echo(s " \n Compilation failed for: ' $testSource' " )
559
533
val buildInstr = testSource.buildInstructions(errorCount, warningCount)
0 commit comments