Skip to content
Merged
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
29 changes: 29 additions & 0 deletions .github/workflows/automerge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# In the first period after creating a new release branch, we often want to
# continue including all changes from `main` into the release branch. This
# workflow automatically creates a PR to merge main into the release branch on a
# set schedule, and it can also be invoked manually.
#
# Later in the release cycle we generally stop this practice to avoid landing
# risky changes. To disable the workflow when ready, follow the steps described
# in https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/disabling-and-enabling-a-workflow

name: Create PR to merge main into release branch

permissions:
contents: read
on:
schedule:
- cron: '0 9 * * MON'
workflow_dispatch:
jobs:
create_merge_pr:
name: Create PR to merge main into release branch
uses: swiftlang/github-workflows/.github/workflows/create_automerge_pr.yml@main
with:
head_branch: main
base_branch: release/6.3
permissions:
contents: write
pull-requests: write
# Ensure that we don't run this on a schedule in a fork
if: (github.event_name == 'schedule' && github.repository == 'swiftlang/swift-testing') || (github.event_name != 'schedule')
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,6 @@ extension AttachableImageFormat {
/// @Metadata {
/// @Available(Swift, introduced: 6.3)
/// }
#if compiler(>=6.3) && !SWT_FIXED_84466
@_spi(_)
#endif
public var encoderCLSID: CLSID {
kind.encoderCLSID
}
Expand All @@ -223,9 +220,6 @@ extension AttachableImageFormat {
/// @Metadata {
/// @Available(Swift, introduced: 6.3)
/// }
#if compiler(>=6.3) && !SWT_FIXED_84466
@_spi(_)
#endif
public init(encoderCLSID: CLSID, encodingQuality: Float = 1.0) {
let encoderCLSID = CLSID.Wrapper(encoderCLSID)
let kind: Kind = if encoderCLSID == CLSID.Wrapper(CLSID_WICPngEncoder) {
Expand Down
16 changes: 2 additions & 14 deletions Sources/Testing/Attachments/Attachment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,6 @@ private import _TestingInternals
/// record the attachment, call ``Attachment/record(_:sourceLocation:)``.
/// Alternatively, pass your attachable value directly to ``Attachment/record(_:named:sourceLocation:)``.
///
/// By default, the testing library saves your attachments as soon as you call
/// ``Attachment/record(_:sourceLocation:)`` or
/// ``Attachment/record(_:named:sourceLocation:)``. You can access saved
/// attachments after your tests finish running:
///
/// - When using Xcode, you can access attachments from the test report.
/// - When using Visual Studio Code, the testing library saves attachments to
/// `.build/attachments` by default. Visual Studio Code reports the paths to
/// individual attachments in its Tests Results panel.
/// - When using Swift Package Manager's `swift test` command, you can pass the
/// `--attachments-path` option. The testing library saves attachments to the
/// specified directory.
///
/// @Metadata {
/// @Available(Swift, introduced: 6.2)
/// @Available(Xcode, introduced: 26.0)
Expand Down Expand Up @@ -104,7 +91,8 @@ public struct Attachment<AttachableValue> where AttachableValue: Attachable & ~C
///
/// The value of this property is used when recording issues associated with
/// the attachment.
var sourceLocation: SourceLocation
@_spi(ForToolsIntegrationOnly)
public internal(set) var sourceLocation: SourceLocation
}

extension Attachment: Sendable where AttachableValue: Sendable {}
Expand Down
15 changes: 3 additions & 12 deletions Sources/Testing/Attachments/Images/AttachableAsImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,9 @@
/// Instead, the testing library provides additional initializers on [`Attachment`](https://developer.apple.com/documentation/testing/attachment)
/// that take instances of such types and handle converting them to image data when needed.
///
/// You can attach instances of the following system-provided image types to a
/// test:
///
/// | Platform | Supported Types |
/// |-|-|
/// | macOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`NSImage`](https://developer.apple.com/documentation/appkit/nsimage) |
/// | iOS, watchOS, tvOS, and visionOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`UIImage`](https://developer.apple.com/documentation/uikit/uiimage) |
/// | Windows | [`HBITMAP`](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmaps), [`HICON`](https://learn.microsoft.com/en-us/windows/win32/menurc/icons), [`IWICBitmapSource`](https://learn.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicbitmapsource) (including its subclasses declared by Windows Imaging Component) |
///
/// You do not generally need to add your own conformances to this protocol. If
/// you have an image in another format that needs to be attached to a test,
/// first convert it to an instance of one of the types above.
/// You do not generally need to add your own conformances to this protocol. For
/// a list of types that automatically conform to this protocol, see
/// <doc:Attachments#Attach-images>.
///
/// @Metadata {
/// @Available(Swift, introduced: 6.3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
/// instance of this type, the testing library infers which format to use based
/// on the attachment's preferred name.
///
/// The PNG and JPEG image formats are always supported. The set of additional
/// supported image formats is platform-specific:
/// The testing library always supports the PNG and JPEG image formats. The set
/// of additional supported image formats is platform-specific:
///
/// - On Apple platforms, you can use [`CGImageDestinationCopyTypeIdentifiers()`](https://developer.apple.com/documentation/imageio/cgimagedestinationcopytypeidentifiers())
/// from the [Image I/O framework](https://developer.apple.com/documentation/imageio)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,6 @@ extension Attachment {
/// This value is used when recording issues associated with the
/// attachment.
///
/// You can attach instances of the following system-provided image types to a
/// test:
///
/// | Platform | Supported Types |
/// |-|-|
/// | macOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`NSImage`](https://developer.apple.com/documentation/appkit/nsimage) |
/// | iOS, watchOS, tvOS, and visionOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`UIImage`](https://developer.apple.com/documentation/uikit/uiimage) |
/// | Windows | [`HBITMAP`](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmaps), [`HICON`](https://learn.microsoft.com/en-us/windows/win32/menurc/icons), [`IWICBitmapSource`](https://learn.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicbitmapsource) (including its subclasses declared by Windows Imaging Component) |
///
/// The testing library uses the image format specified by `imageFormat`. Pass
/// `nil` to let the testing library decide which image format to use. If you
/// pass `nil`, then the image format that the testing library uses depends on
Expand Down Expand Up @@ -70,22 +61,14 @@ extension Attachment {
/// - sourceLocation: The source location of the call to this function.
///
/// This function creates a new instance of ``Attachment`` wrapping `image`
/// and immediately attaches it to the current test. You can attach instances
/// of the following system-provided image types to a test:
///
/// | Platform | Supported Types |
/// |-|-|
/// | macOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`NSImage`](https://developer.apple.com/documentation/appkit/nsimage) |
/// | iOS, watchOS, tvOS, and visionOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`UIImage`](https://developer.apple.com/documentation/uikit/uiimage) |
/// | Windows | [`HBITMAP`](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmaps), [`HICON`](https://learn.microsoft.com/en-us/windows/win32/menurc/icons), [`IWICBitmapSource`](https://learn.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicbitmapsource) (including its subclasses declared by Windows Imaging Component) |
///
/// The testing library uses the image format specified by `imageFormat`. Pass
/// `nil` to let the testing library decide which image format to use. If you
/// pass `nil`, then the image format that the testing library uses depends on
/// the path extension you specify in `preferredName`, if any. If you do not
/// specify a path extension, or if the path extension you specify doesn't
/// correspond to an image format the operating system knows how to write, the
/// testing library selects an appropriate image format for you.
/// and immediately attaches it to the current test. The testing library uses
/// the image format that `imageFormat` specifies. Pass `nil` to let the testing
/// library select which image format to use. If you pass `nil`, the
/// image format that the testing library uses depends on the path extension
/// you specify in `preferredName`, if any. If you don't specify a path
/// extension, or if the path extension you specify doesn't correspond to an
/// image format the operating system knows how to write, the testing library
/// selects an appropriate image format for you.
///
/// @Metadata {
/// @Available(Swift, introduced: 6.3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,6 @@
//

/// A wrapper type for images that can be indirectly attached to a test.
///
/// You can attach instances of the following system-provided image types to a
/// test:
///
/// | Platform | Supported Types |
/// |-|-|
/// | macOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`NSImage`](https://developer.apple.com/documentation/appkit/nsimage) |
/// | iOS, watchOS, tvOS, and visionOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`UIImage`](https://developer.apple.com/documentation/uikit/uiimage) |
/// | Windows | [`HBITMAP`](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmaps), [`HICON`](https://learn.microsoft.com/en-us/windows/win32/menurc/icons), [`IWICBitmapSource`](https://learn.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicbitmapsource) (including its subclasses declared by Windows Imaging Component) |
#if SWT_NO_IMAGE_ATTACHMENTS
@_unavailableInEmbedded
@available(*, unavailable, message: "Image attachments are not available on this platform.")
Expand Down
173 changes: 173 additions & 0 deletions Sources/Testing/Testing.docc/Attachments.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,179 @@ Attach values to tests to help diagnose issues and gather feedback.
Attach values such as strings and files to tests. Implement the ``Attachable``
protocol to create your own attachable types.

### Attach data or strings

If your test produces encoded data that you want to save as an attachment, you
can call ``Attachment/record(_:named:sourceLocation:)``.

```swift
struct SalesReport { ... }

@Test func `sales report adds up`() async throws {
let salesReport = await generateSalesReport()
try salesReport.validate()
let bytes: [UInt8] = try salesReport.convertToCSV()
Attachment.record(bytes, named: "sales report.csv")
}
```

You can attach an instance of [`Array<UInt8>`](https://developer.apple.com/documentation/swift/array),
[`ContiguousArray<UInt8>`](https://developer.apple.com/documentation/swift/contiguousarray),
[`ArraySlice<UInt8>`](https://developer.apple.com/documentation/swift/arrayslice),
or [`Data`](https://developer.apple.com/documentation/foundation/data) because
these types automatically conform to ``Attachable``.

You can also attach an instance of [`String`](https://developer.apple.com/documentation/swift/string)
or [`Substring`](https://developer.apple.com/documentation/swift/substring). The
testing library treats attached strings as UTF-8 text
files. If you want to save a string as an attachment using a different encoding,
convert it to [`Data`](https://developer.apple.com/documentation/foundation/data)
using [`data(using:allowLossyConversion:)`](https://developer.apple.com/documentation/swift/stringprotocol/data(using:allowlossyconversion:))
and attach the resulting data instead of the original string.

### Attach encodable values

If you have a value you want to save as an attachment that conforms to either
[`Encodable`](https://developer.apple.com/documentation/swift/encodable) or
[`NSSecureCoding`](https://developer.apple.com/documentation/foundation/nssecurecoding),
you can extend it to add conformance to ``Attachable``. When you import the
[Foundation](https://developer.apple.com/documentation/foundation) module, the
testing library automatically provides a default implementation of
``Attachable`` to types that also conform to [`Encodable`](https://developer.apple.com/documentation/swift/encodable)
or [`NSSecureCoding`](https://developer.apple.com/documentation/foundation/nssecurecoding).

```swift
import Testing
import Foundation

struct SalesReport { ... }
extension SalesReport: Encodable, Attachable {}

@Test func `sales report adds up`() async throws {
let salesReport = await generateSalesReport()
try salesReport.validate()
Attachment.record(salesReport, named: "sales report.json")
}
```

- Important: The testing library provides these default implementations only if
your test target imports the [Foundation](https://developer.apple.com/documentation/foundation)
module.

### Attach images

You can attach instances of the following system-provided image types to a test:

| Platform | Supported types |
|-|-|
| macOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`NSImage`](https://developer.apple.com/documentation/appkit/nsimage) |
| iOS, tvOS, and visionOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`UIImage`](https://developer.apple.com/documentation/uikit/uiimage) |
| watchOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`UIImage`](https://developer.apple.com/documentation/uikit/uiimage) |
| Windows | [`HBITMAP`](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmaps), [`HICON`](https://learn.microsoft.com/en-us/windows/win32/menurc/icons), [`IWICBitmapSource`](https://learn.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicbitmapsource) (including its subclasses declared by Windows Imaging Component) |

When you attach an image to a test, you can specify the image format to use in
addition to a preferred name.

```swift
struct SalesReport { ... }

@Test func `sales report adds up`() async throws {
let salesReport = await generateSalesReport()
let image = try salesReport.renderTrendsGraph()
Attachment.record(image, named: "sales report", as: .png)
}
```

If you don't specify an image format when attaching an image to a test, the
testing library selects the format to use based on the preferred name you pass.

### Attach other values

If you have a value that needs a custom encoded representation when you save it
as an attachment, implement ``Attachable/withUnsafeBytes(for:_:)``. The
implementation of this function calls its `body` argument and passes the encoded
representation of `self` or, if a failure occurs, throws an error representing
that failure.

```swift
struct SalesReport { ... }

extension SalesReport: Attachable {
borrowing func withUnsafeBytes<R>(
for attachment: borrowing Attachment<Self>,
_ body: (UnsafeRawBufferPointer) throws -> R
) throws -> R {
let bytes = try salesReport.convertToCSV() // might fail to convert to CSV
try bytes.withUnsafeBytes { buffer in // rethrows any error from `body`
try body(buffer)
}
}
}
```

If your type conforms to [`Sendable`](https://developer.apple.com/documentation/swift/sendable),
the testing library avoids calling this function until it needs to save the
attachment. If your type _doesn't_ conform to [`Sendable`](https://developer.apple.com/documentation/swift/sendable),
the testing library calls this function as soon as you record the attachment.

#### Customize attachment behavior

If you can reliably estimate in advance how large the encoded representation
will be, implement ``Attachable/estimatedAttachmentByteCount``. The testing
library uses the value of this property as a hint to optimize memory and disk
usage.

```swift
extension SalesReport: Attachable {
...

var estimatedAttachmentByteCount: Int? {
return self.entries.count * 123
}
}
```

You can also implement ``Attachable/preferredName(for:basedOn:)`` if you want to
customize the name of the attachment when saving it.

```swift
extension SalesReport: Attachable {
...

borrowing func preferredName(
for attachment: borrowing Attachment<Self>,
basedOn suggestedName: String
) -> String {
if suggestedName.contains(".") {
// The name already contains a path extension, so don't append another.
return suggestedName
}

// Append ".csv" to the name so the resulting file opens as a spreadsheet.
return "\(suggestedName).csv"
}
}
```

### Inspect attachments after a test run ends

By default, the testing library saves your attachments as soon as you call
``Attachment/record(_:sourceLocation:)`` or
``Attachment/record(_:named:sourceLocation:)``. You can access saved attachments
after your tests finish running:

- When using Xcode, you can access attachments from the test report.
- When using Visual Studio Code, the testing library saves attachments to
`.build/attachments` by default. Visual Studio Code reports the paths to
individual attachments in its Tests Results panel.
- When using Swift Package Manager's `swift test` command, you can pass the
`--attachments-path` option. The testing library saves attachments to the
specified directory.

If you do not pass the `--attachments-path` option, the testing library does
not save any attachments you record.


## Topics

### Attaching values to tests
Expand Down
Loading