Skip to content

Commit 51bb99c

Browse files
committed
fix: automockable to support same name on functions and all variable types
1 parent 380c3bc commit 51bb99c

File tree

4 files changed

+136
-32
lines changed

4 files changed

+136
-32
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
# [0.1.1] - 2024-10-21
9+
10+
### Fixed
11+
12+
- Automockable to support functions with same name
13+
- Automackable to support all kind of variables
14+
815
# [0.1.0] - 2024-10-18
916

1017
### Added

Sources/SageSwiftKitMacros/MockableMacros/Protocols/MockableFunctionBuilder.swift

+5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct MockableFunctionBuilder {
5353
}
5454

5555
private var argumentsRegistration: CodeBlockItemSyntax {
56+
let allParameters = variables.allParameters ?? []
5657
let varName = variables.parametersNameCall
5758

5859
let callVariables: String = variablesName.reduce("", { acc, name in
@@ -65,6 +66,10 @@ struct MockableFunctionBuilder {
6566
}
6667
})
6768

69+
if allParameters.count == 1 {
70+
return .init(stringLiteral: "self.\(varName).append(\(variablesName.first ?? ""))")
71+
}
72+
6873
return .init(stringLiteral: "self.\(varName).append((\(callVariables)))")
6974
}
7075

Sources/SageSwiftKitMacros/MockableMacros/Protocols/MockableVariablesBuilder.swift

+39-19
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,15 @@ struct MockableVariablesBuilder {
1717
self.accessLevel = accessLevel
1818
}
1919

20-
private var name: String { functionSyntax.name.text }
20+
private var name: String {
21+
let name = functionSyntax.name.text
22+
23+
let params = allParameters ?? []
24+
25+
return params.reduce(name, { acc, param -> String in
26+
return acc+"_\(param.firstName.text)"
27+
})
28+
}
2129

2230
var callsCountName: String { "\(name)CallsCount" }
2331
var calledName: String { "\(name)Called" }
@@ -40,30 +48,28 @@ struct MockableVariablesBuilder {
4048
)
4149
}
4250

