From 2b5521dccb1aa93f9dca9793957e6e433281e85c Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Wed, 30 Jul 2025 07:08:48 -0400 Subject: [PATCH 1/6] Various `VersionNumber` changes of merit. This PR does things to `ABI.VersionNumber`: - Renames it to `VersionNumber` as we do have some use cases that aren't related to JSON schema versioning. I initially didn't want to make this type a general version number type, but it's just too useful not to do so. Alas. - Changes the type of the `swiftStandardLibraryVersion` global variable to `VersionNumber?`. - Adds `swiftCompilerVersion` representing the version of the Swift compiler used to compile Swift Testing. We need this value when computing the JSON schema version (see next bullet.) - Clamps the range of supported JSON schema versions to the Swift compiler version _unless_ we've explicitly defined a schema version higher than it: | Compiler | Highest Defined Schema | Requested | Result | |-|-|-|-| | 1.0 | 1.0 | 1.0 | 1.0 | | 2.0 | 1.0 | 1.0 | 1.0 | | 1.0 | 2.0 | 1.0 | 1.0 | | 1.0 | 1.0 | 2.0 | `nil` | | 2.0 | 2.0 | 1.0 | 1.0 | | 2.0 | 1.0 | 2.0 | 1.0 | | 1.0 | 2.0 | 2.0 | 2.0 | | 2.0 | 2.0 | 2.0 | 2.0 | The reasoning here is that, when we're built with a given compiler version, we presumably know about all JSON schema versions up to and including the one aligned with that compiler, so if you ask for the schema version aligned with the compiler, it's equivalent to whatever we support that's less than or equal to the compiler version. But if you ask for something greater than the compiler version, and we haven't defined it, we don't know anything about it and can't provide it. This reasoning breaks down somewhat if you build an old version of the Swift Testing package with a new compiler, but in general we don't support that sort of configuration for very long (and we can't predict the future anyway.) --- Sources/Testing/ABI/ABI.Record.swift | 2 +- Sources/Testing/ABI/ABI.swift | 22 +++++++- .../Testing/ABI/EntryPoints/EntryPoint.swift | 12 ++--- Sources/Testing/CMakeLists.txt | 2 +- .../Event.HumanReadableOutputRecorder.swift | 8 ++- Sources/Testing/ExitTests/SpawnProcess.swift | 2 +- .../VersionNumber.swift} | 52 +++++++++++-------- Sources/Testing/Support/Versions.swift | 40 ++++++++++---- Sources/_TestingInternals/include/Versions.h | 8 +++ Tests/TestingTests/ABIEntryPointTests.swift | 32 ++++++------ Tests/TestingTests/SwiftPMTests.swift | 26 +++++++--- 11 files changed, 140 insertions(+), 66 deletions(-) rename Sources/Testing/{ABI/ABI.VersionNumber.swift => Support/VersionNumber.swift} (72%) diff --git a/Sources/Testing/ABI/ABI.Record.swift b/Sources/Testing/ABI/ABI.Record.swift index e03b5df6a..ef7bc6937 100644 --- a/Sources/Testing/ABI/ABI.Record.swift +++ b/Sources/Testing/ABI/ABI.Record.swift @@ -66,7 +66,7 @@ extension ABI.Record: Codable { init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - let versionNumber = try container.decode(ABI.VersionNumber.self, forKey: .version) + let versionNumber = try container.decode(VersionNumber.self, forKey: .version) if versionNumber != V.versionNumber { throw DecodingError.dataCorrupted( DecodingError.Context( diff --git a/Sources/Testing/ABI/ABI.swift b/Sources/Testing/ABI/ABI.swift index 23b14297c..1707953a0 100644 --- a/Sources/Testing/ABI/ABI.swift +++ b/Sources/Testing/ABI/ABI.swift @@ -45,6 +45,9 @@ extension ABI { /// The current supported ABI version (ignoring any experimental versions.) typealias CurrentVersion = v0 + /// The highest supported ABI version (including any experimental versions.) + typealias HighestVersion = v6_3 + #if !hasFeature(Embedded) /// Get the type representing a given ABI version. /// @@ -55,7 +58,24 @@ extension ABI { /// - Returns: A type conforming to ``ABI/Version`` that represents the given /// ABI version, or `nil` if no such type exists. static func version(forVersionNumber versionNumber: VersionNumber = ABI.CurrentVersion.versionNumber) -> (any Version.Type)? { - switch versionNumber { + if versionNumber > ABI.HighestVersion.versionNumber { + // If the caller requested an ABI version higher than the current Swift + // compiler version and it's not an ABI version we've explicitly defined, + // then we assume we don't know what they're talking about and return nil. + // + // Note that it is possible for the Swift compiler version to be lower + // than the highest defined ABI version (e.g. if you use a 6.2 toolchain + // to build this package's release/6.3 branch with a 6.3 ABI defined.) + // + // Note also that building an old version of Swift Testing with a newer + // compiler may produce incorrect results here. We don't generally support + // that configuration though. + if versionNumber > swiftCompilerVersion { + return nil + } + } + + return switch versionNumber { case ABI.v6_3.versionNumber...: ABI.v6_3.self case ABI.v0.versionNumber...: diff --git a/Sources/Testing/ABI/EntryPoints/EntryPoint.swift b/Sources/Testing/ABI/EntryPoints/EntryPoint.swift index 61f2f92cb..ed16a9841 100644 --- a/Sources/Testing/ABI/EntryPoints/EntryPoint.swift +++ b/Sources/Testing/ABI/EntryPoints/EntryPoint.swift @@ -262,7 +262,7 @@ public struct __CommandLineArguments_v0: Sendable { /// This property is internal because its type is internal. External users of /// this structure can use the ``eventStreamSchemaVersion`` property to get or /// set the value of this property. - var eventStreamVersionNumber: ABI.VersionNumber? + var eventStreamVersionNumber: VersionNumber? /// The value of the `--event-stream-version` or `--experimental-event-stream-version` /// argument, representing the version of the event stream schema to use when @@ -282,7 +282,7 @@ public struct __CommandLineArguments_v0: Sendable { } set { eventStreamVersionNumber = newValue.flatMap { newValue in - guard let newValue = ABI.VersionNumber(newValue) else { + guard let newValue = VersionNumber(newValue) else { preconditionFailure("Invalid event stream version number '\(newValue)'. Specify a version number of the form 'major.minor.patch'.") } return newValue @@ -404,7 +404,7 @@ func parseCommandLineArguments(from args: [String]) throws -> __CommandLineArgum // If the caller specified a version that could not be parsed, treat it as // an invalid argument. - guard let eventStreamVersion = ABI.VersionNumber(versionString) else { + guard let eventStreamVersion = VersionNumber(versionString) else { let argument = allowExperimental ? "--experimental-event-stream-version" : "--event-stream-version" throw _EntryPointError.invalidArgument(argument, value: versionString) } @@ -652,7 +652,7 @@ public func configurationForEntryPoint(from args: __CommandLineArguments_v0) thr /// /// - Throws: If `version` is not a supported ABI version. func eventHandlerForStreamingEvents( - withVersionNumber versionNumber: ABI.VersionNumber?, + withVersionNumber versionNumber: VersionNumber?, encodeAsJSONLines: Bool, forwardingTo targetEventHandler: @escaping @Sendable (UnsafeRawBufferPointer) -> Void ) throws -> Event.Handler { @@ -822,7 +822,7 @@ private enum _EntryPointError: Error { /// /// - Parameters: /// - versionNumber: The experimental ABI version number. - case experimentalABIVersion(_ versionNumber: ABI.VersionNumber) + case experimentalABIVersion(_ versionNumber: VersionNumber) } extension _EntryPointError: CustomStringConvertible { @@ -847,7 +847,7 @@ extension __CommandLineArguments_v0 { eventStreamVersionNumber.map(\.majorComponent).map(Int.init) } set { - eventStreamVersionNumber = newValue.map { ABI.VersionNumber(majorComponent: Int8(clamping: $0), minorComponent: 0) } + eventStreamVersionNumber = newValue.map { VersionNumber(majorComponent: .init(clamping: $0), minorComponent: 0) } } } } diff --git a/Sources/Testing/CMakeLists.txt b/Sources/Testing/CMakeLists.txt index 8ddaa2cb5..f970f43bb 100644 --- a/Sources/Testing/CMakeLists.txt +++ b/Sources/Testing/CMakeLists.txt @@ -13,7 +13,6 @@ add_library(Testing ABI/ABI.Record.swift ABI/ABI.Record+Streaming.swift ABI/ABI.swift - ABI/ABI.VersionNumber.swift ABI/Encoded/ABI.EncodedAttachment.swift ABI/Encoded/ABI.EncodedBacktrace.swift ABI/Encoded/ABI.EncodedError.swift @@ -84,6 +83,7 @@ add_library(Testing Support/JSON.swift Support/Locked.swift Support/Locked+Platform.swift + Support/VersionNumber.swift Support/Versions.swift Discovery+Macro.swift Test.ID.Selection.swift diff --git a/Sources/Testing/Events/Recorder/Event.HumanReadableOutputRecorder.swift b/Sources/Testing/Events/Recorder/Event.HumanReadableOutputRecorder.swift index 248bb4aec..434487e27 100644 --- a/Sources/Testing/Events/Recorder/Event.HumanReadableOutputRecorder.swift +++ b/Sources/Testing/Events/Recorder/Event.HumanReadableOutputRecorder.swift @@ -342,7 +342,13 @@ extension Event.HumanReadableOutputRecorder { case .runStarted: var comments = [Comment]() if verbosity > 0 { - comments.append("Swift Version: \(swiftStandardLibraryVersion)") + if let swiftStandardLibraryVersion { + comments.append("Swift Standard Library Version: \(swiftStandardLibraryVersion)") + } + comments.append("Swift Compiler Version: \(swiftCompilerVersion)") +#if canImport(Glibc) && !os(FreeBSD) && !os(OpenBSD) + comments.append("GNU C Library Version: \(glibcVersion)") +#endif } comments.append("Testing Library Version: \(testingLibraryVersion)") if let targetTriple { diff --git a/Sources/Testing/ExitTests/SpawnProcess.swift b/Sources/Testing/ExitTests/SpawnProcess.swift index 9f01a1d11..24303f632 100644 --- a/Sources/Testing/ExitTests/SpawnProcess.swift +++ b/Sources/Testing/ExitTests/SpawnProcess.swift @@ -138,7 +138,7 @@ func spawnExecutable( // and https://www.austingroupbugs.net/view.php?id=411). _ = posix_spawn_file_actions_adddup2(fileActions, fd, fd) #if canImport(Glibc) && !os(FreeBSD) && !os(OpenBSD) - if _slowPath(glibcVersion.major < 2 || (glibcVersion.major == 2 && glibcVersion.minor < 29)) { + if _slowPath(glibcVersion < VersionNumber(2, 29)) { // This system is using an older version of glibc that does not // implement FD_CLOEXEC clearing in posix_spawn_file_actions_adddup2(), // so we must clear it here in the parent process. diff --git a/Sources/Testing/ABI/ABI.VersionNumber.swift b/Sources/Testing/Support/VersionNumber.swift similarity index 72% rename from Sources/Testing/ABI/ABI.VersionNumber.swift rename to Sources/Testing/Support/VersionNumber.swift index 2235d3c1d..4dfa52994 100644 --- a/Sources/Testing/ABI/ABI.VersionNumber.swift +++ b/Sources/Testing/Support/VersionNumber.swift @@ -8,34 +8,42 @@ // See https://swift.org/CONTRIBUTORS.txt for Swift project authors // -extension ABI { - /// A type describing an ABI version number. +private import _TestingInternals + +/// A type describing an ABI version number. +/// +/// This type implements a subset of the [semantic versioning](https://semver.org) +/// specification (specifically parsing, displaying, and comparing +/// `` values we expect that the testing library will need for the +/// foreseeable future.) +struct VersionNumber: Sendable { + /// The integer type used to store a component. /// - /// This type implements a subset of the [semantic versioning](https://semver.org) - /// specification (specifically parsing, displaying, and comparing - /// `` values we expect that Swift will need for the foreseeable - /// future.) - struct VersionNumber: Sendable { - /// The major version. - var majorComponent: Int8 + /// The testing library does not generally need to deal with version numbers + /// whose components exceed the width of this type. If we need to deal with + /// larger version number components in the future, we can increase the width + /// of this type accordingly. + typealias Component = Int8 - /// The minor version. - var minorComponent: Int8 + /// The major version. + var majorComponent: Component - /// The patch, revision, or bug fix version. - var patchComponent: Int8 = 0 - } + /// The minor version. + var minorComponent: Component + + /// The patch, revision, or bug fix version. + var patchComponent: Component = 0 } -extension ABI.VersionNumber { - init(_ majorComponent: _const Int8, _ minorComponent: _const Int8, _ patchComponent: _const Int8 = 0) { +extension VersionNumber { + init(_ majorComponent: _const Component, _ minorComponent: _const Component, _ patchComponent: _const Component = 0) { self.init(majorComponent: majorComponent, minorComponent: minorComponent, patchComponent: patchComponent) } } // MARK: - CustomStringConvertible -extension ABI.VersionNumber: CustomStringConvertible { +extension VersionNumber: CustomStringConvertible { /// Initialize an instance of this type by parsing the given string. /// /// - Parameters: @@ -55,8 +63,8 @@ extension ABI.VersionNumber: CustomStringConvertible { // Split the string on "." (assuming it is of the form "1", "1.2", or // "1.2.3") and parse the individual components as integers. let components = string.split(separator: ".", omittingEmptySubsequences: false) - func componentValue(_ index: Int) -> Int8? { - components.count > index ? Int8(components[index]) : 0 + func componentValue(_ index: Int) -> Component? { + components.count > index ? Component(components[index]) : 0 } guard let majorComponent = componentValue(0), @@ -81,7 +89,7 @@ extension ABI.VersionNumber: CustomStringConvertible { // MARK: - Equatable, Comparable -extension ABI.VersionNumber: Equatable, Comparable { +extension VersionNumber: Equatable, Comparable { static func <(lhs: Self, rhs: Self) -> Bool { if lhs.majorComponent != rhs.majorComponent { return lhs.majorComponent < rhs.majorComponent @@ -96,10 +104,10 @@ extension ABI.VersionNumber: Equatable, Comparable { // MARK: - Codable -extension ABI.VersionNumber: Codable { +extension VersionNumber: Codable { init(from decoder: any Decoder) throws { let container = try decoder.singleValueContainer() - if let number = try? container.decode(Int8.self) { + if let number = try? container.decode(Component.self) { // Allow for version numbers encoded as integers for compatibility with // Swift 6.2 and earlier. self.init(majorComponent: number, minorComponent: 0) diff --git a/Sources/Testing/Support/Versions.swift b/Sources/Testing/Support/Versions.swift index 7f190ebb2..361bf2139 100644 --- a/Sources/Testing/Support/Versions.swift +++ b/Sources/Testing/Support/Versions.swift @@ -9,6 +9,7 @@ // private import _TestingInternals +private import SwiftShims /// A human-readable string describing the current operating system's version. /// @@ -141,23 +142,44 @@ var targetTriple: String? { /// A human-readable string describing the Swift Standard Library's version. /// -/// This value's format is platform-specific and is not meant to be -/// machine-readable. It is added to the output of a test run when using -/// an event writer. +/// This value is unavailable on some earlier Apple runtime targets. On those +/// targets, this property has a value of `5.0.0`. /// /// This value is not part of the public interface of the testing library. -let swiftStandardLibraryVersion: String = { - if #available(_swiftVersionAPI, *) { - return String(describing: _SwiftStdlibVersion.current) +let swiftStandardLibraryVersion: VersionNumber? = { + guard #available(_swiftVersionAPI, *) else { + return VersionNumber(5, 0) } - return "unknown" + let packedValue = _SwiftStdlibVersion.current._value + return VersionNumber( + majorComponent: .init((packedValue & 0xFFFF0000) >> 16), + minorComponent: .init((packedValue & 0x0000FF00) >> 8), + patchComponent: .init((packedValue & 0x000000FF) >> 0) + ) }() +/// The version of the Swift compiler used to build the testing library. +/// +/// This value is determined at compile time by the Swift compiler. For more +/// information, see [Version.h](https://github.com/swiftlang/swift/blob/main/include/swift/Basic/Version.h) +/// and [ClangImporter.cpp](https://github.com/swiftlang/swift/blob/main/lib/ClangImporter/ClangImporter.cpp) +/// in the Swift repository. +/// +/// This value is not part of the public interface of the testing library. +var swiftCompilerVersion: VersionNumber { + let packedValue = swt_getSwiftCompilerVersion() + return VersionNumber( + majorComponent: .init((packedValue % 1_000_000_000_000_000) / 1_000_000_000_000), + minorComponent: .init((packedValue % 1_000_000_000_000) / 1_000_000_000), + patchComponent: .init((packedValue % 1_000_000_000) / 1_000_000) + ) +} + #if canImport(Glibc) && !os(FreeBSD) && !os(OpenBSD) /// The (runtime, not compile-time) version of glibc in use on this system. /// /// This value is not part of the public interface of the testing library. -let glibcVersion: (major: Int, minor: Int) = { +let glibcVersion: VersionNumber = { // Default to the statically available version number if the function call // fails for some reason. var major = Int(clamping: __GLIBC__) @@ -173,7 +195,7 @@ let glibcVersion: (major: Int, minor: Int) = { } } - return (major, minor) + return VersionNumber(majorComponent: major, minorComponent: minor) }() #endif diff --git a/Sources/_TestingInternals/include/Versions.h b/Sources/_TestingInternals/include/Versions.h index 1be02ba33..eb753291a 100644 --- a/Sources/_TestingInternals/include/Versions.h +++ b/Sources/_TestingInternals/include/Versions.h @@ -16,6 +16,14 @@ SWT_ASSUME_NONNULL_BEGIN +static inline uint64_t swt_getSwiftCompilerVersion(void) { +#if defined(__SWIFT_COMPILER_VERSION) + return __SWIFT_COMPILER_VERSION; +#else + return 0; +#endif +} + /// Get the human-readable version of the testing library. /// /// - Returns: A human-readable string describing the version of the testing diff --git a/Tests/TestingTests/ABIEntryPointTests.swift b/Tests/TestingTests/ABIEntryPointTests.swift index a44942e2a..76af1b83e 100644 --- a/Tests/TestingTests/ABIEntryPointTests.swift +++ b/Tests/TestingTests/ABIEntryPointTests.swift @@ -119,12 +119,12 @@ struct ABIEntryPointTests { @Test func decodeVersionNumber() throws { let version0 = try JSON.withEncoding(of: 0) { versionJSON in - try JSON.decode(ABI.VersionNumber.self, from: versionJSON) + try JSON.decode(VersionNumber.self, from: versionJSON) } - #expect(version0 == ABI.VersionNumber(0, 0)) + #expect(version0 == VersionNumber(0, 0)) let version1_2_3 = try JSON.withEncoding(of: "1.2.3") { versionJSON in - try JSON.decode(ABI.VersionNumber.self, from: versionJSON) + try JSON.decode(VersionNumber.self, from: versionJSON) } #expect(version1_2_3.majorComponent == 1) #expect(version1_2_3.minorComponent == 2) @@ -132,39 +132,39 @@ struct ABIEntryPointTests { #expect(throws: DecodingError.self) { _ = try JSON.withEncoding(of: "not.valid") { versionJSON in - try JSON.decode(ABI.VersionNumber.self, from: versionJSON) + try JSON.decode(VersionNumber.self, from: versionJSON) } } } #endif @Test(arguments: [ - (ABI.VersionNumber(-1, 0), "-1"), - (ABI.VersionNumber(0, 0), "0"), - (ABI.VersionNumber(1, 0), "1.0"), - (ABI.VersionNumber(2, 0), "2.0"), - (ABI.VersionNumber("0.0.1"), "0.0.1"), - (ABI.VersionNumber("0.1.0"), "0.1"), - ]) func abiVersionStringConversion(version: ABI.VersionNumber?, expectedString: String) throws { + (VersionNumber(-1, 0), "-1"), + (VersionNumber(0, 0), "0"), + (VersionNumber(1, 0), "1.0"), + (VersionNumber(2, 0), "2.0"), + (VersionNumber("0.0.1"), "0.0.1"), + (VersionNumber("0.1.0"), "0.1"), + ]) func abiVersionStringConversion(version: VersionNumber?, expectedString: String) throws { let version = try #require(version) #expect(String(describing: version) == expectedString) } @Test func badABIVersionString() { - let version = ABI.VersionNumber("not.valid") + let version = VersionNumber("not.valid") #expect(version == nil) } @Test func abiVersionComparisons() throws { - var versions = [ABI.VersionNumber]() + var versions = [VersionNumber]() for major in 0 ..< 10 { - let version = try #require(ABI.VersionNumber("\(major)")) + let version = try #require(VersionNumber("\(major)")) versions.append(version) for minor in 0 ..< 10 { - let version = try #require(ABI.VersionNumber("\(major).\(minor)")) + let version = try #require(VersionNumber("\(major).\(minor)")) versions.append(version) for patch in 0 ..< 10 { - let version = try #require(ABI.VersionNumber("\(major).\(minor).\(patch)")) + let version = try #require(VersionNumber("\(major).\(minor).\(patch)")) versions.append(version) } } diff --git a/Tests/TestingTests/SwiftPMTests.swift b/Tests/TestingTests/SwiftPMTests.swift index 4a9b70502..3ef0c3378 100644 --- a/Tests/TestingTests/SwiftPMTests.swift +++ b/Tests/TestingTests/SwiftPMTests.swift @@ -235,23 +235,23 @@ struct SwiftPMTests { func deprecatedEventStreamVersionProperty() async throws { var args = __CommandLineArguments_v0() args.eventStreamVersion = 0 - #expect(args.eventStreamVersionNumber == ABI.VersionNumber(0, 0)) + #expect(args.eventStreamVersionNumber == VersionNumber(0, 0)) #expect(args.eventStreamSchemaVersion == "0") args.eventStreamVersion = -1 - #expect(args.eventStreamVersionNumber == ABI.VersionNumber(-1, 0)) + #expect(args.eventStreamVersionNumber == VersionNumber(-1, 0)) #expect(args.eventStreamSchemaVersion == "-1") args.eventStreamVersion = 123 - #expect(args.eventStreamVersionNumber == ABI.VersionNumber(123, 0)) + #expect(args.eventStreamVersionNumber == VersionNumber(123, 0)) #expect(args.eventStreamSchemaVersion == "123.0") - args.eventStreamVersionNumber = ABI.VersionNumber(10, 20, 30) + args.eventStreamVersionNumber = VersionNumber(10, 20, 30) #expect(args.eventStreamVersion == 10) #expect(args.eventStreamSchemaVersion == "10.20.30") args.eventStreamSchemaVersion = "10.20.30" - #expect(args.eventStreamVersionNumber == ABI.VersionNumber(10, 20, 30)) + #expect(args.eventStreamVersionNumber == VersionNumber(10, 20, 30)) #expect(args.eventStreamVersion == 10) #if !SWT_NO_EXIT_TESTS @@ -264,14 +264,24 @@ struct SwiftPMTests { @Test("New-but-not-experimental ABI version") func newButNotExperimentalABIVersion() async throws { - let versionNumber = ABI.VersionNumber(0, 0, 1) + var versionNumber = ABI.CurrentVersion.versionNumber + versionNumber.patchComponent += 1 let version = try #require(ABI.version(forVersionNumber: versionNumber)) #expect(version.versionNumber == ABI.v0.versionNumber) } @Test("Unsupported ABI version") func unsupportedABIVersion() async throws { - let versionNumber = ABI.VersionNumber(-100, 0) + let versionNumber = VersionNumber(-100, 0) + let versionTypeInfo = ABI.version(forVersionNumber: versionNumber).map(TypeInfo.init(describing:)) + #expect(versionTypeInfo == nil) + } + + @Test("Future ABI version (should be nil)") + func futureABIVersion() async throws { + #expect(swiftCompilerVersion >= VersionNumber(6, 1)) + #expect(swiftCompilerVersion < VersionNumber(8, 0), "Swift 8.0 is here! Please update this test.") + let versionNumber = VersionNumber(8, 0) let versionTypeInfo = ABI.version(forVersionNumber: versionNumber).map(TypeInfo.init(describing:)) #expect(versionTypeInfo == nil) } @@ -282,7 +292,7 @@ struct SwiftPMTests { ("--experimental-event-stream-output", "--experimental-event-stream-version", ABI.v0.versionNumber), ("--experimental-event-stream-output", "--experimental-event-stream-version", ABI.v6_3.versionNumber), ]) - func eventStreamOutput(outputArgumentName: String, versionArgumentName: String, version: ABI.VersionNumber) async throws { + func eventStreamOutput(outputArgumentName: String, versionArgumentName: String, version: VersionNumber) async throws { let version = try #require(ABI.version(forVersionNumber: version)) try await eventStreamOutput(outputArgumentName: outputArgumentName, versionArgumentName: versionArgumentName, version: version) } From 0f7437bc2771ce9ab2e643997593ba7772924c6e Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Wed, 30 Jul 2025 09:07:54 -0400 Subject: [PATCH 2/6] Fix glibcVersion clamping --- Sources/Testing/Support/Versions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Testing/Support/Versions.swift b/Sources/Testing/Support/Versions.swift index 361bf2139..eef7adc94 100644 --- a/Sources/Testing/Support/Versions.swift +++ b/Sources/Testing/Support/Versions.swift @@ -195,7 +195,7 @@ let glibcVersion: VersionNumber = { } } - return VersionNumber(majorComponent: major, minorComponent: minor) + return VersionNumber(majorComponent: .init(clamping: major), minorComponent: .init(clampingminor)) }() #endif From fd64d0ef3f13147af919a333e17a33f14fbc43cd Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Wed, 30 Jul 2025 09:13:54 -0400 Subject: [PATCH 3/6] Typo --- Sources/Testing/Support/Versions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Testing/Support/Versions.swift b/Sources/Testing/Support/Versions.swift index eef7adc94..3e56a672a 100644 --- a/Sources/Testing/Support/Versions.swift +++ b/Sources/Testing/Support/Versions.swift @@ -195,7 +195,7 @@ let glibcVersion: VersionNumber = { } } - return VersionNumber(majorComponent: .init(clamping: major), minorComponent: .init(clampingminor)) + return VersionNumber(majorComponent: .init(clamping: major), minorComponent: .init(clamping: minor)) }() #endif From 8eebb3929f3ec162e80a53d0dd631b658b085da5 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Wed, 30 Jul 2025 09:19:35 -0400 Subject: [PATCH 4/6] Substitute stdlib version on non-Apple --- Sources/Testing/Support/Versions.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/Testing/Support/Versions.swift b/Sources/Testing/Support/Versions.swift index 3e56a672a..d60abdeaa 100644 --- a/Sources/Testing/Support/Versions.swift +++ b/Sources/Testing/Support/Versions.swift @@ -168,6 +168,14 @@ let swiftStandardLibraryVersion: VersionNumber? = { /// This value is not part of the public interface of the testing library. var swiftCompilerVersion: VersionNumber { let packedValue = swt_getSwiftCompilerVersion() +#if !SWT_TARGET_OS_APPLE + if packedValue == 0, let swiftStandardLibraryVersion { + // The compiler did not supply its version. This is currently expected on + // non-Darwin targets in particular. Substitute the stdlib version (which + // should generally be aligned on non-Darwin targets.) + return swiftStandardLibraryVersion + } +#endif return VersionNumber( majorComponent: .init((packedValue % 1_000_000_000_000_000) / 1_000_000_000_000), minorComponent: .init((packedValue % 1_000_000_000_000) / 1_000_000_000), From 6d464c80f30ca71f12a2afd14611252e63b2c64e Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Wed, 30 Jul 2025 13:42:56 -0400 Subject: [PATCH 5/6] I guess we don't have a compiler version in the OSS toolchain on Apple platforms either, okay then --- Sources/Testing/Support/Versions.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/Testing/Support/Versions.swift b/Sources/Testing/Support/Versions.swift index d60abdeaa..62193d6c4 100644 --- a/Sources/Testing/Support/Versions.swift +++ b/Sources/Testing/Support/Versions.swift @@ -168,14 +168,12 @@ let swiftStandardLibraryVersion: VersionNumber? = { /// This value is not part of the public interface of the testing library. var swiftCompilerVersion: VersionNumber { let packedValue = swt_getSwiftCompilerVersion() -#if !SWT_TARGET_OS_APPLE if packedValue == 0, let swiftStandardLibraryVersion { // The compiler did not supply its version. This is currently expected on // non-Darwin targets in particular. Substitute the stdlib version (which // should generally be aligned on non-Darwin targets.) return swiftStandardLibraryVersion } -#endif return VersionNumber( majorComponent: .init((packedValue % 1_000_000_000_000_000) / 1_000_000_000_000), minorComponent: .init((packedValue % 1_000_000_000_000) / 1_000_000_000), From 65156e1bc92f219966c0c2095c9d319fc8077565 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Wed, 30 Jul 2025 19:01:56 -0400 Subject: [PATCH 6/6] Lower minimum runtime version in test because CI is still running on an older OS --- Tests/TestingTests/SwiftPMTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/TestingTests/SwiftPMTests.swift b/Tests/TestingTests/SwiftPMTests.swift index 3ef0c3378..3cca1ad55 100644 --- a/Tests/TestingTests/SwiftPMTests.swift +++ b/Tests/TestingTests/SwiftPMTests.swift @@ -279,7 +279,7 @@ struct SwiftPMTests { @Test("Future ABI version (should be nil)") func futureABIVersion() async throws { - #expect(swiftCompilerVersion >= VersionNumber(6, 1)) + #expect(swiftCompilerVersion >= VersionNumber(6, 0)) #expect(swiftCompilerVersion < VersionNumber(8, 0), "Swift 8.0 is here! Please update this test.") let versionNumber = VersionNumber(8, 0) let versionTypeInfo = ABI.version(forVersionNumber: versionNumber).map(TypeInfo.init(describing:))