mirror of https://github.com/sbt/sbt.git
[2.x] fix: Include test arg into hash (#9222)
**Problem** test -- foo passes on MUnit, allowing failing tests to be validated. **Solution** Include test args into the cache input.
This commit is contained in:
parent
68dde13fdc
commit
57495c28dc
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
-> test
|
||||
-> testOnly -- task-boom
|
||||
> testOnly -- task-boom
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
scalaVersion := "3.8.3"
|
||||
libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package example
|
||||
|
||||
class ATest extends munit.FunSuite:
|
||||
test("sum"):
|
||||
assertEquals(3, 1 + 1)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
-> test
|
||||
> test -- foo
|
||||
-> test
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue