-
Notifications
You must be signed in to change notification settings - Fork 155
TaskLocal test trait #1764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
TaskLocal test trait #1764
Changes from 6 commits
e037bb3
57b7d2b
28ee525
80c5ea8
702dffd
04abb70
ae13996
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,57 @@ | ||||||
| // | ||||||
| // This source file is part of the Swift.org open source project | ||||||
| // | ||||||
| // Copyright (c) 2026 Apple Inc. and the Swift project authors | ||||||
| // Licensed under Apache License v2.0 with Runtime Library Exception | ||||||
| // | ||||||
| // See https://swift.org/LICENSE.txt for license information | ||||||
| // See https://swift.org/CONTRIBUTORS.txt for Swift project authors | ||||||
| // | ||||||
|
|
||||||
| extension Trait { | ||||||
| /// Constructs a trait that binds a task local value for the duration of a test | ||||||
| /// or suite. | ||||||
| /// | ||||||
| /// - Parameters: | ||||||
| /// - taskLocal: The task local to bind the value to. | ||||||
| /// - value: The value to set. | ||||||
| /// | ||||||
| /// ```swift | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An example like this is probably not necessary, but if you want to include it then it needs to go after a paragraph or two describing the trait in more detail. It won't render well in DocC immediately after the brief. |
||||||
| /// @Suite(.taskLocal($myValue, 42)) | ||||||
| /// struct MyTests { | ||||||
| /// // ... | ||||||
| /// } | ||||||
| /// ``` | ||||||
| /// | ||||||
| /// - Note: You must define the task local outside the test target where the trait is used. | ||||||
| public static func taskLocal<Value: Sendable>( | ||||||
| _ taskLocal: TaskLocal<Value>, | ||||||
| _ value: Value | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recommend making the
Suggested change
A couple reasons:
Making this a lazily-evaluated stored property on If you take this change, I recommend documenting those semantics in the DocC for the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I've made the change for
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The aspect I would encourage you to document is the lifetime guarantees that lazy evaluation via /// - Parameters:
/// ...
/// - value: The value to bind to `taskLocal`.
///
/// This value will only be evaluated if the test this
// trait is applied to runs, and it will be unbound from
/// the task local and released once the trait is finished
/// providing scope for the test. |
||||||
| ) -> Self | ||||||
| where Self == TaskLocalTrait<Value> { | ||||||
|
grynspan marked this conversation as resolved.
|
||||||
| TaskLocalTrait(taskLocal: taskLocal, value: value) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| /// A type that that binds a task local value for the duration of a test or suite. | ||||||
| /// | ||||||
| /// To add this trait to a test, use ``Trait/taskLocal(_:_:)``. | ||||||
| public struct TaskLocalTrait<Value: Sendable>: SuiteTrait, TestTrait, TestScoping { | ||||||
| /// This trait's task local. | ||||||
| fileprivate var taskLocal: TaskLocal<Value> | ||||||
|
|
||||||
| /// This trait's value. | ||||||
| fileprivate var value: Value | ||||||
|
|
||||||
| public func provideScope( | ||||||
| for test: Test, | ||||||
| testCase: Test.Case?, | ||||||
| performing function: @concurrent () async throws -> Void | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't have |
||||||
| ) async throws { | ||||||
| try await taskLocal.withValue(value, operation: function) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #if DEBUG | ||||||
| @TaskLocal var dummyLocal = false | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you include a DocC comment about why this is here? (It's a convenient place to put it for use in an accompanying test, because it needs to be in a separate module) Also, style nit: we generally outdent code within top-level |
||||||
| #endif | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // | ||
| // This source file is part of the Swift.org open source project | ||
| // | ||
| // Copyright (c) 2026 Apple Inc. and the Swift project authors | ||
| // Licensed under Apache License v2.0 with Runtime Library Exception | ||
| // | ||
| // See https://swift.org/LICENSE.txt for license information | ||
| // See https://swift.org/CONTRIBUTORS.txt for Swift project authors | ||
| // | ||
|
|
||
| @testable @_spi(Experimental) @_spi(ForToolsIntegrationOnly) import Testing | ||
|
|
||
| @Suite("Task Local Tests", .tags(.traitRelated)) | ||
| struct TaskLocalTests { | ||
| @Test( | ||
| ".taskLocal trait", | ||
| .taskLocal($dummyLocal, true) | ||
| ) | ||
| func taskLocalBinding() throws { | ||
| #expect(dummyLocal == true) | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.