How to use parseDeclaredTypes method of conformance. class

Best Mockingbird code snippet using conformance..parseDeclaredTypes

Run Mockingbird automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

MockableType.swift

Source: MockableType.swift Github

copy
1//
2//  MockableType.swift
3//  MockingbirdCli
4//
5//  Created by Andrew Chang on 8/10/19.
6//  Copyright © 2019 Bird Rides, Inc. All rights reserved.
7//
8
9import Foundation
10import SourceKittenFramework
11import PathKit
12
13/// Classes, protocols, and extensions on either.
14class MockableType: Hashable, Comparable {
15  let name: String
16  let moduleName: String
17  let fullyQualifiedName: String
18  let fullyQualifiedModuleName: String
19  let kind: SwiftDeclarationKind
20  let accessLevel: AccessLevel
21  let methods: Set<Method>
22  let methodsCount: [Method.Reduced: UInt] // For de-duping generic methods.
23  let variables: Set<Variable>
24  let inheritedTypes: Set<MockableType>
25  let allInheritedTypeNames: [String] // Includes opaque inherited types, in declaration order.
26  let opaqueInheritedTypeNames: Set<String>
27  let selfConformanceTypes: Set<MockableType> // Types for `Self` constrained protocols.
28  let allSelfConformanceTypeNames: [String] // Includes opaque conformance type names.
29  let primarySelfConformanceType: MockableType? // Guaranteed to be a class conformance.
30  let primarySelfConformanceTypeName: String? // Specialized based on declared inheritance.
31  let genericTypeContext: [[String]] // Generic type names defined by containing types.
32  let genericTypes: [GenericType] // Generic type declarations are ordered.
33  let whereClauses: Set<WhereClause>
34  let shouldMock: Bool
35  let attributes: Attributes
36  var compilationDirectives: [CompilationDirective]
37  var containedTypes = [MockableType]()
38  let isContainedType: Bool
39  let isInGenericContainingType: Bool
40  let subclassesExternalType: Bool
41  let hasSelfConstraint: Bool
42  
43  enum Constants {
44    static let automaticInheritanceMap: [String: (moduleName: String, typeName: String)] = [
45      "Foundation.NSObjectProtocol": (moduleName: "Foundation", typeName: "NSObject"),
46    ]
47  }
48  
49  // MARK: Diagnostics
50  
51  private let baseRawType: RawType
52  let filePath: Path
53  lazy var lineNumber: Int? = {
54    return SourceSubstring.key
55      .extractLinesNumbers(from: baseRawType.dictionary,
56                           contents: baseRawType.parsedFile.file.contents)?.start
57  }()
58  
59  private let sortableIdentifier: String
60  static func < (lhs: MockableType, rhs: MockableType) -> Bool {
61    return lhs.sortableIdentifier < rhs.sortableIdentifier
62  }
63  
64  func hash(into hasher: inout Hasher) {
65    hasher.combine(sortableIdentifier)
66  }
67  
68  static func == (lhs: MockableType, rhs: MockableType) -> Bool {
69    return lhs.hashValue == rhs.hashValue
70  }
71  
72  /// Creates a `MockableType` from a set of partial `RawType` objects.
73  ///
74  /// - Parameters:
75  ///   - rawTypes: A set of partial `RawType` objects that should include the base declaration.
76  ///   - mockableTypes: All currently known `MockableType` objects used for inheritance flattening.
77  init?(from rawTypes: [RawType],
78        mockableTypes: [String: MockableType],
79        moduleNames: [String],
80        specializationContexts: [String: SpecializationContext],
81        opaqueInheritedTypeNames: Set<String>,
82        rawTypeRepository: RawTypeRepository,
83        typealiasRepository: TypealiasRepository) {
84    guard let baseRawType = rawTypes.findBaseRawType(),
85      baseRawType.kind.isMockable
86      else { return nil }
87    self.baseRawType = baseRawType
88    self.filePath = baseRawType.parsedFile.path
89    
90    let accessLevel = AccessLevel(from: baseRawType.dictionary) ?? .defaultLevel
91    guard accessLevel.isMockableType(withinSameModule: baseRawType.parsedFile.shouldMock)
92      else { return nil }
93    // Handle empty types (declared without any members).
94    let substructure = baseRawType.dictionary[SwiftDocKey.substructure.rawValue]
95      as? [StructureDictionary] ?? []
96    
97    var attributes = Attributes()
98    rawTypes.forEach({ attributes.formUnion(Attributes(from: $0.dictionary)) })
99    self.attributes = attributes
100    guard !attributes.contains(.final) else { return nil }
101    
102    self.name = baseRawType.name
103    self.moduleName = baseRawType.parsedFile.moduleName
104    self.fullyQualifiedName = baseRawType.fullyQualifiedName
105    self.fullyQualifiedModuleName = DeclaredType(from: baseRawType.fullyQualifiedModuleName)
106      .serialize(
107        with: SerializationRequest(
108          method: .moduleQualified,
109          context: SerializationRequest.Context(
110            moduleNames: moduleNames,
111            rawType: baseRawType,
112            rawTypeRepository: rawTypeRepository),
113          options: .standard))
114    self.kind = baseRawType.kind
115    self.accessLevel = accessLevel
116    self.isContainedType = !baseRawType.containingTypeNames.isEmpty
117    self.shouldMock = baseRawType.parsedFile.shouldMock
118    self.genericTypeContext = baseRawType.genericTypeContext
119    self.isInGenericContainingType = baseRawType.genericTypeContext.contains(where: { !$0.isEmpty })
120    
121    // Parse top-level declared methods and variables.
122    var (methods, variables) = MockableType
123      .parseDeclaredTypes(rawTypes: rawTypes,
124                          baseRawType: baseRawType,
125                          moduleNames: moduleNames,
126                          rawTypeRepository: rawTypeRepository,
127                          typealiasRepository: typealiasRepository)
128    
129    // Parse top-level declared generics.
130    var genericTypes = substructure
131      .compactMap({ structure -> GenericType? in
132        guard let genericType = GenericType(from: structure,
133                                            rawType: baseRawType,
134                                            moduleNames: moduleNames,
135                                            rawTypeRepository: rawTypeRepository) else { return nil }
136        return genericType
137      })
138    var whereClauses = genericTypes.flatMap({ $0.whereClauses })
139    let selfConstraintClauses: [WhereClause]
140
141    let source = baseRawType.parsedFile.data
142    if let nameSuffix = SourceSubstring.nameSuffixUpToBody.extract(from: baseRawType.dictionary,
143                                                                   contents: source),
144      let whereRange = nameSuffix.range(of: #"\bwhere\b"#, options: .regularExpression) {
145      let topLevelClauses = nameSuffix[whereRange.upperBound..<nameSuffix.endIndex]
146        .components(separatedBy: ",", excluding: .allGroups)
147        .compactMap({ WhereClause(from: String($0)) })
148        .map({ GenericType.qualifyWhereClause($0,
149                                              containingType: baseRawType,
150                                              moduleNames: moduleNames,
151                                              rawTypeRepository: rawTypeRepository) })
152      // Note: Superclass `Self` conformance must be done through the inheritance syntax, which is
153      // passed via `selfConformanceTypes`.
154      whereClauses.append(contentsOf: topLevelClauses.filter({ !$0.hasSelfConstraint }))
155      selfConstraintClauses = topLevelClauses.filter({ $0.hasSelfConstraint })
156    } else {
157      selfConstraintClauses = []
158    }
159    
160    // Parse inherited members and generics.
161    let rawInheritedTypeNames = rawTypes
162      .compactMap({ $0.dictionary[SwiftDocKey.inheritedtypes.rawValue] as? [StructureDictionary] })
163      .flatMap({ $0 })
164      .compactMap({ $0[SwiftDocKey.name.rawValue] as? String })
165    let (inheritedTypes, _, allInheritedTypeNames, subclassesExternalType) =
166      MockableType
167        .parseInheritedTypes(rawInheritedTypeNames: rawInheritedTypeNames,
168                             forConformance: false,
169                             methods: &methods,
170                             variables: &variables,
171                             genericTypes: &genericTypes,
172                             whereClauses: &whereClauses,
173                             selfConstraintClauses: selfConstraintClauses,
174                             mockableTypes: mockableTypes,
175                             moduleNames: moduleNames,
176                             genericTypeContext: genericTypeContext,
177                             specializationContexts: specializationContexts,
178                             baseRawType: baseRawType,
179                             rawTypeRepository: rawTypeRepository,
180                             typealiasRepository: typealiasRepository)
181    self.inheritedTypes = inheritedTypes
182    self.allInheritedTypeNames = allInheritedTypeNames
183    self.opaqueInheritedTypeNames = opaqueInheritedTypeNames
184      .union(Set(inheritedTypes.flatMap({ $0.opaqueInheritedTypeNames })))
185
186    // Parse protocol `Self` conformance.
187    let rawConformanceTypeNames = baseRawType.kind == .protocol ?
188      baseRawType.selfConformanceTypeNames.union(
189        Set(inheritedTypes.map({ $0.fullyQualifiedModuleName }))
190      ) : []
191    let (_, allSelfConformanceTypes, allSelfConformanceTypeNames, conformsToExternalType) =
192      MockableType
193        .parseInheritedTypes(rawInheritedTypeNames: Array(rawConformanceTypeNames),
194                             forConformance: true,
195                             methods: &methods,
196                             variables: &variables,
197                             genericTypes: &genericTypes,
198                             whereClauses: &whereClauses,
199                             selfConstraintClauses: selfConstraintClauses,
200                             mockableTypes: mockableTypes,
201                             moduleNames: moduleNames,
202                             genericTypeContext: genericTypeContext,
203                             specializationContexts: specializationContexts,
204                             baseRawType: baseRawType,
205                             rawTypeRepository: rawTypeRepository,
206                             typealiasRepository: typealiasRepository)
207    self.selfConformanceTypes = allSelfConformanceTypes
208    self.allSelfConformanceTypeNames = allSelfConformanceTypeNames
209    
210    if let inheritedPrimaryType =
211      inheritedTypes.sorted() // e.g. `protocol MyProtocol: ClassOnlyProtocol`
212        .first(where: { $0.primarySelfConformanceType != nil }) ??
213      allSelfConformanceTypes.sorted() // e.g. `protocol MyProtocol where Self: ClassOnlyProtocol`
214        .first(where: { $0.primarySelfConformanceType != nil }),
215      let primarySelfConformanceType = inheritedPrimaryType.primarySelfConformanceType,
216      let primarySelfConformanceTypeName = inheritedPrimaryType.primarySelfConformanceTypeName {
217      
218      self.primarySelfConformanceType = primarySelfConformanceType
219      self.primarySelfConformanceTypeName = primarySelfConformanceTypeName
220
221    } else if let primaryType = allSelfConformanceTypes.sorted()
222      .first(where: { $0.kind == .class }) {
223      self.primarySelfConformanceType = primaryType
224      self.primarySelfConformanceTypeName = MockableType
225        .specializedSelfConformanceTypeName(primaryType,
226                                            specializationContexts: specializationContexts,
227                                            moduleNames: moduleNames,
228                                            baseRawType: baseRawType,
229                                            rawTypeRepository: rawTypeRepository,
230                                            typealiasRepository: typealiasRepository)
231
232    } else {
233      self.primarySelfConformanceType = nil
234      self.primarySelfConformanceTypeName = nil
235    }
236    
237    self.subclassesExternalType = subclassesExternalType || conformsToExternalType
238    self.methods = methods
239    self.variables = variables
240    
241    var methodsCount = [Method.Reduced: UInt]()
242    methods.forEach({ methodsCount[Method.Reduced(from: $0), default: 0] += 1 })
243    self.methodsCount = methodsCount
244    
245    self.genericTypes = genericTypes
246    self.whereClauses = Set(whereClauses)
247    
248    // Parse any containing preprocessor macros.
249    if let offset = baseRawType.dictionary[SwiftDocKey.offset.rawValue] as? Int64 {
250      self.compilationDirectives = baseRawType.parsedFile.compilationDirectives.filter({
251        $0.range.contains(offset)
252      })
253    } else {
254      self.compilationDirectives = []
255    }
256    
257    // Check if any of the members have `Self` constraints.
258    self.hasSelfConstraint = whereClauses.contains(where: { $0.hasSelfConstraint })
259      || methods.contains(where: { $0.hasSelfConstraint })
260      || variables.contains(where: { $0.hasSelfConstraint })
261      || genericTypes.contains(where: { $0.hasSelfConstraint })
262    
263    if baseRawType.parsedFile.shouldMock {
264      self.sortableIdentifier = [
265        self.name,
266        self.genericTypes.map({ "\($0.name):\($0.constraints)" }).joined(separator: ","),
267        self.whereClauses.map({ "\($0)" }).joined(separator: ",")
268      ].joined(separator: "|")
269    } else {
270      self.sortableIdentifier = name
271    }
272  }
273  
274  private static func parseDeclaredTypes(rawTypes: [RawType],
275                                         baseRawType: RawType,
276                                         moduleNames: [String],
277                                         rawTypeRepository: RawTypeRepository,
278                                         typealiasRepository: TypealiasRepository)
279    -> (methods: Set<Method>, variables: Set<Variable>) {
280      var methods = Set<Method>()
281      var variables = Set<Variable>()
282      for rawType in rawTypes {
283        guard let substructure = rawType.dictionary[SwiftDocKey.substructure.rawValue]
284          as? [StructureDictionary] else { continue }
285        // Cannot override declarations in extensions as they are statically defined.
286        guard rawType.kind != .extension else { continue }
287        for structure in substructure {
288          if let method = Method(from: structure,
289                                 rootKind: baseRawType.kind,
290                                 rawType: rawType,
291                                 moduleNames: moduleNames,
292                                 rawTypeRepository: rawTypeRepository,
293                                 typealiasRepository: typealiasRepository) {
294            methods.insert(method)
295          }
296          if let variable = Variable(from: structure,
297                                     rootKind: baseRawType.kind,
298                                     rawType: rawType,
299                                     moduleNames: moduleNames,
300                                     rawTypeRepository: rawTypeRepository) {
301            variables.insert(variable)
302          }
303        }
304      }
305      return (methods, variables)
306  }
307  
308  // TODO: Supporting protocol `Self` conformance has bloated this function. Needs a refactor soon.
309  private static func parseInheritedTypes(rawInheritedTypeNames: [String],
310                                          forConformance: Bool,
311                                          methods: inout Set<Method>,
312                                          variables: inout Set<Variable>,
313                                          genericTypes: inout [GenericType],
314                                          whereClauses: inout [WhereClause],
315                                          selfConstraintClauses: [WhereClause],
316                                          mockableTypes: [String: MockableType],
317                                          moduleNames: [String],
318                                          genericTypeContext: [[String]],
319                                          specializationContexts: [String: SpecializationContext],
320                                          baseRawType: RawType,
321                                          rawTypeRepository: RawTypeRepository,
322                                          typealiasRepository: TypealiasRepository)
323    
324    -> (inheritedTypes: Set<MockableType>, // Directly inherited types
325    allInheritedTypes: Set<MockableType>, // Includes ancestor inheritance
326    allInheritedTypeNames: [String], // Includes ancestor inheritance and opaque type names
327    subclassesExternalType: Bool) {
328      
329      var inheritedTypes = Set<MockableType>()
330      var allInheritedTypes = Set<MockableType>()
331      var allInheritedTypeNames = [String]()
332      var subclassesExternalType = false
333      let definesDesignatedInitializer = methods.contains(where: { $0.isDesignatedInitializer })
334      
335      let resolveRawType: (String) -> RawType? = { typeName in
336        guard let nearestRawType = rawTypeRepository
337          .nearestInheritedType(named: typeName,
338                                trimmedName: typeName.removingGenericTyping(),
339                                moduleNames: moduleNames,
340                                referencingModuleName: baseRawType.parsedFile.moduleName,
341                                containingTypeNames: baseRawType.containingTypeNames[...])?
342          .findBaseRawType() else { return nil }
343        
344        // Map unmockable inherited types to other types.
345        if baseRawType.kind == .protocol,
346          let mappedType = MockableType.Constants.automaticInheritanceMap[
347            nearestRawType.fullyQualifiedModuleName
348          ],
349          let mappedRawType = rawTypeRepository.rawType(named: mappedType.typeName,
350                                                        in: mappedType.moduleName) {
351          return mappedRawType.findBaseRawType()
352        }
353        
354        return nearestRawType
355      }
356      
357      // Find the correct `MockableType` instances for inheritance based on type name.
358      let parsedInheritedTypes = rawInheritedTypeNames.flatMap({ typeName -> [MockableType] in
359        guard let nearestRawType = resolveRawType(typeName) else {
360          log("Unable to resolve inherited type \(typeName.singleQuoted) for \(baseRawType.name.singleQuoted)")
361          allInheritedTypeNames.append(typeName)
362          return []
363        }
364        
365        // Inherited types could be typealiased, which would hide conformance.
366        guard nearestRawType.kind == .typealias else {
367          guard let mockableType = mockableTypes[nearestRawType.fullyQualifiedModuleName] else {
368            return []
369          }
370          return [mockableType]
371        }
372        
373        // Resolve typealias to fully qualified root type name.
374        let actualTypeNames = typealiasRepository
375          .actualTypeNames(for: nearestRawType.fullyQualifiedModuleName,
376                           rawTypeRepository: rawTypeRepository,
377                           moduleNames: moduleNames,
378                           referencingModuleName: baseRawType.parsedFile.moduleName,
379                           containingTypeNames: baseRawType.containingTypeNames[...])
380        
381        // Resolve fully qualified root type name to raw type.
382        return actualTypeNames.compactMap({
383          guard let nearestRawType = rawTypeRepository
384            .nearestInheritedType(named: $0,
385                                  trimmedName: $0.removingGenericTyping(),
386                                  moduleNames: moduleNames,
387                                  referencingModuleName: baseRawType.parsedFile.moduleName,
388                                  containingTypeNames: baseRawType.containingTypeNames[...])?
389            .findBaseRawType() else { return nil }
390          return mockableTypes[nearestRawType.fullyQualifiedModuleName]
391        })
392      })
393
394      // Merge all inheritable members from the `MockableType` instances.
395      for mockableType in parsedInheritedTypes {
396        if baseRawType.kind == .class
397          && mockableType.kind == .class
398          && mockableType.moduleName != baseRawType.parsedFile.moduleName {
399          subclassesExternalType = true
400        }
401        
402        let shouldInheritFromType = baseRawType.kind == .protocol || mockableType.kind != .protocol
403        let specializationContext = specializationContexts[mockableType.fullyQualifiedModuleName]
404        
405        methods = methods.union(mockableType.methods
406          .filter({ method in
407            let isImplicitlySynthesized = method.attributes.contains(.implicit)
408            guard shouldInheritFromType || isImplicitlySynthesized else { return false }
409            return method.kind.typeScope.isMockable(in: baseRawType.kind) &&
410              // Mocking a subclass with designated initializers shouldn't inherit the superclass'
411              // initializers.
412              (baseRawType.kind == .protocol
413                || isImplicitlySynthesized
414                || !definesDesignatedInitializer
415                || !method.isInitializer)
416          })
417          .map({ method in // Specialize methods from generic types.
418            guard let context = specializationContext else { return method }
419            return method.specialize(using: context,
420                                     moduleNames: moduleNames,
421                                     genericTypeContext: genericTypeContext,
422                                     excludedGenericTypeNames: [],
423                                     rawTypeRepository: rawTypeRepository,
424                                     typealiasRepository: typealiasRepository)
425          })
426        )
427        variables = variables.union(mockableType.variables
428          .filter({ variable in
429            guard shouldInheritFromType || variable.attributes.contains(.implicit)
430              else { return false }
431            return variable.kind.typeScope.isMockable(in: baseRawType.kind)
432          })
433          .map({ variable in // Specialize variables from generic types.
434            guard let context = specializationContext else { return variable }
435            return variable.specialize(using: context,
436                                       moduleNames: moduleNames,
437                                       genericTypeContext: genericTypeContext,
438                                       excludedGenericTypeNames: [],
439                                       rawTypeRepository: rawTypeRepository,
440                                       typealiasRepository: typealiasRepository)
441          })
442        )
443        
444        // Classes must already implement generic constraints from protocols they conform to.
445        guard shouldInheritFromType else { continue }
446        
447        inheritedTypes.insert(mockableType)
448        
449        // Indirect inheritance.
450        if !forConformance {
451          allInheritedTypes.formUnion(mockableType.inheritedTypes)
452          allInheritedTypeNames.append(contentsOf: mockableType.allInheritedTypeNames)
453        } else {
454          allInheritedTypes.formUnion(mockableType.selfConformanceTypes)
455          allInheritedTypeNames.append(contentsOf: mockableType.allSelfConformanceTypeNames)
456        }
457        
458        let isSelfConstraintType = selfConstraintClauses.contains(where: {
459          $0.constrainedTypeName == mockableType.fullyQualifiedModuleName
460            || $0.genericConstraint == mockableType.fullyQualifiedModuleName
461        })
462        let shouldIncludeInheritedType = !forConformance ||
463          forConformance && (isSelfConstraintType || mockableType.kind == .class)
464        if shouldIncludeInheritedType {
465          allInheritedTypes.insert(mockableType)
466          allInheritedTypeNames.append(MockableType.specializedSelfConformanceTypeName(
467            mockableType,
468            specializationContexts: specializationContexts,
469            moduleNames: moduleNames,
470            baseRawType: baseRawType,
471            rawTypeRepository: rawTypeRepository,
472            typealiasRepository: typealiasRepository
473          ))
474        }
475
476        // Only bubble-up generics for protocols from inherited protocols.
477        if baseRawType.kind == .protocol && mockableType.kind == .protocol {
478          let uniqueGenericTypes = Set<String>(genericTypes.map({ $0.name }))
479          genericTypes.append(contentsOf: mockableType.genericTypes.filter({
480            !uniqueGenericTypes.contains($0.name)
481          }))
482          whereClauses.append(contentsOf: mockableType.whereClauses)
483        }
484      }
485      return (inheritedTypes, allInheritedTypes, allInheritedTypeNames, subclassesExternalType)
486  }
487  
488  private static func specializedSelfConformanceTypeName(
489    _ type: MockableType,
490    specializationContexts: [String: SpecializationContext],
491    moduleNames: [String],
492    baseRawType: RawType,
493    rawTypeRepository: RawTypeRepository,
494    typealiasRepository: TypealiasRepository
495  ) -> String {
496    guard !type.genericTypes.isEmpty, !specializationContexts.isEmpty,
497      let context = specializationContexts[type.fullyQualifiedModuleName]
498      else { return type.fullyQualifiedModuleName }
499    
500    let specializedGenericTypes = context.typeList.map({ specialization -> String in
501      let serializationContext = SerializationRequest
502        .Context(moduleNames: moduleNames,
503                 rawType: baseRawType,
504                 rawTypeRepository: rawTypeRepository,
505                 typealiasRepository: typealiasRepository)
506      let qualifiedTypeNameRequest = SerializationRequest(method: .moduleQualified,
507                                                          context: serializationContext,
508                                                          options: .standard)
509      return specialization.serialize(with: qualifiedTypeNameRequest)
510    })
511    
512    let specializedTypeName = type.fullyQualifiedModuleName.removingGenericTyping() +
513      "<" + specializedGenericTypes.joined(separator: ", ") + ">"
514    return specializedTypeName
515  }
516}
517
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Trigger parseDeclaredTypes code on LambdaTest Cloud Grid

Execute automation tests with parseDeclaredTypes on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)