Merge pull request #8181 from eed3si9n/wip/test-type

[2.x] refactor: Change the test type
This commit is contained in:
eugene yokota 2025-08-02 18:26:58 -04:00 committed by GitHub
commit 7550356ef6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 41 additions and 27 deletions

View File

@ -106,10 +106,9 @@ object TestResultLogger {
else
run(printFailures)
results.overall match {
results.overall match
case TestResult.Error | TestResult.Failed => throw new TestsFailedException
case TestResult.Passed =>
}
case TestResult.Empty | TestResult.Passed => ()
}
}
@ -164,11 +163,11 @@ object TestResultLogger {
val extra = otherCounts.withFilter(_._2 > 0).map { (label, count) => s", $label $count" }
val postfix = base + extra.mkString
results.overall match {
results.overall match
case TestResult.Empty => ()
case TestResult.Error => log.error("Error: " + postfix)
case TestResult.Passed => log.info("Passed: " + postfix)
case TestResult.Failed => log.error("Failed: " + postfix)
}
})
val printFailures = TestResultLogger((log, results, _) => {

View File

@ -50,7 +50,7 @@ object Tests {
* @param events The result of each test group (suite) executed during this test run.
* @param summaries Explicit summaries directly provided by test frameworks. This may be empty, in which case a default summary will be generated.
*/
final case class Output(
private[sbt] final case class Output(
overall: TestResult,
events: Map[String, SuiteResult],
summaries: Iterable[Summary]
@ -458,11 +458,10 @@ object Tests {
Output(overall(results.map(_._2.result)), results.toMap, Iterable.empty)
private def severity(r: TestResult): Int =
r match {
case TestResult.Passed => 0
case TestResult.Failed => 1
case TestResult.Error => 2
}
r match
case TestResult.Passed | TestResult.Empty => 0
case TestResult.Failed => 1
case TestResult.Error => 2
def foldTasks(results: Seq[Task[Output]], parallel: Boolean): Task[Output] =
if (results.isEmpty) {

View File

@ -19,7 +19,7 @@ import sbt.Scope.RefThenConfig.{ project, config }
*
* @example
* {{{
* Test / test := ()
* Test / test := TestResult.Empty
* console.key / scalacOptions += "-deprecation"
* Compile / console / scalacOptions += "-Ywarn-numeric-widen"
* }}}

View File

@ -76,6 +76,7 @@ import sbt.nio.Keys.*
import sbt.nio.file.syntax.*
import sbt.nio.file.{ FileTreeView, Glob, RecursiveGlob }
import sbt.nio.Watch
import sbt.protocol.testing.TestResult
import sbt.std.TaskExtra.*
import sbt.testing.{ AnnotatedFingerprint, Framework, Runner, SubclassFingerprint }
import sbt.util.CacheImplicits.given
@ -1155,7 +1156,10 @@ object Defaults extends BuildCommon {
testFull := Def.uncached {
val trl = (Test / testFull / testResultLogger).value
val taskName = Project.showContextKey(state.value).show(resolvedScoped.value)
try trl.run(streams.value.log, executeTests.value, taskName)
try
val output = executeTests.value
trl.run(streams.value.log, output, taskName)
output.overall
finally close(testLoader.value)
},
testOnly := {
@ -1287,10 +1291,10 @@ object Defaults extends BuildCommon {
}
@nowarn
def inputTests(key: InputKey[?]): Initialize[InputTask[Unit]] =
def inputTests(key: InputKey[?]): Initialize[InputTask[TestResult]] =
inputTests0.mapReferenced(Def.mapScope((s) => s.rescope(key.key)))
private lazy val inputTests0: Initialize[InputTask[Unit]] = {
private lazy val inputTests0: Initialize[InputTask[TestResult]] = {
val parser = loadForParser(definedTestNames)((s, i) => testOnlyParser(s, i getOrElse Nil))
ParserGen(parser).flatMapTask { (selected, frameworkOptions) =>
val s = streams.value
@ -1318,7 +1322,9 @@ object Defaults extends BuildCommon {
val trl = testResultLogger.value
(Def
.value[Task[Tests.Output]] { output })
.map { out => trl.run(s.log, out, taskName) }
.map: out =>
trl.run(s.log, out, taskName)
out.overall
}
}

View File

@ -35,6 +35,7 @@ import sbt.librarymanagement.LibraryManagementCodec.*
import sbt.librarymanagement.*
import sbt.librarymanagement.ivy.{ Credentials, IvyConfiguration, IvyPaths, UpdateOptions }
import sbt.nio.file.Glob
import sbt.protocol.testing.TestResult
import sbt.testing.Framework
import sbt.util.{ cacheLevel, ActionCacheStore, Digest, Level, Logger, LoggerContext }
import xsbti.{ HashedVirtualFileRef, VirtualFile, VirtualFileRef }
@ -357,10 +358,10 @@ object Keys {
val definedTestNames = taskKey[Seq[String]]("Provides the set of defined test names.").withRank(BMinusTask)
val definedTestDigests = taskKey[Map[String, Digest]]("Provides a unique digest of defined tests.").withRank(DTask)
val executeTests = taskKey[Tests.Output]("Executes all tests, producing a report.").withRank(CTask)
val test = inputKey[Unit]("Executes the tests that either failed before, were not run or whose transitive dependencies changed, among those provided as arguments.").withRank(ATask)
val testFull = taskKey[Unit]("Executes all tests.").withRank(APlusTask)
val testOnly = inputKey[Unit]("Executes the tests provided as arguments or all tests if no arguments are provided.").withRank(ATask)
val testQuick = inputKey[Unit]("Alias for test.").withRank(CTask)
val test = inputKey[TestResult]("Executes the tests that either failed before, were not run or whose transitive dependencies changed, among those provided as arguments.").withRank(ATask)
val testFull = taskKey[TestResult]("Executes all tests.").withRank(APlusTask)
val testOnly = inputKey[TestResult]("Executes the tests provided as arguments or all tests if no arguments are provided.").withRank(ATask)
val testQuick = inputKey[TestResult]("Alias for test.").withRank(CTask)
@cacheLevel(include = Array.empty)
val testOptions = taskKey[Seq[TestOption]]("Options for running tests.").withRank(BPlusTask)
private[sbt] val testOptionDigests = taskKey[Seq[Digest]]("Digest for testOptions").withRank(DTask)

View File

@ -938,7 +938,9 @@ object BuildServerProtocol {
item.classes.toList match {
case Nil => Def.task(())
case classes =>
(scope / testOnly).toTask(" " + classes.mkString(" "))
(scope / testOnly)
.toTask(" " + classes.mkString(" "))
.map(r => ())
}
}
testTasks.joinWith(ts => TaskExtra.joinTasks(ts).join).result
@ -952,7 +954,7 @@ object BuildServerProtocol {
case None =>
// run allTests in testParams.targets
val filter = ScopeFilter.in(testParams.targets.map(workspace.scopes))
test.toTask("").all(filter).result
test.toTask("").map(r => ()).all(filter).result
}
Def.task {

View File

@ -26,7 +26,7 @@ lazy val foo = project
// This tests that +testOnly will respect bar's crossScalaVersions and not switch
val x = (LocalProject("bar") / scalaVersion).value
assert(x == scala212, s"$x == $scala212")
val _ = (Test / testOnly).evaluated
(Test / testOnly).evaluated
},
compile2 := Def.uncached {
// This tests that +build will ignore bar's crossScalaVersions and use root's like sbt 0.13

View File

@ -5,7 +5,7 @@ val copyTestResources = inputKey[Unit]("Copy the native libraries to the base di
val appendToLibraryPath = taskKey[Unit]("Append the base directory to the java.library.path system property")
val dropLibraryPath = taskKey[Unit]("Drop the last path from the java.library.path system property")
val wrappedRun = taskKey[Unit]("Run with modified java.library.path")
val wrappedTest = taskKey[Unit]("Test with modified java.library.path")
val wrappedTest = taskKey[TestResult]("Test with modified java.library.path")
def wrap[A1](task: InputKey[A1]): Def.Initialize[Task[Unit]] =
Def.sequential(appendToLibraryPath, task.toTask(""), dropLibraryPath)
@ -39,5 +39,8 @@ val root = (project in file(".")).settings(
()
},
wrappedRun := wrap(Runtime / run).value,
wrappedTest := wrap(Test / testOnly).value
wrappedTest := Def.uncached {
wrap(Test / testOnly).value
TestResult.Passed
}
)

View File

@ -9,6 +9,7 @@ sealed abstract class TestResult extends Serializable
object TestResult {
case object Empty extends TestResult
case object Passed extends TestResult
case object Failed extends TestResult
case object Error extends TestResult

View File

@ -11,6 +11,7 @@ implicit lazy val TestResultFormat: JsonFormat[sbt.protocol.testing.TestResult]
__jsOpt match {
case Some(__js) =>
unbuilder.readString(__js) match {
case "Empty" => sbt.protocol.testing.TestResult.Empty
case "Passed" => sbt.protocol.testing.TestResult.Passed
case "Failed" => sbt.protocol.testing.TestResult.Failed
case "Error" => sbt.protocol.testing.TestResult.Error
@ -21,6 +22,7 @@ implicit lazy val TestResultFormat: JsonFormat[sbt.protocol.testing.TestResult]
}
override def write[J](obj: sbt.protocol.testing.TestResult, builder: Builder[J]): Unit = {
val str = obj match {
case sbt.protocol.testing.TestResult.Empty => "Empty"
case sbt.protocol.testing.TestResult.Passed => "Passed"
case sbt.protocol.testing.TestResult.Failed => "Failed"
case sbt.protocol.testing.TestResult.Error => "Error"

View File

@ -59,6 +59,7 @@ type TestItemDetail {
## Testing result
enum TestResult {
Empty
Passed
Failed
Error

View File

@ -45,7 +45,7 @@ trait TestsListener extends TestReportListener {
/**
* Provides the overall `result` of a group of tests (a suite) and test counts for each result type.
*/
final class SuiteResult(
private[sbt] final class SuiteResult(
val result: TestResult,
val passedCount: Int,
val failureCount: Int,
@ -99,7 +99,7 @@ final class SuiteResult(
}
}
object SuiteResult {
private[sbt] object SuiteResult {
/**
* Computes the overall result and counts for a suite with individual test results in `events`.