Skip to content

Conversation

Simon-F-AMS
Copy link

@Simon-F-AMS Simon-F-AMS commented Sep 11, 2025

Enhancement: Support Typed Throws

Summary

SpyFactory would use throwableErrorFactory.variableDeclaration(variablePrefix: variablePrefix) to create the throwable error to always be of type (any Error)?.

Main Objective: Support typed throws

Protocol functions with typed throws should result in a throwable error that has the appropriate type in the Spy:

@Spyable
protocol ServiceProtocol {
            func foo(_ added: ((text: String) -> Void)?) throws(ExampleError) -> (() -> Int)?
        }

Should result in a spy:

class ServiceProtocolSpy: ServiceProtocol, @unchecked Sendable {
            init() {
            }
            var fooCallsCount = 0
            var fooCalled: Bool {
                return fooCallsCount > 0
            }
            var fooReceivedAdded: ((text: String) -> Void)?
            var fooReceivedInvocations: [((text: String) -> Void)?] = []
            var fooThrowableError: ExampleError? // Note that this is not (any Error)? anymore
            var fooReturnValue: (() -> Int)?
            var fooClosure: ((((text: String) -> Void)?) throws(ExampleError) -> (() -> Int)?)?
            func foo(_ added: ((text: String) -> Void)?) throws(ExampleError) -> (() -> Int)? {
                fooCallsCount += 1
                fooReceivedAdded = (added)
                fooReceivedInvocations.append((added))
                if let fooThrowableError {
                    throw fooThrowableError // As fooThrowableError now has the correct type, this compiles
                }
                if fooClosure != nil {
                    return try fooClosure!(added)
                } else {
                    return fooReturnValue
                }
            }
        }

Implemented Solution

An additional helper function typedVariableDeclaration(variablePrefix: String, typeSpecifier: String) throws -> VariableDeclSyntax was added to the ThrowableErrorFactory. It distinguishes which function to use by the optional typeSpecifier Parameter that can be passed to variableDeclaration(variablePrefix:, typeSpecifier:)

SpyFactory forwardsfunctionDeclaration.signature.effectSpecifiers?.throwsClause?.type which results in the correct type being set for the error in case the throwing clause is typed

Happy to hear your feedback on this 😊

Copy link

codecov bot commented Sep 21, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.81%. Comparing base (c08b0ed) to head (672206c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #148      +/-   ##
==========================================
+ Coverage   95.58%   95.81%   +0.23%     
==========================================
  Files          22       22              
  Lines        1337     1411      +74     
==========================================
+ Hits         1278     1352      +74     
  Misses         59       59              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant