Skip to content

Instantly share code, notes, and snippets.

@frootloops
Created October 16, 2020 21:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frootloops/de256f714db0bdbde9499381e5dd83cd to your computer and use it in GitHub Desktop.
Save frootloops/de256f714db0bdbde9499381e5dd83cd to your computer and use it in GitHub Desktop.
import Foundation
public struct MockFunc<Input, Output> {
public var parameters: [Input] = []
public var result: (Input) -> Output = { _ in fatalError() }
public init() {}
public init(result: @escaping (Input) -> Output) {
self.result = result
}
public var count: Int {
return parameters.count
}
public var called: Bool {
return !parameters.isEmpty
}
public var output: Output {
return result(input)
}
public var input: Input {
return parameters[count - 1]
}
public static func mock(for function: (Input) throws -> Output) -> MockFunc {
return MockFunc()
}
public mutating func call(with input: Input) {
parameters.append(input)
}
public mutating func callAndReturn(_ input: Input) -> Output {
call(with: input)
return output
}
}
// MARK: Syntactic Sugar
extension MockFunc {
public mutating func returns(_ value: Output) {
result = { _ in value }
}
public mutating func returns() where Output == Void {
result = { _ in () }
}
public mutating func returnsNil<T>()
where Output == Optional<T> {
result = { _ in nil }
}
public mutating func succeeds<T, Error>(_ value: T)
where Output == Result<T, Error> {
result = { _ in .success(value) }
}
public mutating func fails<T, Error>(_ error: Error)
where Output == Result<T, Error> {
result = { _ in .failure(error) }
}
}
extension MockFunc where Input == Void {
public mutating func call() {
parameters.append(())
}
public mutating func callAndReturn() -> Output {
call(with: ())
return output
}
}
public func beCalled<In, Out>() -> Predicate<MockFunc<In, Out>> {
return Predicate.define("be called", matcher: { expression, message -> PredicateResult in
guard let actual = try expression.evaluate() else {
return PredicateResult(status: .fail, message: message)
}
return PredicateResult(bool: actual.called, message: message)
})
}
public func beCalled<In, Out>(count: Int) -> Predicate<MockFunc<In, Out>> {
let msg = "be called \(count) times"
return Predicate.define(msg) { expression, message -> PredicateResult in
guard let actual = try expression.evaluate() else {
return PredicateResult(status: .fail, message: message)
}
return PredicateResult(
bool: actual.count == count,
message: .expectedCustomValueTo(msg, "\(actual.count) times")
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment