From 7de0fc6880c7f9a3e789558c00ac893f25bbe655 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Wed, 8 Nov 2023 23:34:53 +0500 Subject: [PATCH] Add IInternalXcodeProject protocol for testing --- .../Core/Build/BuildManager.swift | 4 +- .../Core/Build/BuildTargetsManager.swift | 4 +- .../XcodeProject/RugbyXcodeProject.swift | 4 +- .../Core/Delete/DeleteTargetsManager.swift | 4 +- .../Core/Rollback/BackupManager.swift | 4 +- .../Core/Use/UseBinariesManager.swift | 4 +- .../Vault/Commands/Vault+Use.swift | 2 +- .../Vault/Common/XcodeVault.swift | 4 +- .../XcodeProject/XcodeProject.swift | 57 +++++- .../IInternalXcodeProjectMock.generated.swift | 168 ++++++++++++++++++ 10 files changed, 235 insertions(+), 20 deletions(-) create mode 100644 Tests/FoundationTests/Mocks/IInternalXcodeProjectMock.generated.swift diff --git a/Sources/RugbyFoundation/Core/Build/BuildManager.swift b/Sources/RugbyFoundation/Core/Build/BuildManager.swift index 22b7fe37..b1920325 100644 --- a/Sources/RugbyFoundation/Core/Build/BuildManager.swift +++ b/Sources/RugbyFoundation/Core/Build/BuildManager.swift @@ -33,7 +33,7 @@ final class BuildManager: Loggable { let logger: ILogger private let buildTargetsManager: BuildTargetsManager private let librariesPatcher: ILibrariesPatcher - private let xcodeProject: XcodeProject + private let xcodeProject: IInternalXcodeProject private let rugbyXcodeProject: RugbyXcodeProject private let backupManager: IBackupManager private let processMonitor: IProcessMonitor @@ -49,7 +49,7 @@ final class BuildManager: Loggable { init(logger: ILogger, buildTargetsManager: BuildTargetsManager, librariesPatcher: ILibrariesPatcher, - xcodeProject: XcodeProject, + xcodeProject: IInternalXcodeProject, rugbyXcodeProject: RugbyXcodeProject, backupManager: IBackupManager, processMonitor: IProcessMonitor, diff --git a/Sources/RugbyFoundation/Core/Build/BuildTargetsManager.swift b/Sources/RugbyFoundation/Core/Build/BuildTargetsManager.swift index 2c03ee77..15be53ec 100644 --- a/Sources/RugbyFoundation/Core/Build/BuildTargetsManager.swift +++ b/Sources/RugbyFoundation/Core/Build/BuildTargetsManager.swift @@ -1,10 +1,10 @@ import Foundation final class BuildTargetsManager { - private let xcodeProject: XcodeProject + private let xcodeProject: IInternalXcodeProject private let buildTargetName = "RugbyPods" - init(xcodeProject: XcodeProject) { + init(xcodeProject: IInternalXcodeProject) { self.xcodeProject = xcodeProject } diff --git a/Sources/RugbyFoundation/Core/Common/XcodeProject/RugbyXcodeProject.swift b/Sources/RugbyFoundation/Core/Common/XcodeProject/RugbyXcodeProject.swift index c6d427ec..0484c2ff 100644 --- a/Sources/RugbyFoundation/Core/Common/XcodeProject/RugbyXcodeProject.swift +++ b/Sources/RugbyFoundation/Core/Common/XcodeProject/RugbyXcodeProject.swift @@ -17,10 +17,10 @@ enum RugbyError: LocalizedError { // MARK: - Implementation final class RugbyXcodeProject { - private let xcodeProject: XcodeProject + private let xcodeProject: IInternalXcodeProject private let yes = "YES" - init(xcodeProject: XcodeProject) { + init(xcodeProject: IInternalXcodeProject) { self.xcodeProject = xcodeProject } diff --git a/Sources/RugbyFoundation/Core/Delete/DeleteTargetsManager.swift b/Sources/RugbyFoundation/Core/Delete/DeleteTargetsManager.swift index 7f994a1a..11fc7869 100644 --- a/Sources/RugbyFoundation/Core/Delete/DeleteTargetsManager.swift +++ b/Sources/RugbyFoundation/Core/Delete/DeleteTargetsManager.swift @@ -20,11 +20,11 @@ public protocol IDeleteTargetsManager { final class DeleteTargetsManager: Loggable { let logger: ILogger - private let xcodeProject: XcodeProject + private let xcodeProject: IInternalXcodeProject private let backupManager: IBackupManager init(logger: ILogger, - xcodeProject: XcodeProject, + xcodeProject: IInternalXcodeProject, backupManager: IBackupManager) { self.logger = logger self.xcodeProject = xcodeProject diff --git a/Sources/RugbyFoundation/Core/Rollback/BackupManager.swift b/Sources/RugbyFoundation/Core/Rollback/BackupManager.swift index 802390c9..e516c13d 100644 --- a/Sources/RugbyFoundation/Core/Rollback/BackupManager.swift +++ b/Sources/RugbyFoundation/Core/Rollback/BackupManager.swift @@ -9,7 +9,7 @@ public protocol IBackupManager { /// - Parameters: /// - xcodeProject: A service for Xcode project managment. /// - kind: The type of backup. - func backup(_ xcodeProject: XcodeProject, kind: BackupKind) async throws + func backup(_ xcodeProject: IXcodeProject, kind: BackupKind) async throws /// Restores Xcode project. /// - Parameter kind: The type of backup. @@ -146,7 +146,7 @@ extension BackupManager { // MARK: - IBackupManager extension BackupManager: IBackupManager { - public func backup(_ xcodeProject: XcodeProject, kind: BackupKind) async throws { + public func backup(_ xcodeProject: IXcodeProject, kind: BackupKind) async throws { let projects = try await xcodeProject.folderPaths().map(Folder.at) switch kind { case .original: diff --git a/Sources/RugbyFoundation/Core/Use/UseBinariesManager.swift b/Sources/RugbyFoundation/Core/Use/UseBinariesManager.swift index 37e1fc44..2d87b1c3 100644 --- a/Sources/RugbyFoundation/Core/Use/UseBinariesManager.swift +++ b/Sources/RugbyFoundation/Core/Use/UseBinariesManager.swift @@ -30,7 +30,7 @@ final class UseBinariesManager: Loggable { private let buildTargetsManager: BuildTargetsManager private let librariesPatcher: ILibrariesPatcher - private let xcodeProject: XcodeProject + private let xcodeProject: IInternalXcodeProject private let rugbyXcodeProject: RugbyXcodeProject private let backupManager: IBackupManager private let binariesManager: IBinariesStorage @@ -41,7 +41,7 @@ final class UseBinariesManager: Loggable { init(logger: ILogger, buildTargetsManager: BuildTargetsManager, librariesPatcher: ILibrariesPatcher, - xcodeProject: XcodeProject, + xcodeProject: IInternalXcodeProject, rugbyXcodeProject: RugbyXcodeProject, backupManager: IBackupManager, binariesManager: IBinariesStorage, diff --git a/Sources/RugbyFoundation/Vault/Commands/Vault+Use.swift b/Sources/RugbyFoundation/Vault/Commands/Vault+Use.swift index 6a592025..745cbc5f 100644 --- a/Sources/RugbyFoundation/Vault/Commands/Vault+Use.swift +++ b/Sources/RugbyFoundation/Vault/Commands/Vault+Use.swift @@ -11,7 +11,7 @@ extension Vault { } func useBinariesManager(workingDirectory: IFolder, - xcodeProject: XcodeProject, + xcodeProject: IInternalXcodeProject, buildTargetsManager: BuildTargetsManager) -> IUseBinariesManager { UseBinariesManager(logger: logger, buildTargetsManager: buildTargetsManager, diff --git a/Sources/RugbyFoundation/Vault/Common/XcodeVault.swift b/Sources/RugbyFoundation/Vault/Common/XcodeVault.swift index 81ee0fed..c471bd5f 100644 --- a/Sources/RugbyFoundation/Vault/Common/XcodeVault.swift +++ b/Sources/RugbyFoundation/Vault/Common/XcodeVault.swift @@ -7,7 +7,7 @@ public final class XcodeVault { private let logsRotator: LogsRotator private let router: Router - private var xcodeProjectsCache: [String: XcodeProject] = [:] + private var xcodeProjectsCache: [String: IInternalXcodeProject] = [:] // MARK: - Init @@ -44,7 +44,7 @@ public final class XcodeVault { // MARK: - Internal Methods - func project(projectPath: String) -> XcodeProject { + func project(projectPath: String) -> IInternalXcodeProject { if let cachedXcodeProject = xcodeProjectsCache[projectPath] { return cachedXcodeProject } let projectDataSource = XcodeProjectDataSource(logger: logger, projectPath: projectPath) diff --git a/Sources/RugbyFoundation/XcodeProject/XcodeProject.swift b/Sources/RugbyFoundation/XcodeProject/XcodeProject.swift index c07ecb26..9a452c40 100644 --- a/Sources/RugbyFoundation/XcodeProject/XcodeProject.swift +++ b/Sources/RugbyFoundation/XcodeProject/XcodeProject.swift @@ -1,7 +1,56 @@ import Foundation -/// The service for Xcode project managment. -public final class XcodeProject { +/// The protocol describing a service for Xcode project managment. +public protocol IXcodeProject: AnyObject { + /// Returns paths to folders with root project and subprojects. + func folderPaths() async throws -> [String] + /// Returns `true` if the root project contains the key in the build settings. + func contains(buildSettingsKey: String) async throws -> Bool + /// Sets the value to the key in the build settings of the root project. + func set(buildSettingsKey: String, value: Any) async throws +} + +protocol IInternalXcodeProject: IXcodeProject { + func resetCache() + func save() async throws + + func findTargets( + by regex: NSRegularExpression?, + except exceptRegex: NSRegularExpression?, + includingDependencies: Bool + ) async throws -> TargetsMap + + func createAggregatedTarget( + name: String, + dependencies: TargetsMap + ) async throws -> IInternalTarget + + func deleteTargets( + _ targetsForRemove: TargetsMap, + keepGroups: Bool + ) async throws +} + +// MARK: - Implementation + +extension IInternalXcodeProject { + func findTargets() async throws -> TargetsMap { + try await findTargets(by: nil, except: nil, includingDependencies: false) + } + + func findTargets( + by regex: NSRegularExpression?, + except exceptRegex: NSRegularExpression? + ) async throws -> TargetsMap { + try await findTargets(by: regex, except: exceptRegex, includingDependencies: false) + } + + func deleteTargets(_ targetsForRemove: TargetsMap) async throws { + try await deleteTargets(targetsForRemove, keepGroups: true) + } +} + +final class XcodeProject { private let projectDataSource: XcodeProjectDataSource private let targetsFinder: XcodeTargetsFinder private let targetsEditor: XcodeTargetsEditor @@ -18,9 +67,7 @@ public final class XcodeProject { } } -// MARK: - Implementation - -extension XcodeProject { +extension XcodeProject: IInternalXcodeProject { // MARK: - File System func folderPaths() async throws -> [String] { diff --git a/Tests/FoundationTests/Mocks/IInternalXcodeProjectMock.generated.swift b/Tests/FoundationTests/Mocks/IInternalXcodeProjectMock.generated.swift new file mode 100644 index 00000000..6ea02e62 --- /dev/null +++ b/Tests/FoundationTests/Mocks/IInternalXcodeProjectMock.generated.swift @@ -0,0 +1,168 @@ +// Generated using Sourcery 2.1.1 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT + +// swiftlint:disable all + +import Foundation +@testable import RugbyFoundation + +final class IInternalXcodeProjectMock: IInternalXcodeProject { + + // MARK: - resetCache + + var resetCacheCallsCount = 0 + var resetCacheCalled: Bool { resetCacheCallsCount > 0 } + var resetCacheClosure: (() -> Void)? + + func resetCache() { + resetCacheCallsCount += 1 + resetCacheClosure?() + } + + // MARK: - save + + var saveThrowableError: Error? + var saveCallsCount = 0 + var saveCalled: Bool { saveCallsCount > 0 } + var saveClosure: (() async throws -> Void)? + + func save() async throws { + if let error = saveThrowableError { + throw error + } + saveCallsCount += 1 + try await saveClosure?() + } + + // MARK: - findTargets + + var findTargetsByExceptIncludingDependenciesThrowableError: Error? + var findTargetsByExceptIncludingDependenciesCallsCount = 0 + var findTargetsByExceptIncludingDependenciesCalled: Bool { findTargetsByExceptIncludingDependenciesCallsCount > 0 } + var findTargetsByExceptIncludingDependenciesReceivedArguments: (regex: NSRegularExpression?, exceptRegex: NSRegularExpression?, includingDependencies: Bool)? + var findTargetsByExceptIncludingDependenciesReceivedInvocations: [(regex: NSRegularExpression?, exceptRegex: NSRegularExpression?, includingDependencies: Bool)] = [] + var findTargetsByExceptIncludingDependenciesReturnValue: TargetsMap! + var findTargetsByExceptIncludingDependenciesClosure: ((NSRegularExpression?, NSRegularExpression?, Bool) async throws -> TargetsMap)? + + func findTargets(by regex: NSRegularExpression?, except exceptRegex: NSRegularExpression?, includingDependencies: Bool) async throws -> TargetsMap { + if let error = findTargetsByExceptIncludingDependenciesThrowableError { + throw error + } + findTargetsByExceptIncludingDependenciesCallsCount += 1 + findTargetsByExceptIncludingDependenciesReceivedArguments = (regex: regex, exceptRegex: exceptRegex, includingDependencies: includingDependencies) + findTargetsByExceptIncludingDependenciesReceivedInvocations.append((regex: regex, exceptRegex: exceptRegex, includingDependencies: includingDependencies)) + if let findTargetsByExceptIncludingDependenciesClosure = findTargetsByExceptIncludingDependenciesClosure { + return try await findTargetsByExceptIncludingDependenciesClosure(regex, exceptRegex, includingDependencies) + } else { + return findTargetsByExceptIncludingDependenciesReturnValue + } + } + + // MARK: - createAggregatedTarget + + var createAggregatedTargetNameDependenciesThrowableError: Error? + var createAggregatedTargetNameDependenciesCallsCount = 0 + var createAggregatedTargetNameDependenciesCalled: Bool { createAggregatedTargetNameDependenciesCallsCount > 0 } + var createAggregatedTargetNameDependenciesReceivedArguments: (name: String, dependencies: TargetsMap)? + var createAggregatedTargetNameDependenciesReceivedInvocations: [(name: String, dependencies: TargetsMap)] = [] + var createAggregatedTargetNameDependenciesReturnValue: IInternalTarget! + var createAggregatedTargetNameDependenciesClosure: ((String, TargetsMap) async throws -> IInternalTarget)? + + func createAggregatedTarget(name: String, dependencies: TargetsMap) async throws -> IInternalTarget { + if let error = createAggregatedTargetNameDependenciesThrowableError { + throw error + } + createAggregatedTargetNameDependenciesCallsCount += 1 + createAggregatedTargetNameDependenciesReceivedArguments = (name: name, dependencies: dependencies) + createAggregatedTargetNameDependenciesReceivedInvocations.append((name: name, dependencies: dependencies)) + if let createAggregatedTargetNameDependenciesClosure = createAggregatedTargetNameDependenciesClosure { + return try await createAggregatedTargetNameDependenciesClosure(name, dependencies) + } else { + return createAggregatedTargetNameDependenciesReturnValue + } + } + + // MARK: - deleteTargets + + var deleteTargetsKeepGroupsThrowableError: Error? + var deleteTargetsKeepGroupsCallsCount = 0 + var deleteTargetsKeepGroupsCalled: Bool { deleteTargetsKeepGroupsCallsCount > 0 } + var deleteTargetsKeepGroupsReceivedArguments: (targetsForRemove: TargetsMap, keepGroups: Bool)? + var deleteTargetsKeepGroupsReceivedInvocations: [(targetsForRemove: TargetsMap, keepGroups: Bool)] = [] + var deleteTargetsKeepGroupsClosure: ((TargetsMap, Bool) async throws -> Void)? + + func deleteTargets(_ targetsForRemove: TargetsMap, keepGroups: Bool) async throws { + if let error = deleteTargetsKeepGroupsThrowableError { + throw error + } + deleteTargetsKeepGroupsCallsCount += 1 + deleteTargetsKeepGroupsReceivedArguments = (targetsForRemove: targetsForRemove, keepGroups: keepGroups) + deleteTargetsKeepGroupsReceivedInvocations.append((targetsForRemove: targetsForRemove, keepGroups: keepGroups)) + try await deleteTargetsKeepGroupsClosure?(targetsForRemove, keepGroups) + } + + // MARK: - folderPaths + + public var folderPathsThrowableError: Error? + public var folderPathsCallsCount = 0 + public var folderPathsCalled: Bool { folderPathsCallsCount > 0 } + public var folderPathsReturnValue: [String]! + public var folderPathsClosure: (() async throws -> [String])? + + public func folderPaths() async throws -> [String] { + if let error = folderPathsThrowableError { + throw error + } + folderPathsCallsCount += 1 + if let folderPathsClosure = folderPathsClosure { + return try await folderPathsClosure() + } else { + return folderPathsReturnValue + } + } + + // MARK: - contains + + public var containsBuildSettingsKeyThrowableError: Error? + public var containsBuildSettingsKeyCallsCount = 0 + public var containsBuildSettingsKeyCalled: Bool { containsBuildSettingsKeyCallsCount > 0 } + public var containsBuildSettingsKeyReceivedBuildSettingsKey: String? + public var containsBuildSettingsKeyReceivedInvocations: [String] = [] + public var containsBuildSettingsKeyReturnValue: Bool! + public var containsBuildSettingsKeyClosure: ((String) async throws -> Bool)? + + public func contains(buildSettingsKey: String) async throws -> Bool { + if let error = containsBuildSettingsKeyThrowableError { + throw error + } + containsBuildSettingsKeyCallsCount += 1 + containsBuildSettingsKeyReceivedBuildSettingsKey = buildSettingsKey + containsBuildSettingsKeyReceivedInvocations.append(buildSettingsKey) + if let containsBuildSettingsKeyClosure = containsBuildSettingsKeyClosure { + return try await containsBuildSettingsKeyClosure(buildSettingsKey) + } else { + return containsBuildSettingsKeyReturnValue + } + } + + // MARK: - set + + public var setBuildSettingsKeyValueThrowableError: Error? + public var setBuildSettingsKeyValueCallsCount = 0 + public var setBuildSettingsKeyValueCalled: Bool { setBuildSettingsKeyValueCallsCount > 0 } + public var setBuildSettingsKeyValueReceivedArguments: (buildSettingsKey: String, value: Any)? + public var setBuildSettingsKeyValueReceivedInvocations: [(buildSettingsKey: String, value: Any)] = [] + public var setBuildSettingsKeyValueClosure: ((String, Any) async throws -> Void)? + + public func set(buildSettingsKey: String, value: Any) async throws { + if let error = setBuildSettingsKeyValueThrowableError { + throw error + } + setBuildSettingsKeyValueCallsCount += 1 + setBuildSettingsKeyValueReceivedArguments = (buildSettingsKey: buildSettingsKey, value: value) + setBuildSettingsKeyValueReceivedInvocations.append((buildSettingsKey: buildSettingsKey, value: value)) + try await setBuildSettingsKeyValueClosure?(buildSettingsKey, value) + } +} + +// swiftlint:enable all