Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
26 changes: 9 additions & 17 deletions Documentation/Porting.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,6 @@ 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 @@ -193,7 +189,7 @@ to load that information:
```

You will also need to update the `makeTestContentRecordDecl()` function in the
`TestingMacros` target to emit the correct `@_section` attribute for your
`TestingMacros` target to emit the correct `@section` attribute for your
platform. If your platform uses the ELF image format and supports the
`dl_iterate_phdr()` function, add it to the existing `#elseif os(Linux) || ...`
case. Otherwise, add a new case for your platform:
Expand All @@ -203,7 +199,7 @@ case. Otherwise, add a new case for your platform:
+++ b/Sources/TestingMacros/Support/TestContentGeneration.swift
// ...
+ #elseif os(Classic)
+ @_section(".rsrc,swft,__swift5_tests")
+ @section(".rsrc,swft,__swift5_tests")
#else
@__testing(warning: "Platform-specific implementation missing: test content section name unavailable")
#endif
Expand All @@ -214,14 +210,18 @@ directly into test authors' test targets, so you will not be able to use
compiler conditionals defined in the Swift Testing package (including those that
start with `"SWT_"`).

> [!NOTE]
> We are not using `objectFormat()` yet to maintain compatibility with the Swift
> 6.2 toolchain. We will migrate to `objectFormat()` when we drop Swift 6.2
> toolchain support (presumably after Swift 6.3 ships).

## Runtime test discovery with static linkage

If your platform does not support dynamic linking and loading, you will need to
use static linkage instead. Define the `"SWT_NO_DYNAMIC_LINKING"` compiler
conditional for your platform in both `Package.swift` and
`CompilerSettings.cmake`, then define the symbols `_testContentSectionBegin`,
`_testContentSectionEnd`, `_typeMetadataSectionBegin`, and
`_typeMetadataSectionEnd` in `SectionBounds.swift`:
`CompilerSettings.cmake`, then define the symbols `_testContentSectionBegin` and
`_testContentSectionEnd` in `SectionBounds.swift`:

```diff
--- a/Sources/_TestDiscovery/SectionBounds.swift
Expand All @@ -230,18 +230,10 @@ conditional for your platform in both `Package.swift` and
+#elseif os(Classic)
+@_silgen_name(raw: "...") private nonisolated(unsafe) var _testContentSectionBegin: _SectionBound
+@_silgen_name(raw: "...") private nonisolated(unsafe) var _testContentSectionEnd: _SectionBound
+#if !SWT_NO_LEGACY_TEST_DISCOVERY
+@_silgen_name(raw: "...") private nonisolated(unsafe) var _typeMetadataSectionBegin: _SectionBound
+@_silgen_name(raw: "...") private nonisolated(unsafe) var _typeMetadataSectionEnd: _SectionBound
+#endif
#else
#warning("Platform-specific implementation missing: Runtime test discovery unavailable (static)")
private nonisolated(unsafe) let _testContentSectionBegin = UnsafeMutableRawPointer.allocate(byteCount: 1, alignment: 16)
private nonisolated(unsafe) let _testContentSectionEnd = _testContentSectionBegin
#if !SWT_NO_LEGACY_TEST_DISCOVERY
private nonisolated(unsafe) let _typeMetadataSectionBegin = UnsafeMutableRawPointer.allocate(byteCount: 1, alignment: 16)
private nonisolated(unsafe) let _typeMetadataSectionEnd = _typeMetadataSectionBegin
#endif
#endif
// ...
```
Expand Down
13 changes: 6 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -385,11 +385,6 @@ extension Array where Element == PackageDescription.SwiftSetting {

.enableUpcomingFeature("MemberImportVisibility"),

// 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"),

.enableUpcomingFeature("InferIsolatedConformances"),

// When building as a package, the macro plugin always builds as an
Expand All @@ -406,10 +401,15 @@ extension Array where Element == PackageDescription.SwiftSetting {
.define("SWT_NO_FOUNDATION_FILE_COORDINATION", .whenEmbedded(or: .whenApple(false))),
.define("SWT_NO_IMAGE_ATTACHMENTS", .whenEmbedded(or: .when(platforms: [.linux, .custom("freebsd"), .openbsd, .wasi, .android]))),

.define("SWT_NO_LEGACY_TEST_DISCOVERY", .whenEmbedded()),
.define("SWT_NO_LIBDISPATCH", .whenEmbedded()),
]

#if compiler(<6.3)
result += [
.enableExperimentalFeature("SymbolLinkageMarkers"),
]
#endif

return result
}

Expand Down Expand Up @@ -464,7 +464,6 @@ extension Array where Element == PackageDescription.CXXSetting {
.define("SWT_NO_PIPES", .whenEmbedded(or: .when(platforms: [.wasi]))),
.define("SWT_NO_FOUNDATION_FILE_COORDINATION", .whenEmbedded(or: .whenApple(false))),

.define("SWT_NO_LEGACY_TEST_DISCOVERY", .whenEmbedded()),
.define("SWT_NO_LIBDISPATCH", .whenEmbedded()),
]

