diff --git a/build.sbt b/build.sbt index 7633fd8bb..6c52aa0f8 100644 --- a/build.sbt +++ b/build.sbt @@ -782,6 +782,7 @@ lazy val mainProj = (project in file("main")) exclude[MissingClassProblem]("sbt.Resolvers$DistributedVCS"), exclude[DirectMissingMethodProblem]("sbt.internal.ClassStamper.stampVf"), exclude[DirectMissingMethodProblem]("sbt.internal.CompileInputs2.*"), + exclude[DirectMissingMethodProblem]("sbt.internal.IncrementalTest.cacheInput"), ), ) .dependsOn(lmCore, lmCoursierShadedPublishing) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 8cca4c6bb..51cdffe8e 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1440,8 +1440,23 @@ object Defaults extends BuildCommon with DefExtra { val st = state.value given display: Show[ScopedKey[?]] = Project.showContextKey(st) val modifiedOpts = - Tests.ExplicitlyRequestedNames(selected) +: Tests.Filters(filter(selected)) +: + Tests.ExplicitlyRequestedNames(selected) +: + Tests.Filters( + filter( + selected ++ (if frameworkOptions.nonEmpty then Seq("--") ++ frameworkOptions else Nil) + ) + ) +: Tests.Argument(frameworkOptions*) +: config.options + if frameworkOptions.nonEmpty then + modifiedOpts.foreach: opt => + opt match + case Tests.Listeners(listeners) => + listeners.toList.foreach: l => + l match + case r: TestStatusReporter => + r.setArguments(frameworkOptions) + case _ => () + case _ => () val newConfig = config.copy(options = modifiedOpts) val output = allTestGroupsTask( s, diff --git a/main/src/main/scala/sbt/internal/IncrementalTest.scala b/main/src/main/scala/sbt/internal/IncrementalTest.scala index b3af1df35..18b8c36eb 100644 --- a/main/src/main/scala/sbt/internal/IncrementalTest.scala +++ b/main/src/main/scala/sbt/internal/IncrementalTest.scala @@ -32,15 +32,22 @@ object IncrementalTest: val cp = (Keys.test / fullClasspath).value val digests = (Keys.definedTestDigests).value val config = Def.cacheConfiguration.value - def hasCachedSuccess(ts: Digest): Boolean = - val input = cacheInput(ts) + def hasCachedSuccess(ts: Digest, options: Seq[String]): Boolean = + val input = cacheInput(ts, options) ActionCache.exists(input._1, input._2, input._3, config) - def hasSucceeded(className: String): Boolean = digests.get(className) match - case None => false - case Some(ts) => hasCachedSuccess(ts) + def hasSucceeded(className: String, options: Seq[String]): Boolean = + digests.get(className) match + case None => false + case Some(ts) => hasCachedSuccess(ts, options) args => - for filter <- selectedFilter(args) - yield (test: String) => filter(test) && !hasSucceeded(test) + val (pattern, options) = + args.indexOf("--") match + case idx if idx >= 0 => + val (s1, s2) = args.splitAt(idx) + (s1, s2.drop(1)) + case _ => (args, Nil) + for filter <- selectedFilter(pattern) + yield (test: String) => filter(test) && !hasSucceeded(test, options) } // cache the test digests against the fullClasspath. @@ -84,17 +91,23 @@ object IncrementalTest: case _ => includeFilters.map(f => (s: String) => (f.accept(s) && !matches(excludeFilters, s))) - private[sbt] def cacheInput(value: Digest): (Unit, Digest, Digest) = - ((), value, Digest.zero) + private[sbt] def cacheInput( + value: Digest, + frameworkOptions: Seq[String] + ): (Seq[String], Digest, Digest) = (frameworkOptions, value, Digest.zero) + end IncrementalTest -private[sbt] class TestStatusReporter( +private[sbt] case class TestStatusReporter( digests: Map[String, Digest], cacheConfiguration: BuildWideCacheConfiguration, ) extends TestsListener: // int value to represent success private final val successfulTest = 0 - + private var _args: Seq[String] = Nil + def getArgs: Seq[String] = _args + def setArguments(args: Seq[String]): Unit = + _args = args def doInit(): Unit = () def startGroup(name: String): Unit = () def testEvent(event: TestEvent): Unit = () @@ -109,7 +122,7 @@ private[sbt] class TestStatusReporter( digests.get(name) match case Some(ts) => // treat each test suite as a successful action that returns 0 - val input = IncrementalTest.cacheInput(ts) + val input = IncrementalTest.cacheInput(ts, getArgs) ActionCache.cache( key = input._1, codeContentHash = input._2, diff --git a/sbt-app/src/sbt-test/tests/fork-uncaught2/build.sbt b/sbt-app/src/sbt-test/tests/fork-uncaught2/build.sbt index 562ee26dd..944d95537 100644 --- a/sbt-app/src/sbt-test/tests/fork-uncaught2/build.sbt +++ b/sbt-app/src/sbt-test/tests/fork-uncaught2/build.sbt @@ -7,11 +7,13 @@ testFrameworks := new TestFramework("build.MyFramework") :: Nil fork := true Test / definedTests += new sbt.TestDefinition( - "my", - // marker fingerprint since there are no test classes - // to be discovered by sbt: - new sbt.testing.AnnotatedFingerprint { - def isModule = true - def annotationName = "my" - }, true, Array() - ) + "my", + // marker fingerprint since there are no test classes + // to be discovered by sbt: + new sbt.testing.AnnotatedFingerprint { + def isModule = true + def annotationName = "my" + }, + true, + Array() +) diff --git a/sbt-app/src/sbt-test/tests/fork-uncaught2/src/test/scala/build/MyFramework.scala b/sbt-app/src/sbt-test/tests/fork-uncaught2/src/test/scala/build/MyFramework.scala index 058630a68..4a966bdea 100644 --- a/sbt-app/src/sbt-test/tests/fork-uncaught2/src/test/scala/build/MyFramework.scala +++ b/sbt-app/src/sbt-test/tests/fork-uncaught2/src/test/scala/build/MyFramework.scala @@ -9,11 +9,14 @@ class MyFramework extends sbt.testing.Framework { new MyRunner(args, remoteArgs, testClassLoader) } -class MyRunner(val args: Array[String], val remoteArgs: Array[String], - val testClassLoader: ClassLoader) extends sbt.testing.Runner { +class MyRunner( + val args: Array[String], + val remoteArgs: Array[String], + val testClassLoader: ClassLoader) extends sbt.testing.Runner { def tasks(taskDefs: Array[TaskDef]): Array[Task] = - if (args contains "task-boom") taskDefs map BoomTask else throw new Throwable() + if (args.contains("task-boom")) taskDefs.map(BoomTask) + else throw new Throwable() def done(): String = "" private case class BoomTask(taskDef: TaskDef) extends Task { @@ -21,4 +24,3 @@ class MyRunner(val args: Array[String], val remoteArgs: Array[String], def execute(handler: EventHandler, loggers: Array[Logger]) = throw new Throwable() } } - diff --git a/sbt-app/src/sbt-test/tests/fork-uncaught2/test b/sbt-app/src/sbt-test/tests/fork-uncaught2/test index 38c301498..70a09384b 100644 --- a/sbt-app/src/sbt-test/tests/fork-uncaught2/test +++ b/sbt-app/src/sbt-test/tests/fork-uncaught2/test @@ -1,2 +1,2 @@ -> test --> testOnly -- task-boom +> testOnly -- task-boom diff --git a/sbt-app/src/sbt-test/tests/test-option/build.sbt b/sbt-app/src/sbt-test/tests/test-option/build.sbt new file mode 100644 index 000000000..c23671f79 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/test-option/build.sbt @@ -0,0 +1,2 @@ +scalaVersion := "3.8.3" +libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test diff --git a/sbt-app/src/sbt-test/tests/test-option/src/test/scala/example/ATest.scala b/sbt-app/src/sbt-test/tests/test-option/src/test/scala/example/ATest.scala new file mode 100644 index 000000000..76e477836 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/test-option/src/test/scala/example/ATest.scala @@ -0,0 +1,5 @@ +package example + +class ATest extends munit.FunSuite: + test("sum"): + assertEquals(3, 1 + 1) diff --git a/sbt-app/src/sbt-test/tests/test-option/test b/sbt-app/src/sbt-test/tests/test-option/test new file mode 100644 index 000000000..26fcdfa27 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/test-option/test @@ -0,0 +1,3 @@ +-> test +> test -- foo +-> test diff --git a/worker/src/main/java/sbt/internal/worker1/ForkTestMain.java b/worker/src/main/java/sbt/internal/worker1/ForkTestMain.java index 8c12ef436..0938be2eb 100644 --- a/worker/src/main/java/sbt/internal/worker1/ForkTestMain.java +++ b/worker/src/main/java/sbt/internal/worker1/ForkTestMain.java @@ -259,6 +259,10 @@ public class ForkTestMain { params, this.id); this.originalOut.println(notification); this.originalOut.flush(); + try { + Thread.sleep(10); + } catch (final Exception e) { + } } private void log(final String message, final ForkTags level) {