Best Mockingbird code snippet using without.methodTemplate
MockableTypeTemplate.swift
Source:MockableTypeTemplate.swift
...41 static let mockProtocolName = "Mockingbird.Mock"42 static let thunkStub = #"fatalError("See 'Thunk Pruning' in the README")"#43 }44 45 private var methodTemplates = [Method: MethodTemplate]()46 init(mockableType: MockableType, mockedTypeNames: Set<String>?) {47 self.mockableType = mockableType48 self.mockedTypeNames = mockedTypeNames49 }50 51 func methodTemplate(for method: Method) -> MethodTemplate {52 if let existing = methodTemplates[method] { return existing }53 let template: MethodTemplate54 if method.isInitializer {55 template = InitializerMethodTemplate(method: method, context: self)56 } else if method.kind == .functionSubscript {57 template = SubscriptMethodTemplate(method: method, context: self)58 } else {59 template = MethodTemplate(method: method, context: self)60 }61 methodTemplates[method] = template62 return template63 }64 65 func render() -> String {66 let (directiveStart, directiveEnd) = compilationDirectiveDeclaration67 return String(lines: [68 "// MARK: - Mocked \(mockableType.name)",69 directiveStart,70 NominalTypeDefinitionTemplate(71 declaration: "public final class \(mockableType.name)Mock",72 genericTypes: genericTypes,73 genericConstraints: mockableType.whereClauses.sorted().map({ specializeTypeName("\($0)") }),74 inheritedTypes: (isAvailable ? inheritedTypes : []) + [Constants.mockProtocolName],75 body: renderBody()).render(),76 directiveEnd,77 ])78 }79 80 lazy var compilationDirectiveDeclaration: (start: String, end: String) = {81 guard !mockableType.compilationDirectives.isEmpty else { return ("", "") }82 let start = String(lines: mockableType.compilationDirectives.map({ $0.declaration }))83 let end = String(lines: mockableType.compilationDirectives.map({ _ in "#endif" }))84 return (start, end)85 }()86 87 lazy var shouldGenerateThunks: Bool = {88 guard let typeNames = mockedTypeNames else { return true }89 return mockableType.isReferenced(by: typeNames)90 }()91 92 lazy var isAvailable: Bool = {93 return unavailableMockAttribute.isEmpty94 }()95 96 /// Protocols that inherit from opaque external types are considered not available as mocks97 /// because it's not possible to generate a well-formed concrete implementation unless the98 /// inheritance is trivial.99 var nonMockableOpaqueInheritanceMessage: String? {100 let hasCompleteInheritance = mockableType.kind != .protocol101 || mockableType.opaqueInheritedTypeNames.isEmpty102 guard !hasCompleteInheritance else { return nil }103 104 let opaqueTypeNames = mockableType.opaqueInheritedTypeNames.sorted()105 let allOpaqueTypeNames = opaqueTypeNames.enumerated().map({ (index, typeName) -> String in106 (index > 0 && index == opaqueTypeNames.count-1 ? "and " : "") + typeName.singleQuoted107 }).joined(separator: opaqueTypeNames.count > 2 ? ", " : " ")108 109 if opaqueTypeNames.count > 1 {110 return "\(mockableType.name.singleQuoted) inherits from the externally-defined types \(allOpaqueTypeNames) which needs to be declared in a supporting source file"111 } else {112 return "\(mockableType.name.singleQuoted) inherits from the externally-defined type \(allOpaqueTypeNames) which needs to be declared in a supporting source file"113 }114 }115 116 /// Cannot mock a type that inherits a type that isn't declared in the same module and isn't open.117 /// This mainly applies to protocols that have a Self constraint to a non-inheritable type.118 var nonMockableInheritedTypeMessage: String? {119 guard let nonInheritableType = mockableType.inheritedTypes120 .union(mockableType.selfConformanceTypes)121 .first(where: {122 $0.kind == .class && !$0.accessLevel.isInheritableType(withinSameModule: $0.shouldMock)123 })124 else { return nil }125 return "\(mockableType.name.singleQuoted) inherits from the non-open class \(nonInheritableType.name.singleQuoted) and cannot be mocked"126 }127 128 /// Protocols can inherit properties whose names conflict from other protocols, such that it is129 /// not possible to create a class that conforms to the child protocol.130 var nonMockablePropertiesMessage: String? {131 let duplicates = Dictionary(grouping: mockableType.variables, by: {Variable.Reduced(from: $0)})132 .mapValues({ $0.count })133 .filter({ $1 > 1 })134 guard !duplicates.isEmpty else { return nil }135 136 let allDuplicates = duplicates.keys137 .sorted(by: { $0.name < $1.name })138 .enumerated()139 .map({ (index, variable) -> String in140 (index > 0 && index == duplicates.count-1 ? "and " : "") + variable.name.singleQuoted141 })142 .joined(separator: duplicates.count > 2 ? ", " : " ")143 144 if duplicates.count > 1 {145 return "\(mockableType.name.singleQuoted) contains the properties \(allDuplicates) that each conflict with inherited declarations and cannot be mocked"146 } else {147 return "\(mockableType.name.singleQuoted) contains the property \(allDuplicates) that conflicts with an inherited declaration and cannot be mocked"148 }149 }150 151 /// Classes that define designated initializers but none which are accessible.152 var nonMockableDesignatedInitializerMessage: String? {153 guard mockableType.kind == .class, !shouldGenerateDefaultInitializer else { return nil }154 guard !mockableType.methods.contains(where: { $0.isDesignatedInitializer && $0.isMockable })155 else { return nil }156 return "\(mockableType.name.singleQuoted) does not declare any accessible designated initializers and cannot be mocked"157 }158 159 /// Classes that cannot be initialized due to imported accessibility from an external module.160 var nonMockableExternalInitializerMessage: String? {161 guard mockableType.kind == .class, mockableType.subclassesExternalType else { return nil }162 guard !mockableType.methods.contains(where: { $0.isInitializer && $0.isMockable })163 else { return nil }164 return "\(mockableType.name.singleQuoted) subclasses a type from a different module but does not declare any accessible initializers and cannot be mocked"165 }166 167 lazy var unavailableMockAttribute: String = {168 guard let message = nonMockableOpaqueInheritanceMessage169 ?? nonMockableInheritedTypeMessage170 ?? nonMockablePropertiesMessage171 ?? nonMockableDesignatedInitializerMessage172 ?? nonMockableExternalInitializerMessage173 else { return "" }174 175 logWarning(176 message,177 diagnostic: .notMockable,178 filePath: mockableType.filePath,179 line: self.mockableType.lineNumber180 )181 182 return """183 @available(*, unavailable, message: "\(message)")184 """185 }()186 187 /// The static mocking context allows static or class methods to be mocked.188 var staticMockingContext: String {189 if !mockableType.genericTypes.isEmpty || mockableType.isInGenericContainingType {190 // Class-level generic types don't support static variables directly.191 let body = !shouldGenerateThunks ? Constants.thunkStub :192 "return genericStaticMockContext.resolveTypeNames([\(runtimeGenericTypeNames)])"193 return """194 static var staticMock: Mockingbird.StaticMock \(BlockTemplate(body: body, multiline: false))195 """196 } else {197 return "static let staticMock = Mockingbird.StaticMock()"198 }199 }200 201 lazy var runtimeGenericTypeNames: String = {202 let baseTypeName = "\(mockableType.name)Mock\(allGenericTypes)"203 let genericTypeSelfNames = mockableType.genericTypes204 .sorted(by: { $0.name < $1.name })205 .map({ "Swift.ObjectIdentifier(\($0.name).self).debugDescription" })206 return String(list: [baseTypeName.doubleQuoted] + genericTypeSelfNames)207 }()208 209 lazy var genericTypes: [String] = {210 return mockableType.genericTypes.map({ $0.flattenedDeclaration })211 }()212 213 lazy var allGenericTypes: String = {214 guard !mockableType.genericTypes.isEmpty else { return "" }215 return "<\(separated: mockableType.genericTypes.map({ $0.name }))>"216 }()217 218 var allInheritedTypes: String {219 return String(list: inheritedTypes + [Constants.mockProtocolName])220 }221 222 /// For scoped types referenced within their containing type.223 lazy var fullyQualifiedName: String = {224 guard mockableType.kind == .class, mockableType.isContainedType else {225 return mockableType.fullyQualifiedModuleName226 }227 return "\(mockableType.name)\(allGenericTypes)"228 }()229 230 /// For scoped types referenced at the top level but in the same module.231 func createScopedName(with containingTypeNames: [String],232 genericTypeContext: [[String]],233 suffix: String = "",234 moduleQualified: Bool = false) -> String {235 let name = moduleQualified ?236 mockableType.fullyQualifiedModuleName.removingGenericTyping() : mockableType.name237 guard mockableType.kind == .class else { // Protocols can't be nested238 return name + suffix + (!suffix.isEmpty ? allGenericTypes : "")239 }240 guard mockableType.isContainedType else {241 return name + suffix + allGenericTypes242 }243 244 let typeNames = containingTypeNames.enumerated()245 .map({ (index, typeName) -> String in246 guard let genericTypeNames = genericTypeContext.get(index), !genericTypeNames.isEmpty else {247 return typeName + suffix248 }249 // Disambiguate generic types that shadow those defined by a containing type.250 return typeName + suffix + "<\(separated: genericTypeNames.map({ typeName + "_" + $0 }))>"251 })252 + [mockableType.name + suffix + allGenericTypes]253 254 if moduleQualified && mockableType.fullyQualifiedName != mockableType.fullyQualifiedModuleName {255 return String(list: [mockableType.moduleName] + typeNames, separator: ".")256 } else {257 return String(list: typeNames, separator: ".")258 }259 }260 261 lazy var protocolClassConformance: String? = {262 guard mockableType.kind == .protocol,263 let classConformance = mockableType.primarySelfConformanceTypeName264 else { return nil }265 266 // Handle class conformance constraints from where clauses.267 return classConformance268 }()269 270 var inheritedTypes: [String] {271 var types = [String]()272 if let protocolClassConformance = self.protocolClassConformance {273 types.append(protocolClassConformance)274 }275 types.append(fullyQualifiedName)276 277 let classConformanceTypeNames = Set(278 mockableType.selfConformanceTypes279 .filter({ $0.kind == .class })280 .map({ $0.fullyQualifiedModuleName })281 )282 let conformanceTypes = Set(mockableType.allSelfConformanceTypeNames)283 .subtracting(classConformanceTypeNames)284 .subtracting(types)285 .sorted()286 return types + conformanceTypes287 }288 289 func renderBody() -> String {290 let supertypeDeclaration = "typealias MockingbirdSupertype = \(fullyQualifiedName)"291 let mockingbirdContext = """292 public let mockingbirdContext = Mockingbird.Context(["generator_version": "\(mockingbirdVersion.shortString)", "module_name": "\(mockableType.moduleName)"])293 """294 295 var components = [String(lines: [296 // Type declarations297 supertypeDeclaration,298 299 // Properties300 staticMockingContext,301 mockingbirdContext,302 ])]303 304 if isAvailable {305 components.append(contentsOf: [306 renderInitializerProxy(),307 renderVariables(),308 defaultInitializer,309 renderMethods(),310 renderContainedTypes()311 ])312 } else {313 components.append(renderContainedTypes())314 }315 316 return String(lines: components, spacing: 2)317 }318 319 func renderContainedTypes() -> String {320 guard !mockableType.containedTypes.isEmpty else { return "" }321 let containedTypesSubstructure = mockableType.containedTypes322 .map({323 MockableTypeTemplate(mockableType: $0, mockedTypeNames: mockedTypeNames)324 .render().indent()325 })326 return String(lines: containedTypesSubstructure, spacing: 2)327 }328 329 func renderInitializerProxy() -> String {330 let isProxyable: (Method) -> Bool = {331 // This needs to be a designated initializer since if it's a convenience initializer, we can't332 // always infer what concrete argument values to pass to the designated initializer.333 $0.isDesignatedInitializer && $0.isMockable334 }335 336 guard !shouldGenerateDefaultInitializer else { return "" }337 let initializers = mockableType.methods338 .filter(isProxyable)339 .filter(isOverridable)340 .sorted()341 .compactMap({ methodTemplate(for: $0).classInitializerProxy })342 343 guard !initializers.isEmpty else {344 return "public enum InitializerProxy {}"345 }346 return NominalTypeDefinitionTemplate(declaration: "public enum InitializerProxy",347 body: String(lines: initializers, spacing: 2)).render()348 }349 350 /// Store the source location of where the mock was initialized. This allows `XCTest` errors from351 /// unstubbed method invocations to show up in the testing code.352 var shouldGenerateDefaultInitializer: Bool {353 // Opaque types can have designated initializers we don't know about, so it's best to ignore.354 guard mockableType.opaqueInheritedTypeNames.isEmpty else {355 logWarning(356 "Unable to synthesize default initializer for \(mockableType.name.singleQuoted) which inherits from an external type not defined in a supporting source file",357 diagnostic: .undefinedType,358 filePath: mockableType.filePath,359 line: self.mockableType.lineNumber360 )361 return false362 }363 364 let hasDesignatedInitializer =365 mockableType.methods.contains(where: { $0.isDesignatedInitializer })366 367 guard mockableType.kind == .protocol else { // Handle classes.368 if hasDesignatedInitializer {369 log("Skipping default initializer generation for \(mockableType.name.singleQuoted) because it is a class with a designated initializer")370 }371 return !hasDesignatedInitializer372 }373 374 // We can always generate a default initializer for protocols without class conformance.375 guard protocolClassConformance != nil else { return true }376 377 // Ignore protocols conforming to a class with a designated initializer.378 guard !hasDesignatedInitializer else {379 log("Skipping default initializer generation for \(mockableType.name.singleQuoted) because it is a protocol conforming to a class with a designated initializer")380 return false381 }382 383 let isMockableClassConformance = mockableType.primarySelfConformanceType?.shouldMock ?? true384 if !isMockableClassConformance {385 logWarning(386 "\(mockableType.name.singleQuoted) conforms to a class without public initializers and cannot be initialized",387 diagnostic: .notMockable,388 filePath: mockableType.filePath,389 line: self.mockableType.lineNumber390 )391 }392 return isMockableClassConformance393 }394 395 var defaultInitializer: String {396 guard shouldGenerateDefaultInitializer else { return "" }397 let canCallSuper = mockableType.kind == .class || protocolClassConformance != nil398 return FunctionDefinitionTemplate(399 declaration: "fileprivate init(sourceLocation: Mockingbird.SourceLocation)",400 body: String(lines: [401 canCallSuper ? "super.init()" : "",402 "self.mockingbirdContext.sourceLocation = sourceLocation",403 "\(mockableType.name)Mock.staticMock.mockingbirdContext.sourceLocation = sourceLocation",404 ])).render()405 }406 407 lazy var containsOverridableDesignatedInitializer: Bool = {408 return mockableType.methods.contains(where: {409 $0.isOverridable && $0.isDesignatedInitializer && $0.isMockable410 })411 }()412 413 func renderVariables() -> String {414 return String(lines: mockableType.variables.sorted(by: <).map({415 VariableTemplate(variable: $0, context: self).render()416 }), spacing: 2)417 }418 419 func isOverridable(method: Method) -> Bool {420 let isClassMock = mockableType.kind == .class || mockableType.primarySelfConformanceType != nil421 let isGeneric = !method.whereClauses.isEmpty || !method.genericTypes.isEmpty422 guard isClassMock, isGeneric else { return true }423 424 // Not possible to override overloaded methods where uniqueness is from generic constraints.425 // https://forums.swift.org/t/cannot-override-more-than-one-superclass-declaration/22213426 // This is fixed in Swift 5.2, so non-overridable methods require compilation conditions.427 return mockableType.methodsCount[Method.Reduced(from: method)] == 1428 }429 430 func renderMethods() -> String {431 return String(lines: Set(mockableType.methods).sorted(by: <).filter({ $0.isMockable }).map({432 let renderedMethod = methodTemplate(for: $0).render()433 guard !isOverridable(method: $0) else { return renderedMethod }434 return String(lines: [435 "#if swift(>=5.2)",436 renderedMethod,437 "#endif",438 ])439 }), spacing: 2)440 }441 442 func specializeTypeName(_ typeName: String) -> String {443 // NOTE: Checking for an indicator prior to running `replacingOccurrences` is 4x faster.444 let concreteMockTypeName = mockableType.name + "Mock"445 446 if typeName.contains(SerializationRequest.Constants.selfTokenIndicator) {...
MethodTemplate.swift
Source:MethodTemplate.swift
1//2// MethodTemplate.swift3// MockingbirdCli4//5// Created by Andrew Chang on 8/6/19.6// Copyright © 2019 Bird Rides, Inc. All rights reserved.7//8// swiftlint:disable leading_whitespace9import Foundation10/// Renders a `Method` to a `PartialFileContent` object.11class MethodTemplate: Template {12 let method: Method13 let context: MockableTypeTemplate14 15 init(method: Method, context: MockableTypeTemplate) {16 self.method = method17 self.context = context18 }19 20 func render() -> String {21 let (directiveStart, directiveEnd) = compilationDirectiveDeclaration22 return String(lines: [23 directiveStart,24 String(lines: [mockedDeclarations, synthesizedDeclarations], spacing: 2),25 directiveEnd26 ])27 }28 29 enum Constants {30 /// Certain methods have `Self` enforced parameter constraints.31 static let reservedNamesMap: [String: String] = [32 // Equatable33 "==": "_equalTo",34 "!=": "_notEqualTo",35 36 // Comparable37 "<": "_lessThan",38 "<=": "_lessThanOrEqualTo",39 ">": "_greaterThan",40 ">=": "_greaterThanOrEqualTo",41 ]42 }43 44 var compilationDirectiveDeclaration: (start: String, end: String) {45 guard !method.compilationDirectives.isEmpty else { return ("", "") }46 let start = String(lines: method.compilationDirectives.map({ $0.declaration }))47 let end = String(lines: method.compilationDirectives.map({ _ in "#endif" }))48 return (start, end)49 }50 51 var mockableScopedName: String {52 return context.createScopedName(with: [], genericTypeContext: [], suffix: "Mock")53 }54 55 var classInitializerProxy: String? { return nil }56 57 var mockedDeclarations: String {58 let body = !context.shouldGenerateThunks ? MockableTypeTemplate.Constants.thunkStub :59 ThunkTemplate(mockableType: context.mockableType,60 invocation: mockableInvocation,61 shortSignature: method.parameters.isEmpty ? nil : shortSignature,62 longSignature: longSignature,63 returnType: matchableReturnType,64 isBridged: false,65 isThrowing: method.isThrowing,66 isStatic: method.kind.typeScope.isStatic,67 callMember: { scope in68 let scopedName = "\(scope).\(backticked: self.method.shortName)"69 guard self.method.isVariadic else {70 return FunctionCallTemplate(71 name: scopedName,72 arguments: self.invocationArguments,73 isThrowing: self.method.isThrowing).render()74 }75 76 // Variadic functions require casting since Swift doesn't support splatting.77 let name = FunctionCallTemplate(78 name: "Swift.unsafeBitCast",79 arguments: [80 (nil, "\(scopedName) as \(self.originalSignature)"),81 ("to", "\(parenthetical: self.longSignature).self")])82 return FunctionCallTemplate(83 name: name.render(),84 unlabeledArguments: self.invocationArguments.map({ $0.parameterName }),85 isThrowing: self.method.isThrowing).render()86 },87 invocationArguments: invocationArguments).render()88 let declaration = "public \(overridableModifiers)func \(fullNameForMocking)\(returnTypeAttributesForMocking) -> \(mockableReturnType)"89 return String(lines: [90 "// MARK: Mocked \(fullNameForMocking)",91 FunctionDefinitionTemplate(attributes: method.attributes.safeDeclarations,92 declaration: declaration,93 genericConstraints: method.whereClauses.map({ context.specializeTypeName("\($0)") }),94 body: body).render(),95 ])96 }97 98 /// Declared in a class, or a class that the protocol conforms to.99 lazy var isClassBound: Bool = {100 let isClassDefinedProtocolConformance = context.protocolClassConformance != nil101 && method.isOverridable102 return context.mockableType.kind == .class || isClassDefinedProtocolConformance103 }()104 105 var overridableUniqueDeclaration: String {106 return "\(fullNameForMocking)\(returnTypeAttributesForMocking) -> \(mockableReturnType)\(genericConstraints)"107 }108 109 lazy var uniqueDeclaration: String = { return overridableUniqueDeclaration }()110 111 /// Methods synthesized specifically for the stubbing and verification APIs.112 var synthesizedDeclarations: String {113 let invocationType = "(\(separated: matchableParameterTypes)) \(returnTypeAttributesForMatching)-> \(matchableReturnType)"114 115 var methods = [String]()116 let genericTypes = [declarationTypeForMocking, invocationType, matchableReturnType]117 let returnType = "Mockingbird.Mockable<\(separated: genericTypes)>"118 119 let declaration = "public \(regularModifiers)func \(fullNameForMatching) -> \(returnType)"120 let genericConstraints = method.whereClauses.map({ context.specializeTypeName("\($0)") })121 122 let body = !context.shouldGenerateThunks ? MockableTypeTemplate.Constants.thunkStub : """123 return \(ObjectInitializationTemplate(124 name: "Mockingbird.Mockable",125 genericTypes: genericTypes,126 arguments: [("mock", mockObject), ("invocation", matchableInvocation())]))127 """128 methods.append(129 FunctionDefinitionTemplate(attributes: method.attributes.safeDeclarations,130 declaration: declaration,131 genericConstraints: genericConstraints,132 body: body).render())133 134 // Variadics generate both the array and variadic-forms of the function signature to allow use135 // of either when stubbing and verifying.136 if method.isVariadic {137 let body = !context.shouldGenerateThunks ? MockableTypeTemplate.Constants.thunkStub : """138 return \(ObjectInitializationTemplate(139 name: "Mockingbird.Mockable",140 genericTypes: genericTypes,141 arguments: [("mock", mockObject),142 ("invocation", matchableInvocation(isVariadic: true))]))143 """144 let declaration = "public \(regularModifiers)func \(fullNameForMatchingVariadics) -> \(returnType)"145 methods.append(146 FunctionDefinitionTemplate(attributes: method.attributes.safeDeclarations,147 declaration: declaration,148 genericConstraints: genericConstraints,149 body: body).render())150 }151 152 return String(lines: methods, spacing: 2)153 }154 155 /// Modifiers specifically for stubbing and verification methods.156 lazy var regularModifiers: String = { return modifiers(allowOverride: false) }()157 /// Modifiers for mocked methods.158 lazy var overridableModifiers: String = { return modifiers(allowOverride: true) }()159 func modifiers(allowOverride: Bool = true) -> String {160 let isRequired = method.attributes.contains(.required)161 let required = (isRequired || method.isInitializer ? "required " : "")162 let shouldOverride = method.isOverridable && !isRequired && allowOverride163 let override = shouldOverride ? "override " : ""164 let `static` = method.kind.typeScope.isStatic ? "static " : ""165 return "\(required)\(override)\(`static`)"166 }167 168 lazy var genericTypes: [String] = {169 return method.genericTypes.map({ $0.flattenedDeclaration })170 }()171 172 lazy var genericConstraints: String = {173 guard !method.whereClauses.isEmpty else { return "" }174 return " where \(separated: method.whereClauses.map({ context.specializeTypeName("\($0)") }))"175 }()176 177 enum FunctionVariant {178 case function, subscriptGetter, subscriptSetter179 180 var isSubscript: Bool {181 switch self {182 case .function: return false183 case .subscriptGetter, .subscriptSetter: return true184 }185 }186 }187 188 enum FullNameMode {189 case mocking(variant: FunctionVariant)190 case matching(useVariadics: Bool, variant: FunctionVariant)191 case initializerProxy192 193 var isMatching: Bool {194 switch self {195 case .matching: return true196 case .mocking, .initializerProxy: return false197 }198 }199 200 var isInitializerProxy: Bool {201 switch self {202 case .matching, .mocking: return false203 case .initializerProxy: return true204 }205 }206 207 var useVariadics: Bool {208 switch self {209 case .matching(let useVariadics, _): return useVariadics210 case .mocking, .initializerProxy: return false211 }212 }213 214 var variant: FunctionVariant {215 switch self {216 case .matching(_, let variant), .mocking(let variant): return variant217 case .initializerProxy: return .function218 }219 }220 }221 222 func shortName(for mode: FullNameMode) -> String {223 let failable: String224 if mode.isInitializerProxy {225 failable = ""226 } else if method.attributes.contains(.failable) {227 failable = "?"228 } else if method.attributes.contains(.unwrappedFailable) {229 failable = "!"230 } else {231 failable = ""232 }233 234 // Don't escape initializers, subscripts, and special functions with reserved tokens like `==`.235 let shouldEscape = !method.isInitializer236 && method.kind != .functionSubscript237 && (method.shortName.first?.isLetter == true238 || method.shortName.first?.isNumber == true239 || method.shortName.first == "_")240 let escapedShortName = mode.isInitializerProxy ? "initialize" :241 (shouldEscape ? method.shortName.backtickWrapped : method.shortName)242 243 return genericTypes.isEmpty244 ? "\(escapedShortName)\(failable)"245 : "\(escapedShortName)\(failable)<\(separated: genericTypes)>"246 }247 248 lazy var fullNameForMocking: String = {249 return fullName(for: .mocking(variant: .function))250 }()251 lazy var fullNameForMatching: String = {252 return fullName(for: .matching(useVariadics: false, variant: .function))253 }()254 /// It's not possible to have an autoclosure with variadics. However, since a method can only have255 /// one variadic parameter, we can generate one method for wildcard matching using an argument256 /// matcher, and another for specific matching using variadics.257 lazy var fullNameForMatchingVariadics: String = {258 return fullName(for: .matching(useVariadics: true, variant: .function))259 }()260 func fullName(for mode: FullNameMode) -> String {261 let additionalParameters: [String]262 if mode.isInitializerProxy {263 additionalParameters = ["__file: StaticString = #file", "__line: UInt = #line"]264 } else if mode.variant == .subscriptSetter {265 let closureType = mode.isMatching ? "@autoclosure () -> " : ""266 additionalParameters = ["`newValue`: \(closureType)\(matchableReturnType)"]267 } else {268 additionalParameters = []269 }270 271 let parameterNames = method.parameters.map({ parameter -> String in272 let typeName: String273 if mode.isMatching && (!mode.useVariadics || !parameter.attributes.contains(.variadic)) {274 typeName = "@autoclosure () -> \(parameter.matchableTypeName(in: self))"275 } else {276 typeName = parameter.mockableTypeName(context: self)277 }278 let argumentLabel = parameter.argumentLabel ?? "_"279 let parameterName = parameter.name.backtickWrapped280 if argumentLabel.backtickUnwrapped != parameter.name {281 return "\(argumentLabel) \(parameterName): \(typeName)"282 } else if mode.isMatching && mode.variant.isSubscript {283 // Synthesized declarations for subscripts don't use argument labels (unless the parameter284 // name differs) for parity with bracket syntax.285 return "_ \(parameterName): \(typeName)"286 } else {287 return "\(parameterName): \(typeName)"288 }289 }) + additionalParameters290 291 let actualShortName = shortName(for: mode)292 let shortName: String293 if mode.isMatching, let resolvedShortName = Constants.reservedNamesMap[actualShortName] {294 shortName = resolvedShortName295 } else {296 shortName = actualShortName297 }298 299 return "\(shortName)(\(separated: parameterNames))"300 }301 302 lazy var mockableInvocation: String = {303 return ObjectInitializationTemplate(304 name: "Mockingbird.SwiftInvocation",305 arguments: [306 ("selectorName", "\(doubleQuoted: uniqueDeclaration)"),307 ("selectorType", "Mockingbird.SelectorType.method"),308 ("arguments", "[\(separated: mockArgumentMatchers)]"),309 ("returnType", "Swift.ObjectIdentifier(\(parenthetical: matchableReturnType).self)"),310 ]).render()311 }()312 313 func matchableInvocation(isVariadic: Bool = false) -> String {314 let matchers = isVariadic ? resolvedVariadicArgumentMatchers : resolvedArgumentMatchers315 return ObjectInitializationTemplate(316 name: "Mockingbird.SwiftInvocation",317 arguments: [318 ("selectorName", "\(doubleQuoted: uniqueDeclaration)"),319 ("selectorType", "Mockingbird.SelectorType.method"),320 ("arguments", "[\(matchers)]"),321 ("returnType", "Swift.ObjectIdentifier(\(parenthetical: matchableReturnType).self)"),322 ]).render()323 }324 325 lazy var resolvedArgumentMatchers: String = {326 return self.resolvedArgumentMatchers(for: method.parameters.map({ ($0.name, true) }))327 }()328 329 /// Variadic parameters cannot be resolved indirectly using `resolve()`.330 lazy var resolvedVariadicArgumentMatchers: String = {331 let parameters = method.parameters.map({ ($0.name, !$0.attributes.contains(.variadic)) })332 return resolvedArgumentMatchers(for: parameters)333 }()334 335 /// Can create argument matchers via resolving (shouldResolve = true) or by direct initialization.336 func resolvedArgumentMatchers(for parameters: [(name: String, shouldResolve: Bool)]) -> String {337 return String(list: parameters.map({ (name, shouldResolve) in338 let type = shouldResolve ? "resolve" : "ArgumentMatcher"339 return "Mockingbird.\(type)(\(name.backtickWrapped))"340 }))341 }342 343 lazy var returnTypeAttributesForMocking: String = {344 if method.attributes.contains(.rethrows) { return " rethrows" }345 if method.attributes.contains(.throws) { return " throws" }346 return ""347 }()348 349 lazy var returnTypeAttributesForMatching: String = {350 return method.isThrowing ? "throws " : ""351 }()352 353 lazy var declarationTypeForMocking: String = {354 if method.attributes.contains(.throws) {355 return "\(Declaration.throwingFunctionDeclaration)"356 } else {357 return "\(Declaration.functionDeclaration)"358 }359 }()360 361 lazy var mockArgumentMatchers: [String] = {362 return method.parameters.map({ parameter -> String in363 guard !parameter.isNonEscapingClosure else {364 // Can't save the argument in the invocation because it's a non-escaping closure type.365 return ObjectInitializationTemplate(366 name: "Mockingbird.ArgumentMatcher",367 arguments: [368 (nil, ObjectInitializationTemplate(369 name: "Mockingbird.NonEscapingClosure",370 genericTypes: [parameter.matchableTypeName(in: self)]).render())371 ]).render()372 }373 return ObjectInitializationTemplate(374 name: "Mockingbird.ArgumentMatcher",375 arguments: [(nil, "\(backticked: parameter.name)")]).render()376 })377 }()378 379 lazy var mockObject: String = {380 return method.kind.typeScope.isStatic ? "self.staticMock" : "self"381 }()382 383 /// Original function signature for casting to a matchable signature (variadics support).384 lazy var originalSignature: String = {385 let modifiers = method.isThrowing ? " throws" : ""386 let parameterTypes = method.parameters.map({387 $0.matchableTypeName(context: self, bridgeVariadics: false)388 })389 return "(\(separated: parameterTypes))\(modifiers) -> \(matchableReturnType)"390 }()391 392 /// General function signature for matching.393 lazy var longSignature: String = {394 let modifiers = method.isThrowing ? " throws" : ""395 return "(\(separated: matchableParameterTypes))\(modifiers) -> \(matchableReturnType)"396 }()397 398 /// Convenience function signature for matching without any arguments.399 lazy var shortSignature: String = {400 let modifiers = method.isThrowing ? " throws" : ""401 return "()\(modifiers) -> \(matchableReturnType)"402 }()403 404 lazy var mockableReturnType: String = {405 return context.specializeTypeName(method.returnTypeName)406 }()407 408 lazy var matchableReturnType: String = {409 return mockableReturnType.removingImplicitlyUnwrappedOptionals()410 }()411 412 lazy var mockableParameterTypes: [String] = {413 return method.parameters.map({ $0.mockableTypeName(context: self) })414 }()415 416 lazy var matchableParameterTypes: [String] = {417 return method.parameters.map({ $0.matchableTypeName(context: self) })418 }()419 420 lazy var invocationArguments: [(argumentLabel: String?, parameterName: String)] = {421 return method.parameters.map({ ($0.argumentLabel, $0.parameterName) })422 }()423}424extension Method {425 var isThrowing: Bool {426 return attributes.contains(.throws) || attributes.contains(.rethrows)427 }428 429 var isVariadic: Bool {430 return parameters.contains(where: { $0.attributes.contains(.variadic) })431 }432}433private extension MethodParameter {434 func mockableTypeName(context: MethodTemplate) -> String {435 return context.context.specializeTypeName(self.typeName)436 }437 438 func matchableTypeName(context: MethodTemplate, bridgeVariadics: Bool = true) -> String {439 let rawTypeName = mockableTypeName(context: context)440 441 // Type names outside of function declarations differ slightly. Variadics and implicitly442 // unwrapped optionals must be sanitized.443 let typeName = rawTypeName.removingImplicitlyUnwrappedOptionals()444 if bridgeVariadics && attributes.contains(.variadic) {445 return "[\(typeName.dropLast(3))]"446 } else {447 return "\(typeName)"448 }449 }450 451 var parameterName: String {452 let inoutAttribute = attributes.contains(.inout) ? "&" : ""453 let autoclosureForwarding = attributes.contains(.autoclosure) ? "()" : ""454 return "\(inoutAttribute)\(name.backtickWrapped)\(autoclosureForwarding)"455 }456 457 func matchableTypeName(in context: MethodTemplate) -> String {458 let typeName = context.context.specializeTypeName(self.typeName).removingParameterAttributes()459 if attributes.contains(.variadic) {460 return "[" + typeName + "]"461 } else {462 return typeName463 }464 }465 466 var isNonEscapingClosure: Bool {467 return attributes.contains(.closure) && !attributes.contains(.escaping)468 }469}...
methodTemplate
Using AI Code Generation
1let obj = without()2obj.methodTemplate()3let obj = without()4obj.methodTemplate()5let obj = without()6obj.methodTemplate()7let obj = without()8obj.methodTemplate()9let obj = without()10obj.methodTemplate()11let obj = without()12obj.methodTemplate()13let obj = without()14obj.methodTemplate()15let obj = without()16obj.methodTemplate()17let obj = without()18obj.methodTemplate()19let obj = without()20obj.methodTemplate()21let obj = without()22obj.methodTemplate()23let obj = without()24obj.methodTemplate()25let obj = without()26obj.methodTemplate()27let obj = without()28obj.methodTemplate()29let obj = without()30obj.methodTemplate()31let obj = without()32obj.methodTemplate()33let obj = without()34obj.methodTemplate()35let obj = without()36obj.methodTemplate()37let obj = without()38obj.methodTemplate()
methodTemplate
Using AI Code Generation
1let without = Without()2without.methodTemplate()3let without = Without()4without.methodTemplate()5let without = Without()6without.methodTemplate()7let without = Without()8without.methodTemplate()9let without = Without()10without.methodTemplate()11let without = Without()12without.methodTemplate()13let without = Without()14without.methodTemplate()15let without = Without()16without.methodTemplate()17let without = Without()18without.methodTemplate()19let without = Without()20without.methodTemplate()21let without = Without()22without.methodTemplate()23let without = Without()24without.methodTemplate()25let without = Without()26without.methodTemplate()27let without = Without()28without.methodTemplate()29let without = Without()30without.methodTemplate()31let without = Without()32without.methodTemplate()33let without = Without()34without.methodTemplate()35let without = Without()36without.methodTemplate()37let without = Without()38without.methodTemplate()
methodTemplate
Using AI Code Generation
1let withoutObject = without()2withoutObject.methodTemplate()3let withoutObject = without()4withoutObject.methodTemplate()5let withoutObject = without()6withoutObject.methodTemplate()7let withoutObject = without()8withoutObject.methodTemplate()9let withoutObject = without()10withoutObject.methodTemplate()11let withoutObject = without()12withoutObject.methodTemplate()13let withoutObject = without()14withoutObject.methodTemplate()15let withoutObject = without()16withoutObject.methodTemplate()17let withoutObject = without()18withoutObject.methodTemplate()19let withoutObject = without()20withoutObject.methodTemplate()21let withoutObject = without()22withoutObject.methodTemplate()23let withoutObject = without()24withoutObject.methodTemplate()25let withoutObject = without()26withoutObject.methodTemplate()27let withoutObject = without()28withoutObject.methodTemplate()29let withoutObject = without()30withoutObject.methodTemplate()31let withoutObject = without()32withoutObject.methodTemplate()33let withoutObject = without()34withoutObject.methodTemplate()
methodTemplate
Using AI Code Generation
1let object = Without()2object.methodTemplate()3let object = With()4object.methodTemplate()5let object = With()6object.methodTemplate()7let object = With()8object.methodTemplate()9let object = With()10object.methodTemplate()11let object = With()12object.methodTemplate()13let object = With()14object.methodTemplate()15let object = With()16object.methodTemplate()17let object = With()18object.methodTemplate()19let object = With()20object.methodTemplate()21let object = With()22object.methodTemplate()23let object = With()24object.methodTemplate()25let object = With()26object.methodTemplate()27let object = With()28object.methodTemplate()29let object = With()30object.methodTemplate()31let object = With()32object.methodTemplate()33let object = With()34object.methodTemplate()35let object = With()36object.methodTemplate()37let object = With()38object.methodTemplate()
methodTemplate
Using AI Code Generation
1without.methodTemplate()2without.methodTemplate()3without.methodTemplate()4without.methodTemplate()5without.methodTemplate()6without.methodTemplate()7without.methodTemplate()8without.methodTemplate()9without.methodTemplate()10without.methodTemplate()11without.methodTemplate()12without.methodTemplate()13without.methodTemplate()14without.methodTemplate()15without.methodTemplate()16without.methodTemplate()17without.methodTemplate()18without.methodTemplate()19without.methodTemplate()20without.methodTemplate()21without.methodTemplate()22without.methodTemplate()23without.methodTemplate()24without.methodTemplate()25without.methodTemplate()26without.methodTemplate()27without.methodTemplate()28without.methodTemplate()29without.methodTemplate()30without.methodTemplate()
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!