Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Documentation/Porting.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,10 @@ to load that information:
+ let resourceName: Str255 = switch kind {
+ case .testContent:
+ "__swift5_tests"
+#if !SWT_NO_LEGACY_TEST_DISCOVERY
+ case .typeMetadata:
+ "__swift5_types"
+#endif
+ }
+
+ let oldRefNum = CurResFile()
Expand Down Expand Up @@ -219,15 +221,19 @@ diff --git a/Sources/_TestingInternals/Discovery.cpp b/Sources/_TestingInternals
+#elif defined(macintosh)
+extern "C" const char testContentSectionBegin __asm__("...");
+extern "C" const char testContentSectionEnd __asm__("...");
+#if !defined(SWT_NO_LEGACY_TEST_DISCOVERY)
+extern "C" const char typeMetadataSectionBegin __asm__("...");
+extern "C" const char typeMetadataSectionEnd __asm__("...");
+#endif
#else
#warning Platform-specific implementation missing: Runtime test discovery unavailable (static)
static const char testContentSectionBegin = 0;
static const char& testContentSectionEnd = testContentSectionBegin;
#if !defined(SWT_NO_LEGACY_TEST_DISCOVERY)
static const char typeMetadataSectionBegin = 0;
static const char& typeMetadataSectionEnd = testContentSectionBegin;
#endif
#endif
```

These symbols must have unique addresses corresponding to the first byte of the
Expand Down
10 changes: 6 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,7 @@ let package = Package(
"_Testing_CoreGraphics",
"_Testing_Foundation",
],
swiftSettings: .packageSettings + [
// For testing test content section discovery only
.enableExperimentalFeature("SymbolLinkageMarkers"),
]
swiftSettings: .packageSettings
),

.macro(
Expand Down Expand Up @@ -205,6 +202,11 @@ extension Array where Element == PackageDescription.SwiftSetting {
.enableExperimentalFeature("AccessLevelOnImport"),
.enableUpcomingFeature("InternalImportsByDefault"),

// This setting is enabled in the package, but not in the toolchain build
// (via CMake). Enabling it is dependent on acceptance of the @section
// proposal via Swift Evolution.
.enableExperimentalFeature("SymbolLinkageMarkers"),

// When building as a package, the macro plugin always builds as an
// executable rather than a library.
.define("SWT_NO_LIBRARY_MACRO_PLUGINS"),
Expand Down
2 changes: 2 additions & 0 deletions Sources/Testing/ExitTests/ExitTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,14 @@ extension ExitTest {
}
}

#if !SWT_NO_LEGACY_TEST_DISCOVERY
// Call the legacy lookup function that discovers tests embedded in types.
for record in Self.allTypeMetadataBasedTestContentRecords() {
if let exitTest = record.load(withHint: id) {
return exitTest
}
}
#endif

return nil
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/Testing/Test+Discovery+Legacy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
//

#if !SWT_NO_LEGACY_TEST_DISCOVERY
@_spi(Experimental) @_spi(ForToolsIntegrationOnly) internal import _TestDiscovery

/// A shadow declaration of `_TestDiscovery.TestContentRecordContainer` that
Expand Down Expand Up @@ -41,3 +42,4 @@ open class __TestContentRecordContainer: TestContentRecordContainer {

@available(*, unavailable)
extension __TestContentRecordContainer: Sendable {}
#endif
6 changes: 6 additions & 0 deletions Sources/Testing/Test+Discovery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ extension Test {
// the legacy and new mechanisms, but we can set an environment variable
// to explicitly select one or the other. When we remove legacy support,
// we can also remove this enumeration and environment variable check.
#if !SWT_NO_LEGACY_TEST_DISCOVERY
let (useNewMode, useLegacyMode) = switch Environment.flag(named: "SWT_USE_LEGACY_TEST_DISCOVERY") {
case .none:
(true, true)
Expand All @@ -73,6 +74,9 @@ extension Test {
case .some(false):
(true, false)
}
#else
let useNewMode = true
#endif

// Walk all test content and gather generator functions, then call them in
// a task group and collate their results.
Expand All @@ -86,6 +90,7 @@ extension Test {
}
}

#if !SWT_NO_LEGACY_TEST_DISCOVERY
// Perform legacy test discovery if needed.
if useLegacyMode && result.isEmpty {
let generators = Generator.allTypeMetadataBasedTestContentRecords().lazy.compactMap { $0.load() }
Expand All @@ -96,6 +101,7 @@ extension Test {
result = await taskGroup.reduce(into: result) { $0.insert($1) }
}
}
#endif

return result
}
Expand Down
32 changes: 29 additions & 3 deletions Sources/TestingMacros/ConditionMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
public import SwiftSyntax
public import SwiftSyntaxMacros

#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY
#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand #expect(exitsWith:)")
#endif

/// A protocol containing the common implementation for the expansions of the
/// `#expect()` and `#require()` macros.
///
Expand Down Expand Up @@ -460,9 +464,9 @@ extension ExitTestConditionMacro {
accessingWith: .identifier("accessor")
)

