diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cf2de5..b644380 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: - debug - release xcode: - - '16.0' + - '16.2' name: macOS 15 runs-on: macos-15 steps: @@ -55,7 +55,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Select Xcode - run: sudo xcode-select -s /Applications/Xcode_16.0.app + run: sudo xcode-select -s /Applications/Xcode_16.2.app - name: Run tests run: make build-for-library-evolution @@ -66,7 +66,7 @@ jobs: - Debug - Release xcode: - - '16.0' + - '16.2' name: Examples runs-on: macos-15 steps: @@ -125,8 +125,8 @@ jobs: steps: - uses: compnerd/gha-setup-swift@main with: - branch: swift-5.10-release - tag: 5.10-RELEASE + branch: swift-6.0.3-release + tag: 6.0.3-RELEASE - name: Set long paths run: git config --system core.longpaths true - uses: actions/checkout@v4 diff --git a/Sources/IssueReporting/Documentation.docc/Extensions/withErrorReporting.md b/Sources/IssueReporting/Documentation.docc/Extensions/withErrorReporting.md index d57673e..17466d8 100644 --- a/Sources/IssueReporting/Documentation.docc/Extensions/withErrorReporting.md +++ b/Sources/IssueReporting/Documentation.docc/Extensions/withErrorReporting.md @@ -1,7 +1,7 @@ -# ``IssueReporting/withErrorReporting(_:to:fileID:filePath:line:column:catching:)-89omf`` +# ``IssueReporting/withErrorReporting(_:to:fileID:filePath:line:column:catching:)`` ## Topics ### Overloads -- ``withErrorReporting(_:to:fileID:filePath:line:column:catching:)-3dh1h`` +- ``withErrorReporting(_:to:fileID:filePath:line:column:isolation:catching:)`` diff --git a/Sources/IssueReporting/Documentation.docc/Extensions/withIssueReporters.md b/Sources/IssueReporting/Documentation.docc/Extensions/withIssueReporters.md index e15fcd5..8c1e97f 100644 --- a/Sources/IssueReporting/Documentation.docc/Extensions/withIssueReporters.md +++ b/Sources/IssueReporting/Documentation.docc/Extensions/withIssueReporters.md @@ -1,7 +1,7 @@ -# ``IssueReporting/withIssueReporters(_:operation:)-91179`` +# ``IssueReporting/withIssueReporters(_:operation:)`` ## Topics ### Overloads -- ``withIssueReporters(_:operation:)-6xjha`` +- ``withIssueReporters(_:isolation:operation:)`` diff --git a/Sources/IssueReporting/Documentation.docc/IssueReporting.md b/Sources/IssueReporting/Documentation.docc/IssueReporting.md index 0882572..dc51e5a 100644 --- a/Sources/IssueReporting/Documentation.docc/IssueReporting.md +++ b/Sources/IssueReporting/Documentation.docc/IssueReporting.md @@ -53,7 +53,7 @@ that ship in the same target as the library itself. - ``reportIssue(_:fileID:filePath:line:column:)`` - ``withExpectedIssue(_:isIntermittent:fileID:filePath:line:column:_:)-9pinm`` -- ``withErrorReporting(_:to:fileID:filePath:line:column:catching:)-89omf`` +- ``withErrorReporting(_:to:fileID:filePath:line:column:catching:)`` ### Issue reporters @@ -64,7 +64,7 @@ that ship in the same target as the library itself. ### Custom reporting - ``IssueReporter`` -- ``withIssueReporters(_:operation:)-91179`` +- ``withIssueReporters(_:operation:)`` - ``withIssueContext(fileID:filePath:line:column:operation:)-97lux`` - ``IssueReporters`` diff --git a/Sources/IssueReporting/ErrorReporting.swift b/Sources/IssueReporting/ErrorReporting.swift index 029ce9e..502fea6 100644 --- a/Sources/IssueReporting/ErrorReporting.swift +++ b/Sources/IssueReporting/ErrorReporting.swift @@ -52,42 +52,104 @@ public func withErrorReporting( } } -/// Evaluates a throwing closure and automatically catches and reports any error thrown. -/// -/// - Parameters: -/// - message: A message describing the expectation. -/// - reporters: Issue reporters to notify during the operation. -/// - fileID: The source `#fileID` associated with the error reporting. -/// - filePath: The source `#filePath` associated with the error reporting. -/// - line: The source `#line` associated with the error reporting. -/// - column: The source `#column` associated with the error reporting. -/// - body: An asynchronous operation. -/// - Returns: The optional result of the operation, or `nil` if an error was thrown. -@_transparent -public func withErrorReporting( - _ message: @autoclosure () -> String? = nil, - to reporters: [any IssueReporter]? = nil, - fileID: StaticString = #fileID, - filePath: StaticString = #filePath, - line: UInt = #line, - column: UInt = #column, - catching body: () async throws -> R -) async -> R? { - if let reporters { - return await withIssueReporters(reporters) { +#if compiler(>=6) + /// Evaluates a throwing closure and automatically catches and reports any error thrown. + /// + /// - Parameters: + /// - message: A message describing the expectation. + /// - reporters: Issue reporters to notify during the operation. + /// - fileID: The source `#fileID` associated with the error reporting. + /// - filePath: The source `#filePath` associated with the error reporting. + /// - line: The source `#line` associated with the error reporting. + /// - column: The source `#column` associated with the error reporting. + /// - isolation: The isolation associated with the error reporting. + /// - body: An asynchronous operation. + /// - Returns: The optional result of the operation, or `nil` if an error was thrown. + @_transparent + public func withErrorReporting( + _ message: @autoclosure () -> String? = nil, + to reporters: [any IssueReporter]? = nil, + fileID: StaticString = #fileID, + filePath: StaticString = #filePath, + line: UInt = #line, + column: UInt = #column, + isolation: isolated (any Actor)? = #isolation, + catching body: () async throws -> sending R + ) async -> R? { + if let reporters { + return await withIssueReporters(reporters) { + do { + return try await body() + } catch { + reportIssue( + error, + message(), + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) + return nil + } + } + } else { do { return try await body() } catch { - reportIssue(error, fileID: fileID, filePath: filePath, line: line, column: column) + reportIssue( + error, + message(), + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) return nil } } - } else { - do { - return try await body() - } catch { - reportIssue(error, fileID: fileID, filePath: filePath, line: line, column: column) - return nil + } +#else + @_transparent + @_unsafeInheritExecutor + public func withErrorReporting( + _ message: @autoclosure () -> String? = nil, + to reporters: [any IssueReporter]? = nil, + fileID: StaticString = #fileID, + filePath: StaticString = #filePath, + line: UInt = #line, + column: UInt = #column, + catching body: () async throws -> R + ) async -> R? { + if let reporters { + return await withIssueReporters(reporters) { + do { + return try await body() + } catch { + reportIssue( + error, + message(), + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) + return nil + } + } + } else { + do { + return try await body() + } catch { + reportIssue( + error, + message(), + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) + return nil + } } } -} +#endif diff --git a/Sources/IssueReporting/IssueReporter.swift b/Sources/IssueReporting/IssueReporter.swift index 235f1e8..29672d9 100644 --- a/Sources/IssueReporting/IssueReporter.swift +++ b/Sources/IssueReporting/IssueReporter.swift @@ -183,16 +183,28 @@ public func withIssueReporters( try IssueReporters.$_current.withValue(LockIsolated(reporters), operation: operation) } -/// Overrides the task's issue reporters for the duration of the asynchronous operation. -/// -/// An asynchronous version of ``withIssueReporters(_:operation:)-91179``. -/// -/// - Parameters: -/// - reporters: Issue reporters to notify during the operation. -/// - operation: An asynchronous operation. -public func withIssueReporters( - _ reporters: [any IssueReporter], - operation: () async throws -> R -) async rethrows -> R { - try await IssueReporters.$_current.withValue(LockIsolated(reporters), operation: operation) -} +#if compiler(>=6) + /// Overrides the task's issue reporters for the duration of the asynchronous operation. + /// + /// An asynchronous version of ``withIssueReporters(_:operation:)-91179``. + /// + /// - Parameters: + /// - reporters: Issue reporters to notify during the operation. + /// - isolation: The isolation associated with the operation. + /// - operation: An asynchronous operation. + public func withIssueReporters( + _ reporters: [any IssueReporter], + isolation: isolated (any Actor)? = #isolation, + operation: () async throws -> R + ) async rethrows -> R { + try await IssueReporters.$_current.withValue(LockIsolated(reporters), operation: operation) + } +#else + @_unsafeInheritExecutor + public func withIssueReporters( + _ reporters: [any IssueReporter], + operation: () async throws -> R + ) async rethrows -> R { + try await IssueReporters.$_current.withValue(LockIsolated(reporters), operation: operation) + } +#endif diff --git a/Tests/IssueReportingTests/SwiftTestingTests.swift b/Tests/IssueReportingTests/SwiftTestingTests.swift index 0b63e27..fef8993 100644 --- a/Tests/IssueReportingTests/SwiftTestingTests.swift +++ b/Tests/IssueReportingTests/SwiftTestingTests.swift @@ -1,4 +1,4 @@ -#if canImport(Testing) +#if canImport(Testing) && !os(Windows) import Testing import IssueReporting diff --git a/Tests/IssueReportingTests/UnimplementedTests.swift b/Tests/IssueReportingTests/UnimplementedTests.swift index bff4182..858e30f 100644 --- a/Tests/IssueReportingTests/UnimplementedTests.swift +++ b/Tests/IssueReportingTests/UnimplementedTests.swift @@ -1,4 +1,4 @@ -#if canImport(Testing) +#if canImport(Testing) && !os(Windows) import IssueReporting import Testing diff --git a/Tests/IssueReportingTests/WithErrorReportingTests.swift b/Tests/IssueReportingTests/WithErrorReportingTests.swift index 0e875a6..54d9357 100644 --- a/Tests/IssueReportingTests/WithErrorReportingTests.swift +++ b/Tests/IssueReportingTests/WithErrorReportingTests.swift @@ -1,4 +1,4 @@ -#if canImport(Testing) +#if canImport(Testing) && !os(Windows) import Testing import IssueReporting @@ -21,7 +21,37 @@ issue.description == "Caught error: SomeError(): Failed" } } + + @Test func overload() async { + await withKnownIssue { + await withErrorReporting { () async throws in + throw SomeError() + } + } matching: { issue in + issue.description == "Caught error: SomeError()" + } + + await withKnownIssue { + await withErrorReporting("Failed") { () async throws in + throw SomeError() + } + } matching: { issue in + issue.description == "Caught error: SomeError(): Failed" + } + } + + @MainActor + @Test func isolation() async { + await withKnownIssue { + await withErrorReporting { () async throws in + throw SomeError() + } + } matching: { issue in + issue.description == "Caught error: SomeError()" + } + } } private struct SomeError: Error {} #endif +