@@ -391,6 +391,11 @@ trait ParallelTesting extends RunnerOrchestration { self =>
391391 /** Number of failed tests */
392392 def failureCount : Int = _failureCount
393393
394+ private var _skipCount = 0
395+ protected final def skip (): Unit = synchronized { _skipCount += 1 }
396+ def skipCount : Int = _skipCount
397+ def skipped : Boolean = skipCount > 0
398+
394399 protected def logBuildInstructions (testSource : TestSource , reporters : Seq [TestReporter ]) = {
395400 val (errCount, warnCount) = countErrorsAndWarnings(reporters)
396401 val errorMsg = testSource.buildInstructions(errCount, warnCount)
@@ -464,13 +469,20 @@ trait ParallelTesting extends RunnerOrchestration { self =>
464469 val toolArgs = toolArgsFor(files.toList.map(_.toPath), getCharsetFromEncodingOpt(flags0))
465470
466471 val spec = raw " (\d+)(\+)? " .r
467- val testFilter = toolArgs.get(ToolName .Test ) match
472+ val testIsFiltered = toolArgs.get(ToolName .Test ) match
468473 case Some (" -jvm" :: spec(n, more) :: Nil ) =>
469474 if more == " +" then isJavaAtLeast(n) else javaSpecVersion == n
470475 case Some (args) => throw new IllegalStateException (args.mkString(" unknown test option: " , " , " , " " ))
471476 case None => true
477+ val minRelease = toolArgs.get(ToolName .Test ) match
478+ case Some (" -jvm" :: spec(n, more) :: Nil ) =>
479+ if more == " +" then javaSpecVersion else n
480+ case _ => " 8"
472481
473- def scalacOptions = toolArgs.get(ToolName .Scalac ).getOrElse(Nil )
482+ def scalacOptions =
483+ toolArgs.get(ToolName .Scalac )
484+ .map(args => if args.exists(_.startsWith(" -release" )) then args else " -release" :: minRelease :: args)
485+ .getOrElse(Nil )
474486
475487 val flags = flags0
476488 .and(scalacOptions : _* )
@@ -509,7 +521,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
509521
510522 val allArgs = flags.all
511523
512- if testFilter then
524+ if testIsFiltered then
513525 // If a test contains a Java file that cannot be parsed by Dotty's Java source parser, its
514526 // name must contain the string "JAVA_ONLY".
515527 val dottyFiles = files.filterNot(_.getName.contains(" JAVA_ONLY" )).map(_.getPath)
@@ -523,6 +535,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>
523535 echo(s " \n java compilation failed: \n ${ javaErrors.get }" )
524536 fail(failure = JavaCompilationFailure (javaErrors.get))
525537 }
538+ else
539+ skip()
526540 end if
527541
528542 reporter
@@ -724,7 +738,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>
724738 }
725739
726740 private def verifyOutput (checkFile : Option [JFile ], dir : JFile , testSource : TestSource , warnings : Int , reporters : Seq [TestReporter ], logger : LoggedRunnable ) = {
727- if (Properties .testsNoRun) addNoRunWarning()
741+ if skipped then ()
742+ else if Properties .testsNoRun then addNoRunWarning()
728743 else runMain(testSource.runClassPath, testSource.allToolArgs) match {
729744 case Success (output) => checkFile match {
730745 case Some (file) if file.exists => diffTest(testSource, file, output.linesIterator.toList, reporters, logger)
@@ -748,7 +763,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
748763 extends Test (testSources, times, threadLimit, suppressAllOutput) {
749764 override def suppressErrors = true
750765
751- override def maybeFailureMessage (testSource : TestSource , reporters : Seq [TestReporter ]): Option [String ] = {
766+ override def maybeFailureMessage (testSource : TestSource , reporters : Seq [TestReporter ]): Option [String ] = if skipped then None else
752767 def compilerCrashed = reporters.exists(_.compilerCrashed)
753768 lazy val (errorMap, expectedErrors) = getErrorMapAndExpectedCount(testSource.sourceFiles.toIndexedSeq)
754769 lazy val actualErrors = reporters.foldLeft(0 )(_ + _.errorCount)
@@ -772,20 +787,21 @@ trait ParallelTesting extends RunnerOrchestration { self =>
772787 else if ! errorMap.isEmpty then s " \n Expected error(s) have {<error position>=<unreported error>}: $errorMap"
773788 else null
774789 }
775- }
790+ end maybeFailureMessage
776791
777792 override def onSuccess (testSource : TestSource , reporters : Seq [TestReporter ], logger : LoggedRunnable ): Unit =
778793 checkFile(testSource).foreach(diffTest(testSource, _, reporterOutputLines(reporters), reporters, logger))
779794
780795 def reporterOutputLines (reporters : Seq [TestReporter ]): List [String ] =
781796 reporters.flatMap(_.consoleOutput.split(" \n " )).toList
782797
783- // In neg-tests we allow two types of error annotations,
784- // "nopos-error" which doesn't care about position and "error" which
785- // has to be annotated on the correct line number.
798+ // In neg-tests we allow two or three types of error annotations.
799+ // Normally, `// error` must be annotated on the correct line number.
800+ // `// nopos-error` allows for an error reported without a position.
801+ // `// anypos-error` allows for an error reported with a position that can't be annotated in the check file.
786802 //
787803 // We collect these in a map `"file:row" -> numberOfErrors`, for
788- // nopos errors we save them in `"file" -> numberOfNoPosErrors`
804+ // nopos and anypos errors we save them in `"file" -> numberOfNoPosErrors`
789805 def getErrorMapAndExpectedCount (files : Seq [JFile ]): (HashMap [String , Integer ], Int ) =
790806 val comment = raw " //( *)(nopos-|anypos-)?error " .r
791807 val errorMap = new HashMap [String , Integer ]()
@@ -950,8 +966,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
950966 * ===============
951967 * Since this is a parallel test suite, it is essential to be able to
952968 * compose tests to take advantage of the concurrency. This is done using
953- * the `+` function. This function will make sure that tests being combined
954- * are compatible according to the `require`s in `+`.
969+ * `aggregateTests` in the companion, which will ensure that aggregation is allowed.
955970 */
956971 final class CompilationTest private (
957972 private [ParallelTesting ] val targets : List [TestSource ],
@@ -969,6 +984,14 @@ trait ParallelTesting extends RunnerOrchestration { self =>
969984 def this (targets : List [TestSource ]) =
970985 this (targets, 1 , true , None , false , false )
971986
987+ def copy (targets : List [TestSource ],
988+ times : Int = times,
989+ shouldDelete : Boolean = shouldDelete,
990+ threadLimit : Option [Int ] = threadLimit,
991+ shouldFail : Boolean = shouldFail,
992+ shouldSuppressOutput : Boolean = shouldSuppressOutput): CompilationTest =
993+ CompilationTest (targets, times, shouldDelete, threadLimit, shouldFail, shouldSuppressOutput)
994+
972995 /** Creates a "pos" test run, which makes sure that all tests pass
973996 * compilation without generating errors and that they do not crash the
974997 * compiler
@@ -989,23 +1012,23 @@ trait ParallelTesting extends RunnerOrchestration { self =>
9891012 }
9901013
9911014 /** Creates a "neg" test run, which makes sure that each test generates the
992- * correct amount of errors at the correct positions. It also makes sure
993- * that none of these tests crash the compiler
1015+ * correct number of errors at the correct positions. It also makes sure
1016+ * that none of these tests crashes the compiler.
9941017 */
995- def checkExpectedErrors ()(implicit summaryReport : SummaryReporting ): this .type = {
1018+ def checkExpectedErrors ()(implicit summaryReport : SummaryReporting ): this .type =
9961019 val test = new NegTest (targets, times, threadLimit, shouldFail || shouldSuppressOutput).executeTestSuite()
9971020
9981021 cleanup()
9991022
1000- if (shouldFail && ! test.didFail) {
1001- fail( s " Neg test shouldn't have failed, but did. Reasons: \n ${ reasonsForFailure(test) } " )
1002- }
1003- else if ( ! shouldFail && test.didFail) {
1004- fail(" Neg test should have failed, but did not" )
1005- }
1023+ if ! test.skipped then
1024+ if shouldFail && ! test.didFail then
1025+ fail( s " Neg test shouldn't have failed, but did. Reasons: \n ${ reasonsForFailure(test) } " )
1026+ else if ! shouldFail && test.didFail then
1027+ fail(" Neg test should have failed, but did not" )
1028+ end if
10061029
10071030 this
1008- }
1031+ end checkExpectedErrors
10091032
10101033 /** Creates a "fuzzy" test run, which makes sure that each test compiles (or not) without crashing */
10111034 def checkNoCrash ()(implicit summaryReport : SummaryReporting ): this .type = {
@@ -1030,12 +1053,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
10301053
10311054 cleanup()
10321055
1033- if ( ! shouldFail && test.didFail) {
1034- fail( s " Run test failed, but should not, reasons: \n ${ reasonsForFailure( test) } " )
1035- }
1036- else if ( shouldFail && ! test.didFail) {
1037- fail(" Run test should have failed, but did not" )
1038- }
1056+ if ! test.skipped then
1057+ if ! shouldFail && test.didFail then
1058+ fail( s " Run test failed, but should not, reasons: \n ${ reasonsForFailure(test) } " )
1059+ else if shouldFail && ! test.didFail then
1060+ fail(" Run test should have failed, but did not" )
1061+ end if
10391062
10401063 this
10411064 }
@@ -1160,35 +1183,32 @@ trait ParallelTesting extends RunnerOrchestration { self =>
11601183 }
11611184 }
11621185
1163- object CompilationTest {
1186+ object CompilationTest :
11641187
11651188 /** Compose test targets from `tests`
1166- *
1167- * It does this, only if the two tests are compatible. Otherwise it throws
1168- * an `IllegalArgumentException`.
1169- *
1170- * Grouping tests together like this allows us to take advantage of the
1171- * concurrency offered by this test suite as each call to an executing
1172- * method (`pos()` / `checkExpectedErrors()`/ `run()`) will spin up a thread pool with the
1173- * maximum allowed level of concurrency. Doing this for only a few targets
1174- * does not yield any real benefit over sequential compilation.
1175- *
1176- * As such, each `CompilationTest` should contain as many targets as
1177- * possible.
1178- */
1179- def aggregateTests (tests : CompilationTest * ): CompilationTest = {
1189+ *
1190+ * It does this, only if all the tests are mutally compatible.
1191+ * Otherwise it throws an `IllegalArgumentException`.
1192+ *
1193+ * Grouping tests together like this allows us to take advantage of the
1194+ * concurrency offered by this test suite, as each call to an executing
1195+ * method (`pos()` / `checkExpectedErrors()`/ `run()`) will spin up a thread pool with the
1196+ * maximum allowed level of concurrency. Doing this for only a few targets
1197+ * does not yield any real benefit over sequential compilation.
1198+ *
1199+ * As such, each `CompilationTest` should contain as many targets as
1200+ * possible.
1201+ */
1202+ def aggregateTests (tests : CompilationTest * ): CompilationTest =
11801203 assert(tests.nonEmpty)
1181- def aggregate (test1 : CompilationTest , test2 : CompilationTest ) = {
1204+ def aggregate (test1 : CompilationTest , test2 : CompilationTest ) =
11821205 require(test1.times == test2.times, " can't combine tests that are meant to be benchmark compiled" )
11831206 require(test1.shouldDelete == test2.shouldDelete, " can't combine tests that differ on deleting output" )
11841207 require(test1.shouldFail == test2.shouldFail, " can't combine tests that have different expectations on outcome" )
11851208 require(test1.shouldSuppressOutput == test2.shouldSuppressOutput, " can't combine tests that both suppress and don't suppress output" )
1186- new CompilationTest (test1.targets ++ test2.targets, test1.times, test1.shouldDelete, test1.threadLimit, test1.shouldFail, test1.shouldSuppressOutput)
1187- }
1209+ test1.copy(test1.targets ++ test2.targets) // what if thread limit differs? currently threads are limited on aggregate only
11881210 tests.reduce(aggregate)
1189- }
1190-
1191- }
1211+ end CompilationTest
11921212
11931213 /** Create out directory for directory `d` */
11941214 def createOutputDirsForDir (d : JFile , sourceDir : JFile , outDir : String ): JFile = {
0 commit comments