From 384df6d3baf858791b138ec7b55629f18903a47a Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Tue, 7 Oct 2025 16:06:04 -0400 Subject: [PATCH 1/4] [ST-NNNN] Adjustments to image attachments in Swift Testing --- .../NNNN-image-attachment-adjustments.md | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 proposals/testing/NNNN-image-attachment-adjustments.md diff --git a/proposals/testing/NNNN-image-attachment-adjustments.md b/proposals/testing/NNNN-image-attachment-adjustments.md new file mode 100644 index 0000000000..093661fd15 --- /dev/null +++ b/proposals/testing/NNNN-image-attachment-adjustments.md @@ -0,0 +1,162 @@ +# Adjustments to image attachments in Swift Testing + +* Proposal: [ST-NNNN](NNNN-image-attachment-adjustments.md) +* Authors: [Jonathan Grynspan](https://github.com/grynspan) +* Review Manager: TBD +* Status: **Awaiting review** +* Implementation: [swiftlang/swift-testing#1359](https://github.com/swiftlang/swift-testing/pull/1359) +* Review: ([pitch](https://forums.swift.org/...)) + +## Introduction + +This proposal includes a small number of adjustments to the API surface of Swift +Testing's image attachments feature introduced in [ST-0014](0014-image-attachments-in-swift-testing-apple-platforms.md) +and [ST-0015](0015-image-attachments-in-swift-testing-windows.md). + +## Motivation + +These changes will help to align the platform-specific interfaces of the feature +more closely. + +## Proposed solution + +The `AttachableAsCGImage` and `AttachableAsIWICBitmapSource` protocols are +combined into a single protocol, `AttachableAsImage` with adjusted protocol +requirements; a change is made to `AttachableImageFormat` to more closely +align its interface between Darwin and Windows; `AttachableImageFormat` is made +to conform to `Equatable` and `Hashable`; and an additional property is added to +`Attachment` to query its image format. + +## Detailed design + +The following changes are proposed: + +### Combining AttachableAsCGImage and AttachableAsIWICBitmapSource + +The `AttachableAsCGImage` and `AttachableAsIWICBitmapSource` protocols are +combined into a single protocol, `AttachableAsImage`. + +These platform-specific requirements are removed: + +```diff +- var attachableCGImage: CGImage { get throws } +- func copyAttachableIWICBitmapSource() throws -> UnsafeMutablePointer +``` + +They are replaced with a new requirement that encapsulates the image encoding +operation. This requirement is implemented by the CoreGraphics and WinSDK +overlays and is made publicly available for test authors who wish to declare +additional conformances to this protocol for types that are not based on +`CGImage` or `IWICBitmapSource`: + +```swift +public protocol AttachableAsImage { + // ... + + /// Encode a representation of this image in a given image format. + /// + /// - Parameters: + /// - imageFormat: The image format to use when encoding this image. + /// - body: A function to call. A temporary buffer containing a data + /// representation of this instance is passed to it. + /// + /// - Returns: Whatever is returned by `body`. + /// + /// - Throws: Whatever is thrown by `body`, or any error that prevented the + /// creation of the buffer. + /// + /// The testing library uses this function when saving an image as an + /// attachment. The implementation should use `imageFormat` to determine what + /// encoder to use. + borrowing func withUnsafeBytes(as imageFormat: AttachableImageFormat, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R +} +``` + +If a developer has an image type that should conform to `AttachableAsImage` and +wraps an instance of `CGImage` or `IWICBitmapSource`, it is straightforward for +them to delegate to that object. For example: + +```swift +import Testing +import CoreGraphics + +struct MyImage { + var cgImage: CGImage + // ... +} + +extension MyImage: AttachableAsImage { + func withUnsafeBytes(as imageFormat: AttachableImageFormat, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R { + try cgImage.withUnsafeBytes(as: imageFormat, body) + } +} +``` + +### Adjusting AttachableImageFormat + +The following Apple-specific `AttachableImageFormat` initializer is renamed so +that its first argument has an explicit label: + +```diff + public struct AttachableImageFormat { + // ... +- public init(_ contentType: UTType, encodingQuality: Float = 1.0) ++ public init(contentType: UTType, encodingQuality: Float = 1.0) + } +``` + +This change makes the type's interface more consistent between Darwin and +Windows (where it has an `init(encoderCLSID:encodingQuality:)` initializer.) + +As well, conformance to `Equatable` and `Hashable` is added: + +```swift +extension AttachableImageFormat: Equatable, Hashable {} +``` + +Conformance to `Equatable` is necessary to correctly implement the +`withUnsafeBytes(as:_:)` protocol requirement mentioned above, and conformance +to `Hashable` is generally useful and straightforward to implement. + +### Adding an imageFormat property to Attachment + +The following property is added to `Attachment` when the attachable value is an +image: + +```swift +extension Attachment where AttachableValue: AttachableWrapper, + AttachableValue.Wrapped: AttachableAsImage { + /// The image format to use when encoding the represented image. + public var imageFormat: AttachableImageFormat? { get } +} +``` + +## Source compatibility + +These changes are breaking for anyone who has created a type that conforms to +either `AttachableAsCGImage` or `AttachableAsIWICBitmapSource`, or anyone who +has adopted `AttachableImageFormat.init(_:encodingQuality:)`. + +This feature is new in Swift 6.3 and has not shipped to developers outside of +nightly toolchain builds. As such, we feel confident that any real-world impact +to developers will be both minimal and manageable. + +## Integration with supporting tools + +No changes. + +## Future directions + +N/A + +## Alternatives considered + +- Leaving the two protocols separate. Combining them allows us to lower more + code into the main Swift Testing library and improves our ability to generate + DocC documentation, while also simplifying the story for developers who want + to use this feature across platforms. + +## Acknowledgments + +Thanks to my colleagues for their feedback on the image attachments feature and +to the Swift community for putting up with the churn! From bc2130df0ad2d65c0fa23a3d2b82a6b37e0cf09d Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Tue, 7 Oct 2025 16:06:04 -0400 Subject: [PATCH 2/4] [ST-NNNN] Adjustments to image attachments in Swift Testing --- .../NNNN-image-attachment-adjustments.md | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 proposals/testing/NNNN-image-attachment-adjustments.md diff --git a/proposals/testing/NNNN-image-attachment-adjustments.md b/proposals/testing/NNNN-image-attachment-adjustments.md new file mode 100644 index 0000000000..600b0d155b --- /dev/null +++ b/proposals/testing/NNNN-image-attachment-adjustments.md @@ -0,0 +1,166 @@ +# Adjustments to image attachments in Swift Testing + +* Proposal: [ST-NNNN](NNNN-image-attachment-adjustments.md) +* Authors: [Jonathan Grynspan](https://github.com/grynspan) +* Review Manager: TBD +* Status: **Awaiting review** +* Implementation: [swiftlang/swift-testing#1359](https://github.com/swiftlang/swift-testing/pull/1359) +* Review: ([pitch](https://forums.swift.org/...)) + +## Introduction + +This proposal includes a small number of adjustments to the API surface of Swift +Testing's image attachments feature introduced in [ST-0014](0014-image-attachments-in-swift-testing-apple-platforms.md) +and [ST-0015](0015-image-attachments-in-swift-testing-windows.md). + +## Motivation + +These changes will help to align the platform-specific interfaces of the feature +more closely. + +## Proposed solution + +The `AttachableAsCGImage` and `AttachableAsIWICBitmapSource` protocols are +combined into a single protocol, `AttachableAsImage` with adjusted protocol +requirements; a change is made to `AttachableImageFormat` to more closely +align its interface between Darwin and Windows; `AttachableImageFormat` is made +to conform to `Equatable` and `Hashable`; and an additional property is added to +`Attachment` to query its image format. + +## Detailed design + +The following changes are proposed: + +### Combining AttachableAsCGImage and AttachableAsIWICBitmapSource + +The `AttachableAsCGImage` and `AttachableAsIWICBitmapSource` protocols are +combined into a single protocol, `AttachableAsImage`. + +These platform-specific requirements are removed: + +```diff +- var attachableCGImage: CGImage { get throws } +- func copyAttachableIWICBitmapSource() throws -> UnsafeMutablePointer +``` + +They are replaced with a new requirement that encapsulates the image encoding +operation. This requirement is implemented by the CoreGraphics and WinSDK +overlays and is made publicly available for test authors who wish to declare +additional conformances to this protocol for types that are not based on +`CGImage` or `IWICBitmapSource`: + +```swift +public protocol AttachableAsImage { + // ... + + /// Encode a representation of this image in a given image format. + /// + /// - Parameters: + /// - imageFormat: The image format to use when encoding this image. + /// - body: A function to call. A temporary buffer containing a data + /// representation of this instance is passed to it. + /// + /// - Returns: Whatever is returned by `body`. + /// + /// - Throws: Whatever is thrown by `body`, or any error that prevented the + /// creation of the buffer. + /// + /// The testing library uses this function when saving an image as an + /// attachment. The implementation should use `imageFormat` to determine what + /// encoder to use. + borrowing func withUnsafeBytes(as imageFormat: AttachableImageFormat, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R +} +``` + +If a developer has an image type that should conform to `AttachableAsImage` and +wraps an instance of `CGImage` or `IWICBitmapSource`, it is straightforward for +them to delegate to that object. For example: + +```swift +import Testing +import CoreGraphics + +struct MyImage { + var cgImage: CGImage + // ... +} + +extension MyImage: AttachableAsImage { + func withUnsafeBytes(as imageFormat: AttachableImageFormat, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R { + try cgImage.withUnsafeBytes(as: imageFormat, body) + } +} +``` + +### Adjusting AttachableImageFormat + +The following Apple-specific `AttachableImageFormat` initializer is renamed so +that its first argument has an explicit label: + +```diff + public struct AttachableImageFormat { + // ... +- public init(_ contentType: UTType, encodingQuality: Float = 1.0) ++ public init(contentType: UTType, encodingQuality: Float = 1.0) + } +``` + +This change makes the type's interface more consistent between Darwin and +Windows (where it has an `init(encoderCLSID:encodingQuality:)` initializer.) + +As well, conformances to `Equatable`, `Hashable`, `CustomStringConvertible`, and +`CustomDebugStringConvertible` are added: + +```swift +extension AttachableImageFormat: Equatable, Hashable {} +extension AttachableImageFormat: CustomStringConvertible, CustomDebugStringConvertible {} +``` + +Conformance to `Equatable` is necessary to correctly implement the +`withUnsafeBytes(as:_:)` protocol requirement mentioned above, and conformance +to `Hashable` is generally useful and straightforward to implement. Conformance +to `CustomStringConvertible` and `CustomDebugStringConvertible` allows for +better diagnostic output (especially if an encoding failure occurs.) + +### Adding an imageFormat property to Attachment + +The following property is added to `Attachment` when the attachable value is an +image: + +```swift +extension Attachment where AttachableValue: AttachableWrapper, + AttachableValue.Wrapped: AttachableAsImage { + /// The image format to use when encoding the represented image. + public var imageFormat: AttachableImageFormat? { get } +} +``` + +## Source compatibility + +These changes are breaking for anyone who has created a type that conforms to +either `AttachableAsCGImage` or `AttachableAsIWICBitmapSource`, or anyone who +has adopted `AttachableImageFormat.init(_:encodingQuality:)`. + +This feature is new in Swift 6.3 and has not shipped to developers outside of +nightly toolchain builds. As such, we feel confident that any real-world impact +to developers will be both minimal and manageable. + +## Integration with supporting tools + +No changes. + +## Future directions + +N/A + +## Alternatives considered + +- Leaving the two protocols separate. Combining them allows us to lower more + code into the main Swift Testing library and improves our ability to generate + DocC documentation, while also simplifying the story for developers who want + to use this feature across platforms. + +## Acknowledgments + +Thanks to my colleagues for their feedback on the image attachments feature and +to the Swift community for putting up with the churn! From 94de61b3bbf1636d517a5926b39aa43787279542 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Mon, 20 Oct 2025 16:49:24 -0400 Subject: [PATCH 3/4] Adjust title --- proposals/testing/NNNN-image-attachment-adjustments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/testing/NNNN-image-attachment-adjustments.md b/proposals/testing/NNNN-image-attachment-adjustments.md index 600b0d155b..21f621fa17 100644 --- a/proposals/testing/NNNN-image-attachment-adjustments.md +++ b/proposals/testing/NNNN-image-attachment-adjustments.md @@ -1,4 +1,4 @@ -# Adjustments to image attachments in Swift Testing +# Consolidate Swift Testing's image attachments API across platforms * Proposal: [ST-NNNN](NNNN-image-attachment-adjustments.md) * Authors: [Jonathan Grynspan](https://github.com/grynspan) From 623c22389e6c30f2b71734f548213cd106e90c6f Mon Sep 17 00:00:00 2001 From: Rachel Brindle Date: Wed, 22 Oct 2025 18:13:52 -0700 Subject: [PATCH 4/4] Begin review of image attachment consolidation - Assign the proposal ST-0017 - Rename the proposal document as appropriate - Update the relevant metadata about the current state of the proposal document --- ...ustments.md => 0017-image-attachment-consolidation.md} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename proposals/testing/{NNNN-image-attachment-adjustments.md => 0017-image-attachment-consolidation.md} (95%) diff --git a/proposals/testing/NNNN-image-attachment-adjustments.md b/proposals/testing/0017-image-attachment-consolidation.md similarity index 95% rename from proposals/testing/NNNN-image-attachment-adjustments.md rename to proposals/testing/0017-image-attachment-consolidation.md index 21f621fa17..c5bff460b5 100644 --- a/proposals/testing/NNNN-image-attachment-adjustments.md +++ b/proposals/testing/0017-image-attachment-consolidation.md @@ -1,11 +1,11 @@ # Consolidate Swift Testing's image attachments API across platforms -* Proposal: [ST-NNNN](NNNN-image-attachment-adjustments.md) +* Proposal: [ST-0017](0017-image-attachment-consolidation.md) * Authors: [Jonathan Grynspan](https://github.com/grynspan) -* Review Manager: TBD -* Status: **Awaiting review** +* Review Manager: [Rachel Brindle](https://github.com/younata) +* Status: **Active Review (October 22-30, 2025)** * Implementation: [swiftlang/swift-testing#1359](https://github.com/swiftlang/swift-testing/pull/1359) -* Review: ([pitch](https://forums.swift.org/...)) +* Review: ([pitch](https://forums.swift.org/t/pitch-adjustments-to-image-attachments-in-swift-testing/82581), Review TBA) ## Introduction