How to use flattenInheritance method of Result class

Best Mockingbird code snippet using Result.flattenInheritance

Run Mockingbird automation tests on LambdaTest cloud grid

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

FlattenInheritanceOperation.swift

Source: FlattenInheritanceOperation.swift Github

copy
1//
2//  FlattenInheritanceOperation.swift
3//  MockingbirdGenerator
4//
5//  Created by Andrew Chang on 9/15/19.
6//
7
8import Foundation
9import SourceKittenFramework
10
11/// Given a set of `RawType` partials for a single type, creates a `MockableType` object by going to
12/// the top of the type inheritance tree and walking downwards. Each step flattens the tree and
13/// memoizes a `MockableType` object. Once the process reaches the bottom original type, all
14/// inherited dependency types exist and can be merged. See the `MockableType` initializer for the
15/// merging strategy.
16class FlattenInheritanceOperation: BasicOperation {
17  let rawType: [RawType]
18  let moduleDependencies: [String: Set<String>]
19  let rawTypeRepository: RawTypeRepository
20  let typealiasRepository: TypealiasRepository
21  let useRelaxedLinking: Bool
22  
23  class Result {
24    fileprivate(set) var mockableType: MockableType?
25  }
26  
27  let result = Result()
28  
29  override var description: String { "Flatten Inheritance" }
30  
31  init(rawType: [RawType],
32       moduleDependencies: [String: Set<String>],
33       rawTypeRepository: RawTypeRepository,
34       typealiasRepository: TypealiasRepository,
35       useRelaxedLinking: Bool) {
36    precondition(!rawType.isEmpty)
37    self.rawType = rawType
38    self.moduleDependencies = moduleDependencies
39    self.rawTypeRepository = rawTypeRepository
40    self.typealiasRepository = typealiasRepository
41    self.useRelaxedLinking = useRelaxedLinking
42  }
43  
44  override func run() throws {
45    result.mockableType = flattenInheritance(for: rawType)
46  }
47  
48  private enum ReferencedType {
49    case inheritance(typeName: String)
50    case conformance(typeName: String)
51    case typeAliased(typeName: String)
52    
53    var typeName: String {
54      switch self {
55      case .inheritance(let typeName),
56           .conformance(let typeName),
57           .typeAliased(let typeName): return typeName
58      }
59    }
60    
61    var useAutomaticInheritance: Bool {
62      switch self {
63      case .inheritance, .conformance: return true
64      case .typeAliased: return false
65      }
66    }
67  }
68  
69  /// Recursively traverse the inheritance graph from bottom up (children to parents). Note that
70  /// `rawType` is actually an unmerged set of all `RawType` declarations found eg in extensions.
71  private static var memoizedMockbleTypes = Synchronized<[String: MockableType]>([:])
72
73  private func flattenInheritance(for rawType: [RawType]) -> MockableType? {
74    // All module names that were explicitly referenced from an import declaration.
75    let importedModuleNames = Set(rawType.flatMap({
76      $0.parsedFile.importedModuleNames.flatMap({ moduleDependencies[$0] ?? [$0] })
77        + [$0.parsedFile.moduleName]
78    }))
79    // Module names are put into an array and sorted so that looking up types is deterministic.
80    let moduleNames: [String]
81    if useRelaxedLinking {
82      // Relaxed linking aims to fix mixed source (ObjC + Swift) targets that implicitly import
83      // modules using the bridging header. The type system checks explicitly imported modules
84      // first, then falls back to any modules listed as a direct dependency for each raw type
85      // partial.
86      let implicitModuleNames = Set(rawType.flatMap({
87        Array(moduleDependencies[$0.parsedFile.moduleName] ?? [])
88      }))
89      moduleNames = Array(importedModuleNames).sorted()
90        + Array(implicitModuleNames.subtracting(importedModuleNames)).sorted()
91    } else {
92      moduleNames = Array(importedModuleNames).sorted()
93    }
94
95    // Create a copy of `memoizedMockableTypes` to reduce lock contention.
96    let memoizedMockableTypes = FlattenInheritanceOperation.memoizedMockbleTypes
97      .read({ $0.mapValues({ $0 }) })
98    guard let baseRawType = rawType.findBaseRawType() else { return nil }
99    
100    let fullyQualifiedName = baseRawType.fullyQualifiedModuleName
101    if let memoized = memoizedMockableTypes[fullyQualifiedName] { return memoized }
102    
103    let referencedTypes: [ReferencedType] = rawType
104      .compactMap({ $0.dictionary[SwiftDocKey.inheritedtypes.rawValue] as? [StructureDictionary] })
105      .flatMap({ $0 })
106      .compactMap({ $0[SwiftDocKey.name.rawValue] as? String })
107      .map({ ReferencedType.inheritance(typeName: $0) })
108      + baseRawType.selfConformanceTypeNames.map({ ReferencedType.conformance(typeName: $0) })
109      + baseRawType.aliasedTypeNames.map({ ReferencedType.typeAliased(typeName: $0) })
110    
111    // Check the base case where the type doesn't inherit from anything.
112    guard !referencedTypes.isEmpty else {
113      return createMockableType(for: rawType,
114                                moduleNames: moduleNames,
115                                specializationContexts: [:],
116                                opaqueInheritedTypeNames: [])
117    }
118    
119    var opaqueInheritedTypeNames = Set<String>()
120    let (rawInheritedTypes, specializationContexts) = referencedTypes
121      .reduce(into: ([[RawType]](), [String: SpecializationContext]()), { (result, type) in
122        let typeName = type.typeName
123        
124        // Check if this is a closure instead of a raw type.
125        guard !typeName.contains("->", excluding: .allGroups) else { return }
126        
127        let resolveRawType: (Bool) -> [RawType]? = { useAutomaticInheritance in
128          guard let nearestRawType = self.rawTypeRepository
129            .nearestInheritedType(named: typeName,
130                                  moduleNames: moduleNames,
131                                  referencingModuleName: baseRawType.parsedFile.moduleName,
132                                  containingTypeNames: baseRawType.containingTypeNames[...])
133            else {
134              logWarning(
135                "\(typeName.singleQuoted) is not defined in the project or in a supporting source file",
136                diagnostic: .undefinedType,
137                filePath: baseRawType.parsedFile.path,
138                line: SourceSubstring.key
139                  .extractLinesNumbers(from: baseRawType.dictionary,
140                                       contents: baseRawType.parsedFile.file.contents)?.start
141              )
142              opaqueInheritedTypeNames.insert(typeName)
143              return nil
144          }
145          
146          // MockableType maps unmockable inherited raw types to mockable raw types during creation.
147          if useAutomaticInheritance,
148            let rawType = nearestRawType.findBaseRawType(),
149            let mappedType = MockableType.Constants.automaticInheritanceMap[
150              rawType.fullyQualifiedModuleName
151            ],
152            let mappedRawType = self.rawTypeRepository.rawType(named: mappedType.typeName,
153                                                               in: mappedType.moduleName) {
154            return mappedRawType
155          }
156          
157          return nearestRawType
158        }
159        
160        // Get stored raw type and specialization contexts.
161        let useAutomaticInheritance = type.useAutomaticInheritance && baseRawType.kind == .protocol
162        guard let rawType = resolveRawType(useAutomaticInheritance) else { return }
163        
164        result.0.append(rawType)
165        
166        // Handle specialization of inherited type.
167        guard let baseInheritedRawType = rawType.findBaseRawType(),
168          !baseInheritedRawType.genericTypes.isEmpty else { return }
169        
170        result.1[baseInheritedRawType.fullyQualifiedModuleName] =
171          SpecializationContext(typeName: typeName, baseRawType: baseInheritedRawType)
172      })
173    
174    // If there are inherited types that aren't processed, flatten them first.
175    rawInheritedTypes
176      .filter({
177        guard let baseRawInheritedType = $0.findBaseRawType() ?? $0.first else { return false }
178        return memoizedMockableTypes[baseRawInheritedType.fullyQualifiedModuleName] == nil
179      })
180      .forEach({
181        guard let rawInheritedType = $0.first else { return }
182        log("Flattening inherited type \(rawInheritedType.name.singleQuoted) for \(baseRawType.name.singleQuoted)")
183        _ = flattenInheritance(for: $0)
184      })
185    
186    return createMockableType(for: rawType,
187                              moduleNames: moduleNames,
188                              specializationContexts: specializationContexts,
189                              opaqueInheritedTypeNames: opaqueInheritedTypeNames)
190  }
191  
192  private func createMockableType(
193    for rawType: [RawType],
194    moduleNames: [String],
195    specializationContexts: [String: SpecializationContext],
196    opaqueInheritedTypeNames: Set<String>
197  ) -> MockableType? {
198    guard let baseRawType = rawType.findBaseRawType() else { return nil }
199    let fullyQualifiedName = baseRawType.fullyQualifiedModuleName
200    
201    // Flattening inherited types could have updated `memoizedMockableTypes`.
202    var memoizedMockableTypes = FlattenInheritanceOperation.memoizedMockbleTypes.value
203    let mockableType = MockableType(from: rawType,
204                                    mockableTypes: memoizedMockableTypes,
205                                    moduleNames: moduleNames,
206                                    specializationContexts: specializationContexts,
207                                    opaqueInheritedTypeNames: opaqueInheritedTypeNames,
208                                    rawTypeRepository: self.rawTypeRepository,
209                                    typealiasRepository: self.typealiasRepository)
210    // Contained types can inherit from their containing types, so store store this potentially
211    // preliminary result first.
212    FlattenInheritanceOperation.memoizedMockbleTypes.update {
213      $0[fullyQualifiedName] = mockableType
214    }
215    
216    if let mockableType = mockableType {
217      log("Created mockable type \(mockableType.name.singleQuoted)")
218    } else {
219      log("Raw type \(baseRawType.name.singleQuoted) is not mockable")
220    }
221    
222    let containedTypes = rawType.flatMap({ $0.containedTypes })
223    guard !containedTypes.isEmpty else { return mockableType } // No contained types, early out.
224    
225    // For each contained type, flatten it before adding it to `mockableType`.
226    memoizedMockableTypes[fullyQualifiedName] = mockableType
227    mockableType?.containedTypes = containedTypes.compactMap({
228      self.flattenInheritance(for: [$0])
229    })
230    FlattenInheritanceOperation.memoizedMockbleTypes.update {
231      $0[fullyQualifiedName] = mockableType
232    }
233    retainForever(mockableType)
234    return mockableType
235  }
236}
237
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 flattenInheritance code on LambdaTest Cloud Grid

Execute automation tests with flattenInheritance 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)