-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Store test content in a custom metadata section.
This PR uses the experimental symbol linkage margers feature in the Swift compiler to emit metadata about tests (and exit tests) into a dedicated section of the test executable being built. At runtime, we discover that section and read out the tests from it. This has several benefits over our current model, which involves walking Swift's type metadata table looking for types that conform to a protocol: 1. We don't need to define that protocol as public API in Swift Testing, 1. We don't need to emit type metadata (much larger than what we really need) for every test function, 1. We don't need to duplicate a large chunk of the Swift ABI sources in order to walk the type metadata table correctly, and 1. Almost all the new code is written in Swift, whereas the code it is intended to replace could not be fully represented in Swift and needed to be written in C++. The change also opens up the possibility of supporting generic types in the future because we can emit metadata without needing to emit a nested type (which is not always valid in a generic context.) That's a "future direction" and not covered by this PR specifically. I've defined a layout for entries in the new `swift5_tests` section that should be flexible enough for us in the short-to-medium term and which lets us define additional arbitrary test content record types. The layout of this section is covered in depth in the new [TestContent.md](Documentation/ABI/TestContent.md) article. This functionality is only available if a test target enables the experimental `"SymbolLinkageMarkers"` feature. We continue to emit protocol-conforming types for now—that code will be removed if and when the experimental feature is properly supported (modulo us adopting relevant changes to the feature's API.) #735 swiftlang/swift#76698 swiftlang/swift#78411
Showing
17 changed files
with
388 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
Sources/TestingMacros/Support/Additions/IntegerLiteralExprSyntaxAdditions.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2024 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 | ||
// | ||
|
||
import SwiftSyntax | ||
|
||
extension IntegerLiteralExprSyntax { | ||
init(_ value: some BinaryInteger, radix: IntegerLiteralExprSyntax.Radix = .decimal) { | ||
let stringValue = "\(radix.literalPrefix)\(String(value, radix: radix.size))" | ||
self.init(literal: .integerLiteral(stringValue)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2024 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 | ||
// | ||
|
||
import SwiftSyntax | ||
import SwiftSyntaxMacros | ||
|
||
/// An enumeration representing the different kinds of test content known to the | ||
/// testing library. | ||
/// | ||
/// When adding cases to this enumeration, be sure to also update the | ||
/// corresponding enumeration in TestContent.md. | ||
enum TestContentKind: UInt32 { | ||
/// A test or suite declaration. | ||
case testDeclaration = 0x74657374 | ||
|
||
/// An exit test. | ||
case exitTest = 0x65786974 | ||
|
||
/// This kind value as a comment (`/* 'abcd' */`) if it looks like it might be | ||
/// a [FourCC](https://en.wikipedia.org/wiki/FourCC) value, or `nil` if not. | ||
var commentRepresentation: Trivia? { | ||
return withUnsafeBytes(of: rawValue.bigEndian) { bytes in | ||
if bytes.allSatisfy(Unicode.ASCII.isASCII) { | ||
let characters = String(decoding: bytes, as: Unicode.ASCII.self) | ||
let allAlphanumeric = characters.allSatisfy { $0.isLetter || $0.isWholeNumber } | ||
if allAlphanumeric { | ||
return .blockComment("/* '\(characters)' */") | ||
} | ||
} | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
/// Make a test content record that can be discovered at runtime by the testing | ||
/// library. | ||
/// | ||
/// - Parameters: | ||
/// - name: The name of the record declaration to use in Swift source. The | ||
/// value of this argument should be unique in the context in which the | ||
/// declaration will be emitted. | ||
/// - typeName: The name of the type enclosing the resulting declaration, or | ||
/// `nil` if it will not be emitted into a type's scope. | ||
/// - kind: The kind of test content record being emitted. | ||
/// - accessorName: The Swift name of an `@convention(c)` function to emit | ||
/// into the resulting record. | ||
/// - context: A value to emit as the `context` field of the test content | ||
/// record. | ||
/// | ||
/// - Returns: A variable declaration that, when emitted into Swift source, will | ||
/// cause the linker to emit data in a location that is discoverable at | ||
/// runtime. | ||
func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax? = nil, ofKind kind: TestContentKind, accessingWith accessorName: TokenSyntax, context: UInt32 = 0) -> DeclSyntax { | ||
let kindExpr = IntegerLiteralExprSyntax(kind.rawValue, radix: .hex) | ||
let kindComment = kind.commentRepresentation.map { .space + $0 } ?? Trivia() | ||
let contextExpr = if context == 0 { | ||
IntegerLiteralExprSyntax(0) | ||
} else { | ||
IntegerLiteralExprSyntax(context, radix: .binary) | ||
} | ||
|
||
return """ | ||
#if hasFeature(SymbolLinkageMarkers) | ||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS) | ||
@_section("__DATA_CONST,__swift5_tests") | ||
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI) | ||
@_section("swift5_tests") | ||
#elseif os(Windows) | ||
@_section(".sw5test$B") | ||
#else | ||
@__testing(warning: "Platform-specific implementation missing: test content section name unavailable") | ||
#endif | ||
@_used | ||
@available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") | ||
private \(staticKeyword(for: typeName)) let \(name): Testing.__TestContentRecord = ( | ||
\(kindExpr),\(kindComment) | ||
0, | ||
\(accessorName), | ||
\(contextExpr), | ||
0 | ||
) | ||
#endif | ||
""" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters