ios/TestHelpers/Support/InvocationMocker.swift
2025-10-06 15:18:35 -05:00

176 lines
6.5 KiB
Swift

import Foundation
import XCTest
/// Errors that the invocation mockers can throw.
public enum InvocationMockerError: LocalizedError {
case paramVerificationFailed
case resultNotSet
public var errorDescription: String? {
switch self {
case .paramVerificationFailed:
"The verification of the parameter failed."
case .resultNotSet:
"The result of the InvocationMocker has not been set yet."
}
}
}
/// A mocker of a func invocation that has one parameter.
/// This is useful for tests where we need to verify a correct parameter is passed on invocation.
public class InvocationMocker<TParam> {
/// The parameter that was invoked.
public var invokedParam: TParam?
/// Whether or not the mock was called.
public var called = false
/// Initialize an `InvocationMocker`.
///
public init() {}
/// Executes the `verification` and if it passes returns the `result`, throwing otherwise.
/// - Parameter param: The parameter of the function to invoke.
/// - Returns: Returns the result setup.
public func invoke(param: TParam?) {
called = true
invokedParam = param
}
/// Asserts by verifying the parameter which was passed to the invoked function.
/// - Parameters:
/// - verification: Verification to run.
/// - message: Message if fails.
/// - file: File where this was originated.
/// - line: Line number where this was originated.
public func assert(
verification: (TParam?) -> Bool,
_ message: @autoclosure () -> String = "\(TParam.self) verification failed",
file: StaticString = #filePath,
line: UInt = #line,
) {
XCTAssert(verification(invokedParam), message(), file: file, line: line)
}
/// Asserts by verifying the parameter which was passed to the invoked function.
/// This unwraps the parameter, but if can't be done then fails.
/// - Parameters:
/// - verification: Verification to run.
/// - message: Message if fails.
/// - file: File where this was originated.
/// - line: Line number where this was originated.
public func assertUnwrapping(
verification: (TParam) -> Bool,
_ message: @autoclosure () -> String = "\(TParam.self) verification failed",
file: StaticString = #filePath,
line: UInt = #line,
) {
guard let invokedParam else {
XCTFail("\(TParam.self) verification failed because parameter has not been set.")
return
}
XCTAssert(verification(invokedParam), message(), file: file, line: line)
}
}
/// A mocker of a func invocation that has one parameter, a result and can throw.
/// This is useful for tests where we need to verify a correct parameter is passed
/// to return the correct result.
public class InvocationMockerWithThrowingResult<TParam, TResult> {
/// Whether or not the mock was called.
public var called = false
/// What parameter the mock was invoked with.
public var invokedParam: TParam?
var result: (TParam) throws -> TResult = { _ in throw InvocationMockerError.resultNotSet }
var verification: (TParam) -> Bool = { _ in true }
/// Initialize an `InvocationMockerWithThrowingResult`.
///
public init() {}
/// Asserts by verifying the parameter which was passed to the invoked function.
/// - Parameters:
/// - verification: Verification to run.
/// - message: Message if fails.
/// - file: File where this was originated.
/// - line: Line number where this was originated.
func assert(
verification: (TParam?) -> Bool,
_ message: @autoclosure () -> String = "\(TParam.self) verification failed",
file: StaticString = #filePath,
line: UInt = #line,
) {
XCTAssert(verification(invokedParam), message(), file: file, line: line)
}
/// Asserts by verifying the parameter which was passed to the invoked function.
/// This unwraps the parameter, but if can't be done then fails.
/// - Parameters:
/// - verification: Verification to run.
/// - message: Message if fails.
/// - file: File where this was originated.
/// - line: Line number where this was originated.
public func assertUnwrapping(
verification: (TParam) -> Bool,
_ message: @autoclosure () -> String = "\(TParam.self) verification failed",
file: StaticString = #filePath,
line: UInt = #line,
) {
guard let invokedParam else {
XCTFail("\(TParam.self) verification failed because parameter has not been set.")
return
}
XCTAssert(verification(invokedParam), message(), file: file, line: line)
}
/// Executes the `verification` and if it passes returns the `result`, throwing otherwise.
/// - Parameter param: The parameter of the function to invoke.
/// - Returns: Returns the result setup.
public func invoke(param: TParam) throws -> TResult {
called = true
guard verification(param) else {
XCTFail("\(TParam.self) verification failed.")
throw InvocationMockerError.paramVerificationFailed
}
invokedParam = param
return try result(param)
}
/// Sets up a verification to be executed and needs to pass in order to return the result.
/// - Parameter verification: Verification to run.
/// - Returns: `Self` for fluent coding.
public func withVerification(verification: @escaping (TParam) -> Bool) -> Self {
self.verification = verification
return self
}
/// Sets up the result that will be returned if the verification passes.
/// - Parameter result: The result to return.
/// - Returns: `Self` for fluent coding
@discardableResult
public func withResult(_ result: TResult) -> Self {
self.result = { _ in result }
return self
}
/// Sets up the result that will be returned if the verification passes.
/// - Parameter resultFunc: The result func to execute.
/// - Returns: `Self` for fluent coding
@discardableResult
public func withResult(_ resultFunc: @escaping (TParam) throws -> TResult) -> Self {
result = resultFunc
return self
}
/// Sets up the error to throw if the verification passes.
/// - Parameter error: The error to throw.
/// - Returns: `Self` for fluent coding
@discardableResult
public func throwing(_ error: Error) -> Self {
result = { _ in throw error }
return self
}
}