Make Scheme Generation Methods More Generic (#730)

Addresses https://github.com/tuist/tuist/issues/667

### Short description 📝

In order to support custom workspace schemes, we need to make the current scheme generation functions more generic and decouple it from the `Project` type. We now make graph look ups in the project scheme generation functions so that in a follow up pull request it will be easy to add custom workspace scheme support.

*Note that this pull request should make no user facing changes.* 

I've pasted the steps listed in #667 below and marked the items completed by this pull request:
- [X] Changing the functions in the SchemeGenerator to use the graph for look ups by default (as this is the main difference between the project and workspace schemes)
- [X] Update the scheme model (in TuistGenerator) to start referencing targets using the .project(...)
- [ ] Expose workspace scheme type in the project manifest (ProjectDescription)

### Solution 📦

I've added a new `TargetReference` type in place of simple target names of type `String`. `TargetReference` has the name of a target and the relative path to its project. This `TargetReference` type works well for both project scheme generation and workspace scheme generation (in the follow up pull request). This new type enables functions in the scheme generator to do graph lookups to any target in the graph. 

### Implementation 👩‍💻👨‍💻

- [X] Add `TargetReference` type to model
- [X] Change instances of simple target `String` types to `TargetReference` within the `Scheme` type in the model
- [X] Update `GeneratorModelLoader` to convert simple target name `String`s into `TargetReference` types by propagating the project path
- [X] Update instances where a simple target `String` type is expected to work with the name property in `TargetReference`
- [X] Update tests in `SchemesGeneratorTests`, `ProjectGeneratorTests`, `GeneratorModelLoaderTests`
This commit is contained in:
Adam Khazi 2019-12-03 12:37:57 +00:00 committed by GitHub
parent b0290e7711
commit 37e44f5a09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 940 additions and 671 deletions

View File

@ -20,6 +20,8 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
- Support for paths relative to root https://github.com/tuist/tuist/pull/727 by @pepibumur.
- Replace `Sheme.testAction.targets` type from `String` to `TestableTarget` is a description of target that adds to the `TestAction`, you can specify execution tests parallelizable, random execution order or skip tests https://github.com/tuist/tuist/pull/728 by @rowwingman.
- Galaxy manifest model https://github.com/tuist/tuist/pull/729 by @pepibumur.
- Make scheme generation methods more generic by @adamkhazi @kwridan.
## 0.19.0

View File

@ -101,6 +101,7 @@ public protocol Graphing: AnyObject, Encodable {
func librariesSearchPaths(path: AbsolutePath, name: String) -> [AbsolutePath]
func librariesSwiftIncludePaths(path: AbsolutePath, name: String) -> [AbsolutePath]
func embeddableFrameworks(path: AbsolutePath, name: String) throws -> [DependencyReference]
func target(path: AbsolutePath, name: String) throws -> TargetNode?
func targetDependencies(path: AbsolutePath, name: String) -> [TargetNode]
func staticDependencies(path: AbsolutePath, name: String) -> [DependencyReference]
func resourceBundleDependencies(path: AbsolutePath, name: String) -> [TargetNode]
@ -185,6 +186,10 @@ public class Graph: Graphing {
public var targets: [TargetNode] {
return cache.targetNodes.flatMap { $0.value.values }
}
public func target(path: AbsolutePath, name: String) -> TargetNode? {
return findTargetNode(path: path, name: name)
}
public func targetDependencies(path: AbsolutePath, name: String) -> [TargetNode] {
guard let targetNode = findTargetNode(path: path, name: name) else {

View File

@ -66,13 +66,13 @@ public class ExecutionAction: Equatable {
public let title: String
public let scriptText: String
public let target: String?
public let target: TargetReference?
// MARK: - Init
public init(title: String,
scriptText: String,
target: String?) {
target: TargetReference?) {
self.title = title
self.scriptText = scriptText
self.target = target
@ -85,16 +85,30 @@ public class ExecutionAction: Equatable {
}
}
public struct TargetReference: Equatable {
public var projectPath: AbsolutePath
public var name: String
public static func project(path: AbsolutePath, target: String) -> TargetReference {
return .init(projectPath: path, name: target)
}
public init(projectPath: AbsolutePath, name: String) {
self.projectPath = projectPath
self.name = name
}
}
public class BuildAction: Equatable {
// MARK: - Attributes
public let targets: [String]
public let targets: [TargetReference]
public let preActions: [ExecutionAction]
public let postActions: [ExecutionAction]
// MARK: - Init
public init(targets: [String] = [],
public init(targets: [TargetReference] = [],
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = []) {
self.targets = targets
@ -118,7 +132,7 @@ public class TestAction: Equatable {
public let arguments: Arguments?
public let configurationName: String
public let coverage: Bool
public let codeCoverageTargets: [String]
public let codeCoverageTargets: [TargetReference]
public let preActions: [ExecutionAction]
public let postActions: [ExecutionAction]
@ -128,7 +142,7 @@ public class TestAction: Equatable {
arguments: Arguments? = nil,
configurationName: String,
coverage: Bool = false,
codeCoverageTargets: [String] = [],
codeCoverageTargets: [TargetReference] = [],
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = []) {
self.targets = targets
@ -153,13 +167,13 @@ public class TestAction: Equatable {
}
}
public struct TestableTarget: Equatable, Hashable {
public let target: String
public struct TestableTarget: Equatable {
public let target: TargetReference
public let isSkipped: Bool
public let isParallelizable: Bool
public let isRandomExecutionOrdering: Bool
public init(target: String, skipped: Bool = false, parallelizable: Bool = false, randomExecutionOrdering: Bool = false) {
public init(target: TargetReference, skipped: Bool = false, parallelizable: Bool = false, randomExecutionOrdering: Bool = false) {
self.target = target
self.isSkipped = skipped
self.isParallelizable = parallelizable
@ -171,13 +185,13 @@ public class RunAction: Equatable {
// MARK: - Attributes
public let configurationName: String
public let executable: String?
public let executable: TargetReference?
public let arguments: Arguments?
// MARK: - Init
public init(configurationName: String,
executable: String? = nil,
executable: TargetReference? = nil,
arguments: Arguments? = nil) {
self.configurationName = configurationName
self.executable = executable

View File

@ -12,7 +12,7 @@ public extension Arguments {
public extension RunAction {
static func test(configurationName: String = BuildConfiguration.debug.name,
executable: String? = "App",
executable: TargetReference? = TargetReference(projectPath: "/Project", name: "App"),
arguments: Arguments? = Arguments.test()) -> RunAction {
return RunAction(configurationName: configurationName,
executable: executable,
@ -21,11 +21,11 @@ public extension RunAction {
}
public extension TestAction {
static func test(targets: [TestableTarget] = [TestableTarget(target: "AppTests")],
static func test(targets: [TestableTarget] = [TestableTarget(target: TargetReference(projectPath: "/Project", name: "AppTests"))],
arguments: Arguments? = Arguments.test(),
configurationName: String = BuildConfiguration.debug.name,
coverage: Bool = false,
codeCoverageTargets: [String] = [],
codeCoverageTargets: [TargetReference] = [],
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = []) -> TestAction {
return TestAction(targets: targets,
@ -39,7 +39,7 @@ public extension TestAction {
}
public extension BuildAction {
static func test(targets: [String] = ["App"],
static func test(targets: [TargetReference] = [TargetReference(projectPath: "/Project", name: "App")],
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = []) -> BuildAction {
return BuildAction(targets: targets, preActions: preActions, postActions: postActions)

View File

@ -38,7 +38,7 @@ final class ProjectGenerator: ProjectGenerating {
let configGenerator: ConfigGenerating
/// Generator for the project schemes.
let schemesGenerator: SchemesGenerating
let schemesGenerator: SchemesGenerator
/// Generator for the project derived files.
let derivedFileGenerator: DerivedFileGenerating
@ -54,7 +54,7 @@ final class ProjectGenerator: ProjectGenerating {
/// - derivedFileGenerator: Generator for the project derived files.
init(targetGenerator: TargetGenerating = TargetGenerator(),
configGenerator: ConfigGenerating = ConfigGenerator(),
schemesGenerator: SchemesGenerating = SchemesGenerator(),
schemesGenerator: SchemesGenerator = SchemesGenerator(),
derivedFileGenerator: DerivedFileGenerating = DerivedFileGenerator()) {
self.targetGenerator = targetGenerator
self.configGenerator = configGenerator
@ -103,9 +103,7 @@ final class ProjectGenerator: ProjectGenerating {
groups: groups,
pbxproj: pbxproj,
sourceRootPath: sourceRootPath)
let configurationList = try configGenerator.generateProjectConfig(project: project,
pbxproj: pbxproj,
fileElements: fileElements)
let configurationList = try configGenerator.generateProjectConfig(project: project, pbxproj: pbxproj, fileElements: fileElements)
let pbxProject = try generatePbxproject(project: project,
configurationList: configurationList,
groups: groups,
@ -252,7 +250,7 @@ final class ProjectGenerator: ProjectGenerating {
workspace: XCWorkspace,
pbxproj: PBXProj,
project: Project,
graph _: Graphing) throws -> GeneratedProject {
graph: Graphing) throws -> GeneratedProject {
var generatedProject: GeneratedProject!
try FileHandler.shared.inTemporaryDirectory { temporaryPath in
@ -263,9 +261,11 @@ final class ProjectGenerator: ProjectGenerating {
generatedProject = GeneratedProject(pbxproj: pbxproj,
path: temporaryPath,
targets: nativeTargets,
name: xcodeprojPath.components.last!)
name: xcodeprojPath.basename)
try writeSchemes(project: project,
generatedProject: generatedProject)
generatedProject: generatedProject,
xcprojectPath: temporaryPath,
graph: graph)
try FileHandler.shared.replace(xcodeprojPath, with: temporaryPath)
}
@ -280,9 +280,13 @@ final class ProjectGenerator: ProjectGenerating {
}
private func writeSchemes(project: Project,
generatedProject: GeneratedProject) throws {
try schemesGenerator.generateTargetSchemes(project: project,
generatedProject: generatedProject)
generatedProject: GeneratedProject,
xcprojectPath: AbsolutePath,
graph: Graphing) throws {
try schemesGenerator.generateProjectSchemes(project: project,
xcprojectPath: xcprojectPath,
generatedProject: generatedProject,
graph: graph)
}
private func determineProjectConstants(graph: Graphing) throws -> ProjectConstants {

View File

@ -10,10 +10,14 @@ protocol SchemesGenerating {
///
/// - Parameters:
/// - project: Project manifest.
/// - xcprojectPath: Path to the Xcode project.
/// - generatedProject: Generated Xcode project.
/// - graph: Tuist graph.
/// - Throws: A FatalError if the generation of the schemes fails.
func generateTargetSchemes(project: Project,
generatedProject: GeneratedProject) throws
func generateProjectSchemes(project: Project,
xcprojectPath: AbsolutePath,
generatedProject: GeneratedProject,
graph: Graphing) throws
}
// swiftlint:disable:next type_body_length
@ -23,57 +27,93 @@ final class SchemesGenerator: SchemesGenerating {
/// Default version for generated schemes.
private static let defaultVersion = "1.3"
/// Generates the schemes for the project manifest.
/// Generate schemes for a project.
///
/// - Parameters:
/// - project: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - Throws: A FatalError if the generation of the schemes fails.
func generateTargetSchemes(project: Project, generatedProject: GeneratedProject) throws {
/// Generate scheme from manifest
/// - project: Project manifest.
/// - xcprojectPath: Path to project's .xcodeproj.
/// - generatedProject: Generated Project
/// - graph: Tuist graph.
func generateProjectSchemes(project: Project,
xcprojectPath: AbsolutePath,
generatedProject: GeneratedProject,
graph: Graphing) throws {
/// Generate custom schemes from manifest
try project.schemes.forEach { scheme in
try generateScheme(scheme: scheme, project: project, generatedProject: generatedProject)
try generateScheme(scheme: scheme,
xcPath: xcprojectPath,
path: project.path,
graph: graph,
generatedProjects: [project.path: generatedProject])
}
/// Generate scheme for every targets in Project that is not defined in Manifest
/// Generate default schemes for targets in Project that are not defined in Manifest
let buildConfiguration = defaultDebugBuildConfigurationName(in: project)
try project.targets.forEach { target in
let userDefinedSchemes = Set(project.schemes.map(\.name))
let defaultSchemeTargets = project.targets.filter { !userDefinedSchemes.contains($0.name) }
try defaultSchemeTargets.forEach { target in
let scheme = createDefaultScheme(target: target, project: project, buildConfiguration: buildConfiguration)
try generateScheme(scheme: scheme,
xcPath: xcprojectPath,
path: project.path,
graph: graph,
generatedProjects: [project.path: generatedProject])
if !project.schemes.contains(where: { $0.name == target.name }) {
let scheme = Scheme(name: target.name,
shared: true,
buildAction: BuildAction(targets: [target.name]),
testAction: TestAction(targets: [TestableTarget(target: target.name)], configurationName: buildConfiguration),
runAction: RunAction(configurationName: buildConfiguration,
executable: target.productName,
arguments: Arguments(environment: target.environment)))
try generateScheme(scheme: scheme,
project: project,
generatedProject: generatedProject)
}
}
}
/// Generates the scheme.
private func createDefaultScheme(target: Target, project: Project, buildConfiguration: String) -> Scheme {
let targetReference = TargetReference.project(path: project.path, target: target.name)
let testTargets = target.product.testsBundle ? [TestableTarget(target: targetReference)] : []
return Scheme(name: target.name,
shared: true,
buildAction: BuildAction(targets: [targetReference]),
testAction: TestAction(targets: testTargets, configurationName: buildConfiguration),
runAction: RunAction(configurationName: buildConfiguration, executable: targetReference, arguments: Arguments(environment: target.environment)))
}
/// Generate schemes for a project or workspace.
///
/// - Parameters:
/// - scheme: Scheme manifest.
/// - project: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - Throws: An error if the generation fails.
func generateScheme(scheme: Scheme,
project: Project,
generatedProject: GeneratedProject) throws {
let schemesDirectory = try createSchemesDirectory(projectPath: generatedProject.path, shared: scheme.shared)
let schemePath = schemesDirectory.appending(component: "\(scheme.name).xcscheme")
let generatedBuildAction = schemeBuildAction(scheme: scheme, project: project, generatedProject: generatedProject)
let generatedTestAction = schemeTestAction(scheme: scheme, project: project, generatedProject: generatedProject)
let generatedLaunchAction = schemeLaunchAction(scheme: scheme, project: project, generatedProject: generatedProject)
let generatedProfileAction = schemeProfileAction(scheme: scheme, project: project, generatedProject: generatedProject)
let generatedArchiveAction = schemeArchiveAction(scheme: scheme, project: project, generatedProject: generatedProject)
/// - scheme: Project scheme.
/// - xcPath: Path to workspace's .xcworkspace or project's .xcodeproj.
/// - path: Path to workspace or project folder.
/// - graph: Tuist graph.
/// - generatedProjects: Project paths mapped to generated projects.
private func generateScheme(scheme: Scheme,
xcPath: AbsolutePath,
path: AbsolutePath,
graph: Graphing,
generatedProjects: [AbsolutePath: GeneratedProject]) throws {
let schemeDirectory = try createSchemesDirectory(path: xcPath, shared: scheme.shared)
let schemePath = schemeDirectory.appending(component: "\(scheme.name).xcscheme")
let generatedBuildAction = try schemeBuildAction(scheme: scheme,
graph: graph,
rootPath: path,
generatedProjects: generatedProjects)
let generatedTestAction = try schemeTestAction(scheme: scheme,
graph: graph,
rootPath: path,
generatedProjects: generatedProjects)
let generatedLaunchAction = try schemeLaunchAction(scheme: scheme,
graph: graph,
rootPath: path,
generatedProjects: generatedProjects)
let generatedProfileAction = try schemeProfileAction(scheme: scheme,
graph: graph,
rootPath: path,
generatedProjects: generatedProjects)
let generatedAnalyzeAction = try schemeAnalyzeAction(scheme: scheme,
graph: graph,
rootPath: path,
generatedProjects: generatedProjects)
let generatedArchiveAction = try schemeArchiveAction(scheme: scheme,
graph: graph,
rootPath: path,
generatedProjects: generatedProjects)
let scheme = XCScheme(name: scheme.name,
lastUpgradeVersion: SchemesGenerator.defaultLastUpgradeVersion,
@ -82,158 +122,96 @@ final class SchemesGenerator: SchemesGenerating {
testAction: generatedTestAction,
launchAction: generatedLaunchAction,
profileAction: generatedProfileAction,
analyzeAction: schemeAnalyzeAction(for: project),
analyzeAction: generatedAnalyzeAction,
archiveAction: generatedArchiveAction)
try scheme.write(path: schemePath.path, override: true)
}
/// Returns the build action for the project scheme.
/// Generates the scheme build action.
///
/// - Parameters:
/// - project: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - graph: Dependencies graph.
/// - scheme: Scheme manifest.
/// - graph: Tuist graph.
/// - rootPath: Path to the project or workspace.
/// - generatedProjects: Project paths mapped to generated projects.
/// - Returns: Scheme build action.
func projectBuildAction(project: Project,
generatedProject: GeneratedProject,
graph: Graphing) -> XCScheme.BuildAction {
let targets = project.sortedTargetsForProjectScheme(graph: graph)
let entries: [XCScheme.BuildAction.Entry] = targets.map { (target) -> XCScheme.BuildAction.Entry in
func schemeBuildAction(scheme: Scheme,
graph: Graphing,
rootPath: AbsolutePath,
generatedProjects: [AbsolutePath: GeneratedProject]) throws -> XCScheme.BuildAction? {
guard let buildAction = scheme.buildAction else { return nil }
let pbxTarget = generatedProject.targets[target.name]!
let buildableReference = targetBuildableReference(target: target,
pbxTarget: pbxTarget,
projectName: generatedProject.name)
var buildFor: [XCScheme.BuildAction.Entry.BuildFor] = []
if target.product.testsBundle {
buildFor.append(.testing)
} else {
buildFor.append(contentsOf: [.analyzing, .archiving, .profiling, .running, .testing])
}
let buildFor: [XCScheme.BuildAction.Entry.BuildFor] = [
.analyzing, .archiving, .profiling, .running, .testing,
]
return XCScheme.BuildAction.Entry(buildableReference: buildableReference,
buildFor: buildFor)
var entries: [XCScheme.BuildAction.Entry] = []
var preActions: [XCScheme.ExecutionAction] = []
var postActions: [XCScheme.ExecutionAction] = []
try buildAction.targets.forEach { buildActionTarget in
guard let buildableReference = try createBuildableReference(targetReference: buildActionTarget,
graph: graph,
rootPath: rootPath,
generatedProjects: generatedProjects) else { return }
entries.append(XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildFor))
}
preActions = try buildAction.preActions.map {
try schemeExecutionAction(action: $0, graph: graph, generatedProjects: generatedProjects, rootPath: rootPath)
}
postActions = try buildAction.postActions.map {
try schemeExecutionAction(action: $0, graph: graph, generatedProjects: generatedProjects, rootPath: rootPath)
}
return XCScheme.BuildAction(buildActionEntries: entries,
preActions: preActions,
postActions: postActions,
parallelizeBuild: true,
buildImplicitDependencies: true)
}
/// Generates the test action for the project scheme.
///
/// - Parameters:
/// - project: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - Returns: Scheme test action.
func projectTestAction(project: Project,
generatedProject: GeneratedProject) -> XCScheme.TestAction {
var testables: [XCScheme.TestableReference] = []
let testTargets = project.targets.filter { $0.product.testsBundle }
testTargets.forEach { target in
let pbxTarget = generatedProject.targets[target.name]!
let reference = targetBuildableReference(target: target,
pbxTarget: pbxTarget,
projectName: generatedProject.name)
let testable = XCScheme.TestableReference(skipped: false,
buildableReference: reference)
testables.append(testable)
}
let buildConfiguration = defaultDebugBuildConfigurationName(in: project)
return XCScheme.TestAction(buildConfiguration: buildConfiguration,
macroExpansion: nil,
testables: testables)
}
/// Generates the scheme archive action.
/// - Parameter scheme: Scheme manifest.
/// - Parameter project: Project manifest.
/// - Parameter generatedProject: Generated Xcode project.
/// - Returns: Scheme archive action.
func schemeArchiveAction(scheme: Scheme,
project: Project,
generatedProject: GeneratedProject) -> XCScheme.ArchiveAction {
guard let archiveAction = scheme.archiveAction else {
return defaultSchemeArchiveAction(for: project)
}
return XCScheme.ArchiveAction(buildConfiguration: archiveAction.configurationName,
revealArchiveInOrganizer: archiveAction.revealArchiveInOrganizer,
customArchiveName: archiveAction.customArchiveName,
preActions: schemeExecutionActions(actions: archiveAction.preActions,
project: project,
generatedProject: generatedProject),
postActions: schemeExecutionActions(actions: archiveAction.postActions,
project: project,
generatedProject: generatedProject))
}
/// Generates the array of BuildableReference for targets that the
/// coverage report should be generated for them.
///
/// - Parameters:
/// - testAction: test actions.
/// - project: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - Returns: Array of buildable references.
private func testCoverageTargetReferences(testAction: TestAction, project: Project, generatedProject: GeneratedProject) -> [XCScheme.BuildableReference] {
var codeCoverageTargets: [XCScheme.BuildableReference] = []
testAction.codeCoverageTargets.forEach { name in
guard let target = project.targets.first(where: { $0.name == name }) else { return }
guard let pbxTarget = generatedProject.targets[name] else { return }
let reference = self.targetBuildableReference(target: target,
pbxTarget: pbxTarget,
projectName: generatedProject.name)
codeCoverageTargets.append(reference)
}
return codeCoverageTargets
}
/// Generates the scheme test action.
///
/// - Parameters:
/// - scheme: Scheme manifest.
/// - project: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - graph: Tuist graph.
/// - rootPath: Root path to either project or workspace.
/// - generatedProjects: Project paths mapped to generated projects.
/// - Returns: Scheme test action.
func schemeTestAction(scheme: Scheme,
project: Project,
generatedProject: GeneratedProject) -> XCScheme.TestAction? {
graph: Graphing,
rootPath: AbsolutePath,
generatedProjects: [AbsolutePath: GeneratedProject]) throws -> XCScheme.TestAction? {
guard let testAction = scheme.testAction else { return nil }
var testables: [XCScheme.TestableReference] = []
var preActions: [XCScheme.ExecutionAction] = []
var postActions: [XCScheme.ExecutionAction] = []
testAction.targets.forEach { test in
let targetName = test.target
guard let target = project.targets.first(where: { $0.name == targetName }), target.product.testsBundle else { return }
guard let pbxTarget = generatedProject.targets[targetName] else { return }
let reference = self.targetBuildableReference(target: target,
pbxTarget: pbxTarget,
projectName: generatedProject.name)
let testable = XCScheme.TestableReference(skipped: test.isSkipped,
parallelizable: test.isParallelizable,
randomExecutionOrdering: test.isRandomExecutionOrdering,
try testAction.targets.forEach { testableTarget in
guard let reference = try createBuildableReference(targetReference: testableTarget.target,
graph: graph,
rootPath: rootPath,
generatedProjects: generatedProjects) else { return }
let testable = XCScheme.TestableReference(skipped: testableTarget.isSkipped,
parallelizable: testableTarget.isParallelizable,
randomExecutionOrdering: testableTarget.isRandomExecutionOrdering,
buildableReference: reference)
testables.append(testable)
}
preActions = schemeExecutionActions(actions: testAction.preActions,
project: project,
generatedProject: generatedProject)
postActions = schemeExecutionActions(actions: testAction.postActions,
project: project,
generatedProject: generatedProject)
preActions = try testAction.preActions.map { try schemeExecutionAction(action: $0,
graph: graph,
generatedProjects: generatedProjects,
rootPath: rootPath) }
postActions = try testAction.postActions.map { try schemeExecutionAction(action: $0,
graph: graph,
generatedProjects: generatedProjects,
rootPath: rootPath) }
var args: XCScheme.CommandLineArguments?
var environments: [XCScheme.EnvironmentVariable]?
@ -242,8 +220,13 @@ final class SchemesGenerator: SchemesGenerating {
args = XCScheme.CommandLineArguments(arguments: commandlineArgruments(arguments.launch))
environments = environmentVariables(arguments.environment)
}
let codeCoverageTargets = testCoverageTargetReferences(testAction: testAction, project: project, generatedProject: generatedProject)
let codeCoverageTargets = try testAction.codeCoverageTargets.compactMap {
try testCoverageTargetReferences(target: $0,
graph: graph,
generatedProjects: generatedProjects,
rootPath: rootPath)
}
let onlyGenerateCoverageForSpecifiedTargets = codeCoverageTargets.count > 0 ? true : nil
@ -261,75 +244,35 @@ final class SchemesGenerator: SchemesGenerating {
commandlineArguments: args,
environmentVariables: environments)
}
/// Generates the scheme build action.
///
/// - Parameters:
/// - scheme: Scheme manifest.
/// - project: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - Returns: Scheme build action.
func schemeBuildAction(scheme: Scheme,
project: Project,
generatedProject: GeneratedProject) -> XCScheme.BuildAction? {
guard let buildAction = scheme.buildAction else { return nil }
let buildFor: [XCScheme.BuildAction.Entry.BuildFor] = [
.analyzing, .archiving, .profiling, .running, .testing,
]
var entries: [XCScheme.BuildAction.Entry] = []
var preActions: [XCScheme.ExecutionAction] = []
var postActions: [XCScheme.ExecutionAction] = []
buildAction.targets.forEach { name in
guard let target = project.targets.first(where: { $0.name == name }) else { return }
guard let pbxTarget = generatedProject.targets[name] else { return }
let buildableReference = self.targetBuildableReference(target: target,
pbxTarget: pbxTarget,
projectName: generatedProject.name)
entries.append(XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildFor))
}
preActions = schemeExecutionActions(actions: buildAction.preActions,
project: project,
generatedProject: generatedProject)
postActions = schemeExecutionActions(actions: buildAction.postActions,
project: project,
generatedProject: generatedProject)
return XCScheme.BuildAction(buildActionEntries: entries,
preActions: preActions,
postActions: postActions,
parallelizeBuild: true,
buildImplicitDependencies: true)
}
/// Generates the scheme launch action.
///
/// - Parameters:
/// - scheme: Scheme manifest.
/// - project: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - graph: Tuist graph.
/// - rootPath: Root path to either project or workspace.
/// - generatedProjects: Project paths mapped to generated projects.
/// - Returns: Scheme launch action.
func schemeLaunchAction(scheme: Scheme,
project: Project,
generatedProject: GeneratedProject) -> XCScheme.LaunchAction? {
guard var target = project.targets.first(where: { $0.name == scheme.buildAction?.targets.first }) else { return nil }
graph: Graphing,
rootPath: AbsolutePath,
generatedProjects: [AbsolutePath: GeneratedProject]) throws -> XCScheme.LaunchAction? {
guard var target = try defaultTargetReference(scheme: scheme) else { return nil }
if let executable = scheme.runAction?.executable {
guard let runableTarget = project.targets.first(where: { $0.name == executable }) else { return nil }
target = runableTarget
target = executable
}
guard let pbxTarget = generatedProject.targets[target.name] else { return nil }
guard let targetNode = try graph.target(path: target.projectPath, name: target.name) else { return nil }
guard let buildableReference = try createBuildableReference(targetReference: target,
graph: graph,
rootPath: rootPath,
generatedProjects: generatedProjects) else { return nil }
var buildableProductRunnable: XCScheme.BuildableProductRunnable?
var macroExpansion: XCScheme.BuildableReference?
let buildableReference = targetBuildableReference(target: target, pbxTarget: pbxTarget, projectName: generatedProject.name)
if target.product.runnable {
if targetNode.target.product.runnable {
buildableProductRunnable = XCScheme.BuildableProductRunnable(buildableReference: buildableReference, runnableDebuggingMode: "0")
} else {
macroExpansion = buildableReference
@ -343,127 +286,276 @@ final class SchemesGenerator: SchemesGenerating {
environments = environmentVariables(arguments.environment)
}
let buildConfiguration = scheme.runAction?.configurationName ?? defaultDebugBuildConfigurationName(in: project)
let buildConfiguration = scheme.runAction?.configurationName ?? defaultDebugBuildConfigurationName(in: targetNode.project)
return XCScheme.LaunchAction(runnable: buildableProductRunnable,
buildConfiguration: buildConfiguration,
macroExpansion: macroExpansion,
commandlineArguments: commandlineArguments,
environmentVariables: environments)
}
/// Generates the scheme profile action for a given target.
///
/// - Parameters:
/// - target: Target manifest.
/// - pbxTarget: Xcode native target.
/// - projectName: Project name with .xcodeproj extension.
/// - scheme: Target manifest.
/// - graph: Tuist graph.
/// - rootPath: Root path to either project or workspace.
/// - generatedProjects: Project paths mapped to generated projects.
/// - Returns: Scheme profile action.
func schemeProfileAction(scheme: Scheme,
project: Project,
generatedProject: GeneratedProject) -> XCScheme.ProfileAction? {
guard var target = project.targets.first(where: { $0.name == scheme.buildAction?.targets.first }) else { return nil }
graph: Graphing,
rootPath: AbsolutePath,
generatedProjects: [AbsolutePath: GeneratedProject]) throws -> XCScheme.ProfileAction? {
guard var target = try defaultTargetReference(scheme: scheme) else { return nil }
if let executable = scheme.runAction?.executable {
guard let runableTarget = project.targets.first(where: { $0.name == executable }) else { return nil }
target = runableTarget
target = executable
}
guard let pbxTarget = generatedProject.targets[target.name] else { return nil }
guard let targetNode = try graph.target(path: target.projectPath, name: target.name) else { return nil }
guard let buildableReference = try createBuildableReference(targetReference: target,
graph: graph,
rootPath: rootPath,
generatedProjects: generatedProjects) else { return nil }
var buildableProductRunnable: XCScheme.BuildableProductRunnable?
var macroExpansion: XCScheme.BuildableReference?
let buildableReference = targetBuildableReference(target: target, pbxTarget: pbxTarget, projectName: generatedProject.name)
if target.product.runnable {
if targetNode.target.product.runnable {
buildableProductRunnable = XCScheme.BuildableProductRunnable(buildableReference: buildableReference, runnableDebuggingMode: "0")
} else {
macroExpansion = buildableReference
}
let buildConfiguration = defaultReleaseBuildConfigurationName(in: project)
let buildConfiguration = defaultReleaseBuildConfigurationName(in: targetNode.project)
return XCScheme.ProfileAction(buildableProductRunnable: buildableProductRunnable,
buildConfiguration: buildConfiguration,
macroExpansion: macroExpansion)
}
/// Returns the scheme analyze action.
///
/// - Parameters:
/// - scheme: Scheme manifest.
/// - graph: Tuist graph.
/// - rootPath: Root path to either project or workspace.
/// - generatedProjects: Project paths mapped to generated projects.
/// - Returns: Scheme analyze action.
func schemeAnalyzeAction(scheme: Scheme,
graph: Graphing,
rootPath: AbsolutePath,
generatedProjects: [AbsolutePath: GeneratedProject]) throws -> XCScheme.AnalyzeAction? {
guard let target = try defaultTargetReference(scheme: scheme),
let targetNode = try graph.target(path: target.projectPath, name: target.name) else { return nil }
let buildConfiguration = defaultDebugBuildConfigurationName(in: targetNode.project)
return XCScheme.AnalyzeAction(buildConfiguration: buildConfiguration)
}
/// Generates the scheme archive action.
///
/// - Parameters:
/// - scheme: Scheme manifest.
/// - graph: Tuist graph.
/// - rootPath: Root path to either project or workspace.
/// - generatedProjects: Project paths mapped to generated projects.
/// - Returns: Scheme archive action.
func schemeArchiveAction(scheme: Scheme,
graph: Graphing,
rootPath: AbsolutePath,
generatedProjects: [AbsolutePath: GeneratedProject]) throws -> XCScheme.ArchiveAction? {
guard let target = try defaultTargetReference(scheme: scheme),
let targetNode = try graph.target(path: target.projectPath, name: target.name) else { return nil }
guard let archiveAction = scheme.archiveAction else {
return defaultSchemeArchiveAction(for: targetNode.project)
}
let preActions = try archiveAction.preActions.map {
try schemeExecutionAction(action: $0, graph: graph, generatedProjects: generatedProjects, rootPath: rootPath)
}
let postActions = try archiveAction.postActions.map {
try schemeExecutionAction(action: $0, graph: graph, generatedProjects: generatedProjects, rootPath: rootPath)
}
return XCScheme.ArchiveAction(buildConfiguration: archiveAction.configurationName,
revealArchiveInOrganizer: archiveAction.revealArchiveInOrganizer,
customArchiveName: archiveAction.customArchiveName,
preActions: preActions,
postActions: postActions)
}
func schemeExecutionAction(action: ExecutionAction,
graph: Graphing,
generatedProjects: [AbsolutePath: GeneratedProject],
rootPath: AbsolutePath) throws -> XCScheme.ExecutionAction {
guard let targetReference = action.target,
let targetNode = try graph.target(path: targetReference.projectPath, name: targetReference.name),
let generatedProject = generatedProjects[targetReference.projectPath] else {
return schemeExecutionAction(action: action)
}
return schemeExecutionAction(action: action,
target: targetNode.target,
generatedProject: generatedProject)
}
private func schemeExecutionAction(action: ExecutionAction) -> XCScheme.ExecutionAction {
return XCScheme.ExecutionAction(scriptText: action.scriptText,
title: action.title,
environmentBuildable: nil)
}
/// Returns the scheme pre/post actions.
///
/// - Parameters:
/// - actions: pre/post action manifest.
/// - project: Project manifest.
/// - action: pre/post action manifest.
/// - target: Project manifest.
/// - generatedProject: Generated Xcode project.
/// - Returns: Scheme actions.
func schemeExecutionActions(actions: [ExecutionAction],
project: Project,
generatedProject: GeneratedProject) -> [XCScheme.ExecutionAction] {
private func schemeExecutionAction(action: ExecutionAction,
target: Target,
generatedProject: GeneratedProject) -> XCScheme.ExecutionAction {
/// Return Buildable Reference for Scheme Action
func schemeBuildableReference(targetName: String?, project: Project, generatedProject: GeneratedProject) -> XCScheme.BuildableReference? {
guard let targetName = targetName else { return nil }
guard let target = project.targets.first(where: { $0.name == targetName }) else { return nil }
guard let pbxTarget = generatedProject.targets[targetName] else { return nil }
return targetBuildableReference(target: target, pbxTarget: pbxTarget, projectName: generatedProject.name)
func schemeBuildableReference(target: Target, generatedProject: GeneratedProject) -> XCScheme.BuildableReference? {
guard let pbxTarget = generatedProject.targets[target.name] else { return nil }
return targetBuildableReference(target: target,
pbxTarget: pbxTarget,
projectPath: generatedProject.name)
}
var schemeActions: [XCScheme.ExecutionAction] = []
actions.forEach { action in
let schemeAction = XCScheme.ExecutionAction(scriptText: action.scriptText,
title: action.title,
environmentBuildable: nil)
let schemeAction = XCScheme.ExecutionAction(scriptText: action.scriptText,
title: action.title,
environmentBuildable: nil)
schemeAction.environmentBuildable = schemeBuildableReference(targetName: action.target,
project: project,
generatedProject: generatedProject)
schemeActions.append(schemeAction)
}
return schemeActions
schemeAction.environmentBuildable = schemeBuildableReference(target: target,
generatedProject: generatedProject)
return schemeAction
}
// MARK: - Helpers
private func resolveRelativeProjectPath(targetNode: TargetNode,
generatedProject: GeneratedProject,
rootPath: AbsolutePath) -> RelativePath {
let xcodeProjectPath = targetNode.path.appending(component: generatedProject.name)
return xcodeProjectPath.relative(to: rootPath)
}
/// Creates a target buildable refernece for a target
///
/// - Parameters:
/// - targetReference: The target reference.
/// - graph: Tuist graph.
/// - rootPath: Path to the project or workspace.
/// - generatedProjects: Project paths mapped to generated projects.
private func createBuildableReference(targetReference: TargetReference,
graph: Graphing,
rootPath: AbsolutePath,
generatedProjects: [AbsolutePath: GeneratedProject]) throws -> XCScheme.BuildableReference? {
let projectPath = targetReference.projectPath
guard let target = try graph.target(path: projectPath, name: targetReference.name) else { return nil }
guard let generatedProject = generatedProjects[projectPath] else { return nil }
guard let pbxTarget = generatedProject.targets[targetReference.name] else { return nil }
let relativeXcodeProjectPath = resolveRelativeProjectPath(targetNode: target,
generatedProject: generatedProject,
rootPath: rootPath)
return targetBuildableReference(target: target.target,
pbxTarget: pbxTarget,
projectPath: relativeXcodeProjectPath.pathString)
}
/// Generates the array of BuildableReference for targets that the
/// coverage report should be generated for them.
///
/// - Parameters:
/// - target: test actions.
/// - graph: tuist graph.
/// - generatedProjects: Generated Xcode projects.
/// - rootPath: Root path to workspace or project.
/// - Returns: Array of buildable references.
private func testCoverageTargetReferences(target: TargetReference,
graph: Graphing,
generatedProjects: [AbsolutePath: GeneratedProject],
rootPath: AbsolutePath) throws -> XCScheme.BuildableReference? {
return try createBuildableReference(targetReference: target,
graph: graph,
rootPath: rootPath,
generatedProjects: generatedProjects)
}
/// Creates the directory where the schemes are stored inside the project.
/// If the directory exists it does not re-create it.
///
/// - Parameters:
/// - path: Path to the Xcode workspace or project.
/// - shared: Scheme should be shared or not
/// - Returns: Path to the schemes directory.
/// - Throws: A FatalError if the creation of the directory fails.
private func createSchemesDirectory(path: AbsolutePath, shared: Bool = true) throws -> AbsolutePath {
let schemePath: AbsolutePath
if shared {
schemePath = path.appending(RelativePath("xcshareddata/xcschemes"))
} else {
let username = NSUserName()
schemePath = path.appending(RelativePath("xcuserdata/\(username).xcuserdatad/xcschemes"))
}
if !FileHandler.shared.exists(schemePath) {
try FileHandler.shared.createFolder(schemePath)
}
return schemePath
}
/// Returns the scheme commandline argument passed on launch
///
/// - Parameters:
/// - environments: commandline argument keys.
/// - environments: commandline argument keys.
/// - Returns: XCScheme.CommandLineArguments.CommandLineArgument.
func commandlineArgruments(_ arguments: [String: Bool]) -> [XCScheme.CommandLineArguments.CommandLineArgument] {
private func commandlineArgruments(_ arguments: [String: Bool]) -> [XCScheme.CommandLineArguments.CommandLineArgument] {
return arguments.map { key, enabled in
XCScheme.CommandLineArguments.CommandLineArgument(name: key, enabled: enabled)
}
}
/// Returns the scheme environment variables
///
/// - Parameters:
/// - environments: environment variables
/// - environments: environment variables
/// - Returns: XCScheme.EnvironmentVariable.
func environmentVariables(_ environments: [String: String]) -> [XCScheme.EnvironmentVariable] {
private func environmentVariables(_ environments: [String: String]) -> [XCScheme.EnvironmentVariable] {
return environments.map { key, value in
XCScheme.EnvironmentVariable(variable: key, value: value, enabled: true)
}
}
private func defaultDebugBuildConfigurationName(in project: Project) -> String {
let debugConfiguration = project.settings.defaultDebugBuildConfiguration()
let buildConfiguration = debugConfiguration ?? project.settings.configurations.keys.first
return buildConfiguration?.name ?? BuildConfiguration.debug.name
}
/// Returns the scheme buildable reference for a given target.
///
/// - Parameters:
/// - target: Target manifest.
/// - pbxTarget: Xcode native target.
/// - projectName: Project name with the .xcodeproj extension.
/// - projectPath: Project name with the .xcodeproj extension.
/// - Returns: Buildable reference.
func targetBuildableReference(target: Target, pbxTarget: PBXNativeTarget, projectName: String) -> XCScheme.BuildableReference {
return XCScheme.BuildableReference(referencedContainer: "container:\(projectName)",
private func targetBuildableReference(target: Target,
pbxTarget: PBXNativeTarget,
projectPath: String) -> XCScheme.BuildableReference {
return XCScheme.BuildableReference(referencedContainer: "container:\(projectPath)",
blueprint: pbxTarget,
buildableName: target.productNameWithExtension,
blueprintName: target.name,
buildableIdentifier: "primary")
}
/// Returns the scheme analyze action
///
/// - Returns: Scheme analyze action.
func schemeAnalyzeAction(for project: Project) -> XCScheme.AnalyzeAction {
let buildConfiguration = defaultDebugBuildConfigurationName(in: project)
return XCScheme.AnalyzeAction(buildConfiguration: buildConfiguration)
}
/// Returns the scheme archive action
///
/// - Returns: Scheme archive action.
@ -472,40 +564,15 @@ final class SchemesGenerator: SchemesGenerating {
return XCScheme.ArchiveAction(buildConfiguration: buildConfiguration,
revealArchiveInOrganizer: true)
}
/// Creates the directory where the schemes are stored inside the project.
/// If the directory exists it does not re-create it.
///
/// - Parameters:
/// - projectPath: Path to the Xcode project.
/// - shared: Scheme should be shared or not
/// - Returns: Path to the schemes directory.
/// - Throws: A FatalError if the creation of the directory fails.
private func createSchemesDirectory(projectPath: AbsolutePath, shared: Bool = true) throws -> AbsolutePath {
var path: AbsolutePath!
if shared {
path = projectPath.appending(RelativePath("xcshareddata/xcschemes"))
} else {
let username = NSUserName()
path = projectPath.appending(RelativePath("xcuserdata/\(username).xcuserdatad/xcschemes"))
}
if !FileHandler.shared.exists(path) {
try FileHandler.shared.createFolder(path)
}
return path
}
private func defaultDebugBuildConfigurationName(in project: Project) -> String {
let debugConfiguration = project.settings.defaultDebugBuildConfiguration()
let buildConfiguration = debugConfiguration ?? project.settings.configurations.keys.first
return buildConfiguration?.name ?? BuildConfiguration.debug.name
}
private func defaultReleaseBuildConfigurationName(in project: Project) -> String {
let releaseConfiguration = project.settings.defaultReleaseBuildConfiguration()
let buildConfiguration = releaseConfiguration ?? project.settings.configurations.keys.first
return buildConfiguration?.name ?? BuildConfiguration.release.name
}
private func defaultTargetReference(scheme: Scheme) throws -> TargetReference? {
return scheme.buildAction?.targets.first
}
}

View File

@ -66,8 +66,8 @@ private extension SchemeLinter {
for scheme in schemes {
for target in scheme.testAction?.codeCoverageTargets ?? [] {
if !targetNames.contains(target) {
issues.append(missingCodeCoverageTargetIssue(missingTargetName: target, schemaName: scheme.name))
if !targetNames.contains(target.name) {
issues.append(missingCodeCoverageTargetIssue(missingTargetName: target.name, schemaName: scheme.name))
}
}
}

View File

@ -225,7 +225,7 @@ extension TuistCore.Project {
generatorPaths: generatorPaths)
}
let schemes = manifest.schemes.map { TuistCore.Scheme.from(manifest: $0) }
let schemes = manifest.schemes.map { TuistCore.Scheme.from(manifest: $0, projectPath: path) }
let additionalFiles = try manifest.additionalFiles.flatMap {
try TuistCore.FileElement.from(manifest: $0,
@ -273,6 +273,7 @@ extension TuistCore.Project {
}
extension TuistCore.Target {
// swiftlint:disable:next function_body_length
static func from(manifest: ProjectDescription.Target,
path: AbsolutePath,
generatorPaths: GeneratorPaths) throws -> TuistCore.Target {
@ -569,13 +570,13 @@ extension TuistCore.Dependency {
}
extension TuistCore.Scheme {
static func from(manifest: ProjectDescription.Scheme) -> TuistCore.Scheme {
static func from(manifest: ProjectDescription.Scheme, projectPath: AbsolutePath) -> TuistCore.Scheme {
let name = manifest.name
let shared = manifest.shared
let buildAction = manifest.buildAction.map { TuistCore.BuildAction.from(manifest: $0) }
let testAction = manifest.testAction.map { TuistCore.TestAction.from(manifest: $0) }
let runAction = manifest.runAction.map { TuistCore.RunAction.from(manifest: $0) }
let archiveAction = manifest.archiveAction.map { TuistCore.ArchiveAction.from(manifest: $0) }
let buildAction = manifest.buildAction.map { TuistCore.BuildAction.from(manifest: $0, projectPath: projectPath) }
let testAction = manifest.testAction.map { TuistCore.TestAction.from(manifest: $0, projectPath: projectPath) }
let runAction = manifest.runAction.map { TuistCore.RunAction.from(manifest: $0, projectPath: projectPath) }
let archiveAction = manifest.archiveAction.map { TuistCore.ArchiveAction.from(manifest: $0, projectPath: projectPath) }
return Scheme(name: name,
shared: shared,
@ -587,24 +588,26 @@ extension TuistCore.Scheme {
}
extension TuistCore.BuildAction {
static func from(manifest: ProjectDescription.BuildAction) -> TuistCore.BuildAction {
let preActions = manifest.preActions.map { TuistCore.ExecutionAction.from(manifest: $0) }
let postActions = manifest.postActions.map { TuistCore.ExecutionAction.from(manifest: $0) }
return BuildAction(targets: manifest.targets, preActions: preActions, postActions: postActions)
static func from(manifest: ProjectDescription.BuildAction, projectPath: AbsolutePath) -> TuistCore.BuildAction {
let preActions = manifest.preActions.map { TuistCore.ExecutionAction.from(manifest: $0, projectPath: projectPath) }
let postActions = manifest.postActions.map { TuistCore.ExecutionAction.from(manifest: $0, projectPath: projectPath) }
let targets: [TuistCore.TargetReference] = manifest.targets.map {
.project(path: projectPath, target: $0)
}
return TuistCore.BuildAction(targets: targets, preActions: preActions, postActions: postActions)
}
}
extension TuistCore.TestAction {
static func from(manifest: ProjectDescription.TestAction) -> TuistCore.TestAction {
let targets = manifest.targets.map { TuistCore.TestableTarget.from(manifest: $0) }
static func from(manifest: ProjectDescription.TestAction, projectPath: AbsolutePath) -> TuistCore.TestAction {
let targets = manifest.targets.map { TuistCore.TestableTarget.from(manifest: $0, projectPath: projectPath) }
let arguments = manifest.arguments.map { TuistCore.Arguments.from(manifest: $0) }
let configurationName = manifest.configurationName
let coverage = manifest.coverage
let codeCoverageTargets = manifest.codeCoverageTargets
let preActions = manifest.preActions.map { TuistCore.ExecutionAction.from(manifest: $0) }
let postActions = manifest.postActions.map { TuistCore.ExecutionAction.from(manifest: $0) }
let codeCoverageTargets = manifest.codeCoverageTargets.map { TuistCore.TargetReference(projectPath: projectPath, name: $0) }
let preActions = manifest.preActions.map { TuistCore.ExecutionAction.from(manifest: $0, projectPath: projectPath) }
let postActions = manifest.postActions.map { TuistCore.ExecutionAction.from(manifest: $0, projectPath: projectPath) }
return TestAction(targets: targets,
arguments: arguments,
configurationName: configurationName,
@ -616,8 +619,8 @@ extension TuistCore.TestAction {
}
extension TuistCore.TestableTarget {
static func from(manifest: ProjectDescription.TestableTarget) -> TuistCore.TestableTarget {
return TestableTarget(target: manifest.target,
static func from(manifest: ProjectDescription.TestableTarget, projectPath: AbsolutePath) -> TuistCore.TestableTarget {
return TestableTarget(target: TuistCore.TargetReference(projectPath: projectPath, name: manifest.target),
skipped: manifest.isSkipped,
parallelizable: manifest.isParallelizable,
randomExecutionOrdering: manifest.isRandomExecutionOrdering)
@ -625,24 +628,28 @@ extension TuistCore.TestableTarget {
}
extension TuistCore.RunAction {
static func from(manifest: ProjectDescription.RunAction) -> TuistCore.RunAction {
static func from(manifest: ProjectDescription.RunAction, projectPath: AbsolutePath) -> TuistCore.RunAction {
let configurationName = manifest.configurationName
let executable = manifest.executable
let arguments = manifest.arguments.map { TuistCore.Arguments.from(manifest: $0) }
var executableResolved: TuistCore.TargetReference?
if let executable = manifest.executable {
executableResolved = TargetReference(projectPath: projectPath, name: executable)
}
return RunAction(configurationName: configurationName,
executable: executable,
executable: executableResolved,
arguments: arguments)
}
}
extension TuistCore.ArchiveAction {
static func from(manifest: ProjectDescription.ArchiveAction) -> TuistCore.ArchiveAction {
static func from(manifest: ProjectDescription.ArchiveAction, projectPath: AbsolutePath) -> TuistCore.ArchiveAction {
let configurationName = manifest.configurationName
let revealArchiveInOrganizer = manifest.revealArchiveInOrganizer
let customArchiveName = manifest.customArchiveName
let preActions = manifest.preActions.map { TuistCore.ExecutionAction.from(manifest: $0) }
let postActions = manifest.postActions.map { TuistCore.ExecutionAction.from(manifest: $0) }
let preActions = manifest.preActions.map { TuistCore.ExecutionAction.from(manifest: $0, projectPath: projectPath) }
let postActions = manifest.postActions.map { TuistCore.ExecutionAction.from(manifest: $0, projectPath: projectPath) }
return TuistCore.ArchiveAction(configurationName: configurationName,
revealArchiveInOrganizer: revealArchiveInOrganizer,
@ -653,8 +660,10 @@ extension TuistCore.ArchiveAction {
}
extension TuistCore.ExecutionAction {
static func from(manifest: ProjectDescription.ExecutionAction) -> TuistCore.ExecutionAction {
return ExecutionAction(title: manifest.title, scriptText: manifest.scriptText, target: manifest.target)
static func from(manifest: ProjectDescription.ExecutionAction,
projectPath: AbsolutePath) -> TuistCore.ExecutionAction {
let targetReference: TuistCore.TargetReference? = manifest.target.map { .project(path: projectPath, target: $0) }
return ExecutionAction(title: manifest.title, scriptText: manifest.scriptText, target: targetReference)
}
}

View File

@ -1,17 +1,13 @@
import Foundation
import Basic
import TuistCore
import TuistCoreTesting
@testable import TuistGenerator
final class MockSchemesGenerator: SchemesGenerating {
var generateTargetSchemesArgs: [(project: Project, generatedProject: GeneratedProject)] = []
var generateProjectSchemeArgs: [(project: Project, generatedProject: GeneratedProject, graph: Graphing)] = []
func generateTargetSchemes(project: Project, generatedProject: GeneratedProject) throws {
generateTargetSchemesArgs.append((project: project, generatedProject: generatedProject))
}
func generateProjectScheme(project: Project, generatedProject: GeneratedProject, graph: Graphing) throws {
generateProjectSchemeArgs.append((project: project, generatedProject: generatedProject, graph: graph))
var generateProjectSchemeArgs: [(project: Project, xcprojectPath: AbsolutePath, generatedProject: GeneratedProject, graph: Graphing)] = []
func generateProjectSchemes(project: Project, xcprojectPath: AbsolutePath, generatedProject: GeneratedProject, graph: Graphing) throws {
generateProjectSchemeArgs.append((project: project, xcprojectPath: xcprojectPath, generatedProject: generatedProject, graph: graph))
}
}

View File

@ -52,7 +52,7 @@ final class ProjectGeneratorTests: TuistUnitTestCase {
// Given
let temporaryPath = try self.temporaryPath()
let target = Target.test(name: "Target", platform: .iOS, product: .framework)
let sharedScheme = Scheme.test(name: "Target-Scheme", shared: true, buildAction: BuildAction(targets: ["Target"]))
let sharedScheme = Scheme.test(name: "Target-Scheme", shared: true, buildAction: BuildAction(targets: [TargetReference(projectPath: temporaryPath, name: "Target")]))
let targets = [target]
let project = Project.test(path: temporaryPath, name: "Project", targets: targets, schemes: [sharedScheme])
@ -79,7 +79,7 @@ final class ProjectGeneratorTests: TuistUnitTestCase {
// Given
let temporaryPath = try self.temporaryPath()
let target = Target.test(name: "Target", platform: .iOS, product: .framework)
let localScheme = Scheme.test(name: "Target-Local", shared: false, buildAction: BuildAction(targets: ["Target"]))
let localScheme = Scheme.test(name: "Target-Local", shared: false, buildAction: BuildAction(targets: [TargetReference(projectPath: temporaryPath, name: "Target")]))
let targets = [target]
let project = Project.test(path: temporaryPath, name: "Project", targets: targets, schemes: [localScheme])

View File

@ -9,374 +9,518 @@ import XCTest
@testable import TuistGenerator
@testable import TuistSupportTesting
final class SchemeGeneratorTests: XCTestCase {
final class SchemesGeneratorTests: XCTestCase {
var subject: SchemesGenerator!
override func setUp() {
super.setUp()
subject = SchemesGenerator()
}
// MARK: - Build Action Tests
func test_projectBuildAction() {
func test_schemeBuildAction_whenSingleProject() throws {
// Given
let projectPath = AbsolutePath("/somepath/Workspace/Projects/Project")
let scheme = Scheme.test(buildAction: BuildAction(targets: [TargetReference(projectPath: projectPath, name: "App")]))
let app = Target.test(name: "App", product: .app)
let appTests = Target.test(name: "AppTests", product: .unitTests)
let appUITests = Target.test(name: "AppUITests", product: .uiTests)
let targets = [app, appTests, appUITests]
let targets = [app]
let project = Project.test(path: projectPath)
let graph = Graph.create(dependencies: [(project: project, target: app, dependencies: [])])
// Then
let got = try subject.schemeBuildAction(scheme: scheme,
graph: graph,
rootPath: AbsolutePath("/somepath/Workspace"),
generatedProjects: [projectPath:
generatedProject(targets: targets, projectPath: "\(projectPath)/project.xcodeproj")])
let project = Project.test(targets: targets)
let graphCache = GraphLoaderCache()
let graph = Graph.test(cache: graphCache)
// When
let result = try XCTUnwrap(got)
XCTAssertEqual(result.buildActionEntries.count, 1)
let entry = try XCTUnwrap(result.buildActionEntries.first)
let buildableReference = entry.buildableReference
XCTAssertEqual(entry.buildFor, [.analyzing, .archiving, .profiling, .running, .testing])
let got = subject.projectBuildAction(project: project,
generatedProject: generatedProject(targets: targets),
graph: graph)
XCTAssertEqual(buildableReference.referencedContainer, "container:Projects/Project/project.xcodeproj")
XCTAssertEqual(buildableReference.buildableName, "App.app")
XCTAssertEqual(buildableReference.blueprintName, "App")
XCTAssertEqual(buildableReference.buildableIdentifier, "primary")
XCTAssertTrue(got.parallelizeBuild)
XCTAssertTrue(got.buildImplicitDependencies)
XCTAssertEqual(got.buildActionEntries.count, 3)
let appEntry = got.buildActionEntries[0]
let testsEntry = got.buildActionEntries[1]
let uiTestsEntry = got.buildActionEntries[2]
XCTAssertEqual(appEntry.buildFor, [.analyzing, .archiving, .profiling, .running, .testing])
XCTAssertEqual(appEntry.buildableReference.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(appEntry.buildableReference.buildableName, app.productNameWithExtension)
XCTAssertEqual(appEntry.buildableReference.blueprintName, app.name)
XCTAssertEqual(appEntry.buildableReference.buildableIdentifier, "primary")
XCTAssertEqual(testsEntry.buildFor, [.testing])
XCTAssertEqual(testsEntry.buildableReference.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(testsEntry.buildableReference.buildableName, appTests.productNameWithExtension)
XCTAssertEqual(testsEntry.buildableReference.blueprintName, appTests.name)
XCTAssertEqual(testsEntry.buildableReference.buildableIdentifier, "primary")
XCTAssertEqual(uiTestsEntry.buildFor, [.testing])
XCTAssertEqual(uiTestsEntry.buildableReference.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(uiTestsEntry.buildableReference.buildableName, appUITests.productNameWithExtension)
XCTAssertEqual(uiTestsEntry.buildableReference.blueprintName, appUITests.name)
XCTAssertEqual(uiTestsEntry.buildableReference.buildableIdentifier, "primary")
XCTAssertEqual(result.parallelizeBuild, true)
XCTAssertEqual(result.buildImplicitDependencies, true)
}
func test_schemeBuildAction_whenMultipleProject() throws {
// Given
let projectAPath = AbsolutePath("/somepath/Workspace/Projects/ProjectA")
let projectBPath = AbsolutePath("/somepath/Workspace/Projects/ProjectB")
let buildAction = BuildAction(targets: [
TargetReference(projectPath: projectAPath, name: "FrameworkA"),
TargetReference(projectPath: projectBPath, name: "FrameworkB")
])
let scheme = Scheme.test(buildAction: buildAction)
let frameworkA = Target.test(name: "FrameworkA", product: .staticFramework)
let frameworkB = Target.test(name: "FrameworkB", product: .staticFramework)
let targets = [frameworkA, frameworkB]
let projectA = Project.test(path: projectAPath)
let projectB = Project.test(path: projectBPath)
let graph = Graph.create(dependencies: [
(project: projectA, target: frameworkA, dependencies: []),
(project: projectB, target: frameworkB, dependencies: [])
])
// Then
let got = try subject.schemeBuildAction(scheme: scheme,
graph: graph,
rootPath: AbsolutePath("/somepath/Workspace"),
generatedProjects: [
projectAPath: generatedProject(targets: targets, projectPath: "\(projectAPath)/project.xcodeproj"),
projectBPath: generatedProject(targets: targets, projectPath: "\(projectBPath)/project.xcodeproj")
])
func test_projectTestAction() {
let app = Target.test(name: "App", product: .app)
let appTests = Target.test(name: "AppTests", product: .unitTests)
let targets = [app, appTests]
let project = Project.test(targets: targets)
// When
let result = try XCTUnwrap(got)
XCTAssertEqual(result.buildActionEntries.count, 2)
let firstEntry = try XCTUnwrap(result.buildActionEntries[0])
let firstBuildableReference = firstEntry.buildableReference
XCTAssertEqual(firstEntry.buildFor, [.analyzing, .archiving, .profiling, .running, .testing])
let secondEntry = try XCTUnwrap(result.buildActionEntries[1])
let secondBuildableReference = secondEntry.buildableReference
XCTAssertEqual(secondEntry.buildFor, [.analyzing, .archiving, .profiling, .running, .testing])
let got = subject.projectTestAction(project: project,
generatedProject: generatedProject(targets: targets))
XCTAssertEqual(firstBuildableReference.referencedContainer, "container:Projects/ProjectA/project.xcodeproj")
XCTAssertEqual(firstBuildableReference.buildableName, "FrameworkA.framework")
XCTAssertEqual(firstBuildableReference.blueprintName, "FrameworkA")
XCTAssertEqual(firstBuildableReference.buildableIdentifier, "primary")
XCTAssertEqual(secondBuildableReference.referencedContainer, "container:Projects/ProjectB/project.xcodeproj")
XCTAssertEqual(secondBuildableReference.buildableName, "FrameworkB.framework")
XCTAssertEqual(secondBuildableReference.blueprintName, "FrameworkB")
XCTAssertEqual(secondBuildableReference.buildableIdentifier, "primary")
XCTAssertEqual(got.buildConfiguration, "Debug")
XCTAssertNil(got.macroExpansion)
XCTAssertEqual(got.testables.count, 1)
let testable = got.testables.first
XCTAssertEqual(testable?.skipped, false)
XCTAssertEqual(testable?.buildableReference.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(testable?.buildableReference.buildableName, appTests.productNameWithExtension)
XCTAssertEqual(testable?.buildableReference.blueprintName, appTests.name)
XCTAssertEqual(testable?.buildableReference.buildableIdentifier, "primary")
XCTAssertEqual(result.parallelizeBuild, true)
XCTAssertEqual(result.buildImplicitDependencies, true)
}
func test_schemeTestAction_when_notTestsTarget() {
let scheme = Scheme.test()
let project = Project.test()
let generatedProject = GeneratedProject.test()
let got = subject.schemeTestAction(scheme: scheme, project: project, generatedProject: generatedProject)
XCTAssertEqual(got?.buildConfiguration, "Debug")
XCTAssertEqual(got?.shouldUseLaunchSchemeArgsEnv, false)
XCTAssertNil(got?.macroExpansion)
XCTAssertEqual(got?.testables.count, 0)
}
func test_schemeTestAction_when_testsTarget() {
func test_schemeBuildAction_with_executionAction() throws {
// Given
let projectPath = AbsolutePath("/somepath/Project")
let target = Target.test(name: "App", product: .app)
let testTarget = Target.test(name: "AppTests", product: .unitTests)
let preAction = ExecutionAction(title: "Pre Action", scriptText: "echo Pre Actions", target: TargetReference(projectPath: projectPath, name: "App"))
let postAction = ExecutionAction(title: "Post Action", scriptText: "echo Post Actions", target: TargetReference(projectPath: projectPath, name: "App"))
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "Library")], preActions: [preAction], postActions: [postAction])
let testAction = TestAction.test(arguments: nil)
let scheme = Scheme.test(name: "AppTests", testAction: testAction)
let project = Project.test(targets: [target, testTarget])
let scheme = Scheme.test(name: "App", shared: true, buildAction: buildAction)
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [
(project: project, target: target, dependencies: [])
])
let pbxTarget = PBXNativeTarget(name: "App")
let pbxTestTarget = PBXNativeTarget(name: "AppTests", productType: .unitTestBundle)
let generatedProject = GeneratedProject.test(targets: ["App": pbxTarget, "AppTests": pbxTestTarget])
let got = subject.schemeTestAction(scheme: scheme, project: project, generatedProject: generatedProject)
XCTAssertEqual(got?.buildConfiguration, "Debug")
XCTAssertEqual(got?.shouldUseLaunchSchemeArgsEnv, true)
XCTAssertNil(got?.macroExpansion)
let testable = got?.testables.first
let buildableReference = testable?.buildableReference
XCTAssertEqual(testable?.skipped, false)
XCTAssertEqual(buildableReference?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(buildableReference?.buildableName, "AppTests.xctest")
XCTAssertEqual(buildableReference?.blueprintName, "AppTests")
XCTAssertEqual(buildableReference?.buildableIdentifier, "primary")
}
func test_schemeTestAction_with_executionAction() {
let testTarget = Target.test(name: "AppTests", product: .unitTests)
let preAction = ExecutionAction(title: "Pre Action", scriptText: "echo Pre Actions", target: "AppTests")
let postAction = ExecutionAction(title: "Post Action", scriptText: "echo Post Actions", target: "AppTests")
let testAction = TestAction.test(targets: [TestableTarget(target: "AppTests")], preActions: [preAction], postActions: [postAction])
let scheme = Scheme.test(name: "AppTests", shared: true, testAction: testAction)
let project = Project.test(targets: [testTarget])
let pbxTestTarget = PBXNativeTarget(name: "AppTests", productType: .unitTestBundle)
let generatedProject = GeneratedProject.test(targets: ["AppTests": pbxTestTarget])
let got = subject.schemeTestAction(scheme: scheme, project: project, generatedProject: generatedProject)
// When
let got = try subject.schemeBuildAction(scheme: scheme,
graph: graph,
rootPath: projectPath,
generatedProjects: createGeneratedProjects(projects: [project]))
// Then
// Pre Action
XCTAssertEqual(got?.preActions.first?.title, "Pre Action")
XCTAssertEqual(got?.preActions.first?.scriptText, "echo Pre Actions")
let preBuildableReference = got?.preActions.first?.environmentBuildable
XCTAssertEqual(preBuildableReference?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(preBuildableReference?.buildableName, "AppTests.xctest")
XCTAssertEqual(preBuildableReference?.blueprintName, "AppTests")
XCTAssertEqual(preBuildableReference?.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(preBuildableReference?.buildableName, "App.app")
XCTAssertEqual(preBuildableReference?.blueprintName, "App")
XCTAssertEqual(preBuildableReference?.buildableIdentifier, "primary")
// Post Action
XCTAssertEqual(got?.postActions.first?.title, "Post Action")
XCTAssertEqual(got?.postActions.first?.scriptText, "echo Post Actions")
let postBuildableReference = got?.postActions.first?.environmentBuildable
XCTAssertEqual(postBuildableReference?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(postBuildableReference?.buildableName, "AppTests.xctest")
XCTAssertEqual(postBuildableReference?.blueprintName, "AppTests")
XCTAssertEqual(postBuildableReference?.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(postBuildableReference?.buildableName, "App.app")
XCTAssertEqual(postBuildableReference?.blueprintName, "App")
XCTAssertEqual(postBuildableReference?.buildableIdentifier, "primary")
}
// MARK: - Test Action Tests
func test_schemeTestAction_when_testsTarget() throws {
// Given
let target = Target.test(name: "App", product: .app)
let testTarget = Target.test(name: "AppTests", product: .unitTests)
let project = Project.test(targets: [target, testTarget])
let testAction = TestAction.test(targets: [TestableTarget(target: TargetReference(projectPath: project.path, name: "AppTests"))],
arguments: nil)
let scheme = Scheme.test(name: "AppTests", testAction: testAction)
let generatedProjects = createGeneratedProjects(projects: [project])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: []),
(project: project, target: testTarget, dependencies: [target])])
// When
let got = try subject.schemeTestAction(scheme: scheme, graph: graph, rootPath: project.path, generatedProjects: generatedProjects)
// Then
let result = try XCTUnwrap(got)
XCTAssertEqual(result.buildConfiguration, "Debug")
XCTAssertEqual(result.shouldUseLaunchSchemeArgsEnv, true)
XCTAssertNil(result.macroExpansion)
let testable = try XCTUnwrap(result.testables.first)
let buildableReference = testable.buildableReference
XCTAssertEqual(testable.skipped, false)
XCTAssertEqual(buildableReference.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(buildableReference.buildableName, "AppTests.xctest")
XCTAssertEqual(buildableReference.blueprintName, "AppTests")
XCTAssertEqual(buildableReference.buildableIdentifier, "primary")
}
func test_schemeTestAction_with_codeCoverageTargets() {
func test_schemeTestAction_with_codeCoverageTargets() throws {
// Given
let projectPath = AbsolutePath("/somepath/Project")
let target = Target.test(name: "App", product: .app)
let testTarget = Target.test(name: "AppTests", product: .unitTests)
let testAction = TestAction.test(targets: [TestableTarget(target: "AppTests")], coverage: true, codeCoverageTargets: ["App"])
let buildAction = BuildAction.test(targets: ["App"])
let testAction = TestAction.test(targets: [TestableTarget(target: TargetReference(projectPath: projectPath, name: "AppTests"))],
coverage: true,
codeCoverageTargets: [TargetReference(projectPath: projectPath, name: "App")])
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "App")])
let scheme = Scheme.test(name: "AppTests", shared: true, buildAction: buildAction, testAction: testAction)
let project = Project.test(targets: [target, testTarget])
let project = Project.test(path: projectPath, targets: [target, testTarget])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: []),
(project: project, target: testTarget, dependencies: [target])])
// When
let got = try subject.schemeTestAction(scheme: scheme, graph: graph, rootPath: AbsolutePath("/somepath/Workspace"), generatedProjects: createGeneratedProjects(projects: [project]))
// Then
let result = try XCTUnwrap(got)
let codeCoverageTargetsBuildableReference = try XCTUnwrap(result.codeCoverageTargets)
let pbxTarget = PBXNativeTarget(name: "App", productType: .application)
let pbxTestTarget = PBXNativeTarget(name: "AppTests", productType: .unitTestBundle)
let generatedProject = GeneratedProject.test(targets: ["AppTests": pbxTestTarget, "App": pbxTarget])
XCTAssertEqual(result.onlyGenerateCoverageForSpecifiedTargets, true)
XCTAssertEqual(codeCoverageTargetsBuildableReference.count, 1)
XCTAssertEqual(codeCoverageTargetsBuildableReference.first?.buildableName, "App.app")
}
func test_schemeTestAction_when_notTestsTarget() throws {
// Given
let scheme = Scheme.test()
let project = Project.test()
let generatedProject = GeneratedProject.test()
let graph = Graph.create(dependencies: [])
let got = subject.schemeTestAction(scheme: scheme, project: project, generatedProject: generatedProject)
// Then
let got = try subject.schemeTestAction(scheme: scheme, graph: graph, rootPath: project.path, generatedProjects: [project.path: generatedProject])
let codeCoverageTargetsBuildableReference = got?.codeCoverageTargets
XCTAssertEqual(got?.onlyGenerateCoverageForSpecifiedTargets, true)
XCTAssertEqual(codeCoverageTargetsBuildableReference?.count, 1)
XCTAssertEqual(codeCoverageTargetsBuildableReference?.first?.buildableName, "App.app")
// When
let result = try XCTUnwrap(got)
XCTAssertEqual(result.buildConfiguration, "Debug")
XCTAssertEqual(result.shouldUseLaunchSchemeArgsEnv, false)
XCTAssertNil(result.macroExpansion)
XCTAssertEqual(result.testables.count, 0)
}
func test_schemeTestAction_with_testable_info() {
func test_schemeTestAction_with_testable_info() throws {
// Given
let target = Target.test(name: "App", product: .app)
let testTarget = Target.test(name: "AppTests", product: .unitTests)
let project = Project.test(targets: [target, testTarget])
let testableTarget = TestableTarget(target: "AppTests", skipped: false, parallelizable: true, randomExecutionOrdering: true)
let testableTarget = TestableTarget(target: TargetReference(projectPath: project.path, name: "AppTests"),
skipped: false,
parallelizable: true,
randomExecutionOrdering: true)
let testAction = TestAction.test(targets: [testableTarget])
let buildAction = BuildAction.test(targets: ["App"])
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: project.path, name: "App")])
let scheme = Scheme.test(name: "AppTests", shared: true, buildAction: buildAction, testAction: testAction)
let project = Project.test(targets: [target, testTarget])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: []),
(project: project, target: testTarget, dependencies: [testTarget])])
let pbxTarget = PBXNativeTarget(name: "App", productType: .application)
let pbxTestTarget = PBXNativeTarget(name: "AppTests", productType: .unitTestBundle)
let generatedProject = GeneratedProject.test(targets: ["AppTests": pbxTestTarget, "App": pbxTarget])
// When
let got = try subject.schemeTestAction(scheme: scheme, graph: graph, rootPath: project.path, generatedProjects: createGeneratedProjects(projects: [project]))
let got = subject.schemeTestAction(scheme: scheme, project: project, generatedProject: generatedProject)
// Then
let testableTargetReference = got!.testables[0]
XCTAssertEqual(testableTargetReference.skipped, false)
XCTAssertEqual(testableTargetReference.parallelizable, true)
XCTAssertEqual(testableTargetReference.randomExecutionOrdering, true)
}
func test_schemeBuildAction() {
func test_schemeBuildAction() throws {
let target = Target.test(name: "App", product: .app)
let pbxTarget = PBXNativeTarget(name: "App")
let testTarget = Target.test(name: "AppTests", product: .unitTests)
let project = Project.test(targets: [target, testTarget])
let testAction = TestAction.test(targets: [TestableTarget(target: TargetReference(projectPath: project.path, name: "AppTests"))],
arguments: nil)
let scheme = Scheme.test(name: "AppTests", testAction: testAction)
let generatedProjects = createGeneratedProjects(projects: [project])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: []),
(project: project, target: testTarget, dependencies: [target])])
// When
let got = try subject.schemeTestAction(scheme: scheme, graph: graph, rootPath: project.path, generatedProjects: generatedProjects)
// Then
let result = try XCTUnwrap(got)
XCTAssertEqual(result.buildConfiguration, "Debug")
XCTAssertEqual(result.shouldUseLaunchSchemeArgsEnv, true)
XCTAssertNil(result.macroExpansion)
let testable = try XCTUnwrap(result.testables.first)
let buildableReference = testable.buildableReference
let scheme = Scheme.test(name: "App")
let project = Project.test(targets: [target])
let generatedProject = GeneratedProject.test(targets: ["App": pbxTarget])
let got = subject.schemeBuildAction(scheme: scheme, project: project, generatedProject: generatedProject)
XCTAssertEqual(got?.buildActionEntries.count, 1)
let entry = got?.buildActionEntries.first
let buildableReference = entry?.buildableReference
XCTAssertEqual(entry?.buildFor, [.analyzing, .archiving, .profiling, .running, .testing])
XCTAssertEqual(buildableReference?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(buildableReference?.buildableName, "App.app")
XCTAssertEqual(buildableReference?.blueprintName, "App")
XCTAssertEqual(buildableReference?.buildableIdentifier, "primary")
XCTAssertEqual(got?.parallelizeBuild, true)
XCTAssertEqual(got?.buildImplicitDependencies, true)
XCTAssertEqual(testable.skipped, false)
XCTAssertEqual(buildableReference.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(buildableReference.buildableName, "AppTests.xctest")
XCTAssertEqual(buildableReference.blueprintName, "AppTests")
XCTAssertEqual(buildableReference.buildableIdentifier, "primary")
}
func test_schemeTestAction_with_executionAction() throws {
// Given
let projectPath = AbsolutePath("/somepath/Project")
let testTarget = Target.test(name: "AppTests", product: .unitTests)
func test_schemeBuildAction_with_executionAction() {
let target = Target.test(name: "App", product: .app)
let pbxTarget = PBXNativeTarget(name: "App")
let preAction = ExecutionAction(title: "Pre Action", scriptText: "echo Pre Actions", target: TargetReference(projectPath: projectPath, name: "AppTests"))
let postAction = ExecutionAction(title: "Post Action", scriptText: "echo Post Actions", target: TargetReference(projectPath: projectPath, name: "AppTests"))
let testAction = TestAction.test(targets: [TestableTarget(target: TargetReference(projectPath: projectPath, name: "AppTests"))], preActions: [preAction], postActions: [postAction])
let preAction = ExecutionAction(title: "Pre Action", scriptText: "echo Pre Actions", target: "App")
let postAction = ExecutionAction(title: "Post Action", scriptText: "echo Post Actions", target: "App")
let buildAction = BuildAction.test(targets: ["Library"], preActions: [preAction], postActions: [postAction])
let scheme = Scheme.test(name: "AppTests", shared: true, testAction: testAction)
let project = Project.test(path: projectPath, targets: [testTarget])
let scheme = Scheme.test(name: "App", shared: true, buildAction: buildAction)
let project = Project.test(targets: [target])
let generatedProject = GeneratedProject.test(targets: ["App": pbxTarget])
let generatedProjects = createGeneratedProjects(projects: [project])
let graph = Graph.create(dependencies: [(project: project, target: testTarget, dependencies: [])])
let got = subject.schemeBuildAction(scheme: scheme, project: project, generatedProject: generatedProject)
// When
let got = try subject.schemeTestAction(scheme: scheme, graph: graph, rootPath: project.path, generatedProjects: generatedProjects)
// Then
// Pre Action
XCTAssertEqual(got?.preActions.first?.title, "Pre Action")
XCTAssertEqual(got?.preActions.first?.scriptText, "echo Pre Actions")
let result = try XCTUnwrap(got)
XCTAssertEqual(result.preActions.first?.title, "Pre Action")
XCTAssertEqual(result.preActions.first?.scriptText, "echo Pre Actions")
let preBuildableReference = got?.preActions.first?.environmentBuildable
let preBuildableReference = try XCTUnwrap(result.preActions.first?.environmentBuildable)
XCTAssertEqual(preBuildableReference?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(preBuildableReference?.buildableName, "App.app")
XCTAssertEqual(preBuildableReference?.blueprintName, "App")
XCTAssertEqual(preBuildableReference?.buildableIdentifier, "primary")
XCTAssertEqual(preBuildableReference.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(preBuildableReference.buildableName, "AppTests.xctest")
XCTAssertEqual(preBuildableReference.blueprintName, "AppTests")
XCTAssertEqual(preBuildableReference.buildableIdentifier, "primary")
// Post Action
XCTAssertEqual(got?.postActions.first?.title, "Post Action")
XCTAssertEqual(got?.postActions.first?.scriptText, "echo Post Actions")
XCTAssertEqual(result.postActions.first?.title, "Post Action")
XCTAssertEqual(result.postActions.first?.scriptText, "echo Post Actions")
let postBuildableReference = got?.postActions.first?.environmentBuildable
let postBuildableReference = try XCTUnwrap(result.postActions.first?.environmentBuildable)
XCTAssertEqual(postBuildableReference?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(postBuildableReference?.buildableName, "App.app")
XCTAssertEqual(postBuildableReference?.blueprintName, "App")
XCTAssertEqual(postBuildableReference?.buildableIdentifier, "primary")
XCTAssertEqual(postBuildableReference.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(postBuildableReference.buildableName, "AppTests.xctest")
XCTAssertEqual(postBuildableReference.blueprintName, "AppTests")
XCTAssertEqual(postBuildableReference.buildableIdentifier, "primary")
}
// MARK: - Launch Action Tests
func test_schemeLaunchAction_when_runnableTarget() {
let target = Target.test(name: "App", product: .app, environment: ["a": "b"])
let pbxTarget = PBXNativeTarget(name: "App")
let scheme = Scheme.test(runAction: RunAction.test(arguments: Arguments.test(environment: ["a": "b"])))
let project = Project.test(path: AbsolutePath("/project.xcodeproj"), targets: [target])
let generatedProject = GeneratedProject.test(targets: ["App": pbxTarget])
func test_schemeLaunchAction() throws {
// Given
let projectPath = AbsolutePath("/somepath/Workspace/Projects/Project")
let got = subject.schemeLaunchAction(scheme: scheme, project: project, generatedProject: generatedProject)
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "App")])
let runAction = RunAction.test(configurationName: "Release",
executable: TargetReference(projectPath: projectPath, name: "App"),
arguments: Arguments(environment:["a": "b"], launch: ["some": true]))
let scheme = Scheme.test(buildAction: buildAction, runAction: runAction)
let app = Target.test(name: "App", product: .app, environment: ["a": "b"])
let project = Project.test(path: projectPath, targets: [app])
let graph = Graph.create(dependencies: [(project: project, target: app, dependencies: [])])
// When
let got = try subject.schemeLaunchAction(scheme: scheme,
graph: graph,
rootPath: AbsolutePath("/somepath/Workspace"),
generatedProjects: createGeneratedProjects(projects: [project]))
// Then
let result = try XCTUnwrap(got)
XCTAssertNil(result.macroExpansion)
XCTAssertNil(got?.macroExpansion)
let buildableReference = try XCTUnwrap(result.runnable?.buildableReference)
let buildableReference = got?.runnable?.buildableReference
XCTAssertEqual(got?.buildConfiguration, "Debug")
XCTAssertEqual(got?.environmentVariables, [XCScheme.EnvironmentVariable(variable: "a", value: "b", enabled: true)])
XCTAssertEqual(buildableReference?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(buildableReference?.buildableName, "App.app")
XCTAssertEqual(buildableReference?.blueprintName, "App")
XCTAssertEqual(buildableReference?.buildableIdentifier, "primary")
XCTAssertEqual(result.buildConfiguration, "Release")
XCTAssertEqual(result.environmentVariables, [XCScheme.EnvironmentVariable(variable: "a", value: "b", enabled: true)])
XCTAssertEqual(buildableReference.referencedContainer, "container:Projects/Project/Project.xcodeproj")
XCTAssertEqual(buildableReference.buildableName, "App.app")
XCTAssertEqual(buildableReference.blueprintName, "App")
XCTAssertEqual(buildableReference.buildableIdentifier, "primary")
}
func test_schemeLaunchAction_when_notRunnableTarget() {
func test_schemeLaunchAction_when_notRunnableTarget() throws {
// Given
let projectPath = AbsolutePath("/somepath/Project")
let target = Target.test(name: "Library", platform: .iOS, product: .dynamicLibrary)
let pbxTarget = PBXNativeTarget(name: "App")
let buildAction = BuildAction.test(targets: ["Library"])
let testAction = TestAction.test(targets: [TestableTarget(target: "Library")])
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "Library")])
let testAction = TestAction.test(targets: [TestableTarget(target: TargetReference(projectPath: projectPath, name: "Library"))])
let scheme = Scheme.test(name: "Library", buildAction: buildAction, testAction: testAction, runAction: nil)
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: [])])
let project = Project.test(path: AbsolutePath("/project.xcodeproj"), targets: [target])
let generatedProject = GeneratedProject.test(targets: ["Library": pbxTarget])
// When
let got = try subject.schemeLaunchAction(scheme: scheme,
graph: graph,
rootPath: projectPath,
generatedProjects: createGeneratedProjects(projects: [project]))
let got = subject.schemeLaunchAction(scheme: scheme, project: project, generatedProject: generatedProject)
// Then
let result = try XCTUnwrap(got)
XCTAssertNil(result.runnable?.buildableReference)
XCTAssertNil(got?.runnable?.buildableReference)
XCTAssertEqual(got?.buildConfiguration, "Debug")
XCTAssertEqual(got?.macroExpansion?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(got?.macroExpansion?.buildableName, "libLibrary.dylib")
XCTAssertEqual(got?.macroExpansion?.blueprintName, "Library")
XCTAssertEqual(got?.macroExpansion?.buildableIdentifier, "primary")
XCTAssertEqual(result.buildConfiguration, "Debug")
XCTAssertEqual(result.macroExpansion?.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(result.macroExpansion?.buildableName, "libLibrary.dylib")
XCTAssertEqual(result.macroExpansion?.blueprintName, "Library")
XCTAssertEqual(result.macroExpansion?.buildableIdentifier, "primary")
}
// MARK: - Profile Action Tests
func test_schemeProfileAction_when_runnableTarget() {
func test_schemeProfileAction_when_runnableTarget() throws {
// Given
let projectPath = AbsolutePath("/somepath/Project")
let target = Target.test(name: "App", platform: .iOS, product: .app)
let scheme = Scheme.test()
let pbxTarget = PBXNativeTarget(name: "App")
let project = Project.test(path: AbsolutePath("/project.xcodeproj"), targets: [target])
let generatedProject = GeneratedProject.test(targets: ["App": pbxTarget])
let appTargetReference = TargetReference(projectPath: projectPath, name: "App")
let buildAction = BuildAction.test(targets: [appTargetReference])
let testAction = TestAction.test(targets: [TestableTarget(target: appTargetReference)])
let runAction = RunAction.test(configurationName: "Release", executable: appTargetReference, arguments: nil)
let scheme = Scheme.test(name: "App", buildAction: buildAction, testAction: testAction, runAction: runAction)
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: [])])
// When
let got = try subject.schemeProfileAction(scheme: scheme,
graph: graph,
rootPath: projectPath,
generatedProjects: createGeneratedProjects(projects: [project]))
let got = subject.schemeProfileAction(scheme: scheme, project: project, generatedProject: generatedProject)
// Then
let result = try XCTUnwrap(got)
let buildable = try XCTUnwrap(result.buildableProductRunnable?.buildableReference)
let buildable = got?.buildableProductRunnable?.buildableReference
XCTAssertNil(result.macroExpansion)
XCTAssertEqual(result.buildableProductRunnable?.runnableDebuggingMode, "0")
XCTAssertEqual(buildable.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(buildable.buildableName, target.productNameWithExtension)
XCTAssertEqual(buildable.blueprintName, target.name)
XCTAssertEqual(buildable.buildableIdentifier, "primary")
XCTAssertNil(got?.macroExpansion)
XCTAssertEqual(got?.buildableProductRunnable?.runnableDebuggingMode, "0")
XCTAssertEqual(buildable?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(buildable?.buildableName, target.productNameWithExtension)
XCTAssertEqual(buildable?.blueprintName, target.name)
XCTAssertEqual(buildable?.buildableIdentifier, "primary")
XCTAssertEqual(got?.buildConfiguration, "Release")
XCTAssertEqual(got?.preActions, [])
XCTAssertEqual(got?.postActions, [])
XCTAssertEqual(got?.shouldUseLaunchSchemeArgsEnv, true)
XCTAssertEqual(got?.savedToolIdentifier, "")
XCTAssertEqual(got?.ignoresPersistentStateOnLaunch, false)
XCTAssertEqual(got?.useCustomWorkingDirectory, false)
XCTAssertEqual(got?.debugDocumentVersioning, true)
XCTAssertNil(got?.commandlineArguments)
XCTAssertNil(got?.environmentVariables)
XCTAssertEqual(got?.enableTestabilityWhenProfilingTests, true)
XCTAssertEqual(result.buildConfiguration, "Release")
XCTAssertEqual(result.preActions, [])
XCTAssertEqual(result.postActions, [])
XCTAssertEqual(result.shouldUseLaunchSchemeArgsEnv, true)
XCTAssertEqual(result.savedToolIdentifier, "")
XCTAssertEqual(result.ignoresPersistentStateOnLaunch, false)
XCTAssertEqual(result.useCustomWorkingDirectory, false)
XCTAssertEqual(result.debugDocumentVersioning, true)
XCTAssertNil(result.commandlineArguments)
XCTAssertNil(result.environmentVariables)
XCTAssertEqual(result.enableTestabilityWhenProfilingTests, true)
}
func test_schemeProfileAction_when_notRunnableTarget() {
func test_schemeProfileAction_when_notRunnableTarget() throws {
// Given
let projectPath = AbsolutePath("/somepath/Project")
let target = Target.test(name: "Library", platform: .iOS, product: .dynamicLibrary)
let buildAction = BuildAction.test(targets: ["Library"])
let testAction = TestAction.test(targets: [TestableTarget(target: "Library")])
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "Library")])
let testAction = TestAction.test(targets: [TestableTarget(target: TargetReference(projectPath: projectPath, name: "Library"))])
let scheme = Scheme.test(name: "Library", buildAction: buildAction, testAction: testAction, runAction: nil)
let project = Project.test(path: AbsolutePath("/project.xcodeproj"), targets: [target])
let pbxTarget = PBXNativeTarget(name: "Library")
let generatedProject = GeneratedProject.test(targets: ["Library": pbxTarget])
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: [])])
let got = subject.schemeProfileAction(scheme: scheme, project: project, generatedProject: generatedProject)
let buildable = got?.buildableProductRunnable?.buildableReference
// When
let got = try subject.schemeProfileAction(scheme: scheme,
graph: graph,
rootPath: projectPath,
generatedProjects: createGeneratedProjects(projects: [project]))
// Then
let result = try XCTUnwrap(got)
let buildable = result.buildableProductRunnable?.buildableReference
XCTAssertNil(buildable)
XCTAssertEqual(got?.buildConfiguration, "Release")
XCTAssertEqual(got?.preActions, [])
XCTAssertEqual(got?.postActions, [])
XCTAssertEqual(got?.shouldUseLaunchSchemeArgsEnv, true)
XCTAssertEqual(got?.savedToolIdentifier, "")
XCTAssertEqual(got?.ignoresPersistentStateOnLaunch, false)
XCTAssertEqual(got?.useCustomWorkingDirectory, false)
XCTAssertEqual(got?.debugDocumentVersioning, true)
XCTAssertNil(got?.commandlineArguments)
XCTAssertNil(got?.environmentVariables)
XCTAssertEqual(got?.enableTestabilityWhenProfilingTests, true)
XCTAssertEqual(result.buildConfiguration, "Release")
XCTAssertEqual(result.preActions, [])
XCTAssertEqual(result.postActions, [])
XCTAssertEqual(result.shouldUseLaunchSchemeArgsEnv, true)
XCTAssertEqual(result.savedToolIdentifier, "")
XCTAssertEqual(result.ignoresPersistentStateOnLaunch, false)
XCTAssertEqual(result.useCustomWorkingDirectory, false)
XCTAssertEqual(result.debugDocumentVersioning, true)
XCTAssertNil(result.commandlineArguments)
XCTAssertNil(result.environmentVariables)
XCTAssertEqual(result.enableTestabilityWhenProfilingTests, true)
XCTAssertEqual(got?.buildConfiguration, "Release")
XCTAssertEqual(got?.macroExpansion?.referencedContainer, "container:project.xcodeproj")
XCTAssertEqual(got?.macroExpansion?.buildableName, "libLibrary.dylib")
XCTAssertEqual(got?.macroExpansion?.blueprintName, "Library")
XCTAssertEqual(got?.macroExpansion?.buildableIdentifier, "primary")
XCTAssertEqual(result.buildConfiguration, "Release")
XCTAssertEqual(result.macroExpansion?.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(result.macroExpansion?.buildableName, "libLibrary.dylib")
XCTAssertEqual(result.macroExpansion?.blueprintName, "Library")
XCTAssertEqual(result.macroExpansion?.buildableIdentifier, "primary")
}
func test_schemeAnalyzeAction() {
let got = subject.schemeAnalyzeAction(for: .test())
XCTAssertEqual(got.buildConfiguration, "Debug")
func test_schemeAnalyzeAction() throws {
// Given
let projectPath = AbsolutePath("/Project")
let target = Target.test(name: "App", platform: .iOS, product: .app)
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "App")])
let scheme = Scheme.test(buildAction: buildAction)
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: [])])
// When
let got = try subject.schemeAnalyzeAction(scheme: scheme,
graph: graph,
rootPath: project.path,
generatedProjects: createGeneratedProjects(projects: [project]))
// Then
let result = try XCTUnwrap(got)
XCTAssertEqual(result.buildConfiguration, "Debug")
}
func test_defaultSchemeArchiveAction() {
@ -385,27 +529,43 @@ final class SchemeGeneratorTests: XCTestCase {
XCTAssertEqual(got.revealArchiveInOrganizer, true)
}
func test_schemeArchiveAction() {
func test_schemeArchiveAction() throws {
// Given
let projectPath = AbsolutePath("/Project")
let target = Target.test(name: "App", platform: .iOS, product: .app)
let scheme = Scheme.test(archiveAction: ArchiveAction.test(configurationName: "Beta Release",
revealArchiveInOrganizer: true,
customArchiveName: "App [Beta]"))
let pbxTarget = PBXNativeTarget(name: "App")
let project = Project.test(path: AbsolutePath("/project.xcodeproj"), targets: [target])
let generatedProject = GeneratedProject.test(targets: ["App": pbxTarget])
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "App")])
let archiveAction = ArchiveAction.test(configurationName: "Beta Release",
revealArchiveInOrganizer: true,
customArchiveName: "App [Beta]")
let scheme = Scheme.test(buildAction: buildAction, archiveAction: archiveAction)
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: [])])
let got = subject.schemeArchiveAction(scheme: scheme, project: project, generatedProject: generatedProject)
// When
let got = try subject.schemeArchiveAction(scheme: scheme,
graph: graph,
rootPath: project.path,
generatedProjects: createGeneratedProjects(projects: [project]))
XCTAssertEqual(got.buildConfiguration, "Beta Release")
XCTAssertEqual(got.customArchiveName, "App [Beta]")
XCTAssertEqual(got.revealArchiveInOrganizer, true)
// Then
let result = try XCTUnwrap(got)
XCTAssertEqual(result.buildConfiguration, "Beta Release")
XCTAssertEqual(result.customArchiveName, "App [Beta]")
XCTAssertEqual(result.revealArchiveInOrganizer, true)
}
// MARK: - Private
private func generatedProject(targets: [Target]) -> GeneratedProject {
private func createGeneratedProjects(projects: [Project]) -> [AbsolutePath: GeneratedProject] {
return Dictionary(uniqueKeysWithValues: projects.map {
($0.path, generatedProject(targets: $0.targets,
projectPath: $0.path.appending(component: "\($0.name).xcodeproj").pathString))
})
}
private func generatedProject(targets: [Target], projectPath: String = "/Project.xcodeproj") -> GeneratedProject {
var pbxTargets: [String: PBXNativeTarget] = [:]
targets.forEach { pbxTargets[$0.name] = PBXNativeTarget(name: $0.name) }
return GeneratedProject(pbxproj: .init(), path: AbsolutePath("/project.xcodeproj"), targets: pbxTargets, name: "project.xcodeproj")
let path = AbsolutePath(projectPath)
return GeneratedProject(pbxproj: .init(), path: path, targets: pbxTargets, name: path.basename)
}
}

View File

@ -539,11 +539,13 @@ class GeneratorModelLoaderTest: TuistUnitTestCase {
// Given
let manifest = SchemeManifest.test(name: "Scheme",
shared: false)
let projectPath = AbsolutePath("/somepath/Project")
// When
let model = TuistCore.Scheme.from(manifest: manifest)
let model = TuistCore.Scheme.from(manifest: manifest, projectPath: projectPath)
// Then
assert(scheme: model, matches: manifest)
assert(scheme: model, matches: manifest, path: projectPath)
}
func test_scheme_withActions() throws {
@ -564,11 +566,14 @@ class GeneratorModelLoaderTest: TuistUnitTestCase {
buildAction: buildAction,
testAction: testAction,
runAction: runActions)
let projectPath = AbsolutePath("/somepath/Project")
// When
let model = TuistCore.Scheme.from(manifest: manifest)
let model = TuistCore.Scheme.from(manifest: manifest, projectPath: projectPath)
// Then
assert(scheme: model, matches: manifest)
assert(scheme: model, matches: manifest, path: projectPath)
}
func test_generatorModelLoaderError_type() {
@ -791,16 +796,17 @@ class GeneratorModelLoaderTest: TuistUnitTestCase {
func assert(scheme: TuistCore.Scheme,
matches manifest: ProjectDescription.Scheme,
path: AbsolutePath,
file: StaticString = #file,
line: UInt = #line) {
XCTAssertEqual(scheme.name, manifest.name, file: file, line: line)
XCTAssertEqual(scheme.shared, manifest.shared, file: file, line: line)
optionalAssert(scheme.buildAction, manifest.buildAction) {
assert(buildAction: $0, matches: $1, file: file, line: line)
assert(buildAction: $0, matches: $1, path: path, file: file, line: line)
}
optionalAssert(scheme.testAction, manifest.testAction) {
assert(testAction: $0, matches: $1, file: file, line: line)
assert(testAction: $0, matches: $1, path: path, file: file, line: line)
}
optionalAssert(scheme.runAction, manifest.runAction) {
@ -810,16 +816,19 @@ class GeneratorModelLoaderTest: TuistUnitTestCase {
func assert(buildAction: TuistCore.BuildAction,
matches manifest: ProjectDescription.BuildAction,
path: AbsolutePath,
file: StaticString = #file,
line: UInt = #line) {
XCTAssertEqual(buildAction.targets, manifest.targets, file: file, line: line)
XCTAssertEqual(buildAction.targets, manifest.targets.map { TargetReference(projectPath: path, name: $0) }, file: file, line: line)
}
func assert(testAction: TuistCore.TestAction,
matches manifest: ProjectDescription.TestAction,
path: AbsolutePath,
file: StaticString = #file,
line: UInt = #line) {
let targets = manifest.targets.map { TestableTarget.from(manifest: $0) }
let targets = manifest.targets.map { TestableTarget.from(manifest: $0, projectPath: path) }
XCTAssertEqual(testAction.targets, targets, file: file, line: line)
XCTAssertTrue(testAction.configurationName == manifest.configurationName, file: file, line: line)
XCTAssertEqual(testAction.coverage, manifest.coverage, file: file, line: line)
@ -832,10 +841,13 @@ class GeneratorModelLoaderTest: TuistUnitTestCase {
matches manifest: ProjectDescription.RunAction,
file: StaticString = #file,
line: UInt = #line) {
XCTAssertEqual(runAction.executable, manifest.executable, file: file, line: line)
var runActionExecutable: String?
if let executable = runAction.executable { runActionExecutable = executable.name }
XCTAssertEqual(runActionExecutable, manifest.executable, file: file, line: line)
XCTAssertTrue(runAction.configurationName == manifest.configurationName, file: file, line: line)
optionalAssert(runAction.arguments, manifest.arguments) {
assert(arguments: $0, matches: $1, file: file, line: line)
self.assert(arguments: $0, matches: $1, file: file, line: line)
}
}