testing: Update to Latest ABI Protocol for Test Discovery

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-05-22 00:04:11 -04:00
parent 017d5670c0
commit 16a798cc39
2 changed files with 90 additions and 29 deletions
+1 -1
View File
@@ -1 +1 @@
6.2.4 main-snapshot
+89 -28
View File
@@ -291,6 +291,77 @@ public struct MustOr: CodeItemMacro {
public struct CliTestDeclarationMacro: PeerMacro, Sendable { public struct CliTestDeclarationMacro: PeerMacro, Sendable {
// NOTE: Taken from swift-testing.
/// Get an expression initializing an instance of ``SourceLocation`` from an
/// arbitrary syntax node.
///
/// - Parameters:
/// - node: The syntax node for which an instance of ``SourceLocation`` is
/// needed.
/// - context: The macro context in which the expression is being parsed.
///
/// - Returns: An expression value that initializes an instance of
/// ``SourceLocation`` for `node`.
static func createSourceLocationExpr(
of node: some SyntaxProtocol, context: some MacroExpansionContext
) -> ExprSyntax {
if node.isProtocol((any FreestandingMacroExpansionSyntax).self) {
// Freestanding macro expressions can just use __here()
// directly and do not need to talk to the macro context to get source
// location info.
return "Testing.SourceLocation.__here()"
}
// Get the equivalent source location in both `#fileID` and `#filePath` modes.
guard let fileIDSourceLoc: AbstractSourceLocation = context.location(of: node),
let filePathSourceLoc: AbstractSourceLocation = context.location(
of: node, at: .afterLeadingTrivia, filePathMode: .filePath)
else {
return "Testing.SourceLocation.__here()"
}
return
"Testing.SourceLocation(__uncheckedFileID: \(fileIDSourceLoc.file), filePath: \(filePathSourceLoc.file), line: \(fileIDSourceLoc.line), column: \(fileIDSourceLoc.column))"
}
/// Get an expression initializing an instance of `__SourceBounds` from two
/// arbitrary syntax nodesvalues.
///
/// - Parameters:
/// - lowerBoundNode: The syntax node representing the lower bound. The start
/// of this node (after leading trivia) is used.
/// - upperBoundNode: The syntax node representing the upper bound. The end of
/// this node (before trailing trivia) is used.
/// - context: The macro context in which the expression is being parsed.
///
/// - Returns: An expression value that initializes an instance of
/// `__SourceBounds`.
///
/// The resulting source bounds instance represents (approximately):
///
/// ```swift
/// lowerBoundNode.positionAfterSkippingLeadingTrivia ..< upperBoundNode.endPositionBeforeTrailingTrivia
/// ```
static func createSourceBoundsExpr(
from lowerBoundNode: some SyntaxProtocol, to upperBoundNode: some SyntaxProtocol,
in context: some MacroExpansionContext
) -> ExprSyntax {
let lowerBoundExpr = createSourceLocationExpr(of: lowerBoundNode, context: context)
let upperBoundExpr: ExprSyntax =
if let upperBoundSourceLoc = context.location(
of: upperBoundNode, at: .beforeTrailingTrivia, filePathMode: .fileID)
{
"(\(upperBoundSourceLoc.line), \(upperBoundSourceLoc.column))"
} else {
"(.max, .max)"
}
return
"Testing.__SourceBounds(__uncheckedLowerBound: \(lowerBoundExpr), upperBound: \(upperBoundExpr))"
}
// NOTE: End of what was taken from swift-testing
private static func doc_shrink(_ from: String) -> String { private static func doc_shrink(_ from: String) -> String {
return from.replacing(Regex(#/^.*\/\/\/[\s]+/#), with: "") return from.replacing(Regex(#/^.*\/\/\/[\s]+/#), with: "")
} }
@@ -307,8 +378,7 @@ public struct CliTestDeclarationMacro: PeerMacro, Sendable {
doc_shrink("\($0)") doc_shrink("\($0)")
}).joined(separator: "\\n") }).joined(separator: "\\n")
let cli_test_driver_thunk_name = context.makeUniqueName( let cli_test_driver_thunk_name = context.makeUniqueName("_thunk_")
declaration.cast(FunctionDeclSyntax.self).name.text + "_thunk_")
let (expected_decl, expected_label) = let (expected_decl, expected_label) =
if cli_test_expected_output.isEmpty { if cli_test_expected_output.isEmpty {
@@ -327,53 +397,44 @@ public struct CliTestDeclarationMacro: PeerMacro, Sendable {
} }
""" """
let cli_test_driver_generator_name = context.makeUniqueName(test_name.text + "_generator_") let source_bounds = createSourceBoundsExpr(from: node, to: declaration, in: context)
let cli_test_driver_generator_name = context.makeUniqueName("_generator_")
let cli_test_driver_generator: DeclSyntax = """ let cli_test_driver_generator: DeclSyntax = """
@Sendable private func \(cli_test_driver_generator_name)() async -> Testing.Test { @Sendable private func \(cli_test_driver_generator_name)() async -> Testing.Test {
return .__function( return .__function(
named: "\(test_name)", named: "\(test_name)",
in: nil, in: nil as Swift.Never.Type?,
xcTestCompatibleSelector: Testing.__xcTestCompatibleSelector("\(test_name)"), xcTestCompatibleSelector: Testing.__xcTestCompatibleSelector("\(test_name)"),
traits: [], traits: [],
sourceLocation: Testing.SourceLocation.__here(), sourceBounds: \(source_bounds),
parameters: [], parameters: [],
testFunction: \(cli_test_driver_thunk_name) testFunction: \(cli_test_driver_thunk_name)
) )
} }
""" """
let cli_test_driver_accessor_name = context.makeUniqueName(test_name.text + "_accessor_") #if os(macOS)
let cli_test_driver_accessor: DeclSyntax = """ let section = "__DATA_CONST,__swift5_tests"
private nonisolated let \(cli_test_driver_accessor_name): Accessor = { outValue, type, _, _ in #else
let section = "swift5_tests"
#endif
Testing.Test.__store(\(cli_test_driver_generator_name), into: outValue, asTypeAt: type) let cli_test_driver_content_record_name = context.makeUniqueName("testContentRecord")
}
"""
let cli_test_driver_content_record_name = context.makeUniqueName(
declaration.cast(FunctionDeclSyntax.self).name.text + "_cr_")
let cli_test_driver_cr: DeclSyntax = """ let cli_test_driver_cr: DeclSyntax = """
private nonisolated let \(cli_test_driver_content_record_name): TestContentRecord = ( @section("\(raw: section)")
@used
private nonisolated let \(cli_test_driver_content_record_name): Testing.__TestContentRecord = (
0x7465_7374, /* indicate a test */ 0x7465_7374, /* indicate a test */
0, 0,
unsafe \(cli_test_driver_accessor_name), { outValue, type, _, _ in
Testing.Test.__store(\(cli_test_driver_generator_name), into: outValue, asTypeAt: type)
},
0, 0,
0 0
) )
""" """
let cli_test_driver_content_container_name = context.makeUniqueName(
test_name.text + "__🟡$_container_")
let cli_test_driver_container: DeclSyntax = """
struct \(cli_test_driver_content_container_name): Testing.__TestContentRecordContainer {
nonisolated static var __testContentRecord: TestContentRecord {
unsafe \(cli_test_driver_content_record_name)
}
}
"""
return [ return [
cli_test_driver_thunk, cli_test_driver_generator, cli_test_driver_accessor, cli_test_driver_thunk, cli_test_driver_generator, cli_test_driver_cr,
cli_test_driver_cr, cli_test_driver_container,
] ]
} }
} }