Skip to content

Merge 'main' branch to 'release/6.2' #1088

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e37b6f9
Revert "Ensure `Locked+Platform.swift` is not stripped when staticall…
grynspan Apr 4, 2025
a2ea8fc
Merge pull request #1050 from swiftlang/jgrynspan/revert-1035
grynspan Apr 5, 2025
1eba9c0
Update the build version to 6.3-dev. (#1052)
grynspan Apr 5, 2025
526ef76
Miscellaneous bookkeeping/cleanup of `_TestDiscovery`. (#1055)
grynspan Apr 7, 2025
1ba4e6f
Use the entire SHA-256 hash as an exit test ID. (#1053)
grynspan Apr 7, 2025
27d09f0
Add signal handler for `SIGABRT_COMPAT` on Windows. (#1056)
grynspan Apr 7, 2025
7907a4a
[Experimental] Add Embedded Swift support to the `_TestDiscovery` tar…
grynspan Apr 8, 2025
6cf0110
Don't use a class to store the current exit test. (#1065)
grynspan Apr 9, 2025
756316c
Fully-qualify reference to Swift's `Actor` protocol in macro expansio…
stmontgomery Apr 9, 2025
45384e5
Promote attachments to API (#973)
grynspan Apr 10, 2025
d8d20a5
Introduce a severity level when recording issues (#1070)
suzannaratcliff Apr 10, 2025
197d6b3
Add support for the `--attachments-path` CLI argument. (#1074)
grynspan Apr 12, 2025
55f82ed
Add `CustomStringConvertible` conformance to `ExitTest.Condition` and…
grynspan Apr 12, 2025
72bed50
Add isFailure to Issue (#1078)
suzannaratcliff Apr 14, 2025
7097c2b
Add `unsafe` keyword handling to macro expansions. (#1069)
grynspan Apr 15, 2025
4e4885d
[Experimental] Capturing values in exit tests (#1040)
grynspan Apr 15, 2025
64789e2
Fix typo in #1040
grynspan Apr 15, 2025
78506a5
Make sure ExitTest.CapturedValue is still sufficiently available for …
grynspan Apr 16, 2025
d75d0e3
Ensure the .whenEmbedded() build setting condition evaluates to false…
stmontgomery Apr 17, 2025
9342542
Relax the alignment requirement for `DiscoverableAsTestContent.Contex…
grynspan Apr 17, 2025
390cb1c
Enable Library Evolution for package-based builds of the _TestDiscove…
stmontgomery Apr 17, 2025
3abbb2b
Update README to reference 6.1 CI jobs instead of 6.0 and add Windows…
stmontgomery Apr 17, 2025
05ae424
Enable experimental 'AllowUnsafeAttribute' feature to continue suppor…
stmontgomery Apr 19, 2025
ef2df0c
Merge remote-tracking branch 'origin/main' into release/6.2
stmontgomery Apr 21, 2025
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
7 changes: 6 additions & 1 deletion Documentation/ABI/JSON.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,19 +188,24 @@ sufficient information to display the event in a human-readable format.
"kind": <event-kind>,
"instant": <instant>, ; when the event occurred
["issue": <issue>,] ; the recorded issue (if "kind" is "issueRecorded")
["attachment": <attachment>,] ; the attachment (if kind is "valueAttached")
"messages": <array:message>,
["testID": <test-id>,]
}

<event-kind> ::= "runStarted" | "testStarted" | "testCaseStarted" |
"issueRecorded" | "testCaseEnded" | "testEnded" | "testSkipped" |
"runEnded" ; additional event kinds may be added in the future
"runEnded" | "valueAttached"; additional event kinds may be added in the future

<issue> ::= {
"isKnown": <bool>, ; is this a known issue or not?
["sourceLocation": <source-location>,] ; where the issue occurred, if known
}

<attachment> ::= {
"path": <string>, ; the absolute path to the attachment on disk
}

<message> ::= {
"symbol": <message-symbol>,
"text": <string>, ; the human-readable text of this message
Expand Down
31 changes: 11 additions & 20 deletions Documentation/ABI/TestContent.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ or a third-party library are inadvertently loaded into the same process. If the
value at `type` does not match the test content record's expected type, the
accessor function must return `false` and must not modify `outValue`.

<!-- TODO: discuss this argument's value in Embedded Swift (no metatypes) -->
When building for **Embedded Swift**, the value passed as `type` by Swift
Testing is unspecified because type metadata pointers are not available in that
environment.
<!-- TODO: specify what they are instead (FQN type name C strings maybe?) -->

[^mightNotBeSwift]: Although this document primarily deals with Swift, the test
content record section is generally language-agnostic. The use of languages
Expand All @@ -146,25 +149,12 @@ The fourth argument to this function, `reserved`, is reserved for future use.
Accessor functions should assume it is `0` and must not access it.

The concrete Swift type of the value written to `outValue`, the type pointed to
by `type`, and the value pointed to by `hint` depend on the kind of record:
by `type`, and the value pointed to by `hint` depend on the kind of record.

- For test or suite declarations (kind `0x74657374`), the accessor produces a
structure of type `Testing.Test.Generator` that the testing library can use
to generate the corresponding test[^notAccessorSignature].

[^notAccessorSignature]: This level of indirection is necessary because
loading a test or suite declaration is an asynchronous operation, but C
functions cannot be `async`.

Test content records of this kind do not specify a type for `hint`. Always
pass `nil`.

- For exit test declarations (kind `0x65786974`), the accessor produces a
structure describing the exit test (of type `Testing.ExitTest`.)

Test content records of this kind accept a `hint` of type `Testing.ExitTest.ID`.
They only produce a result if they represent an exit test declared with the
same ID (or if `hint` is `nil`.)
The record kinds defined by Swift Testing (kinds `0x74657374` and `0x65786974`)
make use of the `DiscoverableAsTestContent` protocol in the `_TestDiscovery`
module and do not publicly expose the types of their accessor functions'
arguments. Do not call the accessor functions for these records directly.

> [!WARNING]
> Calling code should use [`withUnsafeTemporaryAllocation(of:capacity:_:)`](https://developer.apple.com/documentation/swift/withunsafetemporaryallocation(of:capacity:_:))
Expand Down Expand Up @@ -271,7 +261,8 @@ extension FoodTruckDiagnostic: DiscoverableAsTestContent {
```

If you customize `TestContentContext`, be aware that the type you specify must
have the same stride and alignment as `UInt`.
have the same stride as `UInt` and must have an alignment less than or equal to
that of `UInt`.

When you are done configuring your type's protocol conformance, you can then
enumerate all test content records matching it as instances of
Expand Down
138 changes: 116 additions & 22 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// swift-tools-version: 6.0
// swift-tools-version: 6.1

//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Copyright (c) 2023–2025 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
Expand All @@ -20,17 +20,49 @@ let git = Context.gitInformation
/// distribution as a package dependency.
let buildingForDevelopment = (git?.currentTag == nil)

/// Whether or not this package is being built for Embedded Swift.
///
/// This value is `true` if `SWT_EMBEDDED` is set in the environment to `true`
/// when `swift build` is invoked. This inference is experimental and is subject
/// to change in the future.
///
/// - Bug: There is currently no way for us to tell if we are being asked to
/// build for an Embedded Swift target at the package manifest level.
/// ([swift-syntax-#8431](https://github.com/swiftlang/swift-package-manager/issues/8431))
let buildingForEmbedded: Bool = {
guard let envvar = Context.environment["SWT_EMBEDDED"] else {
return false
}
return Bool(envvar) ?? ((Int(envvar) ?? 0) != 0)
}()

let package = Package(
name: "swift-testing",

platforms: [
.macOS(.v10_15),
.iOS(.v13),
.watchOS(.v6),
.tvOS(.v13),
.macCatalyst(.v13),
.visionOS(.v1),
],
platforms: {
if !buildingForEmbedded {
[
.macOS(.v10_15),
.iOS(.v13),
.watchOS(.v6),
.tvOS(.v13),
.macCatalyst(.v13),
.visionOS(.v1),
]
} else {
// Open-source main-branch toolchains (currently required to build this
// package for Embedded Swift) have higher Apple platform deployment
// targets than we would otherwise require.
[
.macOS(.v14),
.iOS(.v18),
.watchOS(.v10),
.tvOS(.v18),
.macCatalyst(.v18),
.visionOS(.v1),
]
}
}(),

products: {
var result = [Product]()
Expand Down Expand Up @@ -63,8 +95,15 @@ let package = Package(
return result
}(),

traits: [
.trait(
name: "ExperimentalExitTestValueCapture",
description: "Enable experimental support for capturing values in exit tests"
),
],

dependencies: [
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "601.0.0-latest"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "602.0.0-latest"),
],

targets: [
Expand Down Expand Up @@ -132,7 +171,7 @@ let package = Package(
dependencies: ["_TestingInternals",],
exclude: ["CMakeLists.txt"],
cxxSettings: .packageSettings,
swiftSettings: .packageSettings
swiftSettings: .packageSettings + .enableLibraryEvolution()
),

// Cross-import overlays (not supported by Swift Package Manager)
Expand Down Expand Up @@ -185,6 +224,32 @@ package.targets.append(contentsOf: [
])
#endif

extension BuildSettingCondition {
/// Creates a build setting condition that evaluates to `true` for Embedded
/// Swift.
///
/// - Parameters:
/// - nonEmbeddedCondition: The value to return if the target is not
/// Embedded Swift. If `nil`, the build condition evaluates to `false`.
///
/// - Returns: A build setting condition that evaluates to `true` for Embedded
/// Swift or is equal to `nonEmbeddedCondition` for non-Embedded Swift.
static func whenEmbedded(or nonEmbeddedCondition: @autoclosure () -> Self? = nil) -> Self? {
if !buildingForEmbedded {
if let nonEmbeddedCondition = nonEmbeddedCondition() {
nonEmbeddedCondition
} else {
// The caller did not supply a fallback. Specify a non-existent platform
// to ensure this condition never matches.
.when(platforms: [.custom("DoesNotExist")])
}
} else {
// Enable unconditionally because the target is Embedded Swift.
nil
}
}
}

extension Array where Element == PackageDescription.SwiftSetting {
/// Settings intended to be applied to every Swift target in this package.
/// Analogous to project-level build settings in an Xcode project.
Expand All @@ -195,6 +260,10 @@ extension Array where Element == PackageDescription.SwiftSetting {
result.append(.unsafeFlags(["-require-explicit-sendable"]))
}

if buildingForEmbedded {
result.append(.enableExperimentalFeature("Embedded"))
}

result += [
.enableUpcomingFeature("ExistentialAny"),

Expand All @@ -208,19 +277,41 @@ extension Array where Element == PackageDescription.SwiftSetting {
// proposal via Swift Evolution.
.enableExperimentalFeature("SymbolLinkageMarkers"),

// This setting is no longer needed when building with a 6.2 or later
// toolchain now that SE-0458 has been accepted and implemented, but it is
// needed in order to preserve support for building with 6.1 development
// snapshot toolchains. (Production 6.1 toolchains can build the testing
// library even without this setting since this experimental feature is
// _suppressible_.) This setting can be removed once the minimum supported
// toolchain for building the testing library is ≥ 6.2. It is not needed
// in the CMake settings since that is expected to build using a
// new-enough toolchain.
.enableExperimentalFeature("AllowUnsafeAttribute"),

// When building as a package, the macro plugin always builds as an
// executable rather than a library.
.define("SWT_NO_LIBRARY_MACRO_PLUGINS"),

.define("SWT_TARGET_OS_APPLE", .when(platforms: [.macOS, .iOS, .macCatalyst, .watchOS, .tvOS, .visionOS])),

.define("SWT_NO_EXIT_TESTS", .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android])),
.define("SWT_NO_PROCESS_SPAWNING", .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android])),
.define("SWT_NO_SNAPSHOT_TYPES", .when(platforms: [.linux, .custom("freebsd"), .openbsd, .windows, .wasi, .android])),
.define("SWT_NO_DYNAMIC_LINKING", .when(platforms: [.wasi])),
.define("SWT_NO_PIPES", .when(platforms: [.wasi])),
.define("SWT_NO_EXIT_TESTS", .whenEmbedded(or: .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android]))),
.define("SWT_NO_PROCESS_SPAWNING", .whenEmbedded(or: .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android]))),
.define("SWT_NO_SNAPSHOT_TYPES", .whenEmbedded(or: .when(platforms: [.linux, .custom("freebsd"), .openbsd, .windows, .wasi, .android]))),
.define("SWT_NO_DYNAMIC_LINKING", .whenEmbedded(or: .when(platforms: [.wasi]))),
.define("SWT_NO_PIPES", .whenEmbedded(or: .when(platforms: [.wasi]))),

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

// Unconditionally enable 'ExperimentalExitTestValueCapture' when building
// for development.
if buildingForDevelopment {
result += [
.define("ExperimentalExitTestValueCapture")
]
}

return result
}

Expand Down Expand Up @@ -271,11 +362,14 @@ extension Array where Element == PackageDescription.CXXSetting {
var result = Self()

result += [
.define("SWT_NO_EXIT_TESTS", .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android])),
.define("SWT_NO_PROCESS_SPAWNING", .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android])),
.define("SWT_NO_SNAPSHOT_TYPES", .when(platforms: [.linux, .custom("freebsd"), .openbsd, .windows, .wasi, .android])),
.define("SWT_NO_DYNAMIC_LINKING", .when(platforms: [.wasi])),
.define("SWT_NO_PIPES", .when(platforms: [.wasi])),
.define("SWT_NO_EXIT_TESTS", .whenEmbedded(or: .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android]))),
.define("SWT_NO_PROCESS_SPAWNING", .whenEmbedded(or: .when(platforms: [.iOS, .watchOS, .tvOS, .visionOS, .wasi, .android]))),
.define("SWT_NO_SNAPSHOT_TYPES", .whenEmbedded(or: .when(platforms: [.linux, .custom("freebsd"), .openbsd, .windows, .wasi, .android]))),
.define("SWT_NO_DYNAMIC_LINKING", .whenEmbedded(or: .when(platforms: [.wasi]))),
.define("SWT_NO_PIPES", .whenEmbedded(or: .when(platforms: [.wasi]))),

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

// Capture the testing library's version as a C++ string constant.
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ very best ideas, from anywhere, can help shape the future of testing in Swift.
The table below describes the current level of support that Swift Testing has
for various platforms:

| **Platform** | **CI Status (6.0)** | **CI Status (main)** | **Support Status** |
| **Platform** | **CI Status (6.1)** | **CI Status (main)** | **Support Status** |
|---|:-:|:-:|---|
| **macOS** | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-6.0-macos)](https://ci.swift.org/job/swift-testing-main-swift-6.0-macos/) | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-main-macos)](https://ci.swift.org/view/Swift%20Packages/job/swift-testing-main-swift-main-macos/) | Supported |
| **macOS** | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-6.1-macos)](https://ci.swift.org/job/swift-testing-main-swift-6.1-macos/) | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-main-macos)](https://ci.swift.org/view/Swift%20Packages/job/swift-testing-main-swift-main-macos/) | Supported |
| **iOS** | | | Supported |
| **watchOS** | | | Supported |
| **tvOS** | | | Supported |
| **visionOS** | | | Supported |
| **Ubuntu 22.04** | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-6.0-linux)](https://ci.swift.org/job/swift-testing-main-swift-6.0-linux/) | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-main-linux)](https://ci.swift.org/view/Swift%20Packages/job/swift-testing-main-swift-main-linux/) | Supported |
| **Windows** | | [![Build Status](https://ci-external.swift.org/buildStatus/icon?job=swift-testing-main-swift-main-windows)](https://ci-external.swift.org/job/swift-testing-main-swift-main-windows/) | Supported |
| **Ubuntu 22.04** | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-6.1-linux)](https://ci.swift.org/job/swift-testing-main-swift-6.1-linux/) | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-main-linux)](https://ci.swift.org/view/Swift%20Packages/job/swift-testing-main-swift-main-linux/) | Supported |
| **Windows** | [![Build Status](https://ci.swift.org/buildStatus/icon?job=swift-testing-main-swift-6.1-windows)](https://ci-external.swift.org/view/all/job/swift-testing-main-swift-6.1-windows/) | [![Build Status](https://ci-external.swift.org/buildStatus/icon?job=swift-testing-main-swift-main-windows)](https://ci-external.swift.org/job/swift-testing-main-swift-main-windows/) | Supported |
| **Wasm** | | | Experimental |

### Works with XCTest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ extension Attachment {
contentType: (any Sendable)?,
encodingQuality: Float,
sourceLocation: SourceLocation
) where AttachableValue == _AttachableImageContainer<T> {
let imageContainer = _AttachableImageContainer(image: attachableValue, encodingQuality: encodingQuality, contentType: contentType)
self.init(imageContainer, named: preferredName, sourceLocation: sourceLocation)
) where AttachableValue == _AttachableImageWrapper<T> {
let imageWrapper = _AttachableImageWrapper(image: attachableValue, encodingQuality: encodingQuality, contentType: contentType)
self.init(imageWrapper, named: preferredName, sourceLocation: sourceLocation)
}

/// Initialize an instance of this type that encloses the given image.
Expand Down Expand Up @@ -79,7 +79,7 @@ extension Attachment {
as contentType: UTType?,
encodingQuality: Float = 1.0,
sourceLocation: SourceLocation = #_sourceLocation
) where AttachableValue == _AttachableImageContainer<T> {
) where AttachableValue == _AttachableImageWrapper<T> {
self.init(attachableValue: attachableValue, named: preferredName, contentType: contentType, encodingQuality: encodingQuality, sourceLocation: sourceLocation)
}

Expand Down Expand Up @@ -109,7 +109,7 @@ extension Attachment {
named preferredName: String? = nil,
encodingQuality: Float = 1.0,
sourceLocation: SourceLocation = #_sourceLocation
) where AttachableValue == _AttachableImageContainer<T> {
) where AttachableValue == _AttachableImageWrapper<T> {
self.init(attachableValue: attachableValue, named: preferredName, contentType: nil, encodingQuality: encodingQuality, sourceLocation: sourceLocation)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//

#if SWT_TARGET_OS_APPLE && canImport(CoreGraphics)
@_spi(Experimental) public import Testing
public import Testing
private import CoreGraphics

private import ImageIO
Expand Down Expand Up @@ -48,7 +48,7 @@ import UniformTypeIdentifiers
///
/// - [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage)
@_spi(Experimental)
public struct _AttachableImageContainer<Image>: Sendable where Image: AttachableAsCGImage {
public struct _AttachableImageWrapper<Image>: Sendable where Image: AttachableAsCGImage {
/// The underlying image.
///
/// `CGImage` and `UIImage` are sendable, but `NSImage` is not. `NSImage`
Expand Down Expand Up @@ -127,8 +127,8 @@ public struct _AttachableImageContainer<Image>: Sendable where Image: Attachable

// MARK: -

extension _AttachableImageContainer: AttachableContainer {
public var attachableValue: Image {
extension _AttachableImageWrapper: AttachableWrapper {
public var wrappedValue: Image {
image
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//

#if canImport(Foundation)
@_spi(Experimental) public import Testing
public import Testing
public import Foundation

// This implementation is necessary to let the compiler disambiguate when a type
Expand All @@ -18,7 +18,9 @@ public import Foundation
// (which explicitly document what happens when a type conforms to both
// protocols.)

@_spi(Experimental)
/// @Metadata {
/// @Available(Swift, introduced: 6.2)
/// }
extension Attachable where Self: Encodable & NSSecureCoding {
@_documentation(visibility: private)
public func withUnsafeBytes<R>(for attachment: borrowing Attachment<Self>, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R {
Expand Down
Loading