Expand Down
1 change: 0 additions & 1 deletion Sources/Testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ add_library(Testing
Test.swift
Test+Cancellation.swift
Test+Discovery.swift
Test+Discovery+Legacy.swift
Test+Macro.swift
Traits/AttachmentSavingTrait.swift
Traits/Bug.swift
Expand Down
2 changes: 1 addition & 1 deletion Sources/Testing/Discovery+Macro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public typealias __TestContentRecordAccessor = @convention(c) (
public typealias __TestContentRecord = (
kind: UInt32,
reserved1: UInt32,
accessor: __TestContentRecordAccessor?,
accessor: __TestContentRecordAccessor,
context: UInt,
reserved2: UInt
)
9 changes: 0 additions & 9 deletions Sources/Testing/ExitTests/ExitTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -420,15 +420,6 @@ extension ExitTest {
}
}

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

return nil
}
}
Expand Down
47 changes: 0 additions & 47 deletions Sources/Testing/Test+Discovery+Legacy.swift

This file was deleted.

46 changes: 6 additions & 40 deletions Sources/Testing/Test+Discovery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,51 +63,17 @@ extension Test {
// defective test records.)
var result = Set<Self>()

// Figure out which discovery mechanism to use. By default, we'll use both
// 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)
case .some(true):
(false, true)
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.
if useNewMode {
let generators = Generator.allTestContentRecords().lazy.compactMap { $0.load() }
await withTaskGroup { taskGroup in
for (i, generator) in generators.enumerated() {
taskGroup.addTask(name: decorateTaskName("test discovery", withAction: "loading test #\(i)")) {
await generator.rawValue()
}
}
result = await taskGroup.reduce(into: result) { $0.insert($1) }
}
}

#if !SWT_NO_LEGACY_TEST_DISCOVERY
// Perform legacy test discovery if needed.
if useLegacyMode && result.isEmpty {
let generators = Generator.allTypeMetadataBasedTestContentRecords().lazy.compactMap { $0.load() }
await withTaskGroup { taskGroup in
for (i, generator) in generators.enumerated() {
taskGroup.addTask(name: decorateTaskName("type-based test discovery", withAction: "loading test #\(i)")) {
await generator.rawValue()
}
let generators = Generator.allTestContentRecords().lazy.compactMap { $0.load() }
await withTaskGroup(of: Self.self) { taskGroup in
for (i, generator) in generators.enumerated() {
taskGroup.addTask(name: decorateTaskName("test discovery", withAction: "loading test #\(i)")) {
await generator.rawValue()
}
result = await taskGroup.reduce(into: result) { $0.insert($1) }
}
result = await taskGroup.reduce(into: result) { $0.insert($1) }
}
#endif

return result
}
Expand Down
19 changes: 0 additions & 19 deletions Sources/TestingMacros/ConditionMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ public import SwiftSyntax
import SwiftSyntaxBuilder
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(processExitsWith:)")
#endif

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

// Create another local type for legacy test discovery.
var recordDecl: DeclSyntax?
#if !SWT_NO_LEGACY_TEST_DISCOVERY
let legacyEnumName = context.makeUniqueName("__🟡$")
recordDecl = """
enum \(legacyEnumName): Testing.__TestContentRecordContainer {
nonisolated static var __testContentRecord: Testing.__TestContentRecord {
unsafe \(enumName).testContentRecord
}
}
"""
#endif

decls.append(
"""
@available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.")
Expand All @@ -522,8 +505,6 @@ extension ExitTestConditionMacro {
}

\(testContentRecordDecl)

\(recordDecl)
}
"""
)
Expand Down
19 changes: 0 additions & 19 deletions Sources/TestingMacros/SuiteDeclarationMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ public import SwiftSyntax
import SwiftSyntaxBuilder
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 @@ -166,21 +162,6 @@ 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 enumName = context.makeUniqueName("__🟡$")
result.append(
"""
@available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.")
enum \(enumName): Testing.__TestContentRecordContainer {
nonisolated static var __testContentRecord: Testing.__TestContentRecord {
unsafe \(testContentRecordName)
}
}
"""
)
#endif

return result
}
}
18 changes: 15 additions & 3 deletions Sources/TestingMacros/Support/TestContentGeneration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,22 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax?
)
"""

#if hasFeature(SymbolLinkageMarkers)
#if compiler(>=6.3)
result = """
#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.__testing(warning: "Platform-specific implementation missing: test content section name unavailable")
#endif
@used
\(result)
"""
#else
result = """
#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)
Expand All @@ -87,7 +100,6 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax?
@Testing.__testing(warning: "Platform-specific implementation missing: test content section name unavailable")
#endif
@_used
#endif
\(result)
"""
#endif
Expand Down
19 changes: 0 additions & 19 deletions Sources/TestingMacros/TestDeclarationMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ public import SwiftSyntax
import SwiftSyntaxBuilder
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 @@ -493,21 +489,6 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
)
)

#if !SWT_NO_LEGACY_TEST_DISCOVERY
// Emit a type that contains a reference to the test content record.
let enumName = context.makeUniqueName(thunking: functionDecl, withPrefix: "__🟡$")
result.append(
"""
@available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.")
enum \(enumName): Testing.__TestContentRecordContainer {
nonisolated static var __testContentRecord: Testing.__TestContentRecord {
unsafe \(testContentRecordName)
}
}
"""
)
#endif

return result
}
}
Loading
Loading