Skip to content

Commit

Permalink
Merge pull request #62 from MetalheadSanya/57-point-verify-failure-to…
Browse files Browse the repository at this point in the history
…-verify-call

Point verify failure to 'verify' call
  • Loading branch information
MetalheadSanya authored Nov 20, 2023
2 parents 0e851a6 + 4a642a7 commit 54b3e1b
Show file tree
Hide file tree
Showing 23 changed files with 159 additions and 150 deletions.
6 changes: 3 additions & 3 deletions Sources/SwiftMock/InOrder/InOrder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ public struct InOrder {
/// - Returns: `Verify` structure specific to the passed mock object.
///
/// - Note: You don't have to verify all interactions one-by-one but only those that you are interested in testing in order.
public func verify<Mock: AnyObject & Verifiable>(_ mock: Mock, times: @escaping TimesMatcher = times(1)) -> Mock.Verify {
public func verify<Mock: AnyObject & Verifiable>(_ mock: Mock, times: @escaping TimesMatcher = times(1), file: StaticString = #filePath, line: UInt = #line) -> Mock.Verify {
guard mocks.contains(where: { $0 === mock }) else {
testFailureReport("")
fatalError("")
testFailureReport("The 'InOrder' doesn't contains such a mock", file, line)
fatalError("The 'InOrder' doesn't contains such a mock", file: (file), line: line)
}

return Mock.Verify(mock: mock, container: container, times: times)
Expand Down
8 changes: 5 additions & 3 deletions Sources/SwiftMock/InOrder/InOrderContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ class InOrderContainer: CallContainer {
matcher match: ArgumentMatcher<T>,
times: (Int) -> Bool,
type: String,
function: String
function: String,
file: StaticString,
line: UInt
) {
var callCount = 0

Expand All @@ -42,7 +44,7 @@ class InOrderContainer: CallContainer {
let functions = InOrderContainer.functions

guard startIndex < calls.count else {
testFailureReport("\(type).\(function): incorrect calls count: \(callCount)")
testFailureReport("\(type).\(function): incorrect calls count: \(callCount)", file, line)
return
}

Expand All @@ -66,7 +68,7 @@ class InOrderContainer: CallContainer {
lastCheckedIndex = index
}
guard times(callCount) else {
testFailureReport("\(type).\(function): incorrect calls count: \(callCount)")
testFailureReport("\(type).\(function): incorrect calls count: \(callCount)", file, line)
return
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftMock/SwiftMock.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@attached(peer, names: suffixed(Mock))
public macro Mock() = #externalMacro(module: "SwiftMockMacros", type: "MockMacro")

public var testFailureReport: (String) -> Void = { _ in
public var testFailureReport: (String, StaticString, UInt) -> Void = { _, _, _ in
assertionFailure("Please import SwiftMockConfiguration module and call 'SwiftMockConfiguration.setUp()' in 'setUp()' method of your XCTestCase subclass.")
}

Expand Down
4 changes: 3 additions & 1 deletion Sources/SwiftMock/Verify/Container.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public protocol CallContainer {
matcher: ArgumentMatcher<T>,
times: TimesMatcher,
type: String,
function: String
function: String,
file: StaticString,
line: UInt
)
}
14 changes: 0 additions & 14 deletions Sources/SwiftMock/Verify/MethodCall.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,4 @@ public struct MethodCall<Arguments> {
public init(arguments: Arguments) {
self.arguments = arguments
}

public static func verify(
in container: [MethodCall<Arguments>],
matcher match: ArgumentMatcher<Arguments>,
times: TimesMatcher,
type: String,
function: String
) {
let callCount = container.filter { match($0.arguments) }.count
guard times(callCount) else {
testFailureReport("\(type).\(function): incorrect calls count: \(callCount)")
return
}
}
}
6 changes: 4 additions & 2 deletions Sources/SwiftMock/Verify/VerifyContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ public class VerifyContainer: CallContainer {
matcher match: ArgumentMatcher<T>,
times: (Int) -> Bool,
type: String,
function: String
function: String,
file: StaticString,
line: UInt
) {
var callCount = 0
var indexes: [Array.Index] = []
Expand All @@ -48,7 +50,7 @@ public class VerifyContainer: CallContainer {
callCount += 1
}
guard times(callCount) else {
testFailureReport("\(type).\(function): incorrect calls count: \(callCount)")
testFailureReport("\(type).\(function): incorrect calls count: \(callCount)", file, line)
return
}
for index in indexes {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public final class AsyncMethodInvocationContainer {
guard let invocation = invocations.last(where: { invocation in
invocation.match(arguments)
}) else {
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)")
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)", #file, #line)
fatalError("\(type).\(function): could not find invocation for arguments: \(arguments)")
}
return await invocation.eval(arguments)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public final class AsyncRethrowsMethodInvocationContainer {
guard let invocation = invocations.last(where: { invocation in
invocation.match(arguments)
}) else {
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)")
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)", #file, #line)
fatalError("\(type).\(function): could not find invocation for arguments: \(arguments)")
}
return try await invocation.eval(arguments, f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public final class AsyncThrowsMethodInvocationContainer {
guard let invocation = invocations.last(where: { invocation in
invocation.match(arguments)
}) else {
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)")
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)", #file, #line)
fatalError("\(type).\(function): could not find invocation for arguments: \(arguments)")
}
return try await invocation.eval(arguments)
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftMock/When/MethodInvocationContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public final class MethodInvocationContainer {
guard let invocation = invocations.last(where: { invocation in
invocation.match(arguments)
}) else {
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)")
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)", #file, #line)
fatalError("\(type).\(function): could not find invocation for arguments: \(arguments)")
}
return invocation.eval(arguments)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public final class RethrowsMethodInvocationContainer {
guard let invocation = invocations.last(where: { invocation in
invocation.match(arguments)
}) else {
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)")
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)", #file, #line)
fatalError("\(type).\(function): could not find invocation for arguments: \(arguments)")
}
return try invocation.eval(arguments, f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public final class ThrowsMethodInvocationContainer {
guard let invocation = invocations.last(where: { invocation in
invocation.match(arguments)
}) else {
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)")
testFailureReport("\(type).\(function): could not find invocation for arguments: \(arguments)", #file, #line)
fatalError("\(type).\(function): could not find invocation for arguments: \(arguments)")
}
return try invocation.eval(arguments)
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftMockConfiguration/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import XCTest
public enum SwiftMockConfiguration {
public static func setUp() {
testFailureReport = {
XCTFail($0)
XCTFail($0, file: $1, line: $2)
}
}

Expand Down
30 changes: 0 additions & 30 deletions Sources/SwiftMockMacros/General.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,6 @@ import SwiftSyntaxBuilder
extension MockMacro {
// MARK: - Making Method Wrapper Types

static func makeMethodInvocationType(
isAsync: Bool = false,
isThrows: Bool = false,
isRethrows: Bool = false,
arguments: [TypeSyntax] = [],
returnType: TypeSyntax? = nil
) -> TypeSyntax {
makeMethodWrapperType(
baseName: .identifier("MethodInvocation"),
isAsync: isAsync,
isThrows: isThrows,
isRethrows: isRethrows,
arguments: arguments,
returnType: returnType
)
}

static func makeMethodSignatureType(
isAsync: Bool = false,
isThrows: Bool = false,
Expand All @@ -38,19 +21,6 @@ extension MockMacro {
)
}

static func makeMethodCallType(
arguments: [TypeSyntax]
) -> TypeSyntax {
TypeSyntax(
fromProtocol: IdentifierTypeSyntax(
name: .identifier("MethodCall"),
genericArgumentClause: GenericArgumentClauseSyntax {
GenericArgumentSyntax(argument: makeTupleType(from: arguments))
}
)
)
}

private static func makeMethodWrapperType(
baseName: TokenSyntax,
isAsync: Bool,
Expand Down
12 changes: 8 additions & 4 deletions Sources/SwiftMockMacros/SwiftMockMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,16 @@ public struct MockMacro: PeerMacro {
)
}

static func wrapToArgumentMatcher(_ parameterClause: FunctionParameterClauseSyntax) -> FunctionParameterClauseSyntax {
parameterClause.with(\.parameters, FunctionParameterListSyntax {
for parameter in parameterClause.parameters {
static func wrapToArgumentMatcher(_ parameterListSyntax: FunctionParameterListSyntax) -> FunctionParameterListSyntax {
FunctionParameterListSyntax {
for parameter in parameterListSyntax {
wrapToArgumentMatcher(parameter)
}
})
}
}

static func wrapToArgumentMatcher(_ parameterClause: FunctionParameterClauseSyntax) -> FunctionParameterClauseSyntax {
parameterClause.with(\.parameters, wrapToArgumentMatcher(parameterClause.parameters))
}

static func packParametersToTupleExpr<T: BidirectionalCollection>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,4 @@ extension TypeSyntax {
}
return self.name.trimmed.text == TokenSyntax.keyword(.escaping).text
}

var text: String {
String(trimmed.syntaxTextBytes.map { Unicode.Scalar($0) }.map { Character($0) })
}
}
53 changes: 50 additions & 3 deletions Sources/SwiftMockMacros/Verify.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,14 @@ extension MockMacro {
if protocolDecl.isPublic { .public }
})
.with(\.signature, FunctionSignatureSyntax(
parameterClause: wrapToArgumentMatcher(funcDecl.signature.parameterClause),
parameterClause: FunctionParameterClauseSyntax {
for parameter in wrapToArgumentMatcher(funcDecl.signature.parameterClause.parameters) {
parameter
}
for paramter in makeFileAndLineParameterClause() {
paramter
}
},
returnClause: ReturnClauseSyntax(type: IdentifierTypeSyntax(name: .identifier("Void")))
))
.with(\.body, makeVerifyBody(
Expand Down Expand Up @@ -173,7 +180,11 @@ extension MockMacro {
let functionParameterClause: FunctionParameterClauseSyntax
switch accessorDecl.accessorSpecifier.trimmed.text {
case TokenSyntax.keyword(.get).text:
functionParameterClause = FunctionParameterClauseSyntax { }
functionParameterClause = FunctionParameterClauseSyntax {
for property in makeFileAndLineParameterClause() {
property
}
}
case TokenSyntax.keyword(.set).text:
functionParameterClause = FunctionParameterClauseSyntax {
FunctionParameterSyntax(
Expand All @@ -183,6 +194,9 @@ extension MockMacro {
type: wrapToArgumentMatcherType(type: propertyType)
)
)
for property in makeFileAndLineParameterClause() {
property
}
}
default:
fatalError("Unexpected accessor for property. Supported accessors: \"get\" and \"set\"")
Expand Down Expand Up @@ -262,13 +276,23 @@ extension MockMacro {
let functionParameterClause: FunctionParameterClauseSyntax
switch accessorDecl.accessorSpecifier.trimmed.text {
case TokenSyntax.keyword(.get).text:
functionParameterClause = wrapToArgumentMatcher(subscriptDecl.parameterClause)
functionParameterClause = FunctionParameterClauseSyntax{
for parameter in wrapToArgumentMatcher(subscriptDecl.parameterClause.parameters) {
parameter
}
for parameter in makeFileAndLineParameterClause() {
parameter
}
}
case TokenSyntax.keyword(.set).text:
functionParameterClause = FunctionParameterClauseSyntax {
for parameter in wrapToArgumentMatcher(subscriptDecl.parameterClause).parameters {
parameter
}
wrapToArgumentMatcher(FunctionParameterSyntax(firstName: "newValue", type: returnType))
for parameter in makeFileAndLineParameterClause() {
parameter
}
}
default:
let diagnostic = Diagnostic(node: accessorDecl, message: DiagnosticMessage.subscriptAccessorMustBeGetOrSet)
Expand Down Expand Up @@ -328,10 +352,33 @@ extension MockMacro {
label: "function",
expression: funcSignatureExpr
)
LabeledExprSyntax(
label: "file",
expression: ExprSyntax(stringLiteral: "file")
)
LabeledExprSyntax(
label: "line",
expression: ExprSyntax(stringLiteral: "line")
)
}
}
}

private static func makeFileAndLineParameterClause() -> FunctionParameterListSyntax {
FunctionParameterListSyntax {
FunctionParameterSyntax(
firstName: "file",
type: TypeSyntax(stringLiteral: "StaticString"),
defaultValue: InitializerClauseSyntax(value: ExprSyntax(stringLiteral: "#filePath"))
)
FunctionParameterSyntax(
firstName: "line",
type: TypeSyntax(stringLiteral: "UInt"),
defaultValue: InitializerClauseSyntax(value: ExprSyntax(stringLiteral: "#line"))
)
}
}

// MARK: - Integration to other files

static func makeVerifyCallStorageProperty(
Expand Down
20 changes: 10 additions & 10 deletions Tests/SwiftMockTests/Macro/MockMacroAttributeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ final class MockMacroAttributeTests: XCTestCase {
self.container = container
self.times = times
}
func dynamicallyCall(withArguments phoneNumber: @escaping ArgumentMatcher<[Int]> = any()) -> Void {
func dynamicallyCall(withArguments phoneNumber: @escaping ArgumentMatcher<[Int]> = any(), file: StaticString = #filePath, line: UInt = #line) -> Void {
let argumentMatcher0 = phoneNumber
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TelephoneExchangeMock", function: "dynamicallyCall(withArguments:)")
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TelephoneExchangeMock", function: "dynamicallyCall(withArguments:)", file: file, line: line)
}
}
let container = VerifyContainer()
Expand Down Expand Up @@ -170,9 +170,9 @@ final class MockMacroAttributeTests: XCTestCase {
self.container = container
self.times = times
}
func subscriptGetter(dynamicMember member: @escaping ArgumentMatcher<String> = any()) {
func subscriptGetter(dynamicMember member: @escaping ArgumentMatcher<String> = any(), file: StaticString = #filePath, line: UInt = #line) {
let argumentMatcher0 = member
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "SomeProtocolMock", function: "subscript(dynamicMember member: String) -> Int { get }")
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "SomeProtocolMock", function: "subscript(dynamicMember member: String) -> Int { get }", file: file, line: line)
}
}
let container = VerifyContainer()
Expand Down Expand Up @@ -227,9 +227,9 @@ final class MockMacroAttributeTests: XCTestCase {
self.container = container
self.times = times
}
func testGetter() {
func testGetter(file: StaticString = #filePath, line: UInt = #line) {
let argumentMatcher0: ArgumentMatcher<()> = any()
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TelephoneExchangeMock", function: "test")
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TelephoneExchangeMock", function: "test", file: file, line: line)
}
}
let container = VerifyContainer()
Expand Down Expand Up @@ -283,9 +283,9 @@ final class MockMacroAttributeTests: XCTestCase {
self.container = container
self.times = times
}
func testGetter() {
func testGetter(file: StaticString = #filePath, line: UInt = #line) {
let argumentMatcher0: ArgumentMatcher<()> = any()
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TelephoneExchangeMock", function: "test")
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TelephoneExchangeMock", function: "test", file: file, line: line)
}
}
let container = VerifyContainer()
Expand Down Expand Up @@ -339,9 +339,9 @@ final class MockMacroAttributeTests: XCTestCase {
self.container = container
self.times = times
}
func testGetter() {
func testGetter(file: StaticString = #filePath, line: UInt = #line) {
let argumentMatcher0: ArgumentMatcher<()> = any()
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TelephoneExchangeMock", function: "test")
container.verify(mock: mock, matcher: argumentMatcher0, times: times, type: "TelephoneExchangeMock", function: "test", file: file, line: line)
}
}
let container = VerifyContainer()
Expand Down
Loading

0 comments on commit 54b3e1b

Please sign in to comment.