#if !SWT_NO_LEGACY_TEST_DISCOVERY
decls.append(
"""
@available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.")
final class \(className): Testing.__TestContentRecordContainer {
private nonisolated static let accessor: Testing.__TestContentRecordAccessor = { outValue, type, hint in
Testing.ExitTest.__store(
Expand All @@ -482,12 +486,34 @@ extension ExitTestConditionMacro {
}
"""
)
#else
decls.append(
"""
final class \(className) {
private nonisolated static let accessor: Testing.__TestContentRecordAccessor = { outValue, type, hint in
Testing.ExitTest.__store(
\(exitTestIDExpr),
\(bodyThunkName),
into: outValue,
asTypeAt: type,
withHintAt: hint
)
}

\(testContentRecordDecl)
}
"""
)
#endif

arguments[trailingClosureIndex].expression = ExprSyntax(
ClosureExprSyntax {
for decl in decls {
CodeBlockItemSyntax(item: .decl(decl))
.with(\.trailingTrivia, .newline)
CodeBlockItemSyntax(
leadingTrivia: .newline,
item: .decl(decl),
trailingTrivia: .newline
)
}
}
)
Expand Down
6 changes: 6 additions & 0 deletions Sources/TestingMacros/SuiteDeclarationMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
public import SwiftSyntax
public import SwiftSyntaxMacros

#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY
#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand @Suite")
#endif

/// A type describing the expansion of the `@Suite` attribute macro.
///
/// This type is used to implement the `@Suite` attribute macro. Do not use it
Expand Down Expand Up @@ -160,6 +164,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable {
)
)

#if !SWT_NO_LEGACY_TEST_DISCOVERY
// Emit a type that contains a reference to the test content record.
let className = context.makeUniqueName("__🟡$")
result.append(
Expand All @@ -172,6 +177,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable {
}
"""
)
#endif

return result
}
Expand Down
12 changes: 12 additions & 0 deletions Sources/TestingMacros/Support/TestContentGeneration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax?
}

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
#endif
@available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.")
private nonisolated \(staticKeyword(for: typeName)) let \(name): Testing.__TestContentRecord = (
\(kindExpr), \(kind.commentRepresentation)
Expand Down
19 changes: 7 additions & 12 deletions Sources/TestingMacros/TestDeclarationMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
public import SwiftSyntax
public import SwiftSyntaxMacros

#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY
#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand @Test")
#endif

/// A type describing the expansion of the `@Test` attribute macro.
///
/// This type is used to implement the `@Test` attribute macro. Do not use it
Expand Down Expand Up @@ -188,17 +192,6 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
return FunctionParameterClauseSyntax(parameters: parameterList)
}

/// The `static` keyword, if `typeName` is not `nil`.
///
/// - Parameters:
/// - typeName: The name of the type containing the macro being expanded.
///
/// - Returns: A token representing the `static` keyword, or one representing
/// nothing if `typeName` is `nil`.
private static func _staticKeyword(for typeName: TypeSyntax?) -> TokenSyntax {
(typeName != nil) ? .keyword(.static) : .unknown("")
}

/// Create a thunk function with a normalized signature that calls a
/// developer-supplied test function.
///
Expand Down Expand Up @@ -356,7 +349,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
let thunkName = context.makeUniqueName(thunking: functionDecl)
let thunkDecl: DeclSyntax = """
@available(*, deprecated, message: "This function is an implementation detail of the testing library. Do not use it directly.")
@Sendable private \(_staticKeyword(for: typeName)) func \(thunkName)\(thunkParamsExpr) async throws -> Void {
@Sendable private \(staticKeyword(for: typeName)) func \(thunkName)\(thunkParamsExpr) async throws -> Void {
\(thunkBody)
}
"""
Expand Down Expand Up @@ -496,6 +489,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
)
)

#if !SWT_NO_LEGACY_TEST_DISCOVERY
// Emit a type that contains a reference to the test content record.
let className = context.makeUniqueName(thunking: functionDecl, withPrefix: "__🟡$")
result.append(
Expand All @@ -508,6 +502,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
}
"""
)
#endif

return result
}
Expand Down
8 changes: 8 additions & 0 deletions Sources/_TestDiscovery/SectionBounds.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ struct SectionBounds: Sendable {
/// The test content metadata section.
case testContent

#if !SWT_NO_LEGACY_TEST_DISCOVERY
/// The type metadata section.
case typeMetadata
#endif
}

