TaskLocal test trait#1764
Conversation
| /// | ||
| /// To add this trait to a test, use ``Trait/taskLocal(_:_:)``. | ||
| public struct TaskLocalTrait<Value: Sendable>: SuiteTrait, TestScoping, TestTrait { | ||
| public var isRecursive: Bool { true } |
There was a problem hiding this comment.
Because task locals are already implicitly applied recursively to subtasks, there's no need for this property's value to be true. Having it true here just causes us to call withValue repeatedly, which does not have a meaningful effect on test code.
There was a problem hiding this comment.
This is an interesting question to carefully consider, I think! I feel like it'll be common for users to have situations where it's important that the value be reevaluated and re-bound to the task local for every invocation of each test within a suite that a .taskLocal(...) trait is applied to. For example, if the value contains some state which accumulates or is modified during each test, it's very important that be reset to a fresh state for each one.
For that reason I think the safest default for isRecursive is true, as currently written. Per the semantics of Test Scoping Traits, that will mean that whenever you add one of these traits to a suite, value will be reevaluated (by calling its @autoclosure) and (re-)bound to the task local for the invocation of each test within that suite
That said, there could totally be situations when a user doesn't want this work to be redone for each invocation of each test in a suite, they only want the work to happen once per suite. If we want to support that, we could make isRecursive a parameter of the .taskLocal(...) function, with a default value of true, and let it be controlled that way. I'm not certain we need to allow that in the initial version of this API, though; I'd lean towards leaving it as a Future Direction. And either way, I think it's worth discussing this consideration in the proposal.
There was a problem hiding this comment.
We agree that isRecursive: true is the better default and have pushed those changes here b80766b. I also added a test to show the danger of not making it recursive.
|
Additional action items:
|
|
GitHub's multiple assignee feature is broken, I guess. |
|
Keep in mind async autoclosures are broken. |
| public func provideScope( | ||
| for test: Test, | ||
| testCase: Test.Case?, | ||
| performing function: @concurrent () async throws -> Void |
There was a problem hiding this comment.
We don't have @concurrent on other provideScope() implementations in the library. The other implementations do have @Sendable though; can we get away with only @Sendable ?
There was a problem hiding this comment.
I think this is @concurrent only because it was taken from a library we maintain with this tool, and that library is NonisolatedNonSendingByDefault and Swift Testing is not (I believe). Will remove and bring back @Sendable as that's the TestScoping requirement.
Adds a
.taskLocaltest trait for overriding task locals in testsMotivation:
Proposal here: swiftlang/swift-evolution#3329
Checklist: