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