-
Notifications
You must be signed in to change notification settings - Fork 117
[Experimental] Capturing values in exit tests #1040
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
Conversation
@swift-ci test |
c2a2534
to
74101e0
Compare
@swift-ci test |
ec3ff3d
to
514ed01
Compare
@swift-ci test |
1 similar comment
@swift-ci test |
9f06c93
to
6db82cf
Compare
This PR implements an experimental form of state capture in exit tests. If you specify a capture list on the test's body closure and explicitly write the type of each captured value, _and_ each value conforms to `Sendable`, `Codable`, and (implicitly) `Copyable`, we'll encode them and send them "over the wire" to the child process: ```swift let a = Int.random(in: 100 ..< 200) await #expect(exitsWith: .failure) { [a = a as Int] in assert(a > 500) } ``` This PR is incomplete. Among other details: - [] Need to properly transmit the data, not stuff it in an environment variable - [] Need to capture source location information correctly for error handling during value decoding - [] Need to implement diagnostics correctly We are ultimately constrained by the language here as we don't have real type information for the captured values, nor can we infer captures by inspecting the syntax of the exit test body (hence the need for an explicit capture list with types.) If we had something like `decltype()` we could apply during macro expansion, you wouldn't need to write `x = x as T` and could just write `x`.
6db82cf
to
6f87c49
Compare
@swift-ci test |
…uplicate Package.swift file
@swift-ci test |
@swift-ci test |
@swift-ci test |
@swift-ci test |
@swift-ci test |
childEnvironment["SWT_EXPERIMENTAL_BACKCHANNEL"] = backChannelEnvironmentVariable | ||
} | ||
if let capturedValuesEnvironmentVariable = _makeEnvironmentVariable(for: capturedValuesReadEnd) { | ||
childEnvironment["SWT_EXPERIMENTAL_CAPTURED_VALUES"] = capturedValuesEnvironmentVariable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd find it nice if the two env vars used a similar naming convention as each other
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you mean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, sorry for not elaborating…
My understanding of these two env vars is that they essentially contain a file handle to a pipe, and there's now two such pipes: one allowing communication from the parent to exit test child, and one allowing communication from the exit test child to the parent.
My suggestion was to choose names for these two env vars that more closely resemble each other, reflecting that they are "opposites", and convey the direction of communication (since they are each one-way). For example, you might choose:
SWT_EXPERIMENTAL_PARENT_TO_EXIT_TEST_FILE_HANDLE
, andSWT_EXPERIMENTAL_EXIT_TEST_TO_PARENT_FILE_HANDLE
You can tweak the wording of course, but I like that this example has symmetry between the names, you can tell at a glance which one is which direction, and they are more future-proof in the sense that each pipe could evolve to include more kinds of data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the moment, their names represent what they are and what they do. In the future, if either/both become host to more functionality, we can rename them. There's no ABI stability concern here as both endpoints are the same version of Swift Testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood that we're free to evolve them at any time and that's great. Still, I find them more self-describing if they conveyed their direction in the names. For example I don't know whether the "back channel" is going from parent to exit test or vice-versa without looking it up. Both pipes could be considered "back channels".
Can we incorporate this feedback if/when we elevate the feature to public, since that will involve removing "experimental" from the names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's save this discussion for a separate PR.
Sources/TestingMacros/Support/Additions/MacroExpansionContextAdditions.swift
Outdated
Show resolved
Hide resolved
… argument if it's not used
@swift-ci test |
@swift-ci test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be helpful to rename the env vars as I suggested in a comment still, mainly to make their roles more self-describing. On the whole, this looks great though!
@swift-ci test |
This PR implements an experimental form of state capture in exit tests. If you specify a capture list on the test's body closure and explicitly write the type of each captured value, and each value conforms to
Sendable
,Codable
, and (implicitly)Copyable
, we'll encode them and send them "over the wire" to the child process:This PR is incomplete. Among other details:
ExitTest.CapturedValue
and__Expression.Value
have any synergy. (They do, but it's beyond the scope of this initial/experimental PR.)We are ultimately constrained by the language here as we don't have real type information for the captured values, nor can we infer captures by inspecting the syntax of the exit test body (hence the need for an explicit capture list with types.) If we had something like
decltype()
we could apply during macro expansion, you wouldn't need to writex = x as T
and could just writex
. The macro would usedecltype()
to produce a thunk function of the form:Checklist: