@@ -384,6 +384,11 @@ trait ParallelTesting extends RunnerOrchestration { self =>
384
384
/** Number of failed tests */
385
385
def failureCount : Int = _failureCount
386
386
387
+ private var _skipCount = 0
388
+ protected final def skip (): Unit = synchronized { _skipCount += 1 }
389
+ def skipCount : Int = _skipCount
390
+ def skipped : Boolean = skipCount > 0
391
+
387
392
protected def logBuildInstructions (testSource : TestSource , reporters : Seq [TestReporter ]) = {
388
393
val (errCount, warnCount) = countErrorsAndWarnings(reporters)
389
394
val errorMsg = testSource.buildInstructions(errCount, warnCount)
@@ -456,13 +461,20 @@ trait ParallelTesting extends RunnerOrchestration { self =>
456
461
val toolArgs = toolArgsFor(files.toList.map(_.toPath), getCharsetFromEncodingOpt(flags0))
457
462
458
463
val spec = raw " (\d+)(\+)? " .r
459
- val testFilter = toolArgs.get(ToolName .Test ) match
464
+ val testIsFiltered = toolArgs.get(ToolName .Test ) match
460
465
case Some (" -jvm" :: spec(n, more) :: Nil ) =>
461
466
if more == " +" then isJavaAtLeast(n) else javaSpecVersion == n
462
467
case Some (args) => throw new IllegalStateException (args.mkString(" unknown test option: " , " , " , " " ))
463
468
case None => true
469
+ val minRelease = toolArgs.get(ToolName .Test ) match
470
+ case Some (" -jvm" :: spec(n, more) :: Nil ) =>
471
+ if more == " +" then javaSpecVersion else n
472
+ case _ => " 8"
464
473
465
- def scalacOptions = toolArgs.get(ToolName .Scalac ).getOrElse(Nil )
474
+ def scalacOptions =
475
+ toolArgs.get(ToolName .Scalac )
476
+ .map(args => if args.exists(_.startsWith(" -release" )) then args else " -release" :: minRelease :: args)
477
+ .getOrElse(Nil )
466
478
467
479
val flags = flags0
468
480
.and(scalacOptions : _* )
@@ -482,9 +494,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
482
494
else None
483
495
} else None
484
496
485
- val reporter =
486
- TestReporter .reporter(realStdout, logLevel =
487
- if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR )
497
+ val reporter = TestReporter .reporter(realStdout, logLevel = if (suppressErrors || suppressAllOutput) ERROR + 1 else ERROR )
488
498
489
499
val driver =
490
500
if (times == 1 ) new Driver
@@ -503,7 +513,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
503
513
504
514
val allArgs = flags.all
505
515
506
- if testFilter then
516
+ if testIsFiltered then
507
517
// If a test contains a Java file that cannot be parsed by Dotty's Java source parser, its
508
518
// name must contain the string "JAVA_ONLY".
509
519
val dottyFiles = files.filterNot(_.getName.contains(" JAVA_ONLY" )).map(_.getPath)
@@ -517,6 +527,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>
517
527
echo(s " \n java compilation failed: \n ${ javaErrors.get }" )
518
528
fail(failure = JavaCompilationFailure (javaErrors.get))
519
529
}
530
+ else
531
+ skip()
520
532
end if
521
533
522
534
reporter
@@ -738,7 +750,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>
738
750
}
739
751
740
752
private def verifyOutput (checkFile : Option [JFile ], dir : JFile , testSource : TestSource , warnings : Int , reporters : Seq [TestReporter ], logger : LoggedRunnable ) = {
741
- if (Properties .testsNoRun) addNoRunWarning()
753
+ if skipped then ()
754
+ else if Properties .testsNoRun then addNoRunWarning()
742
755
else runMain(testSource.runClassPath) match {
743
756
case Success (output) => checkFile match {
744
757
case Some (file) if file.exists => diffTest(testSource, file, output.linesIterator.toList, reporters, logger)
@@ -762,7 +775,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
762
775
extends Test (testSources, times, threadLimit, suppressAllOutput) {
763
776
override def suppressErrors = true
764
777
765
- override def maybeFailureMessage (testSource : TestSource , reporters : Seq [TestReporter ]): Option [String ] = {
778
+ override def maybeFailureMessage (testSource : TestSource , reporters : Seq [TestReporter ]): Option [String ] = if skipped then None else
766
779
def compilerCrashed = reporters.exists(_.compilerCrashed)
767
780
lazy val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(testSource.sourceFiles.toIndexedSeq)
768
781
lazy val actualErrors = reporters.foldLeft(0 )(_ + _.errorCount)
@@ -786,20 +799,21 @@ trait ParallelTesting extends RunnerOrchestration { self =>
786
799
else if ! errorMap.isEmpty then s " \n Expected error(s) have {<error position>=<unreported error>}: $errorMap"
787
800
else null
788
801
}
789
- }
802
+ end maybeFailureMessage
790
803
791
804
override def onSuccess (testSource : TestSource , reporters : Seq [TestReporter ], logger : LoggedRunnable ): Unit =
792
805
checkFile(testSource).foreach(diffTest(testSource, _, reporterOutputLines(reporters), reporters, logger))
793
806
794
807
def reporterOutputLines (reporters : Seq [TestReporter ]): List [String ] =
795
808
reporters.flatMap(_.consoleOutput.split(" \n " )).toList
796
809
797
- // In neg-tests we allow two types of error annotations,
798
- // "nopos-error" which doesn't care about position and "error" which
799
- // has to be annotated on the correct line number.
810
+ // In neg-tests we allow two or three types of error annotations.
811
+ // Normally, `// error` must be annotated on the correct line number.
812
+ // `// nopos-error` allows for an error reported without a position.
813
+ // `// anypos-error` allows for an error reported with a position that can't be annotated in the check file.
800
814
//
801
815
// We collect these in a map `"file:row" -> numberOfErrors`, for
802
- // nopos errors we save them in `"file" -> numberOfNoPosErrors`
816
+ // nopos and anypos errors we save them in `"file" -> numberOfNoPosErrors`
803
817
def getErrorMapAndExpectedCount (files : Seq [JFile ]): (HashMap [String , Integer ], Int ) =
804
818
val comment = raw " //( *)(nopos-|anypos-)?error " .r
805
819
val errorMap = new HashMap [String , Integer ]()
@@ -964,8 +978,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
964
978
* ===============
965
979
* Since this is a parallel test suite, it is essential to be able to
966
980
* compose tests to take advantage of the concurrency. This is done using
967
- * the `+` function. This function will make sure that tests being combined
968
- * are compatible according to the `require`s in `+`.
981
+ * `aggregateTests` in the companion, which will ensure that aggregation is allowed.
969
982
*/
970
983
final class CompilationTest private (
971
984
private [ParallelTesting ] val targets : List [TestSource ],
@@ -983,6 +996,14 @@ trait ParallelTesting extends RunnerOrchestration { self =>
983
996
def this (targets : List [TestSource ]) =
984
997
this (targets, 1 , true , None , false , false )
985
998
999
+ def copy (targets : List [TestSource ],
1000
+ times : Int = times,
1001
+ shouldDelete : Boolean = shouldDelete,
1002
+ threadLimit : Option [Int ] = threadLimit,
1003
+ shouldFail : Boolean = shouldFail,
1004
+ shouldSuppressOutput : Boolean = shouldSuppressOutput): CompilationTest =
1005
+ CompilationTest (targets, times, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput)
1006
+
986
1007
/** Creates a "pos" test run, which makes sure that all tests pass
987
1008
* compilation without generating errors and that they do not crash the
988
1009
* compiler
@@ -1003,23 +1024,23 @@ trait ParallelTesting extends RunnerOrchestration { self =>
1003
1024
}
1004
1025
1005
1026
/** Creates a "neg" test run, which makes sure that each test generates the
1006
- * correct amount of errors at the correct positions. It also makes sure
1007
- * that none of these tests crash the compiler
1027
+ * correct number of errors at the correct positions. It also makes sure
1028
+ * that none of these tests crashes the compiler.
1008
1029
*/
1009
- def checkExpectedErrors ()(implicit summaryReport : SummaryReporting ): this .type = {
1030
+ def checkExpectedErrors ()(implicit summaryReport : SummaryReporting ): this .type =
1010
1031
val test = new NegTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput).executeTestSuite()
1011
1032
1012
1033
cleanup()
1013
1034
1014
- if (shouldFail && ! test.didFail) {
1015
- fail( s " Neg test shouldn't have failed, but did. Reasons: \n ${ reasonsForFailure(test) } " )
1016
- }
1017
- else if ( ! shouldFail && test.didFail) {
1018
- fail(" Neg test should have failed, but did not" )
1019
- }
1035
+ if ! test.skipped then
1036
+ if shouldFail && ! test.didFail then
1037
+ fail( s " Neg test shouldn't have failed, but did. Reasons: \n ${ reasonsForFailure(test) } " )
1038
+ else if ! shouldFail && test.didFail then
1039
+ fail(" Neg test should have failed, but did not" )
1040
+ end if
1020
1041
1021
1042
this
1022
- }
1043
+ end checkExpectedErrors
1023
1044
1024
1045
/** Creates a "fuzzy" test run, which makes sure that each test compiles (or not) without crashing */
1025
1046
def checkNoCrash ()(implicit summaryReport : SummaryReporting ): this .type = {
@@ -1044,12 +1065,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
1044
1065
1045
1066
cleanup()
1046
1067
1047
- if ( ! shouldFail && test.didFail) {
1048
- fail( s " Run test failed, but should not, reasons: \n ${ reasonsForFailure( test) } " )
1049
- }
1050
- else if ( shouldFail && ! test.didFail) {
1051
- fail(" Run test should have failed, but did not" )
1052
- }
1068
+ if ! test.skipped then
1069
+ if ! shouldFail && test.didFail then
1070
+ fail( s " Run test failed, but should not, reasons: \n ${ reasonsForFailure(test) } " )
1071
+ else if shouldFail && ! test.didFail then
1072
+ fail(" Run test should have failed, but did not" )
1073
+ end if
1053
1074
1054
1075
this
1055
1076
}
@@ -1174,35 +1195,32 @@ trait ParallelTesting extends RunnerOrchestration { self =>
1174
1195
}
1175
1196
}
1176
1197
1177
- object CompilationTest {
1198
+ object CompilationTest :
1178
1199
1179
1200
/** Compose test targets from `tests`
1180
- *
1181
- * It does this, only if the two tests are compatible. Otherwise it throws
1182
- * an `IllegalArgumentException`.
1183
- *
1184
- * Grouping tests together like this allows us to take advantage of the
1185
- * concurrency offered by this test suite as each call to an executing
1186
- * method (`pos()` / `checkExpectedErrors()`/ `run()`) will spin up a thread pool with the
1187
- * maximum allowed level of concurrency. Doing this for only a few targets
1188
- * does not yield any real benefit over sequential compilation.
1189
- *
1190
- * As such, each `CompilationTest` should contain as many targets as
1191
- * possible.
1192
- */
1193
- def aggregateTests (tests : CompilationTest * ): CompilationTest = {
1201
+ *
1202
+ * It does this, only if all the tests are mutally compatible.
1203
+ * Otherwise it throws an `IllegalArgumentException`.
1204
+ *
1205
+ * Grouping tests together like this allows us to take advantage of the
1206
+ * concurrency offered by this test suite, as each call to an executing
1207
+ * method (`pos()` / `checkExpectedErrors()`/ `run()`) will spin up a thread pool with the
1208
+ * maximum allowed level of concurrency. Doing this for only a few targets
1209
+ * does not yield any real benefit over sequential compilation.
1210
+ *
1211
+ * As such, each `CompilationTest` should contain as many targets as
1212
+ * possible.
1213
+ */
1214
+ def aggregateTests (tests : CompilationTest * ): CompilationTest =
1194
1215
assert(tests.nonEmpty)
1195
- def aggregate (test1 : CompilationTest , test2 : CompilationTest ) = {
1216
+ def aggregate (test1 : CompilationTest , test2 : CompilationTest ) =
1196
1217
require(test1.times == test2.times, " can't combine tests that are meant to be benchmark compiled" )
1197
1218
require(test1.shouldDelete == test2.shouldDelete, " can't combine tests that differ on deleting output" )
1198
1219
require(test1.shouldFail == test2.shouldFail, " can't combine tests that have different expectations on outcome" )
1199
1220
require(test1.shouldSuppressOutput == test2.shouldSuppressOutput, " can't combine tests that both suppress and don't suppress output" )
1200
- new CompilationTest (test1.targets ++ test2.targets, test1.times, test1.shouldDelete, test1.threadLimit, test1.shouldFail, test1.shouldSuppressOutput)
1201
- }
1221
+ test1.copy(test1.targets ++ test2.targets) // what if thread limit differs? currently threads are limited on aggregate only
1202
1222
tests.reduce(aggregate)
1203
- }
1204
-
1205
- }
1223
+ end CompilationTest
1206
1224
1207
1225
/** Create out directory for directory `d` */
1208
1226
def createOutputDirsForDir (d : JFile , sourceDir : JFile , outDir : String ): JFile = {
0 commit comments