@@ -9,13 +9,42 @@ import RxSwift
99 let formattedName: String
1010 let lastParamName: String?
1111 }
12+
13+ struct Availability {
14+ let iOS: String?
15+ let macOS: String?
16+ let watchOS: String?
17+ let tvOS: String?
18+
19+ var description: String {
20+ var constraints = [String]()
21+ if let iOSVersion = iOS { constraints.append("iOS \(iOSVersion)") }
22+ if let macOSVersion = macOS { constraints.append("macOS \(macOSVersion)") }
23+ if let watchOSVersion = watchOS { constraints.append("watchOS \(watchOSVersion)") }
24+ if let tvOSVersion = tvOS { constraints.append("tvOS \(tvOSVersion)") }
25+ let value = "@available(\(constraints.joined(separator: ", ")), *)"
26+ return value
27+ }
28+ }
29+
30+ struct MethodDefinition: Equatable {
31+ let selectorName: String
32+ let definedInTypeName: String
33+ }
34+
1235 typealias MethodName = String
1336
1437 class Utils {
1538 static let classNamesToMock = ["CBManager", "CBAttribute", "CBCentralManager", "CBPeripheralManager", "CBPeripheral", "CBDescriptor", "CBService", "CBCharacteristic", "CBL2CAPChannel", "CBPeer", "CBATTRequest", "CBCentral", "PeripheralProvider", "Connector", "CharacteristicNotificationManager"]
1639 static let classNamesToTestable = ["Peripheral", "CentralManager", "PeripheralManager", "Characteristic"]
1740 static let delegateWrapperNamesToMock = ["CBPeripheralDelegateWrapper", "CBCentralManagerDelegateWrapper", "CBPeripheralManagerDelegateWrapper"]
1841 static let namesToMock = classNamesToMock + delegateWrapperNamesToMock
42+ static let restrictedTypes: [String: Availability] = [
43+ "CBManagerAuthorization": Availability(iOS: "13.0", macOS: "10.15", watchOS: "6.0", tvOS: "13.0")
44+ ]
45+ static let unavailableOnMac: [MethodDefinition] = [
46+ MethodDefinition(selectorName: "centralManager(_:didUpdateANCSAuthorizationFor:)", definedInTypeName: "CBCentralManagerDelegateWrapper")
47+ ]
1948
2049 static func capitalizeFirstLetter(_ text: String) -> String {
2150 return text.prefix(1).uppercased() + text.dropFirst()
@@ -74,20 +103,22 @@ import RxSwift
74103
75104 static func printVariable(_ variable: Variable, useDefaultValue: Bool = false) -> String {
76105 let forceUnwrap = variable.isOptional ? "" : "!"
106+ let avaibilityString = restrictedTypes[variable.typeName.name]?.description.appending(" lazy ") ?? ""
107+ let initialization = restrictedTypes[variable.typeName.name] != nil ? " = nil" : ""
77108 if let defaultValue = variable.defaultValue, useDefaultValue {
78109 let changedDefaultValue = changeTypeName(defaultValue)
79- return "var \(variable.name) = \(changedDefaultValue)"
110+ return "\(avaibilityString) var \(variable.name) = \(changedDefaultValue)"
80111 } else {
81112 let changedTypeName = changeTypeName(variable.typeName.name)
82- return "var \(variable.name): \(changedTypeName)\(forceUnwrap)"
113+ return "\(avaibilityString) var \(variable.name): \(changedTypeName)\(forceUnwrap)\(initialization )"
83114 }
84115 }
85116
86117 static func printMethodParamTypes(_ method: SourceryRuntime.Method) -> String {
87118 return String(method.parameters.reduce("", { "\($0)\(changeTypeName($1.typeName.name)), " }).dropLast(2))
88119 }
89120
90- static func printMethodName(_ method: SourceryRuntime.Method, changeTypeNames: Bool = true) -> String {
121+ static func printMethodName(_ method: SourceryRuntime.Method, changeTypeNames: Bool = true) -> String {
91122 var methodParams = method.parameters.reduce("", { value, parameter in
92123 var labelPart = ""
93124 if (value.count == 0 && parameter.argumentLabel == nil) {
@@ -101,6 +132,15 @@ import RxSwift
101132 }).dropLast(2)
102133 return "\(method.callName)(\(methodParams))"
103134 }
135+
136+ static func removeDuplicatesVariables(_ variables: [SourceryRuntime.Variable]) -> [SourceryRuntime.Variable] {
137+ var filteredVariables = [SourceryRuntime.Variable]()
138+ for variable in variables {
139+ guard !filteredVariables.contains(where: { $0.name == variable.name }) else { continue }
140+ filteredVariables.append(variable)
141+ }
142+ return filteredVariables
143+ }
104144 }
105145 -%>
106146
@@ -110,7 +150,10 @@ import RxSwift
110150 let typeToMock = type[classNameToMock]!
111151 let supertypeName = Utils.changeTypeName(typeToMock.supertype?.name ?? "NSObject") -%>
112152class <%= typeToMock.name %>Mock: <%= supertypeName %> {
113- <%_ for variable in typeToMock.variables { -%>
153+ <%_ for containedType in typeToMock.containedTypes { -%>
154+ class <%= containedType.localName %> {}
155+ <% } -%>
156+ <%_ for variable in Utils.removeDuplicatesVariables(typeToMock.variables) { -%>
114157 <%= Utils.printVariable(variable) %>
115158<% } -%>
116159
@@ -169,12 +212,25 @@ class <%= typeToMock.name %>Mock: NSObject <%= inheritedTypes %> {
169212
170213 override init() {
171214 }
172-
173- <%_ let filteredMethods = typeToMock.methods.filter { !$0.isInitializer }
174- for method in filteredMethods { -%>
215+ <%_ let filteredMethods = typeToMock.methods
216+ .filter { !$0.isInitializer }
217+
218+ for method in filteredMethods {
219+ var isUnavailableOnMac = false
220+ if let inTypeName = method.definedInTypeName?.name {
221+ isUnavailableOnMac = !Utils.unavailableOnMac.contains(where: {
222+ return !($0.selectorName == method.selectorName && $0.definedInTypeName == inTypeName)
223+ })
224+ } -%>
225+
226+ <%_ if isUnavailableOnMac { -%>
227+ #if !os(macOS)
228+ <%_ } -%>
175229 func <%= Utils.printMethodName(method, changeTypeNames: false) %> {
176230 }
177-
231+ <%_ if isUnavailableOnMac { -%>
232+ #endif
233+ <%_ } -%>
178234<%_ } -%>
179235}
180236<%_ } -%>
0 commit comments