/// All section bounds of the given kind found in the current process.
Expand Down Expand Up @@ -60,8 +62,10 @@ extension SectionBounds.Kind {
switch self {
case .testContent:
("__DATA_CONST", "__swift5_tests")
#if !SWT_NO_LEGACY_TEST_DISCOVERY
case .typeMetadata:
("__TEXT", "__swift5_types")
#endif
}
}
}
Expand Down Expand Up @@ -186,8 +190,10 @@ private func _sectionBounds(_ kind: SectionBounds.Kind) -> [SectionBounds] {
let range = switch context.pointee.kind {
case .testContent:
sections.swift5_tests
#if !SWT_NO_LEGACY_TEST_DISCOVERY
case .typeMetadata:
sections.swift5_type_metadata
#endif
}
let start = UnsafeRawPointer(bitPattern: range.start)
let size = Int(clamping: range.length)
Expand Down Expand Up @@ -276,8 +282,10 @@ private func _sectionBounds(_ kind: SectionBounds.Kind) -> some Sequence<Section
let sectionName = switch kind {
case .testContent:
".sw5test"
#if !SWT_NO_LEGACY_TEST_DISCOVERY
case .typeMetadata:
".sw5tymd"
#endif
}
return HMODULE.all.lazy.compactMap { _findSection(named: sectionName, in: $0) }
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/_TestDiscovery/TestContentRecord.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ extension DiscoverableAsTestContent where Self: ~Copyable {
}
}

#if !SWT_NO_LEGACY_TEST_DISCOVERY
// MARK: - Legacy test content discovery

private import _TestingInternals
Expand Down Expand Up @@ -344,3 +345,4 @@ extension DiscoverableAsTestContent where Self: ~Copyable {
return AnySequence(result)
}
}
#endif
12 changes: 12 additions & 0 deletions Sources/_TestingInternals/Discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,44 @@
#include "Discovery.h"

#include <algorithm>
#if !defined(SWT_NO_LEGACY_TEST_DISCOVERY)
#include <cstdint>
#include <cstring>
#include <type_traits>
#endif

#if defined(SWT_NO_DYNAMIC_LINKING)
#pragma mark - Statically-linked section bounds

#if defined(__APPLE__)
extern "C" const char testContentSectionBegin __asm("section$start$__DATA_CONST$__swift5_tests");
extern "C" const char testContentSectionEnd __asm("section$end$__DATA_CONST$__swift5_tests");
#if !defined(SWT_NO_LEGACY_TEST_DISCOVERY)
extern "C" const char typeMetadataSectionBegin __asm__("section$start$__TEXT$__swift5_types");
extern "C" const char typeMetadataSectionEnd __asm__("section$end$__TEXT$__swift5_types");
#endif
#elif defined(__wasi__)
extern "C" const char testContentSectionBegin __asm__("__start_swift5_tests");
extern "C" const char testContentSectionEnd __asm__("__stop_swift5_tests");
#if !defined(SWT_NO_LEGACY_TEST_DISCOVERY)
extern "C" const char typeMetadataSectionBegin __asm__("__start_swift5_type_metadata");
extern "C" const char typeMetadataSectionEnd __asm__("__stop_swift5_type_metadata");
#endif
#else
#warning Platform-specific implementation missing: Runtime test discovery unavailable (static)
static const char testContentSectionBegin = 0;
static const char& testContentSectionEnd = testContentSectionBegin;
#if !defined(SWT_NO_LEGACY_TEST_DISCOVERY)
static const char typeMetadataSectionBegin = 0;
static const char& typeMetadataSectionEnd = typeMetadataSectionBegin;
#endif
#endif

static constexpr const char *const staticallyLinkedSectionBounds[][2] = {
{ &testContentSectionBegin, &testContentSectionEnd },
#if !defined(SWT_NO_LEGACY_TEST_DISCOVERY)
{ &typeMetadataSectionBegin, &typeMetadataSectionEnd },
#endif
};

void swt_getStaticallyLinkedSectionBounds(size_t kind, const void **outSectionBegin, size_t *outByteCount) {
Expand All @@ -48,6 +58,7 @@ void swt_getStaticallyLinkedSectionBounds(size_t kind, const void **outSectionBe
}
#endif

#if !defined(SWT_NO_LEGACY_TEST_DISCOVERY)
#pragma mark - Swift ABI

#if defined(__PTRAUTH_INTRINSICS__)
Expand Down Expand Up @@ -221,3 +232,4 @@ const void *swt_getTypeFromTypeMetadataRecord(const void *recordAddress, const c

return nullptr;
}
#endif
Loading