43-
var parametersTupple: String? {
51+
var allParameters: [FunctionParameterSyntax]? {
4452
guard let clause = functionSyntax.signature.parameterClause.as(FunctionParameterClauseSyntax.self) else {
4553
return nil
4654
}
4755

48-
let allParameters: [FunctionParameterSyntax] = clause.parameters.compactMap { $0.as(FunctionParameterSyntax.self) }
56+
return clause.parameters.compactMap { $0.as(FunctionParameterSyntax.self)
57+
}
58+
}
59+
60+
var parametersTupple: String? {
61+
guard let allParameters else { return nil }
4962

50-
var parameterTupple: (FunctionParameterSyntax) -> String = { (param: FunctionParameterSyntax) -> String in
63+
let parameterTupple: (FunctionParameterSyntax) -> String = { (param: FunctionParameterSyntax) -> String in
5164
let name = param.secondName?.text ?? param.firstName.text
5265

53-
if var attributed = param.type.as(AttributedTypeSyntax.self) {
54-
attributed.attributes = .init(stringLiteral: "")
55-
return "\(name): \(attributed.description)"
56-
}
57-
58-
if var identifier = param.type.as(IdentifierTypeSyntax.self) {
59-
return "\(name): \(identifier.description)"
60-
}
66+
let description = param.type.description.replacingOccurrences(of: "@escaping", with: "")
6167

62-
return "\(name): \(param.description)"
68+
return "\(name): \(description)"
6369
}
6470

6571
if allParameters.count == 1 {
66-
return parameterTupple(allParameters[0])
72+
return allParameters[0].type.description
6773
}
6874

6975
return allParameters.reduce("", { acc, param in
@@ -78,7 +84,16 @@ struct MockableVariablesBuilder {
7884
}
7985

8086
func parametersVar() throws -> VariableDeclSyntax? {
81-
guard let parametersTupple else { return nil }
87+
guard let parametersTupple, let allParameters else { return nil }
88+
89+
if allParameters.count == 1 {
90+
return try .init(
91+
.init(stringLiteral: "\(accessLevel) var \(parametersName): \(parametersTupple)?"),
92+
accessor: {
93+
.init(stringLiteral: "self.\(parametersNameCall).last")
94+
}
95+
)
96+
}
8297

8398
return try .init(
8499
.init(stringLiteral: "\(accessLevel) var \(parametersName): (\(parametersTupple))?"),
@@ -97,17 +112,22 @@ struct MockableVariablesBuilder {
97112
}
98113

99114
func returnVariable() throws -> VariableDeclSyntax? {
100-
guard let returnValue = functionSyntax.signature.returnClause,
101-
let type = returnValue.type.as(IdentifierTypeSyntax.self) else {
115+
guard let returnValue = functionSyntax.signature.returnClause else {
102116
return nil
103117
}
104118

105-
if type.name.text == "Void" {
119+
if returnValue.description.contains("Void") {
106120
return nil
107121
}
108122

123+
if returnValue.description.contains("?") {
124+
return try .init(
125+
.init(stringLiteral: "\(accessLevel) var \(returnName): \(returnValue.type.description)")
126+
)
127+
}
128+
109129
return try .init(
110-
.init(stringLiteral: "\(accessLevel) var \(returnName): \(type.description)!")
130+
.init(stringLiteral: "\(accessLevel) var \(returnName): \(returnValue.type.description)!")
111131
)
112132
}
113133
}

Tests/SageSwiftKitTests/MockableMacrosTests/MockableMacrosTests.swift

+85-13
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ import SwiftSyntax
77
import SwiftSyntaxBuilder
88
import SwiftSyntaxMacros
99
import SwiftSyntaxMacrosTestSupport
10+
import SageSwiftKit
11+
import Foundation
12+
import Combine
1013
import XCTest
1114

1215
final class MockableMacrosTests: XCTestCase {
1316
func testMacro() throws {
1417
#if canImport(SageSwiftKitMacros)
1518
assertMacroExpansion(
1619
"""
17-
@AutoMockable
20+
@AutoMockable()
1821
protocol PlayingObject {
1922
var value: String? { get }
2023
@@ -31,21 +34,21 @@ final class MockableMacrosTests: XCTestCase {
3134
class PlayingObjectMock: PlayingObject {
3235
init() {
3336
}
34-
var tmpFuncCallsCount: Int = 0
35-
var tmpFuncCalled: Bool {
36-
tmpFuncCallsCount > 0
37+
var tmpFunc_valueCallsCount: Int = 0
38+
var tmpFunc_valueCalled: Bool {
39+
tmpFunc_valueCallsCount > 0
3740
}
38-
var tmpFuncParameters: (value: String)? {
39-
self.tmpFuncParametersCalls.last
41+
var tmpFunc_valueParameters: String? {
42+
self.tmpFunc_valueParametersCalls.last
4043
}
41-
var tmpFuncParametersCalls: [(value: String)] = []
42-
var tmpFuncReturnValue: Int!
43-
44-
44+
var tmpFunc_valueParametersCalls: [(String)] = []
45+
var tmpFunc_valueReturnValue: Int!
46+
47+
4548
func tmpFunc(value: String) -> Int {
46-
self.tmpFuncCallsCount += 1
47-
self.tmpFuncParametersCalls.append((value: value))
48-
return self.tmpFuncReturnValue
49+
self.tmpFunc_valueCallsCount += 1
50+
self.tmpFunc_valueParametersCalls.append(value)
51+
return self.tmpFunc_valueReturnValue
4952
}
5053
}
5154
""",
@@ -55,4 +58,73 @@ final class MockableMacrosTests: XCTestCase {
5558
throw XCTSkip("macros are only supported when running tests for the host platform")
5659
#endif
5760
}
61+
62+
enum TestError: Error {
63+
case noValue
64+
}
65+
66+
@AutoMockable
67+
public protocol ProtocolToTest {
68+
func fetchPeriodsList(
69+
employeeId: Int,
70+
startDate: Date?,
71+
endDate: Date?
72+
) -> AnyPublisher<[Int], TestError>
73+
74+
func fetchDetailPeriod(
75+
employeeId: Int,
76+
period: Double
77+
) -> AnyPublisher<Int, TestError>
78+
79+
func fetchDetailPeriod(
80+
employeeId: Int,
81+
date: Date
82+
) -> AnyPublisher<Double, TestError>
83+
84+
func detailPeriodCache(date: Date) -> TestError?
85+
func fetchCommentsAndChangelog(
86+
employeeId: Int64,
87+
date: Date
88+
) -> AnyPublisher<Int, TestError>
89+
90+
func saveWorkDay(
91+
employeeId: Int64,
92+
date: Date,
93+
from: Date,
94+
to: Date,
95+
breakStart: Date?,
96+
breakEnd: Date?,
97+
breakLength: Int,
98+
comments: [Bool]
99+
) -> AnyPublisher<Int, TestError>
100+
func cancelTimesheet(employeeId: Int64, period: Bool) -> AnyPublisher<Bool, TestError>
101+
102+
func submitTimesheet(
103+
employeeId: Int64,
104+
period: Bool,
105+
overtime: Int?
106+
) -> AnyPublisher<Bool, TestError>
107+
108+
func fetchGeofencingZones(
109+
employeeId: Int64,
110+
cache: Bool
111+
) -> AnyPublisher<Int, TestError>
112+
113+
func fetchCurrentUser() -> AnyPublisher<Int, TestError>
114+
115+
func updatePermission(
116+
employeeId: Int64,
117+
consent: Bool?,
118+
deviceEnable: Bool?
119+
) -> AnyPublisher<Bool, TestError>
120+
}
121+
122+
func testProtocol() {
123+
let mockProtocol: ProtocolToTestMock = ProtocolToTestMock()
124+
125+
XCTAssertEqual(mockProtocol.detailPeriodCache(date: Date()), nil)
126+
mockProtocol.detailPeriodCache_dateReturnValue = .noValue
127+
128+
XCTAssertEqual(mockProtocol.detailPeriodCache(date: Date()), .noValue)
129+
}
58130
}

0 commit comments

Comments
 (0)