diff --git a/Documentation/Porting.md b/Documentation/Porting.md index 4773e2823..365551d4c 100644 --- a/Documentation/Porting.md +++ b/Documentation/Porting.md @@ -193,7 +193,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: @@ -203,7 +203,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 @@ -214,6 +214,11 @@ 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 diff --git a/Package.swift b/Package.swift index 0d5c5cdb1..4353a164b 100644 --- a/Package.swift +++ b/Package.swift @@ -379,11 +379,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"), - // Enabled to allow tests to be added to ~Escapable suites. .enableExperimentalFeature("Lifetimes"), diff --git a/Sources/Testing/Discovery+Macro.swift b/Sources/Testing/Discovery+Macro.swift index 35b276efe..f3e598e13 100644 --- a/Sources/Testing/Discovery+Macro.swift +++ b/Sources/Testing/Discovery+Macro.swift @@ -34,7 +34,7 @@ public typealias __TestContentRecordAccessor = @convention(c) ( public typealias __TestContentRecord = ( kind: UInt32, reserved1: UInt32, - accessor: __TestContentRecordAccessor?, + accessor: __TestContentRecordAccessor, context: UInt, reserved2: UInt ) diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index 6ba8ff124..9c154b9fa 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -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. /// @@ -496,7 +492,7 @@ extension ExitTestConditionMacro { // Create another local type for legacy test discovery. var recordDecl: DeclSyntax? -#if !SWT_NO_LEGACY_TEST_DISCOVERY +#if compiler(<6.3) let legacyEnumName = context.makeUniqueName("__🟡$") recordDecl = """ enum \(legacyEnumName): Testing.__TestContentRecordContainer { diff --git a/Sources/TestingMacros/SuiteDeclarationMacro.swift b/Sources/TestingMacros/SuiteDeclarationMacro.swift index 14e5a8824..8b428b4cf 100644 --- a/Sources/TestingMacros/SuiteDeclarationMacro.swift +++ b/Sources/TestingMacros/SuiteDeclarationMacro.swift @@ -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 @@ -166,7 +162,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { ) ) -#if !SWT_NO_LEGACY_TEST_DISCOVERY +#if compiler(<6.3) // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName("__🟡$") result.append( diff --git a/Sources/TestingMacros/Support/TestContentGeneration.swift b/Sources/TestingMacros/Support/TestContentGeneration.swift index 05214d1b8..0236a1796 100644 --- a/Sources/TestingMacros/Support/TestContentGeneration.swift +++ b/Sources/TestingMacros/Support/TestContentGeneration.swift @@ -68,26 +68,24 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax? private nonisolated \(staticKeyword(for: typeName)) let \(name): Testing.__TestContentRecord = ( \(kindExpr), \(kind.commentRepresentation) 0, - unsafe \(accessorName), + { unsafe \(accessorName)($0, $1, $2, $3) }, \(contextExpr), 0 ) """ -#if hasFeature(SymbolLinkageMarkers) +#if compiler(>=6.3) result = """ - #if hasFeature(SymbolLinkageMarkers) #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS) - @_section("__DATA_CONST,__swift5_tests") + @section("__DATA_CONST,__swift5_tests") #elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI) - @_section("swift5_tests") + @section("swift5_tests") #elseif os(Windows) - @_section(".sw5test$B") + @section(".sw5test$B") #else @Testing.__testing(warning: "Platform-specific implementation missing: test content section name unavailable") #endif - @_used - #endif + @used \(result) """ #endif diff --git a/Sources/TestingMacros/TestDeclarationMacro.swift b/Sources/TestingMacros/TestDeclarationMacro.swift index 525067a32..89c907e51 100644 --- a/Sources/TestingMacros/TestDeclarationMacro.swift +++ b/Sources/TestingMacros/TestDeclarationMacro.swift @@ -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 @@ -491,7 +487,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { ) ) -#if !SWT_NO_LEGACY_TEST_DISCOVERY +#if compiler(<6.3) // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName(thunking: functionDecl, withPrefix: "__🟡$") result.append( diff --git a/Sources/_TestDiscovery/TestContentRecord.swift b/Sources/_TestDiscovery/TestContentRecord.swift index 8a41924f5..0f074816d 100644 --- a/Sources/_TestDiscovery/TestContentRecord.swift +++ b/Sources/_TestDiscovery/TestContentRecord.swift @@ -244,7 +244,7 @@ extension DiscoverableAsTestContent { return SectionBounds.all(.testContent).lazy.flatMap { sb in sb.buffer.withMemoryRebound(to: _TestContentRecord.self) { records in (0 ..< records.count).lazy - .map { (records.baseAddress! + $0) as UnsafePointer<_TestContentRecord> } + .map { records.baseAddress! + $0 } .filter { $0.pointee.kind == kind } .map { TestContentRecord(imageAddress: sb.imageAddress, recordAddress: $0) } } diff --git a/Tests/TestingMacrosTests/TestDeclarationMacroTests.swift b/Tests/TestingMacrosTests/TestDeclarationMacroTests.swift index e1830ec20..cffb8690e 100644 --- a/Tests/TestingMacrosTests/TestDeclarationMacroTests.swift +++ b/Tests/TestingMacrosTests/TestDeclarationMacroTests.swift @@ -482,10 +482,11 @@ struct TestDeclarationMacroTests { func differentFunctionTypes(input: String, expectedTypeName: String?, otherCode: String?) throws { let (output, _) = try parse(input) -#if hasFeature(SymbolLinkageMarkers) - #expect(output.contains("@_section")) -#endif -#if !SWT_NO_LEGACY_TEST_DISCOVERY +#if compiler(>=6.3) + #expect(output.contains("@section")) + #expect(!output.contains("__TestContentRecordContainer")) +#else + #expect(!output.contains("@section")) #expect(output.contains("__TestContentRecordContainer")) #endif if let expectedTypeName { diff --git a/Tests/TestingTests/DiscoveryTests.swift b/Tests/TestingTests/DiscoveryTests.swift index 24d2eecfa..24aed1bcb 100644 --- a/Tests/TestingTests/DiscoveryTests.swift +++ b/Tests/TestingTests/DiscoveryTests.swift @@ -58,7 +58,7 @@ struct DiscoveryTests { } #endif -#if !SWT_NO_DYNAMIC_LINKING && hasFeature(SymbolLinkageMarkers) +#if compiler(>=6.3) && !SWT_NO_DYNAMIC_LINKING struct MyTestContent: DiscoverableAsTestContent { typealias TestContentAccessorHint = UInt32 @@ -81,16 +81,16 @@ struct DiscoveryTests { } #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS) - @_section("__DATA_CONST,__swift5_tests") + @section("__DATA_CONST,__swift5_tests") #elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI) - @_section("swift5_tests") + @section("swift5_tests") #elseif os(Windows) - @_section(".sw5test$B") + @section(".sw5test$B") #else @__testing(warning: "Platform-specific implementation missing: test content section name unavailable") #endif - @_used - private static let record: __TestContentRecord = ( + @used + fileprivate static let record: __TestContentRecord = ( 0xABCD1234, 0, { outValue, type, hint, _ in @@ -105,12 +105,12 @@ struct DiscoveryTests { _ = outValue.initializeMemory(as: Self.self, to: .init(value: expectedValue)) return true }, - UInt(truncatingIfNeeded: UInt64(0x0204060801030507)), + 0x02040608, 0 ) } - @Test func testDiscovery() async { + @Test func testDiscovery() { // Check the type of the test record sequence (it should be lazy.) let allRecordsSeq = MyTestContent.allTestContentRecords() #if SWT_FIXED_143080508 @@ -142,22 +142,22 @@ struct DiscoveryTests { && record.context == MyTestContent.expectedContext }) } -#endif -#if !SWT_NO_LEGACY_TEST_DISCOVERY && hasFeature(SymbolLinkageMarkers) - @Test("Legacy test discovery finds the same number of tests") func discoveredTestCount() async { - let oldFlag = Environment.variable(named: "SWT_USE_LEGACY_TEST_DISCOVERY") - defer { - Environment.setVariable(oldFlag, named: "SWT_USE_LEGACY_TEST_DISCOVERY") +#if !SWT_NO_LEGACY_TEST_DISCOVERY + struct `__🟡$LegacyTestContentRecord`: __TestContentRecordContainer { + static var __testContentRecord: __TestContentRecord { + MyTestContent.record } + } - Environment.setVariable("1", named: "SWT_USE_LEGACY_TEST_DISCOVERY") - let testsWithOldCode = await Array(Test.all).count - - Environment.setVariable("0", named: "SWT_USE_LEGACY_TEST_DISCOVERY") - let testsWithNewCode = await Array(Test.all).count - - #expect(testsWithOldCode == testsWithNewCode) + @Test func legacyTestDiscovery() throws { + let allRecords = Array(MyTestContent.allTypeMetadataBasedTestContentRecords()) + #expect(allRecords.count == 1) + let record = try #require(allRecords.first) + #expect(record.context == MyTestContent.expectedContext) + let content = try #require(record.load()) + #expect(content.value == MyTestContent.expectedValue) } #endif +#endif }