From 5bb7d1e47c453b19dffefb51c4c3fae79cc80d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Laskowski?= Date: Fri, 28 Aug 2020 00:17:34 +0200 Subject: [PATCH] Updated autogenerated mocks. Updated generate-mocks script to generate mocks which works with Xcode 11: - added option to define Availability attribute for selected properties, - added option to define methods in delegate wrapper mocks which are not available on macOS, - removed duplicated properties. - generate contained types for types mocks Updated code to not generate code which emits warnings. --- .../CharacteristicNotificationManager.swift | 2 +- Templates/Mock.swifttemplate | 72 ++++++++++++++++--- Tests/Autogenerated/Mock.generated.swift | 25 +++++-- ...eristicNotificationManager.generated.swift | 2 +- 4 files changed, 87 insertions(+), 14 deletions(-) diff --git a/Source/CharacteristicNotificationManager.swift b/Source/CharacteristicNotificationManager.swift index 6f977872..7242f524 100644 --- a/Source/CharacteristicNotificationManager.swift +++ b/Source/CharacteristicNotificationManager.swift @@ -64,7 +64,7 @@ class CharacteristicNotificationManager { private func setNotifyValue(_ enabled: Bool, for characteristic: Characteristic) { guard peripheral.state == .connected else { - RxBluetoothKitLog.w("\(peripheral.logDescription) is not connected." + + RxBluetoothKitLog.w("\(String(describing: peripheral.logDescription)) is not connected." + " Changing notification state for not connected peripheral is not possible.") return } diff --git a/Templates/Mock.swifttemplate b/Templates/Mock.swifttemplate index edeb3193..1fbd3f15 100644 --- a/Templates/Mock.swifttemplate +++ b/Templates/Mock.swifttemplate @@ -9,6 +9,29 @@ import RxSwift let formattedName: String let lastParamName: String? } + + struct Availability { + let iOS: String? + let macOS: String? + let watchOS: String? + let tvOS: String? + + var description: String { + var constraints = [String]() + if let iOSVersion = iOS { constraints.append("iOS \(iOSVersion)") } + if let macOSVersion = macOS { constraints.append("macOS \(macOSVersion)") } + if let watchOSVersion = watchOS { constraints.append("watchOS \(watchOSVersion)") } + if let tvOSVersion = tvOS { constraints.append("tvOS \(tvOSVersion)") } + let value = "@available(\(constraints.joined(separator: ", ")), *)" + return value + } + } + + struct MethodDefinition: Equatable { + let selectorName: String + let definedInTypeName: String + } + typealias MethodName = String class Utils { @@ -16,6 +39,12 @@ import RxSwift static let classNamesToTestable = ["Peripheral", "CentralManager", "PeripheralManager", "Characteristic"] static let delegateWrapperNamesToMock = ["CBPeripheralDelegateWrapper", "CBCentralManagerDelegateWrapper", "CBPeripheralManagerDelegateWrapper"] static let namesToMock = classNamesToMock + delegateWrapperNamesToMock + static let restrictedTypes: [String: Availability] = [ + "CBManagerAuthorization": Availability(iOS: "13.0", macOS: "10.15", watchOS: "6.0", tvOS: "13.0") + ] + static let unavailableOnMac: [MethodDefinition] = [ + MethodDefinition(selectorName: "centralManager(_:didUpdateANCSAuthorizationFor:)", definedInTypeName: "CBCentralManagerDelegateWrapper") + ] static func capitalizeFirstLetter(_ text: String) -> String { return text.prefix(1).uppercased() + text.dropFirst() @@ -74,12 +103,14 @@ import RxSwift static func printVariable(_ variable: Variable, useDefaultValue: Bool = false) -> String { let forceUnwrap = variable.isOptional ? "" : "!" + let avaibilityString = restrictedTypes[variable.typeName.name]?.description.appending(" lazy ") ?? "" + let initialization = restrictedTypes[variable.typeName.name] != nil ? " = nil" : "" if let defaultValue = variable.defaultValue, useDefaultValue { let changedDefaultValue = changeTypeName(defaultValue) - return "var \(variable.name) = \(changedDefaultValue)" + return "\(avaibilityString)var \(variable.name) = \(changedDefaultValue)" } else { let changedTypeName = changeTypeName(variable.typeName.name) - return "var \(variable.name): \(changedTypeName)\(forceUnwrap)" + return "\(avaibilityString)var \(variable.name): \(changedTypeName)\(forceUnwrap)\(initialization)" } } @@ -87,7 +118,7 @@ import RxSwift return String(method.parameters.reduce("", { "\($0)\(changeTypeName($1.typeName.name)), " }).dropLast(2)) } - static func printMethodName(_ method: SourceryRuntime.Method, changeTypeNames: Bool = true) -> String { + static func printMethodName(_ method: SourceryRuntime.Method, changeTypeNames: Bool = true) -> String { var methodParams = method.parameters.reduce("", { value, parameter in var labelPart = "" if (value.count == 0 && parameter.argumentLabel == nil) { @@ -101,6 +132,15 @@ import RxSwift }).dropLast(2) return "\(method.callName)(\(methodParams))" } + + static func removeDuplicatesVariables(_ variables: [SourceryRuntime.Variable]) -> [SourceryRuntime.Variable] { + var filteredVariables = [SourceryRuntime.Variable]() + for variable in variables { + guard !filteredVariables.contains(where: { $0.name == variable.name }) else { continue } + filteredVariables.append(variable) + } + return filteredVariables + } } -%> @@ -110,7 +150,10 @@ import RxSwift let typeToMock = type[classNameToMock]! let supertypeName = Utils.changeTypeName(typeToMock.supertype?.name ?? "NSObject") -%> class <%= typeToMock.name %>Mock: <%= supertypeName %> { -<%_ for variable in typeToMock.variables { -%> +<%_ for containedType in typeToMock.containedTypes { -%> + class <%= containedType.localName %> {} +<% } -%> +<%_ for variable in Utils.removeDuplicatesVariables(typeToMock.variables) { -%> <%= Utils.printVariable(variable) %> <% } -%> @@ -169,12 +212,25 @@ class <%= typeToMock.name %>Mock: NSObject <%= inheritedTypes %> { override init() { } - -<%_ let filteredMethods = typeToMock.methods.filter { !$0.isInitializer } - for method in filteredMethods { -%> +<%_ let filteredMethods = typeToMock.methods + .filter { !$0.isInitializer } + + for method in filteredMethods { + var isUnavailableOnMac = false + if let inTypeName = method.definedInTypeName?.name { + isUnavailableOnMac = !Utils.unavailableOnMac.contains(where: { + return !($0.selectorName == method.selectorName && $0.definedInTypeName == inTypeName) + }) + } -%> + + <%_ if isUnavailableOnMac { -%> + #if !os(macOS) + <%_ } -%> func <%= Utils.printMethodName(method, changeTypeNames: false) %> { } - + <%_ if isUnavailableOnMac { -%> + #endif + <%_ } -%> <%_ } -%> } <%_ } -%> \ No newline at end of file diff --git a/Tests/Autogenerated/Mock.generated.swift b/Tests/Autogenerated/Mock.generated.swift index 8eb2dedd..7d361d62 100644 --- a/Tests/Autogenerated/Mock.generated.swift +++ b/Tests/Autogenerated/Mock.generated.swift @@ -1,4 +1,4 @@ -// Generated using Sourcery 0.16.0 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 1.0.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT import CoreBluetooth @@ -10,6 +10,7 @@ import RxSwift class CBManagerMock: NSObject { var state: CBManagerState! + @available(iOS 13.0, macOS 10.15, watchOS 6.0, tvOS 13.0, *) lazy var authorization: CBManagerAuthorization! = nil override init() { } @@ -23,6 +24,7 @@ class CBAttributeMock: NSObject { } class CBCentralManagerMock: CBManagerMock { + class Feature {} var delegate: CBCentralManagerDelegate? var isScanning: Bool! var logDescription: String! @@ -34,6 +36,18 @@ class CBCentralManagerMock: CBManagerMock { init(delegate: CBCentralManagerDelegate?, queue: DispatchQueue?) { } + static var supportsParams: [(CBCentralManagerMock.Feature)] = [] + static var supportsReturns: [Bool] = [] + static var supportsReturn: Bool? + static func supports(_ features: CBCentralManagerMock.Feature) -> Bool { + supportsParams.append((features)) + if supportsReturns.isEmpty { + return supportsReturn! + } else { + return supportsReturns.removeFirst() + } + } + var retrievePeripheralsParams: [([UUID])] = [] var retrievePeripheralsReturns: [[CBPeripheralMock]] = [] var retrievePeripheralsReturn: [CBPeripheralMock]? @@ -78,6 +92,11 @@ class CBCentralManagerMock: CBManagerMock { cancelPeripheralConnectionParams.append((peripheral)) } + var registerForConnectionEventsParams: [([CBConnectionEventMatchingOption : Any]?)] = [] + func registerForConnectionEvents(options: [CBConnectionEventMatchingOption : Any]? = nil) { + registerForConnectionEventsParams.append((options)) + } + } class CBPeripheralManagerMock: CBManagerMock { var delegate: CBPeripheralManagerDelegate? @@ -168,6 +187,7 @@ class CBPeripheralMock: CBPeerMock { var state: CBPeripheralState! var services: [CBServiceMock]? var canSendWriteWithoutResponse: Bool! + var ancsAuthorized: Bool! var logDescription: String! var uuidIdentifier: UUID! @@ -546,7 +566,6 @@ class CBPeripheralDelegateWrapperMock: NSObject , CBPeripheralDelegate { func peripheral(_ peripheral: CBPeripheral, didOpen channel: CBL2CAPChannel?, error: Error?) { } - } class CBCentralManagerDelegateWrapperMock: NSObject , CBCentralManagerDelegate { var didUpdateState = PublishSubject() @@ -576,7 +595,6 @@ class CBCentralManagerDelegateWrapperMock: NSObject , CBCentralManagerDelegate { func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { } - } class CBPeripheralManagerDelegateWrapperMock: NSObject , CBPeripheralManagerDelegate { var didUpdateState = PublishSubject() @@ -631,5 +649,4 @@ class CBPeripheralManagerDelegateWrapperMock: NSObject , CBPeripheralManagerDele func peripheralManager(_ peripheral: CBPeripheralManager, didOpen channel: CBL2CAPChannel?, error: Error?) { } - } diff --git a/Tests/Autogenerated/_CharacteristicNotificationManager.generated.swift b/Tests/Autogenerated/_CharacteristicNotificationManager.generated.swift index 651ba56a..46cff00c 100644 --- a/Tests/Autogenerated/_CharacteristicNotificationManager.generated.swift +++ b/Tests/Autogenerated/_CharacteristicNotificationManager.generated.swift @@ -65,7 +65,7 @@ class _CharacteristicNotificationManager { private func setNotifyValue(_ enabled: Bool, for characteristic: _Characteristic) { guard peripheral.state == .connected else { - RxBluetoothKitLog.w("\(peripheral.logDescription) is not connected." + + RxBluetoothKitLog.w("\(String(describing: peripheral.logDescription)) is not connected." + " Changing notification state for not connected peripheral is not possible.") return }