Sources/NeedleFoundationTest/MockComponentPathBuilder.swift (47 lines of code) (raw):

// // Copyright (c) 2018. Uber Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // import Foundation import NeedleFoundation /// This function allows you to get access to a mock component path builder that you can use to /// build mock component paths of type MockComponentPath. You can use these paths to register mock /// dependency providers during testing. /// /// - Returns: A mock component path builder. public func mockComponentPathBuilder() -> MockComponentPathBuilder { return MockComponentPathBuilder() } /// MockComponentPathBuilder aloows you to build a component path that mirrors the ancestry of a component. /// Once the path is created, you can invoke build to create an instance of MockComponentPath. This class is not /// intended to be subclassed. public final class MockComponentPathBuilder { private var path: [String] = ["^"] fileprivate init() { } /// Extend the component path from the leaf component in the current component path to its next child /// in the ancestry tree. /// /// - Parameter componentType: Type of the component. /// - Returns: Instance of the mock component path builder that has the path extended up to `componentType`. public func extendPath(to componentType: Scope.Type) -> MockComponentPathBuilder { let fullyQualifiedSelfName = String(describing: componentType) let parts = fullyQualifiedSelfName.components(separatedBy: ".") let nodeName = parts.last ?? fullyQualifiedSelfName path.append(nodeName) return self } /// Build the mock component path based. /// /// - Returns: The mock component path built based on the settings provided to the mock component path builder. public func build() -> MockComponentPath { return MockComponentPath(path: pathString()) } private func pathString() -> String { return path.joined(separator: "->") } } /// This class represents the mocked component path that describes the ancestory of a component. /// This can be used to register a mock dependency provider for the component. This class is not /// intended to be subclassed. public final class MockComponentPath { private let path: String private var preexistingDependencyProviderFactory: ((Scope) -> AnyObject)? = nil private var canUnregister = false fileprivate init(path: String) { self.path = path } /// Register a dependency provider for the mocked component path. public func register(dependencyProvider: AnyObject) { preexistingDependencyProviderFactory = __DependencyProviderRegistry.instance.dependencyProviderFactory(for: path) __DependencyProviderRegistry.instance.registerDependencyProviderFactory(for: path) { _ in return dependencyProvider } canUnregister = true } /// Unregister a previously registered dependency provider for the mocked component path. public func unregister() { guard canUnregister else { return } __DependencyProviderRegistry.instance.unregisterDependencyProviderFactory(for: path) if let preexistingDependencyProviderFactory = preexistingDependencyProviderFactory { __DependencyProviderRegistry.instance.registerDependencyProviderFactory(for: path, preexistingDependencyProviderFactory) self.preexistingDependencyProviderFactory = nil } canUnregister = false } }