From c2da69efb95a870e249456d4d0a8267c37cf8940 Mon Sep 17 00:00:00 2001 From: Alexandr Zalutskiy Date: Mon, 16 Oct 2023 13:50:23 +0600 Subject: [PATCH] Refactor Verify structure generation for support different containers --- .../Documentation.docc/Usage/Verifying.md | 4 + Sources/SwiftMock/Functions.swift | 2 +- Sources/SwiftMock/TimesMatcher/And.swift | 1 - Sources/SwiftMock/Verify/Container.swift | 18 +++ Sources/SwiftMock/Verify/MethodCall.swift | 2 +- Sources/SwiftMock/Verify/Verifiable.swift | 4 +- .../SwiftMock/Verify/VerifyContainer.swift | 56 ++++++++ .../When/AsyncMethodInvocation.swift | 2 +- .../When/AsyncThrowsMethodInvocation.swift | 2 +- Sources/SwiftMock/When/MethodInvocation.swift | 2 +- .../When/ThrowsMethodInvocation.swift | 2 +- Sources/SwiftMockMacros/General.swift | 26 ++-- Sources/SwiftMockMacros/Message.swift | 53 +++++++ Sources/SwiftMockMacros/Property.swift | 51 +++++-- Sources/SwiftMockMacros/SwiftMockMacro.swift | 42 +++--- Sources/SwiftMockMacros/Verify.swift | 124 ++++++++--------- .../SwiftMockTests/Macro/MockMacroTests.swift | 130 +++++++++++------- Tests/SwiftMockTests/VerifyTests.swift | 5 +- 18 files changed, 348 insertions(+), 178 deletions(-) delete mode 100644 Sources/SwiftMock/TimesMatcher/And.swift create mode 100644 Sources/SwiftMock/Verify/Container.swift create mode 100644 Sources/SwiftMock/Verify/VerifyContainer.swift create mode 100644 Sources/SwiftMockMacros/Message.swift diff --git a/Sources/SwiftMock/Documentation.docc/Usage/Verifying.md b/Sources/SwiftMock/Documentation.docc/Usage/Verifying.md index e529567..fbccf95 100644 --- a/Sources/SwiftMock/Documentation.docc/Usage/Verifying.md +++ b/Sources/SwiftMock/Documentation.docc/Usage/Verifying.md @@ -31,6 +31,8 @@ func test() { By default, verify checks that the method was called exactly one time. If the method was called more than once, you will receive an error. +> Important: The framework only checks calls that have not yet been checked. If you repeat the method check a second time, you will receive an error that the call was not found. + ### Checking that property was read To verify that the mock property has been read, use the ``verify(_:times:)`` method and pass the mock object as the first argument. This method will create a `Verify` structure for you that has a method to verify that your property has been read. The name of the method is `propertyGetter()`, where `property` is the name of your property. All rules regarding method call verification work similarly for properties. @@ -134,3 +136,5 @@ func test() { verify(mock, times: atLeast(2)).getAlbumName() } ``` + +> Important: Using ``atLeast(_:)`` and ``atMost(_:)`` will mark all calls that match the passed ``ArgumentMatcher``s as verified. diff --git a/Sources/SwiftMock/Functions.swift b/Sources/SwiftMock/Functions.swift index ade540f..a0ed75f 100644 --- a/Sources/SwiftMock/Functions.swift +++ b/Sources/SwiftMock/Functions.swift @@ -177,5 +177,5 @@ public func when( } public func verify(_ mock: Mock, times: @escaping TimesMatcher = times(1)) -> Mock.Verify { - Mock.Verify(mock: mock, times: times) + Mock.Verify(mock: mock, container: mock.container, times: times) } diff --git a/Sources/SwiftMock/TimesMatcher/And.swift b/Sources/SwiftMock/TimesMatcher/And.swift deleted file mode 100644 index 8b13789..0000000 --- a/Sources/SwiftMock/TimesMatcher/And.swift +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Sources/SwiftMock/Verify/Container.swift b/Sources/SwiftMock/Verify/Container.swift new file mode 100644 index 0000000..261f724 --- /dev/null +++ b/Sources/SwiftMock/Verify/Container.swift @@ -0,0 +1,18 @@ +// +// File.swift +// +// +// Created by Alexandr Zalutskiy on 13/10/2023. +// + +public protocol CallContainer { + + func append(mock: AnyObject, call: MethodCall, function: String) + func verify( + mock: AnyObject, + matcher: ArgumentMatcher, + times: TimesMatcher, + type: String, + function: String + ) +} diff --git a/Sources/SwiftMock/Verify/MethodCall.swift b/Sources/SwiftMock/Verify/MethodCall.swift index df2113c..02421bd 100644 --- a/Sources/SwiftMock/Verify/MethodCall.swift +++ b/Sources/SwiftMock/Verify/MethodCall.swift @@ -10,7 +10,7 @@ public struct MethodCall { matcher match: ArgumentMatcher, times: TimesMatcher, type: String, - function: String = #function + function: String ) { let callCount = container.filter { match($0.arguments) }.count guard times(callCount) else { diff --git a/Sources/SwiftMock/Verify/Verifiable.swift b/Sources/SwiftMock/Verify/Verifiable.swift index 3c2fb31..654d0a0 100644 --- a/Sources/SwiftMock/Verify/Verifiable.swift +++ b/Sources/SwiftMock/Verify/Verifiable.swift @@ -1,8 +1,10 @@ public protocol MockVerify { associatedtype Mock - init(mock: Mock, times: @escaping TimesMatcher) + init(mock: Mock, container: CallContainer, times: @escaping TimesMatcher) } public protocol Verifiable { associatedtype Verify: MockVerify where Verify.Mock == Self + + var container: VerifyContainer { get } } diff --git a/Sources/SwiftMock/Verify/VerifyContainer.swift b/Sources/SwiftMock/Verify/VerifyContainer.swift new file mode 100644 index 0000000..5a365bb --- /dev/null +++ b/Sources/SwiftMock/Verify/VerifyContainer.swift @@ -0,0 +1,56 @@ +// +// MethodCallContainer.swift +// +// +// Created by Alexandr Zalutskiy on 12/10/2023. +// + +import Foundation + +public class VerifyContainer: CallContainer { + var calls: [Any] = [] + var functions: [String] = [] + var isVerified: [Bool] = [] + + public init() { } + + public func append(mock: AnyObject, call: MethodCall, function: String) { + calls.append(call) + functions.append(function) + isVerified.append(false) + } + + public func verify( + mock: AnyObject, + matcher match: ArgumentMatcher, + times: (Int) -> Bool, + type: String, + function: String + ) { + var callCount = 0 + var indexes: [Array.Index] = [] + for index in calls.startIndex.. else { + continue + } + guard match(call.arguments) else { + continue + } + indexes.append(index) + callCount += 1 + } + guard times(callCount) else { + testFailureReport("\(type).\(function): incorrect calls count: \(callCount)") + return + } + for index in indexes { + isVerified[index] = true + } + } +} diff --git a/Sources/SwiftMock/When/AsyncMethodInvocation.swift b/Sources/SwiftMock/When/AsyncMethodInvocation.swift index 3bbf4eb..7b48d71 100644 --- a/Sources/SwiftMock/When/AsyncMethodInvocation.swift +++ b/Sources/SwiftMock/When/AsyncMethodInvocation.swift @@ -33,7 +33,7 @@ public final class AsyncMethodInvocation { in container: [AsyncMethodInvocation], with arguments: Arguments, type: String, - function: String = #function + function: String ) async -> Result { guard let invocation = container.last(where: { invocation in invocation.match(arguments) diff --git a/Sources/SwiftMock/When/AsyncThrowsMethodInvocation.swift b/Sources/SwiftMock/When/AsyncThrowsMethodInvocation.swift index 78c53e6..5cdc0f8 100644 --- a/Sources/SwiftMock/When/AsyncThrowsMethodInvocation.swift +++ b/Sources/SwiftMock/When/AsyncThrowsMethodInvocation.swift @@ -33,7 +33,7 @@ public final class AsyncThrowsMethodInvocation { in container: [AsyncThrowsMethodInvocation], with arguments: Arguments, type: String, - function: String = #function + function: String ) async throws -> Result { guard let invocation = container.last(where: { invocation in invocation.match(arguments) diff --git a/Sources/SwiftMock/When/MethodInvocation.swift b/Sources/SwiftMock/When/MethodInvocation.swift index b31cd78..5352aee 100644 --- a/Sources/SwiftMock/When/MethodInvocation.swift +++ b/Sources/SwiftMock/When/MethodInvocation.swift @@ -33,7 +33,7 @@ public final class MethodInvocation { in container: [MethodInvocation], with arguments: Arguments, type: String, - function: String = #function + function: String ) -> Result { guard let invocation = container.last(where: { invocation in invocation.match(arguments) diff --git a/Sources/SwiftMock/When/ThrowsMethodInvocation.swift b/Sources/SwiftMock/When/ThrowsMethodInvocation.swift index 7ec4597..dc746f7 100644 --- a/Sources/SwiftMock/When/ThrowsMethodInvocation.swift +++ b/Sources/SwiftMock/When/ThrowsMethodInvocation.swift @@ -33,7 +33,7 @@ public final class ThrowsMethodInvocation { in container: [ThrowsMethodInvocation], with arguments: Arguments, type: String, - function: String = #function + function: String ) throws -> Result { guard let invocation = container.last(where: { invocation in invocation.match(arguments) diff --git a/Sources/SwiftMockMacros/General.swift b/Sources/SwiftMockMacros/General.swift index aacc48a..ab12e6c 100644 --- a/Sources/SwiftMockMacros/General.swift +++ b/Sources/SwiftMockMacros/General.swift @@ -115,15 +115,21 @@ extension MockMacro { returnType: TypeSyntax? ) -> GenericArgumentClauseSyntax where T.Element == TypeSyntax { GenericArgumentClauseSyntax { - GenericArgumentSyntax( - argument: makeTupleType(from: arguments) - ) + packTypesToGenericArgumentSyntax(types: arguments) GenericArgumentSyntax( argument: returnType ?? voidType ) } } + static func packTypesToGenericArgumentSyntax( + types: T + ) -> GenericArgumentSyntax where T.Element == TypeSyntax { + GenericArgumentSyntax( + argument: makeTupleType(from: types) + ) + } + private static func makeTupleType( from types: T ) -> TypeSyntax where T.Element == TypeSyntax { @@ -203,11 +209,15 @@ extension MockMacro { static func makeArgumentMatcherZipStmts(tokens: [TokenSyntax]) -> [DeclSyntax] { var stmts: [DeclSyntax] = [] - for (index, token) in tokens.enumerated().reversed() { - if index == tokens.count - 1 { - stmts.append("let argumentMatcher\(raw: index) = \(raw: token.text)") - } else { - stmts.append("let argumentMatcher\(raw: index) = zip(\(raw: token.text), argumentMatcher\(raw: index + 1))") + if tokens.isEmpty { + stmts.append("let argumentMatcher0: ArgumentMatcher<()> = any()") + } else { + for (index, token) in tokens.enumerated().reversed() { + if index == tokens.count - 1 { + stmts.append("let argumentMatcher\(raw: index) = \(raw: token.text)") + } else { + stmts.append("let argumentMatcher\(raw: index) = zip(\(raw: token.text), argumentMatcher\(raw: index + 1))") + } } } return stmts diff --git a/Sources/SwiftMockMacros/Message.swift b/Sources/SwiftMockMacros/Message.swift new file mode 100644 index 0000000..82f2dec --- /dev/null +++ b/Sources/SwiftMockMacros/Message.swift @@ -0,0 +1,53 @@ +// +// Message.swift +// +// +// Created by Alexandr Zalutskiy on 15/10/2023. +// + +import SwiftSyntax +import SwiftSyntaxBuilder + +enum MessageError: Error { + case message(String) +} + +extension MockMacro { + static func makeFunctionSignatureString(funcDecl: FunctionDeclSyntax) throws -> String { + var literal = "" + literal += funcDecl.name.text + literal += "(" + for parameter in funcDecl.signature.parameterClause.parameters { + literal += parameter.firstName.text + literal += ":" + } + literal += ")" + if funcDecl.signature.effectSpecifiers?.asyncSpecifier != nil { + literal += " async" + } + if funcDecl.signature.effectSpecifiers?.throwsSpecifier != nil { + literal += " throws" + } + if let returnClause = funcDecl.signature.returnClause { + literal += " -> " + let type = String(returnClause.type.trimmed.syntaxTextBytes.map { Unicode.Scalar($0) }.map { Character($0) }) + literal += type + } + return literal + } + + static func makePropertySignatureString( + bindingSyntax: PatternBindingSyntax, + accessorDecl: AccessorDeclSyntax + ) throws -> String { + guard let text = bindingSyntax.pattern.as(IdentifierPatternSyntax.self)?.identifier.text else { + throw MessageError.message("For property supported only decloration using IdentifierPatternSyntax") + } + var literal = "" + literal += text + if accessorDecl.accessorSpecifier.trimmed.text == TokenSyntax.keyword(.set).text { + literal += "=" + } + return literal + } +} diff --git a/Sources/SwiftMockMacros/Property.swift b/Sources/SwiftMockMacros/Property.swift index 357c65a..1ba95f9 100644 --- a/Sources/SwiftMockMacros/Property.swift +++ b/Sources/SwiftMockMacros/Property.swift @@ -3,7 +3,7 @@ import SwiftSyntaxBuilder extension MockMacro { - static func makeVariableMock(from variableDecl: VariableDeclSyntax, mockTypeToken: TokenSyntax) -> [DeclSyntax] { + static func makeVariableMock(from variableDecl: VariableDeclSyntax, mockTypeToken: TokenSyntax) throws -> [DeclSyntax] { var declarations: [DeclSyntax] = [] for bindingSyntax in variableDecl.bindings { guard let accessorBlock = bindingSyntax.accessorBlock else { @@ -16,10 +16,9 @@ extension MockMacro { } for accessorDecl in accessorList { declarations.append(makeInvocationContainerProperty(patternBinding: bindingSyntax, accessorDecl: accessorDecl)) - declarations.append(makeCallStorageProperty(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl)) declarations.append(makeSignatureMethod(patternBinding: bindingSyntax, accessorDecl: accessorDecl)) } - declarations.append(makeMockProperty(bindingSyntax: bindingSyntax, mockTypeToken: mockTypeToken)) + declarations.append(try makeMockProperty(bindingSyntax: bindingSyntax, mockTypeToken: mockTypeToken)) } return declarations } @@ -257,15 +256,19 @@ extension MockMacro { // MARK: - Making the Mock Property - static func makeMockProperty(bindingSyntax: PatternBindingSyntax, mockTypeToken: TokenSyntax) -> DeclSyntax { - var accessorDeclListSyntax = AccessorDeclListSyntax { - AccessorDeclSyntax( + static func makeMockProperty(bindingSyntax: PatternBindingSyntax, mockTypeToken: TokenSyntax) throws -> DeclSyntax { + var accessorDeclListSyntax = try AccessorDeclListSyntax { + try AccessorDeclSyntax( accessorSpecifier: .keyword(.get) ) { "let arguments = ()" - makeStoreCallToStorageExpr(bindingSyntax: bindingSyntax, accessorDecl: AccessorDeclSyntax(accessorSpecifier: .keyword(.get))) + try makeStoreCallToStorageExpr(bindingSyntax: bindingSyntax, accessorDecl: AccessorDeclSyntax(accessorSpecifier: .keyword(.get))) ReturnStmtSyntax( - expression: makeMockGetterReturnExpr(bindingSyntax: bindingSyntax, mockTypeToken: mockTypeToken) + expression: try makeMockGetterReturnExpr( + bindingSyntax: bindingSyntax, + accessorDecl: AccessorDeclSyntax(accessorSpecifier: .keyword(.get)), + mockTypeToken: mockTypeToken + ) ) } } @@ -280,13 +283,17 @@ extension MockMacro { } if hasSetter { accessorDeclListSyntax.append( - AccessorDeclSyntax( + try AccessorDeclSyntax( accessorSpecifier: .keyword(.set) ) { "let arguments = (newValue)" - makeStoreCallToStorageExpr(bindingSyntax: bindingSyntax, accessorDecl: AccessorDeclSyntax(accessorSpecifier: .keyword(.set))) + try makeStoreCallToStorageExpr(bindingSyntax: bindingSyntax, accessorDecl: AccessorDeclSyntax(accessorSpecifier: .keyword(.set))) ReturnStmtSyntax( - expression: makeMockSetterReturnExpr(bindingSyntax: bindingSyntax, mockTypeToken: mockTypeToken) + expression: try makeMockSetterReturnExpr( + bindingSyntax: bindingSyntax, + accessorDecl: AccessorDeclSyntax(accessorSpecifier: .keyword(.set)), + mockTypeToken: mockTypeToken + ) ) } ) @@ -312,8 +319,13 @@ extension MockMacro { ) } - private static func makeMockGetterReturnExpr(bindingSyntax: PatternBindingSyntax, mockTypeToken: TokenSyntax) -> ExprSyntax { + private static func makeMockGetterReturnExpr( + bindingSyntax: PatternBindingSyntax, + accessorDecl: AccessorDeclSyntax, + mockTypeToken: TokenSyntax + ) throws -> ExprSyntax { let invocationType = TokenSyntax.identifier("MethodInvocation") + let propertySignatureString = try makePropertySignatureString(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl) return ExprSyntax( fromProtocol: FunctionCallExprSyntax( calledExpression: MemberAccessExprSyntax( @@ -335,12 +347,21 @@ extension MockMacro { label: "type", expression: StringLiteralExprSyntax(content: mockTypeToken.text) ) + LabeledExprSyntax( + label: "function", + expression: ExprSyntax(literal: propertySignatureString) + ) } ) } - private static func makeMockSetterReturnExpr(bindingSyntax: PatternBindingSyntax, mockTypeToken: TokenSyntax) -> ExprSyntax { + private static func makeMockSetterReturnExpr( + bindingSyntax: PatternBindingSyntax, + accessorDecl: AccessorDeclSyntax, + mockTypeToken: TokenSyntax + ) throws -> ExprSyntax { let invocationType = TokenSyntax.identifier("MethodInvocation") + let propertySignatureString = try makePropertySignatureString(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl) return ExprSyntax( fromProtocol: FunctionCallExprSyntax( calledExpression: MemberAccessExprSyntax( @@ -362,6 +383,10 @@ extension MockMacro { label: "type", expression: StringLiteralExprSyntax(content: mockTypeToken.text) ) + LabeledExprSyntax( + label: "function", + expression: ExprSyntax(literal: propertySignatureString) + ) } ) } diff --git a/Sources/SwiftMockMacros/SwiftMockMacro.swift b/Sources/SwiftMockMacros/SwiftMockMacro.swift index 45ceb84..2d00adb 100644 --- a/Sources/SwiftMockMacros/SwiftMockMacro.swift +++ b/Sources/SwiftMockMacros/SwiftMockMacro.swift @@ -20,7 +20,7 @@ public struct MockMacro: PeerMacro { return [ DeclSyntax( - ClassDeclSyntax( + try ClassDeclSyntax( modifiers: DeclModifierListSyntax { DeclModifierSyntax(name: .keyword(.public)) DeclModifierSyntax(name: .keyword(.final)) @@ -31,19 +31,19 @@ public struct MockMacro: PeerMacro { InheritedTypeSyntax(type: IdentifierTypeSyntax(name: "Verifiable")) } ) { - makeVerifyType(declaration) + try makeVerifyType(declaration) + try makeVerifyCallStorageProperty() for member in declaration.memberBlock.members { if let funcDecl = member.decl.as(FunctionDeclSyntax.self) { makeInvocationContainerProperty(funcDecl: funcDecl) - makeCallStorageProperty(funcDecl: funcDecl) makeSignatureMethod(from: funcDecl) funcDecl .with(\.modifiers, DeclModifierListSyntax { DeclModifierSyntax(name: .keyword(.public)) }) - .with(\.body, makeMockMethodBody(from: funcDecl, type: mockTypeToken)) + .with(\.body, try makeMockMethodBody(from: funcDecl, type: mockTypeToken)) } else if let variableDecl = member.decl.as(VariableDeclSyntax.self) { - for decl in makeVariableMock(from: variableDecl, mockTypeToken: mockTypeToken) { + for decl in try makeVariableMock(from: variableDecl, mockTypeToken: mockTypeToken) { decl } } @@ -98,23 +98,10 @@ public struct MockMacro: PeerMacro { leftParen: .leftParenToken(), rightParen: .rightParenToken() ) { - if parameters.isEmpty { - LabeledExprSyntax( - label: "argumentMatcher", - expression: FunctionCallExprSyntax( - calledExpression: DeclReferenceExprSyntax( - baseName: .identifier("any") - ), - leftParen: .leftParenToken(), - rightParen: .rightParenToken() - ) { } - ) - } else { - LabeledExprSyntax( - label: "argumentMatcher", - expression: DeclReferenceExprSyntax(baseName: .identifier("argumentMatcher0")) - ) - } + LabeledExprSyntax( + label: "argumentMatcher", + expression: ExprSyntax(stringLiteral: "argumentMatcher0") + ) LabeledExprSyntax( label: "register", expression: ClosureExprSyntax { @@ -138,10 +125,11 @@ public struct MockMacro: PeerMacro { }) } - private static func makeMockMethodBody(from funcDecl: FunctionDeclSyntax, type: TokenSyntax) -> CodeBlockSyntax { + private static func makeMockMethodBody(from funcDecl: FunctionDeclSyntax, type: TokenSyntax) throws -> CodeBlockSyntax { let prefix = makeTypePrefix(funcDecl: funcDecl) let invocationType = TokenSyntax.identifier(prefix + "MethodInvocation") let argumentsExpression = packParametersToTupleExpr(funcDecl.signature.parameterClause.parameters) + let funcSignatureString = try makeFunctionSignatureString(funcDecl: funcDecl) let functionCallExpr = FunctionCallExprSyntax( calledExpression: MemberAccessExprSyntax( base: DeclReferenceExprSyntax(baseName: invocationType), @@ -162,10 +150,14 @@ public struct MockMacro: PeerMacro { label: "type", expression: StringLiteralExprSyntax(content: type.text) ) + LabeledExprSyntax( + label: "function", + expression: ExprSyntax(literal: funcSignatureString) + ) } - return CodeBlockSyntax { + return try CodeBlockSyntax { "let arguments = \(argumentsExpression)" - makeStoreCallToStorageExpr(funcDecl: funcDecl) + try makeStoreCallToStorageExpr(funcDecl: funcDecl) if funcDecl.signature.effectSpecifiers?.throwsSpecifier != nil { if funcDecl.signature.effectSpecifiers?.asyncSpecifier != nil { ReturnStmtSyntax( diff --git a/Sources/SwiftMockMacros/Verify.swift b/Sources/SwiftMockMacros/Verify.swift index 3882b5c..05fb680 100644 --- a/Sources/SwiftMockMacros/Verify.swift +++ b/Sources/SwiftMockMacros/Verify.swift @@ -2,8 +2,8 @@ import SwiftSyntax import SwiftSyntaxBuilder extension MockMacro { - static func makeVerifyType(_ protocolDecl: ProtocolDeclSyntax) -> StructDeclSyntax { - StructDeclSyntax( + static func makeVerifyType(_ protocolDecl: ProtocolDeclSyntax) throws -> StructDeclSyntax { + try StructDeclSyntax( modifiers: DeclModifierListSyntax { DeclModifierSyntax(name: .keyword(.public)) }, @@ -13,13 +13,14 @@ extension MockMacro { } ) { makeVerifyStorageProperty(protocolDecl: protocolDecl) + makeCallContainerProperty() makeTimesStorageProperty() makeInit(protocolDecl: protocolDecl) for member in protocolDecl.memberBlock.members { if let funcDecl = member.decl.as(FunctionDeclSyntax.self) { - makeVerifyMethod(protocolDecl: protocolDecl, funcDecl: funcDecl) + try makeVerifyMethod(protocolDecl: protocolDecl, funcDecl: funcDecl) } else if let variableDecl = member.decl.as(VariableDeclSyntax.self) { - for decl in makeVerifyProperty(protocolDecl: protocolDecl, variableDecl: variableDecl) { + for decl in try makeVerifyProperty(protocolDecl: protocolDecl, variableDecl: variableDecl) { decl } } @@ -51,6 +52,22 @@ extension MockMacro { ) } + private static func makeCallContainerProperty() -> VariableDeclSyntax { + do { + return try VariableDeclSyntax("let container: CallContainer") + } catch { + fatalError() + } + +// VariableDeclSyntax( +// .let, +// name: "container", +// type: TypeAnnotationSyntax( +// type: IdentifierTypeSyntax(name: .identifier("CallContainer")) +// ) +// ) + } + private static func makeInit(protocolDecl: ProtocolDeclSyntax) -> InitializerDeclSyntax { InitializerDeclSyntax( modifiers: DeclModifierListSyntax { @@ -59,11 +76,13 @@ extension MockMacro { signature: FunctionSignatureSyntax( parameterClause: FunctionParameterClauseSyntax { "mock: \(raw: protocolDecl.name.text)Mock" + "container: CallContainer" "times: @escaping TimesMatcher" } ), bodyBuilder: { "self.mock = mock" + "self.container = container" "self.times = times" } ) @@ -71,8 +90,9 @@ extension MockMacro { // MARK: - Vertify Method for Method - private static func makeVerifyMethod(protocolDecl: ProtocolDeclSyntax, funcDecl: FunctionDeclSyntax) -> FunctionDeclSyntax { - funcDecl + private static func makeVerifyMethod(protocolDecl: ProtocolDeclSyntax, funcDecl: FunctionDeclSyntax) throws -> FunctionDeclSyntax { + let funcSignatureString = try makeFunctionSignatureString(funcDecl: funcDecl) + return funcDecl .with(\.modifiers, DeclModifierListSyntax { publicModifier }) @@ -82,8 +102,8 @@ extension MockMacro { )) .with(\.body, makeVerifyBody( arguments: funcDecl.signature.parameterClause.parameters.map { $0.secondName ?? $0.firstName }, - storagePropertyToken: makeCallStorageProperyName(funcDecl: funcDecl), - mockTypeToken: makeMockTypeToken(protocolDecl) + mockTypeToken: makeMockTypeToken(protocolDecl), + funcSignatureExpr: ExprSyntax(literal: funcSignatureString) )) } @@ -93,7 +113,7 @@ extension MockMacro { // MARK: - Verify Method For Property - private static func makeVerifyProperty(protocolDecl: ProtocolDeclSyntax, variableDecl: VariableDeclSyntax) -> [DeclSyntax] { + private static func makeVerifyProperty(protocolDecl: ProtocolDeclSyntax, variableDecl: VariableDeclSyntax) throws -> [DeclSyntax] { var declarations: [DeclSyntax] = [] for bindingSyntax in variableDecl.bindings { guard let accessorBlock = bindingSyntax.accessorBlock else { @@ -105,6 +125,7 @@ extension MockMacro { continue } for accessorDecl in accessorList { + let funcSignatureString = try makePropertySignatureString(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl) let decl = DeclSyntax( fromProtocol: FunctionDeclSyntax( modifiers: DeclModifierListSyntax { @@ -114,8 +135,8 @@ extension MockMacro { signature: makeVerifyPropertyFunctionSignature(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl), body: makeVerifyBody( arguments: makeArgumentList(accessorDecl: accessorDecl), - storagePropertyToken: makeCallStoragePropertyToken(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl), - mockTypeToken: makeMockTypeToken(protocolDecl) + mockTypeToken: makeMockTypeToken(protocolDecl), + funcSignatureExpr: ExprSyntax(literal: funcSignatureString) ) ) ) @@ -172,23 +193,6 @@ extension MockMacro { return FunctionSignatureSyntax(parameterClause: functionParameterClause) } - - private static func makeCallStoragePropertyToken( - bindingSyntax: PatternBindingSyntax, - accessorDecl: AccessorDeclSyntax - ) -> TokenSyntax { - let text: String - switch accessorDecl.accessorSpecifier.trimmed.text { - case TokenSyntax.keyword(.get).text: - text = makeGetterInvocationContainerToken(from: bindingSyntax).text - case TokenSyntax.keyword(.set).text: - text = makeSetterInvocationContainerToken(from: bindingSyntax).text - default: - fatalError("Unexpected accessor for property. Supported accessors: \"get\" and \"set\"") - } - return .identifier(text + "___call") - } - private static func makeArgumentList(accessorDecl: AccessorDeclSyntax) -> [TokenSyntax] { switch accessorDecl.accessorSpecifier.trimmed.text { case TokenSyntax.keyword(.get).text: @@ -204,46 +208,48 @@ extension MockMacro { private static func makeVerifyBody( arguments: [TokenSyntax] = [], - storagePropertyToken: TokenSyntax, - mockTypeToken: TokenSyntax + mockTypeToken: TokenSyntax, + funcSignatureExpr: ExprSyntax ) -> CodeBlockSyntax { - CodeBlockSyntax { + return CodeBlockSyntax { for stmt in makeArgumentMatcherZipStmts(tokens: arguments) { stmt } FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .identifier("MethodCall")), - declName: DeclReferenceExprSyntax(baseName: .identifier("verify")) - ), + calledExpression: ExprSyntax(stringLiteral: "container.verify"), leftParen: .leftParenToken(), rightParen: .rightParenToken() ) { LabeledExprSyntax( - label: "in", - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .identifier("mock")), - declName: DeclReferenceExprSyntax(baseName: storagePropertyToken) - ) + label: "mock", + expression: ExprSyntax(stringLiteral: "mock") ) LabeledExprSyntax( label: "matcher", - expression: DeclReferenceExprSyntax(baseName: arguments.isEmpty ? .identifier("any()") : .identifier("argumentMatcher0")) + expression: ExprSyntax(stringLiteral: "argumentMatcher0") ) LabeledExprSyntax( label: "times", - expression: DeclReferenceExprSyntax(baseName: .identifier("times")) + expression: ExprSyntax(stringLiteral: "times") ) LabeledExprSyntax( label: "type", expression: StringLiteralExprSyntax(content: mockTypeToken.text) ) + LabeledExprSyntax( + label: "function", + expression: funcSignatureExpr + ) } } } // MARK: - Integration to other files + static func makeVerifyCallStorageProperty() throws -> VariableDeclSyntax { + try VariableDeclSyntax("public let container = VerifyContainer()") + } + static func makeCallStorageProperty(funcDecl: FunctionDeclSyntax) -> VariableDeclSyntax { let storageName = makeCallStorageProperyName(funcDecl: funcDecl) let parameterTypes = funcDecl.signature.parameterClause.parameters.map { $0.type } @@ -263,31 +269,9 @@ extension MockMacro { ) } - static func makeStoreCallToStorageExpr(funcDecl: FunctionDeclSyntax) -> ExprSyntax { - "\(makeCallStorageProperyName(funcDecl: funcDecl)).append(MethodCall(arguments: arguments))" - } - - static func makeCallStorageProperty( - bindingSyntax: PatternBindingSyntax, - accessorDecl: AccessorDeclSyntax - ) -> DeclSyntax { - let storageName = makeCallStoragePropertyToken(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl) - - return DeclSyntax( - fromProtocol: VariableDeclSyntax( - modifiers: DeclModifierListSyntax { - DeclModifierSyntax(name: .keyword(.private)) - }, - bindingSpecifier: .keyword(.var), - bindings: PatternBindingListSyntax { - PatternBindingSyntax( - pattern: IdentifierPatternSyntax(identifier: storageName), - typeAnnotation: TypeAnnotationSyntax(type: makeStorageType(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl)), - initializer: InitializerClauseSyntax(value: ArrayExprSyntax(expressions: [])) - ) - } - ) - ) + static func makeStoreCallToStorageExpr(funcDecl: FunctionDeclSyntax) throws -> ExprSyntax { + let functionSignature = try makeFunctionSignatureString(funcDecl: funcDecl) + return "container.append(mock: self, call: MethodCall(arguments: arguments), function: \"\(raw: functionSignature)\")" } private static func makeStorageType( @@ -316,9 +300,9 @@ extension MockMacro { return TypeSyntax(fromProtocol: ArrayTypeSyntax(element: elementType)) } - static func makeStoreCallToStorageExpr(bindingSyntax: PatternBindingSyntax, accessorDecl: AccessorDeclSyntax) -> ExprSyntax { - let storageToken = makeCallStoragePropertyToken(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl) - return "\(storageToken).append(MethodCall(arguments: arguments))" + static func makeStoreCallToStorageExpr(bindingSyntax: PatternBindingSyntax, accessorDecl: AccessorDeclSyntax) throws -> ExprSyntax { + let propertySignatureString = try makePropertySignatureString(bindingSyntax: bindingSyntax, accessorDecl: accessorDecl) + return "container.append(mock: self, call: MethodCall(arguments: arguments), function: \"\(raw: propertySignatureString)\")" } private static func makeGenericType(_ name: TokenSyntax, from funcDecl: FunctionDeclSyntax) -> some TypeSyntaxProtocol { diff --git a/Tests/SwiftMockTests/Macro/MockMacroTests.swift b/Tests/SwiftMockTests/Macro/MockMacroTests.swift index f8c3d2c..08f4dba 100644 --- a/Tests/SwiftMockTests/Macro/MockMacroTests.swift +++ b/Tests/SwiftMockTests/Macro/MockMacroTests.swift @@ -25,12 +25,15 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } } + public let container = VerifyContainer() } """, macros: testMacros, @@ -59,29 +62,33 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func call() -> Void { - MethodCall.verify(in: mock.call_____call, matcher: any(), times: times, type: "TestMock") + let argumentMatcher0: ArgumentMatcher<()> = any() + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "call()") } } + public let container = VerifyContainer() private var call__: [MethodInvocation<(), Void>] = [] - private var call_____call: [MethodCall<()>] = [] public func $call() -> MethodSignature<(), Void> { - return MethodSignature<(), Void>(argumentMatcher: any(), register: { + let argumentMatcher0: ArgumentMatcher<()> = any() + return MethodSignature<(), Void>(argumentMatcher: argumentMatcher0, register: { self.call__.append($0) }) } public func call() { let arguments = () - call_____call.append(MethodCall(arguments: arguments)) - return MethodInvocation.find(in: call__, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "call()") + return MethodInvocation.find(in: call__, with: arguments, type: "TestMock", function: "call()") } } """, @@ -111,17 +118,20 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func propGetter() { - MethodCall.verify(in: mock.prop___getter___call, matcher: any(), times: times, type: "TestMock") + let argumentMatcher0: ArgumentMatcher<()> = any() + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "prop") } } + public let container = VerifyContainer() private var prop___getter: [MethodInvocation<(), Int>] = [] - private var prop___getter___call: [MethodCall<()>] = [] public func $propGetter() -> MethodSignature<(), Int> { return MethodSignature<(), Int>(argumentMatcher: any(), register: { self.prop___getter.append($0) @@ -130,8 +140,8 @@ final class MockMacroTests: XCTestCase { public var prop: Int { get { let arguments = () - prop___getter___call.append(MethodCall(arguments: arguments)) - return MethodInvocation.find(in: prop___getter, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "prop") + return MethodInvocation.find(in: prop___getter, with: arguments, type: "TestMock", function: "prop") } } } @@ -162,28 +172,30 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func propGetter() { - MethodCall.verify(in: mock.prop___getter___call, matcher: any(), times: times, type: "TestMock") + let argumentMatcher0: ArgumentMatcher<()> = any() + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "prop") } public func propSetter(_ value: @escaping ArgumentMatcher) { let argumentMatcher0 = value - MethodCall.verify(in: mock.prop___setter___call, matcher: argumentMatcher0, times: times, type: "TestMock") + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "prop=") } } + public let container = VerifyContainer() private var prop___getter: [MethodInvocation<(), Int>] = [] - private var prop___getter___call: [MethodCall<()>] = [] public func $propGetter() -> MethodSignature<(), Int> { return MethodSignature<(), Int>(argumentMatcher: any(), register: { self.prop___getter.append($0) }) } private var prop___setter: [MethodInvocation<(Int), Void>] = [] - private var prop___setter___call: [MethodCall<(Int)>] = [] public func $propSetter(_ value: @escaping ArgumentMatcher = any()) -> MethodSignature<(Int), Void> { let argumentMatcher0 = value return MethodSignature<(Int), Void>(argumentMatcher: argumentMatcher0, register: { @@ -193,13 +205,13 @@ final class MockMacroTests: XCTestCase { public var prop: Int { get { let arguments = () - prop___getter___call.append(MethodCall(arguments: arguments)) - return MethodInvocation.find(in: prop___getter, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "prop") + return MethodInvocation.find(in: prop___getter, with: arguments, type: "TestMock", function: "prop") } set { let arguments = (newValue) - prop___setter___call.append(MethodCall(arguments: arguments)) - return MethodInvocation.find(in: prop___setter, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "prop=") + return MethodInvocation.find(in: prop___setter, with: arguments, type: "TestMock", function: "prop=") } } } @@ -231,29 +243,33 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func call() -> Void { - MethodCall.verify(in: mock.call_____call, matcher: any(), times: times, type: "TestMock") + let argumentMatcher0: ArgumentMatcher<()> = any() + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "call() -> Int") } } + public let container = VerifyContainer() private var call__: [MethodInvocation<(), Int>] = [] - private var call_____call: [MethodCall<()>] = [] public func $call() -> MethodSignature<(), Int> { - return MethodSignature<(), Int>(argumentMatcher: any(), register: { + let argumentMatcher0: ArgumentMatcher<()> = any() + return MethodSignature<(), Int>(argumentMatcher: argumentMatcher0, register: { self.call__.append($0) }) } public func call() -> Int { let arguments = () - call_____call.append(MethodCall(arguments: arguments)) - return MethodInvocation.find(in: call__, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "call() -> Int") + return MethodInvocation.find(in: call__, with: arguments, type: "TestMock", function: "call() -> Int") } } """, @@ -283,19 +299,21 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func call(argument: @escaping ArgumentMatcher = any()) -> Void { let argumentMatcher0 = argument - MethodCall.verify(in: mock.call_argument____call, matcher: argumentMatcher0, times: times, type: "TestMock") + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "call(argument:)") } } + public let container = VerifyContainer() private var call_argument_: [MethodInvocation<(Int), Void>] = [] - private var call_argument____call: [MethodCall<(Int)>] = [] public func $call(argument: @escaping ArgumentMatcher = any()) -> MethodSignature<(Int), Void> { let argumentMatcher0 = argument @@ -306,8 +324,8 @@ final class MockMacroTests: XCTestCase { public func call(argument: Int) { let arguments = (argument) - call_argument____call.append(MethodCall(arguments: arguments)) - return MethodInvocation.find(in: call_argument_, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "call(argument:)") + return MethodInvocation.find(in: call_argument_, with: arguments, type: "TestMock", function: "call(argument:)") } } """, @@ -337,20 +355,22 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func call(argument0: @escaping ArgumentMatcher = any(), argument1: @escaping ArgumentMatcher = any()) -> Void { let argumentMatcher1 = argument1 let argumentMatcher0 = zip(argument0, argumentMatcher1) - MethodCall.verify(in: mock.call_argument0_argument1____call, matcher: argumentMatcher0, times: times, type: "TestMock") + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "call(argument0:argument1:)") } } + public let container = VerifyContainer() private var call_argument0_argument1_: [MethodInvocation<(Int, (Int)), Void>] = [] - private var call_argument0_argument1____call: [MethodCall<(Int, (Int))>] = [] public func $call(argument0: @escaping ArgumentMatcher = any(), argument1: @escaping ArgumentMatcher = any()) -> MethodSignature<(Int, (Int)), Void> { let argumentMatcher1 = argument1 @@ -362,8 +382,8 @@ final class MockMacroTests: XCTestCase { public func call(argument0: Int, argument1: Int) { let arguments = (argument0, (argument1)) - call_argument0_argument1____call.append(MethodCall(arguments: arguments)) - return MethodInvocation.find(in: call_argument0_argument1_, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "call(argument0:argument1:)") + return MethodInvocation.find(in: call_argument0_argument1_, with: arguments, type: "TestMock", function: "call(argument0:argument1:)") } } """, @@ -393,20 +413,22 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func call(argument0: @escaping ArgumentMatcher = any(), argument1: @escaping ArgumentMatcher = any()) -> Void { let argumentMatcher1 = argument1 let argumentMatcher0 = zip(argument0, argumentMatcher1) - MethodCall.verify(in: mock.call_argument0_argument1_throws___call, matcher: argumentMatcher0, times: times, type: "TestMock") + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "call(argument0:argument1:) throws -> Int") } } + public let container = VerifyContainer() private var call_argument0_argument1_throws: [ThrowsMethodInvocation<(Int, (Int)), Int>] = [] - private var call_argument0_argument1_throws___call: [MethodCall<(Int, (Int))>] = [] public func $call(argument0: @escaping ArgumentMatcher = any(), argument1: @escaping ArgumentMatcher = any()) -> ThrowsMethodSignature<(Int, (Int)), Int> { let argumentMatcher1 = argument1 @@ -418,8 +440,8 @@ final class MockMacroTests: XCTestCase { public func call(argument0: Int, argument1: Int) throws -> Int { let arguments = (argument0, (argument1)) - call_argument0_argument1_throws___call.append(MethodCall(arguments: arguments)) - return try ThrowsMethodInvocation.find(in: call_argument0_argument1_throws, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "call(argument0:argument1:) throws -> Int") + return try ThrowsMethodInvocation.find(in: call_argument0_argument1_throws, with: arguments, type: "TestMock", function: "call(argument0:argument1:) throws -> Int") } } """, @@ -449,20 +471,22 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func call(argument0: @escaping ArgumentMatcher = any(), argument1: @escaping ArgumentMatcher = any()) -> Void { let argumentMatcher1 = argument1 let argumentMatcher0 = zip(argument0, argumentMatcher1) - MethodCall.verify(in: mock.call_argument0_argument1_async___call, matcher: argumentMatcher0, times: times, type: "TestMock") + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "call(argument0:argument1:) async -> Int") } } + public let container = VerifyContainer() private var call_argument0_argument1_async: [AsyncMethodInvocation<(Int, (Int)), Int>] = [] - private var call_argument0_argument1_async___call: [MethodCall<(Int, (Int))>] = [] public func $call(argument0: @escaping ArgumentMatcher = any(), argument1: @escaping ArgumentMatcher = any()) -> AsyncMethodSignature<(Int, (Int)), Int> { let argumentMatcher1 = argument1 @@ -474,8 +498,8 @@ final class MockMacroTests: XCTestCase { public func call(argument0: Int, argument1: Int) async -> Int { let arguments = (argument0, (argument1)) - call_argument0_argument1_async___call.append(MethodCall(arguments: arguments)) - return await AsyncMethodInvocation.find(in: call_argument0_argument1_async, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "call(argument0:argument1:) async -> Int") + return await AsyncMethodInvocation.find(in: call_argument0_argument1_async, with: arguments, type: "TestMock", function: "call(argument0:argument1:) async -> Int") } } """, @@ -505,20 +529,22 @@ final class MockMacroTests: XCTestCase { public final class TestMock: Test , Verifiable { public struct Verify: MockVerify { let mock: TestMock + let container: CallContainer let times: TimesMatcher - public init(mock: TestMock, times: @escaping TimesMatcher) { + public init(mock: TestMock, container: CallContainer, times: @escaping TimesMatcher) { self.mock = mock + self.container = container self.times = times } public func call(argument0: @escaping ArgumentMatcher = any(), argument1: @escaping ArgumentMatcher = any()) -> Void { let argumentMatcher1 = argument1 let argumentMatcher0 = zip(argument0, argumentMatcher1) - MethodCall.verify(in: mock.call_argument0_argument1_asyncthrows___call, matcher: argumentMatcher0, times: times, type: "TestMock") + container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TestMock", function: "call(argument0:argument1:) async throws -> Int") } } + public let container = VerifyContainer() private var call_argument0_argument1_asyncthrows: [AsyncThrowsMethodInvocation<(Int, (Int)), Int>] = [] - private var call_argument0_argument1_asyncthrows___call: [MethodCall<(Int, (Int))>] = [] public func $call(argument0: @escaping ArgumentMatcher = any(), argument1: @escaping ArgumentMatcher = any()) -> AsyncThrowsMethodSignature<(Int, (Int)), Int> { let argumentMatcher1 = argument1 @@ -530,8 +556,8 @@ final class MockMacroTests: XCTestCase { public func call(argument0: Int, argument1: Int) async throws -> Int { let arguments = (argument0, (argument1)) - call_argument0_argument1_asyncthrows___call.append(MethodCall(arguments: arguments)) - return try await AsyncThrowsMethodInvocation.find(in: call_argument0_argument1_asyncthrows, with: arguments, type: "TestMock") + container.append(mock: self, call: MethodCall(arguments: arguments), function: "call(argument0:argument1:) async throws -> Int") + return try await AsyncThrowsMethodInvocation.find(in: call_argument0_argument1_asyncthrows, with: arguments, type: "TestMock", function: "call(argument0:argument1:) async throws -> Int") } } """, diff --git a/Tests/SwiftMockTests/VerifyTests.swift b/Tests/SwiftMockTests/VerifyTests.swift index c25dcea..4c56e9a 100644 --- a/Tests/SwiftMockTests/VerifyTests.swift +++ b/Tests/SwiftMockTests/VerifyTests.swift @@ -87,7 +87,7 @@ final class VerifyTests: XCTestCase { _ = mock.call(argument0: 6, argument1: 0) - verify(mock, times: atLeast(firstTimeCount)).call() + verify(mock).call() } func testAtLeastOnce() { @@ -102,12 +102,13 @@ final class VerifyTests: XCTestCase { #endif _ = mock.call(argument0: 9, argument1: 5) + _ = mock.call(argument0: 4, argument1: 5) verify(mock, times: atLeastOnce()).call() _ = mock.call(argument0: 4, argument1: 9) - verify(mock, times: atLeastOnce()).call() + verify(mock).call() } func testNever() {