From b7464aba880ac63a522066d612a612f576a5d7d6 Mon Sep 17 00:00:00 2001 From: yonaskolb Date: Tue, 12 Nov 2019 21:19:08 +1100 Subject: [PATCH] split up Scheme spec --- Sources/ProjectSpec/Scheme.swift | 667 ------------------ .../Scheme/SchemExecutionAction.swift | 34 + Sources/ProjectSpec/Scheme/Scheme.swift | 83 +++ .../ProjectSpec/Scheme/SchemeAnalyze.swift | 27 + .../ProjectSpec/Scheme/SchemeArchive.swift | 56 ++ Sources/ProjectSpec/Scheme/SchemeBuild.swift | 83 +++ .../ProjectSpec/Scheme/SchemeBuildType.swift | 37 + .../Scheme/SchemeEnvironmentVariable.swift | 56 ++ .../ProjectSpec/Scheme/SchemeProfile.swift | 54 ++ Sources/ProjectSpec/Scheme/SchemeRun.swift | 81 +++ Sources/ProjectSpec/Scheme/SchemeTest.swift | 199 ++++++ 11 files changed, 710 insertions(+), 667 deletions(-) delete mode 100644 Sources/ProjectSpec/Scheme.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemExecutionAction.swift create mode 100644 Sources/ProjectSpec/Scheme/Scheme.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemeAnalyze.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemeArchive.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemeBuild.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemeBuildType.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemeEnvironmentVariable.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemeProfile.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemeRun.swift create mode 100644 Sources/ProjectSpec/Scheme/SchemeTest.swift diff --git a/Sources/ProjectSpec/Scheme.swift b/Sources/ProjectSpec/Scheme.swift deleted file mode 100644 index 93e291b4..00000000 --- a/Sources/ProjectSpec/Scheme.swift +++ /dev/null @@ -1,667 +0,0 @@ -import Foundation -import JSONUtilities -import XcodeProj - -public typealias BuildType = XCScheme.BuildAction.Entry.BuildFor - -public struct Scheme: Equatable { - - public var name: String - public var build: Build - public var run: Run? - public var archive: Archive? - public var analyze: Analyze? - public var test: Test? - public var profile: Profile? - - public init( - name: String, - build: Build, - run: Run? = nil, - test: Test? = nil, - profile: Profile? = nil, - analyze: Analyze? = nil, - archive: Archive? = nil - ) { - self.name = name - self.build = build - self.run = run - self.test = test - self.profile = profile - self.analyze = analyze - self.archive = archive - } - - public struct ExecutionAction: Equatable { - public var script: String - public var name: String - public var settingsTarget: String? - public init(name: String, script: String, settingsTarget: String? = nil) { - self.script = script - self.name = name - self.settingsTarget = settingsTarget - } - } - - public struct Build: Equatable { - public static let parallelizeBuildDefault = true - public static let buildImplicitDependenciesDefault = true - - public var targets: [BuildTarget] - public var parallelizeBuild: Bool - public var buildImplicitDependencies: Bool - public var preActions: [ExecutionAction] - public var postActions: [ExecutionAction] - public init( - targets: [BuildTarget], - parallelizeBuild: Bool = parallelizeBuildDefault, - buildImplicitDependencies: Bool = buildImplicitDependenciesDefault, - preActions: [ExecutionAction] = [], - postActions: [ExecutionAction] = [] - ) { - self.targets = targets - self.parallelizeBuild = parallelizeBuild - self.buildImplicitDependencies = buildImplicitDependencies - self.preActions = preActions - self.postActions = postActions - } - } - - public struct Run: BuildAction { - public static let disableMainThreadCheckerDefault = false - public static let debugEnabledDefault = true - - public var config: String? - public var commandLineArguments: [String: Bool] - public var preActions: [ExecutionAction] - public var postActions: [ExecutionAction] - public var environmentVariables: [XCScheme.EnvironmentVariable] - public var disableMainThreadChecker: Bool - public var language: String? - public var region: String? - public var debugEnabled: Bool - - public init( - config: String? = nil, - commandLineArguments: [String: Bool] = [:], - preActions: [ExecutionAction] = [], - postActions: [ExecutionAction] = [], - environmentVariables: [XCScheme.EnvironmentVariable] = [], - disableMainThreadChecker: Bool = disableMainThreadCheckerDefault, - language: String? = nil, - region: String? = nil, - debugEnabled: Bool = debugEnabledDefault - ) { - self.config = config - self.commandLineArguments = commandLineArguments - self.preActions = preActions - self.postActions = postActions - self.environmentVariables = environmentVariables - self.disableMainThreadChecker = disableMainThreadChecker - self.language = language - self.region = region - self.debugEnabled = debugEnabled - } - } - - public struct Test: BuildAction { - public static let gatherCoverageDataDefault = false - public static let disableMainThreadCheckerDefault = false - public static let debugEnabledDefault = true - - public var config: String? - public var gatherCoverageData: Bool - public var coverageTargets: [TargetReference] - public var disableMainThreadChecker: Bool - public var commandLineArguments: [String: Bool] - public var targets: [TestTarget] - public var preActions: [ExecutionAction] - public var postActions: [ExecutionAction] - public var environmentVariables: [XCScheme.EnvironmentVariable] - public var language: String? - public var region: String? - public var debugEnabled: Bool - public var testPlans: [String] - - public struct TestTarget: Equatable, ExpressibleByStringLiteral { - public static let randomExecutionOrderDefault = false - public static let parallelizableDefault = false - - public var name: String { targetReference.name } - public let targetReference: TargetReference - public var randomExecutionOrder: Bool - public var parallelizable: Bool - public var skippedTests: [String] - - public init( - targetReference: TargetReference, - randomExecutionOrder: Bool = randomExecutionOrderDefault, - parallelizable: Bool = parallelizableDefault, - skippedTests: [String] = [] - ) { - self.targetReference = targetReference - self.randomExecutionOrder = randomExecutionOrder - self.parallelizable = parallelizable - self.skippedTests = skippedTests - } - - public init(stringLiteral value: String) { - do { - targetReference = try TargetReference(value) - randomExecutionOrder = false - parallelizable = false - skippedTests = [] - } catch { - fatalError(SpecParsingError.invalidTargetReference(value).description) - } - } - } - - public init( - config: String? = nil, - gatherCoverageData: Bool = gatherCoverageDataDefault, - coverageTargets: [TargetReference] = [], - disableMainThreadChecker: Bool = disableMainThreadCheckerDefault, - randomExecutionOrder: Bool = false, - parallelizable: Bool = false, - commandLineArguments: [String: Bool] = [:], - targets: [TestTarget] = [], - preActions: [ExecutionAction] = [], - postActions: [ExecutionAction] = [], - environmentVariables: [XCScheme.EnvironmentVariable] = [], - testPlans: [String] = [], - language: String? = nil, - region: String? = nil, - debugEnabled: Bool = debugEnabledDefault - ) { - self.config = config - self.gatherCoverageData = gatherCoverageData - self.coverageTargets = coverageTargets - self.disableMainThreadChecker = disableMainThreadChecker - self.commandLineArguments = commandLineArguments - self.targets = targets - self.preActions = preActions - self.postActions = postActions - self.environmentVariables = environmentVariables - self.testPlans = testPlans - self.language = language - self.region = region - self.debugEnabled = debugEnabled - } - - public var shouldUseLaunchSchemeArgsEnv: Bool { - commandLineArguments.isEmpty && environmentVariables.isEmpty - } - } - - public struct Analyze: BuildAction { - public var config: String? - public init(config: String) { - self.config = config - } - } - - public struct Profile: BuildAction { - public var config: String? - public var commandLineArguments: [String: Bool] - public var preActions: [ExecutionAction] - public var postActions: [ExecutionAction] - public var environmentVariables: [XCScheme.EnvironmentVariable] - public init( - config: String? = nil, - commandLineArguments: [String: Bool] = [:], - preActions: [ExecutionAction] = [], - postActions: [ExecutionAction] = [], - environmentVariables: [XCScheme.EnvironmentVariable] = [] - ) { - self.config = config - self.commandLineArguments = commandLineArguments - self.preActions = preActions - self.postActions = postActions - self.environmentVariables = environmentVariables - } - - public var shouldUseLaunchSchemeArgsEnv: Bool { - commandLineArguments.isEmpty && environmentVariables.isEmpty - } - } - - public struct Archive: BuildAction { - public static let revealArchiveInOrganizerDefault = true - - public var config: String? - public var customArchiveName: String? - public var revealArchiveInOrganizer: Bool - public var preActions: [ExecutionAction] - public var postActions: [ExecutionAction] - public init( - config: String? = nil, - customArchiveName: String? = nil, - revealArchiveInOrganizer: Bool = revealArchiveInOrganizerDefault, - preActions: [ExecutionAction] = [], - postActions: [ExecutionAction] = [] - ) { - self.config = config - self.customArchiveName = customArchiveName - self.revealArchiveInOrganizer = revealArchiveInOrganizer - self.preActions = preActions - self.postActions = postActions - } - } - - public struct BuildTarget: Equatable, Hashable { - public var target: TargetReference - public var buildTypes: [BuildType] - - public init(target: TargetReference, buildTypes: [BuildType] = BuildType.all) { - self.target = target - self.buildTypes = buildTypes - } - } -} - -extension Scheme: PathContainer { - - static var pathProperties: [PathProperty] { - [ - .dictionary([ - .object("test", Test.pathProperties), - ]), - ] - } -} - -protocol BuildAction: Equatable { - var config: String? { get } -} - -extension Scheme.ExecutionAction: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - script = try jsonDictionary.json(atKeyPath: "script") - name = jsonDictionary.json(atKeyPath: "name") ?? "Run Script" - settingsTarget = jsonDictionary.json(atKeyPath: "settingsTarget") - } -} - -extension Scheme.ExecutionAction: JSONEncodable { - public func toJSONValue() -> Any { - [ - "script": script, - "name": name, - "settingsTarget": settingsTarget, - ] - } -} - -extension Scheme.Run: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - config = jsonDictionary.json(atKeyPath: "config") - commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:] - preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] - postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] - environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) - disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Run.disableMainThreadCheckerDefault - language = jsonDictionary.json(atKeyPath: "language") - region = jsonDictionary.json(atKeyPath: "region") - debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Run.debugEnabledDefault - } -} - -extension Scheme.Run: JSONEncodable { - public func toJSONValue() -> Any { - var dict: [String: Any?] = [ - "commandLineArguments": commandLineArguments, - "preActions": preActions.map { $0.toJSONValue() }, - "postActions": postActions.map { $0.toJSONValue() }, - "environmentVariables": environmentVariables.map { $0.toJSONValue() }, - "config": config, - "language": language, - "region": region, - ] - - if disableMainThreadChecker != Scheme.Run.disableMainThreadCheckerDefault { - dict["disableMainThreadChecker"] = disableMainThreadChecker - } - - if debugEnabled != Scheme.Run.debugEnabledDefault { - dict["debugEnabled"] = debugEnabled - } - return dict - } -} - -extension Scheme.Test: PathContainer { - - static var pathProperties: [PathProperty] { - [ - .string("testPlans") - ] - } -} - -extension Scheme.Test: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - config = jsonDictionary.json(atKeyPath: "config") - gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? Scheme.Test.gatherCoverageDataDefault - coverageTargets = try (jsonDictionary.json(atKeyPath: "coverageTargets") ?? []).map { try TargetReference($0) } - disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Test.disableMainThreadCheckerDefault - commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:] - if let targets = jsonDictionary["targets"] as? [Any] { - self.targets = try targets.compactMap { target in - if let string = target as? String { - return try TestTarget(targetReference: TargetReference(string)) - } else if let dictionary = target as? JSONDictionary { - return try TestTarget(jsonDictionary: dictionary) - } else { - return nil - } - } - } else { - targets = [] - } - preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] - postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] - environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) - testPlans = jsonDictionary.json(atKeyPath: "testPlans") ?? [] - language = jsonDictionary.json(atKeyPath: "language") - region = jsonDictionary.json(atKeyPath: "region") - debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Test.debugEnabledDefault - } -} - -extension Scheme.Test: JSONEncodable { - public func toJSONValue() -> Any { - var dict: [String: Any?] = [ - "commandLineArguments": commandLineArguments, - "targets": targets.map { $0.toJSONValue() }, - "preActions": preActions.map { $0.toJSONValue() }, - "postActions": postActions.map { $0.toJSONValue() }, - "environmentVariables": environmentVariables.map { $0.toJSONValue() }, - "testPlans": testPlans, - "config": config, - "language": language, - "region": region, - "coverageTargets": coverageTargets.map { $0.reference }, - ] - - if gatherCoverageData != Scheme.Test.gatherCoverageDataDefault { - dict["gatherCoverageData"] = gatherCoverageData - } - - if disableMainThreadChecker != Scheme.Test.disableMainThreadCheckerDefault { - dict["disableMainThreadChecker"] = disableMainThreadChecker - } - - if debugEnabled != Scheme.Run.debugEnabledDefault { - dict["debugEnabled"] = debugEnabled - } - - return dict - } -} - -extension Scheme.Test.TestTarget: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - targetReference = try TargetReference(jsonDictionary.json(atKeyPath: "name")) - randomExecutionOrder = jsonDictionary.json(atKeyPath: "randomExecutionOrder") ?? Scheme.Test.TestTarget.randomExecutionOrderDefault - parallelizable = jsonDictionary.json(atKeyPath: "parallelizable") ?? Scheme.Test.TestTarget.parallelizableDefault - skippedTests = jsonDictionary.json(atKeyPath: "skippedTests") ?? [] - } -} - -extension Scheme.Test.TestTarget: JSONEncodable { - public func toJSONValue() -> Any { - if randomExecutionOrder == Scheme.Test.TestTarget.randomExecutionOrderDefault, - parallelizable == Scheme.Test.TestTarget.parallelizableDefault { - return targetReference.reference - } - - var dict: JSONDictionary = [ - "name": targetReference.reference, - ] - - if randomExecutionOrder != Scheme.Test.TestTarget.randomExecutionOrderDefault { - dict["randomExecutionOrder"] = randomExecutionOrder - } - if parallelizable != Scheme.Test.TestTarget.parallelizableDefault { - dict["parallelizable"] = parallelizable - } - - return dict - } -} - -extension Scheme.Profile: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - config = jsonDictionary.json(atKeyPath: "config") - commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:] - preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] - postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] - environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) - } -} - -extension Scheme.Profile: JSONEncodable { - public func toJSONValue() -> Any { - [ - "commandLineArguments": commandLineArguments, - "preActions": preActions.map { $0.toJSONValue() }, - "postActions": postActions.map { $0.toJSONValue() }, - "environmentVariables": environmentVariables.map { $0.toJSONValue() }, - "config": config, - ] as [String: Any?] - } -} - -extension Scheme.Analyze: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - config = jsonDictionary.json(atKeyPath: "config") - } -} - -extension Scheme.Analyze: JSONEncodable { - public func toJSONValue() -> Any { - [ - "config": config, - ] - } -} - -extension Scheme.Archive: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - config = jsonDictionary.json(atKeyPath: "config") - customArchiveName = jsonDictionary.json(atKeyPath: "customArchiveName") - revealArchiveInOrganizer = jsonDictionary.json(atKeyPath: "revealArchiveInOrganizer") ?? Scheme.Archive.revealArchiveInOrganizerDefault - preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] - postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] - } -} - -extension Scheme.Archive: JSONEncodable { - public func toJSONValue() -> Any { - var dict: [String: Any?] = [ - "preActions": preActions.map { $0.toJSONValue() }, - "postActions": postActions.map { $0.toJSONValue() }, - "config": config, - "customArchiveName": customArchiveName, - ] - - if revealArchiveInOrganizer != Scheme.Archive.revealArchiveInOrganizerDefault { - dict["revealArchiveInOrganizer"] = revealArchiveInOrganizer - } - - return dict - } -} - -extension Scheme: NamedJSONDictionaryConvertible { - - public init(name: String, jsonDictionary: JSONDictionary) throws { - self.name = name - build = try jsonDictionary.json(atKeyPath: "build") - run = jsonDictionary.json(atKeyPath: "run") - test = jsonDictionary.json(atKeyPath: "test") - analyze = jsonDictionary.json(atKeyPath: "analyze") - profile = jsonDictionary.json(atKeyPath: "profile") - archive = jsonDictionary.json(atKeyPath: "archive") - } -} - -extension Scheme: JSONEncodable { - public func toJSONValue() -> Any { - [ - "build": build.toJSONValue(), - "run": run?.toJSONValue(), - "test": test?.toJSONValue(), - "analyze": analyze?.toJSONValue(), - "profile": profile?.toJSONValue(), - "archive": archive?.toJSONValue(), - ] as [String: Any?] - } -} - -extension Scheme.Build: JSONObjectConvertible { - - public init(jsonDictionary: JSONDictionary) throws { - let targetDictionary: JSONDictionary = try jsonDictionary.json(atKeyPath: "targets") - var targets: [Scheme.BuildTarget] = [] - for (targetRepr, possibleBuildTypes) in targetDictionary { - let buildTypes: [BuildType] - if let string = possibleBuildTypes as? String { - switch string { - case "all": buildTypes = BuildType.all - case "none": buildTypes = [] - case "testing": buildTypes = [.testing, .analyzing] - case "indexing": buildTypes = [.testing, .analyzing, .archiving] - default: buildTypes = BuildType.all - } - } else if let enabledDictionary = possibleBuildTypes as? [String: Bool] { - buildTypes = enabledDictionary.filter { $0.value }.compactMap { BuildType.from(jsonValue: $0.key) } - } else if let array = possibleBuildTypes as? [String] { - buildTypes = array.compactMap(BuildType.from) - } else { - buildTypes = BuildType.all - } - let target = try TargetReference(targetRepr) - targets.append(Scheme.BuildTarget(target: target, buildTypes: buildTypes)) - } - self.targets = targets.sorted { $0.target.name < $1.target.name } - preActions = try jsonDictionary.json(atKeyPath: "preActions")?.map(Scheme.ExecutionAction.init) ?? [] - postActions = try jsonDictionary.json(atKeyPath: "postActions")?.map(Scheme.ExecutionAction.init) ?? [] - parallelizeBuild = jsonDictionary.json(atKeyPath: "parallelizeBuild") ?? Scheme.Build.parallelizeBuildDefault - buildImplicitDependencies = jsonDictionary.json(atKeyPath: "buildImplicitDependencies") ?? Scheme.Build.buildImplicitDependenciesDefault - } -} - -extension Scheme.Build: JSONEncodable { - public func toJSONValue() -> Any { - let targetPairs = targets.map { ($0.target.reference, $0.buildTypes.map { $0.toJSONValue() }) } - - var dict: JSONDictionary = [ - "targets": Dictionary(uniqueKeysWithValues: targetPairs), - "preActions": preActions.map { $0.toJSONValue() }, - "postActions": postActions.map { $0.toJSONValue() }, - ] - - if parallelizeBuild != Scheme.Build.parallelizeBuildDefault { - dict["parallelizeBuild"] = parallelizeBuild - } - if buildImplicitDependencies != Scheme.Build.buildImplicitDependenciesDefault { - dict["buildImplicitDependencies"] = buildImplicitDependencies - } - - return dict - } -} - -extension BuildType: JSONPrimitiveConvertible { - - public typealias JSONType = String - - public static func from(jsonValue: String) -> BuildType? { - switch jsonValue { - case "test", "testing": return .testing - case "profile", "profiling": return .profiling - case "run", "running": return .running - case "archive", "archiving": return .archiving - case "analyze", "analyzing": return .analyzing - default: return nil - } - } - - public static var all: [BuildType] { - [.running, .testing, .profiling, .analyzing, .archiving] - } -} - -extension BuildType: JSONEncodable { - public func toJSONValue() -> Any { - switch self { - case .testing: return "testing" - case .profiling: return "profiling" - case .running: return "running" - case .archiving: return "archiving" - case .analyzing: return "analyzing" - } - } -} - -extension XCScheme.EnvironmentVariable: JSONObjectConvertible { - public static let enabledDefault = true - - private static func parseValue(_ value: Any) -> String { - if let bool = value as? Bool { - return bool ? "YES" : "NO" - } else { - return String(describing: value) - } - } - - public init(jsonDictionary: JSONDictionary) throws { - - let value: String - if let jsonValue = jsonDictionary["value"] { - value = XCScheme.EnvironmentVariable.parseValue(jsonValue) - } else { - // will throw error - value = try jsonDictionary.json(atKeyPath: "value") - } - let variable: String = try jsonDictionary.json(atKeyPath: "variable") - let enabled: Bool = jsonDictionary.json(atKeyPath: "isEnabled") ?? XCScheme.EnvironmentVariable.enabledDefault - self.init(variable: variable, value: value, enabled: enabled) - } - - static func parseAll(jsonDictionary: JSONDictionary) throws -> [XCScheme.EnvironmentVariable] { - if let variablesDictionary: [String: Any] = jsonDictionary.json(atKeyPath: "environmentVariables") { - return variablesDictionary.mapValues(parseValue) - .map { XCScheme.EnvironmentVariable(variable: $0.key, value: $0.value, enabled: true) } - .sorted { $0.variable < $1.variable } - } else if let variablesArray: [JSONDictionary] = jsonDictionary.json(atKeyPath: "environmentVariables") { - return try variablesArray.map(XCScheme.EnvironmentVariable.init) - } else { - return [] - } - } -} - -extension XCScheme.EnvironmentVariable: JSONEncodable { - public func toJSONValue() -> Any { - var dict: [String: Any] = [ - "variable": variable, - "value": value, - ] - - if enabled != XCScheme.EnvironmentVariable.enabledDefault { - dict["isEnabled"] = enabled - } - - return dict - } -} diff --git a/Sources/ProjectSpec/Scheme/SchemExecutionAction.swift b/Sources/ProjectSpec/Scheme/SchemExecutionAction.swift new file mode 100644 index 00000000..94761fb5 --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemExecutionAction.swift @@ -0,0 +1,34 @@ +import Foundation +import JSONUtilities + +extension Scheme { + public struct ExecutionAction: Equatable { + public var script: String + public var name: String + public var settingsTarget: String? + public init(name: String, script: String, settingsTarget: String? = nil) { + self.script = script + self.name = name + self.settingsTarget = settingsTarget + } + } +} + +extension Scheme.ExecutionAction: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + script = try jsonDictionary.json(atKeyPath: "script") + name = jsonDictionary.json(atKeyPath: "name") ?? "Run Script" + settingsTarget = jsonDictionary.json(atKeyPath: "settingsTarget") + } +} + +extension Scheme.ExecutionAction: JSONEncodable { + public func toJSONValue() -> Any { + [ + "script": script, + "name": name, + "settingsTarget": settingsTarget, + ] + } +} diff --git a/Sources/ProjectSpec/Scheme/Scheme.swift b/Sources/ProjectSpec/Scheme/Scheme.swift new file mode 100644 index 00000000..49b0635f --- /dev/null +++ b/Sources/ProjectSpec/Scheme/Scheme.swift @@ -0,0 +1,83 @@ +import Foundation +import JSONUtilities +import XcodeProj + +public struct Scheme: Equatable { + + public var name: String + public var build: Build + public var run: Run? + public var archive: Archive? + public var analyze: Analyze? + public var test: Test? + public var profile: Profile? + + public init( + name: String, + build: Build, + run: Run? = nil, + test: Test? = nil, + profile: Profile? = nil, + analyze: Analyze? = nil, + archive: Archive? = nil + ) { + self.name = name + self.build = build + self.run = run + self.test = test + self.profile = profile + self.analyze = analyze + self.archive = archive + } + + public struct BuildTarget: Equatable, Hashable { + public var target: TargetReference + public var buildTypes: [BuildType] + + public init(target: TargetReference, buildTypes: [BuildType] = BuildType.all) { + self.target = target + self.buildTypes = buildTypes + } + } +} + +extension Scheme: PathContainer { + + static var pathProperties: [PathProperty] { + [ + .dictionary([ + .object("test", Test.pathProperties), + ]), + ] + } +} + +extension Scheme: NamedJSONDictionaryConvertible { + + public init(name: String, jsonDictionary: JSONDictionary) throws { + self.name = name + build = try jsonDictionary.json(atKeyPath: "build") + run = jsonDictionary.json(atKeyPath: "run") + test = jsonDictionary.json(atKeyPath: "test") + analyze = jsonDictionary.json(atKeyPath: "analyze") + profile = jsonDictionary.json(atKeyPath: "profile") + archive = jsonDictionary.json(atKeyPath: "archive") + } +} + +extension Scheme: JSONEncodable { + public func toJSONValue() -> Any { + [ + "build": build.toJSONValue(), + "run": run?.toJSONValue(), + "test": test?.toJSONValue(), + "analyze": analyze?.toJSONValue(), + "profile": profile?.toJSONValue(), + "archive": archive?.toJSONValue(), + ] as [String: Any?] + } +} + +protocol BuildAction: Equatable { + var config: String? { get } +} diff --git a/Sources/ProjectSpec/Scheme/SchemeAnalyze.swift b/Sources/ProjectSpec/Scheme/SchemeAnalyze.swift new file mode 100644 index 00000000..da185912 --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemeAnalyze.swift @@ -0,0 +1,27 @@ +import Foundation +import JSONUtilities + +extension Scheme { + + public struct Analyze: BuildAction { + public var config: String? + public init(config: String) { + self.config = config + } + } +} + +extension Scheme.Analyze: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + config = jsonDictionary.json(atKeyPath: "config") + } +} + +extension Scheme.Analyze: JSONEncodable { + public func toJSONValue() -> Any { + [ + "config": config, + ] + } +} diff --git a/Sources/ProjectSpec/Scheme/SchemeArchive.swift b/Sources/ProjectSpec/Scheme/SchemeArchive.swift new file mode 100644 index 00000000..22a66774 --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemeArchive.swift @@ -0,0 +1,56 @@ +import Foundation +import JSONUtilities + +extension Scheme { + + public struct Archive: BuildAction { + public static let revealArchiveInOrganizerDefault = true + + public var config: String? + public var customArchiveName: String? + public var revealArchiveInOrganizer: Bool + public var preActions: [ExecutionAction] + public var postActions: [ExecutionAction] + public init( + config: String? = nil, + customArchiveName: String? = nil, + revealArchiveInOrganizer: Bool = revealArchiveInOrganizerDefault, + preActions: [ExecutionAction] = [], + postActions: [ExecutionAction] = [] + ) { + self.config = config + self.customArchiveName = customArchiveName + self.revealArchiveInOrganizer = revealArchiveInOrganizer + self.preActions = preActions + self.postActions = postActions + } + } +} + +extension Scheme.Archive: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + config = jsonDictionary.json(atKeyPath: "config") + customArchiveName = jsonDictionary.json(atKeyPath: "customArchiveName") + revealArchiveInOrganizer = jsonDictionary.json(atKeyPath: "revealArchiveInOrganizer") ?? Scheme.Archive.revealArchiveInOrganizerDefault + preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] + postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] + } +} + +extension Scheme.Archive: JSONEncodable { + public func toJSONValue() -> Any { + var dict: [String: Any?] = [ + "preActions": preActions.map { $0.toJSONValue() }, + "postActions": postActions.map { $0.toJSONValue() }, + "config": config, + "customArchiveName": customArchiveName, + ] + + if revealArchiveInOrganizer != Scheme.Archive.revealArchiveInOrganizerDefault { + dict["revealArchiveInOrganizer"] = revealArchiveInOrganizer + } + + return dict + } +} diff --git a/Sources/ProjectSpec/Scheme/SchemeBuild.swift b/Sources/ProjectSpec/Scheme/SchemeBuild.swift new file mode 100644 index 00000000..5a625e1d --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemeBuild.swift @@ -0,0 +1,83 @@ +import Foundation +import JSONUtilities + +extension Scheme { + + public struct Build: Equatable { + public static let parallelizeBuildDefault = true + public static let buildImplicitDependenciesDefault = true + + public var targets: [BuildTarget] + public var parallelizeBuild: Bool + public var buildImplicitDependencies: Bool + public var preActions: [ExecutionAction] + public var postActions: [ExecutionAction] + public init( + targets: [BuildTarget], + parallelizeBuild: Bool = parallelizeBuildDefault, + buildImplicitDependencies: Bool = buildImplicitDependenciesDefault, + preActions: [ExecutionAction] = [], + postActions: [ExecutionAction] = [] + ) { + self.targets = targets + self.parallelizeBuild = parallelizeBuild + self.buildImplicitDependencies = buildImplicitDependencies + self.preActions = preActions + self.postActions = postActions + } + } +} + +extension Scheme.Build: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + let targetDictionary: JSONDictionary = try jsonDictionary.json(atKeyPath: "targets") + var targets: [Scheme.BuildTarget] = [] + for (targetRepr, possibleBuildTypes) in targetDictionary { + let buildTypes: [BuildType] + if let string = possibleBuildTypes as? String { + switch string { + case "all": buildTypes = BuildType.all + case "none": buildTypes = [] + case "testing": buildTypes = [.testing, .analyzing] + case "indexing": buildTypes = [.testing, .analyzing, .archiving] + default: buildTypes = BuildType.all + } + } else if let enabledDictionary = possibleBuildTypes as? [String: Bool] { + buildTypes = enabledDictionary.filter { $0.value }.compactMap { BuildType.from(jsonValue: $0.key) } + } else if let array = possibleBuildTypes as? [String] { + buildTypes = array.compactMap(BuildType.from) + } else { + buildTypes = BuildType.all + } + let target = try TargetReference(targetRepr) + targets.append(Scheme.BuildTarget(target: target, buildTypes: buildTypes)) + } + self.targets = targets.sorted { $0.target.name < $1.target.name } + preActions = try jsonDictionary.json(atKeyPath: "preActions")?.map(Scheme.ExecutionAction.init) ?? [] + postActions = try jsonDictionary.json(atKeyPath: "postActions")?.map(Scheme.ExecutionAction.init) ?? [] + parallelizeBuild = jsonDictionary.json(atKeyPath: "parallelizeBuild") ?? Scheme.Build.parallelizeBuildDefault + buildImplicitDependencies = jsonDictionary.json(atKeyPath: "buildImplicitDependencies") ?? Scheme.Build.buildImplicitDependenciesDefault + } +} + +extension Scheme.Build: JSONEncodable { + public func toJSONValue() -> Any { + let targetPairs = targets.map { ($0.target.reference, $0.buildTypes.map { $0.toJSONValue() }) } + + var dict: JSONDictionary = [ + "targets": Dictionary(uniqueKeysWithValues: targetPairs), + "preActions": preActions.map { $0.toJSONValue() }, + "postActions": postActions.map { $0.toJSONValue() }, + ] + + if parallelizeBuild != Scheme.Build.parallelizeBuildDefault { + dict["parallelizeBuild"] = parallelizeBuild + } + if buildImplicitDependencies != Scheme.Build.buildImplicitDependenciesDefault { + dict["buildImplicitDependencies"] = buildImplicitDependencies + } + + return dict + } +} diff --git a/Sources/ProjectSpec/Scheme/SchemeBuildType.swift b/Sources/ProjectSpec/Scheme/SchemeBuildType.swift new file mode 100644 index 00000000..f28996c6 --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemeBuildType.swift @@ -0,0 +1,37 @@ +import Foundation +import JSONUtilities +import XcodeProj + +public typealias BuildType = XCScheme.BuildAction.Entry.BuildFor + +extension BuildType: JSONPrimitiveConvertible { + + public typealias JSONType = String + + public static func from(jsonValue: String) -> BuildType? { + switch jsonValue { + case "test", "testing": return .testing + case "profile", "profiling": return .profiling + case "run", "running": return .running + case "archive", "archiving": return .archiving + case "analyze", "analyzing": return .analyzing + default: return nil + } + } + + public static var all: [BuildType] { + [.running, .testing, .profiling, .analyzing, .archiving] + } +} + +extension BuildType: JSONEncodable { + public func toJSONValue() -> Any { + switch self { + case .testing: return "testing" + case .profiling: return "profiling" + case .running: return "running" + case .archiving: return "archiving" + case .analyzing: return "analyzing" + } + } +} diff --git a/Sources/ProjectSpec/Scheme/SchemeEnvironmentVariable.swift b/Sources/ProjectSpec/Scheme/SchemeEnvironmentVariable.swift new file mode 100644 index 00000000..d22e5583 --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemeEnvironmentVariable.swift @@ -0,0 +1,56 @@ +import Foundation +import JSONUtilities +import XcodeProj + +extension XCScheme.EnvironmentVariable: JSONObjectConvertible { + public static let enabledDefault = true + + private static func parseValue(_ value: Any) -> String { + if let bool = value as? Bool { + return bool ? "YES" : "NO" + } else { + return String(describing: value) + } + } + + public init(jsonDictionary: JSONDictionary) throws { + + let value: String + if let jsonValue = jsonDictionary["value"] { + value = XCScheme.EnvironmentVariable.parseValue(jsonValue) + } else { + // will throw error + value = try jsonDictionary.json(atKeyPath: "value") + } + let variable: String = try jsonDictionary.json(atKeyPath: "variable") + let enabled: Bool = jsonDictionary.json(atKeyPath: "isEnabled") ?? XCScheme.EnvironmentVariable.enabledDefault + self.init(variable: variable, value: value, enabled: enabled) + } + + static func parseAll(jsonDictionary: JSONDictionary) throws -> [XCScheme.EnvironmentVariable] { + if let variablesDictionary: [String: Any] = jsonDictionary.json(atKeyPath: "environmentVariables") { + return variablesDictionary.mapValues(parseValue) + .map { XCScheme.EnvironmentVariable(variable: $0.key, value: $0.value, enabled: true) } + .sorted { $0.variable < $1.variable } + } else if let variablesArray: [JSONDictionary] = jsonDictionary.json(atKeyPath: "environmentVariables") { + return try variablesArray.map(XCScheme.EnvironmentVariable.init) + } else { + return [] + } + } +} + +extension XCScheme.EnvironmentVariable: JSONEncodable { + public func toJSONValue() -> Any { + var dict: [String: Any] = [ + "variable": variable, + "value": value, + ] + + if enabled != XCScheme.EnvironmentVariable.enabledDefault { + dict["isEnabled"] = enabled + } + + return dict + } +} diff --git a/Sources/ProjectSpec/Scheme/SchemeProfile.swift b/Sources/ProjectSpec/Scheme/SchemeProfile.swift new file mode 100644 index 00000000..0dfa7880 --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemeProfile.swift @@ -0,0 +1,54 @@ +import Foundation +import JSONUtilities +import XcodeProj + +extension Scheme { + + public struct Profile: BuildAction { + public var config: String? + public var commandLineArguments: [String: Bool] + public var preActions: [ExecutionAction] + public var postActions: [ExecutionAction] + public var environmentVariables: [XCScheme.EnvironmentVariable] + public init( + config: String? = nil, + commandLineArguments: [String: Bool] = [:], + preActions: [ExecutionAction] = [], + postActions: [ExecutionAction] = [], + environmentVariables: [XCScheme.EnvironmentVariable] = [] + ) { + self.config = config + self.commandLineArguments = commandLineArguments + self.preActions = preActions + self.postActions = postActions + self.environmentVariables = environmentVariables + } + + public var shouldUseLaunchSchemeArgsEnv: Bool { + commandLineArguments.isEmpty && environmentVariables.isEmpty + } + } +} + +extension Scheme.Profile: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + config = jsonDictionary.json(atKeyPath: "config") + commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:] + preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] + postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] + environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) + } +} + +extension Scheme.Profile: JSONEncodable { + public func toJSONValue() -> Any { + [ + "commandLineArguments": commandLineArguments, + "preActions": preActions.map { $0.toJSONValue() }, + "postActions": postActions.map { $0.toJSONValue() }, + "environmentVariables": environmentVariables.map { $0.toJSONValue() }, + "config": config, + ] as [String: Any?] + } +} diff --git a/Sources/ProjectSpec/Scheme/SchemeRun.swift b/Sources/ProjectSpec/Scheme/SchemeRun.swift new file mode 100644 index 00000000..0deb7d03 --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemeRun.swift @@ -0,0 +1,81 @@ +import Foundation +import XcodeProj +import JSONUtilities + +extension Scheme { + + public struct Run: BuildAction { + public static let disableMainThreadCheckerDefault = false + public static let debugEnabledDefault = true + + public var config: String? + public var commandLineArguments: [String: Bool] + public var preActions: [ExecutionAction] + public var postActions: [ExecutionAction] + public var environmentVariables: [XCScheme.EnvironmentVariable] + public var disableMainThreadChecker: Bool + public var language: String? + public var region: String? + public var debugEnabled: Bool + + public init( + config: String? = nil, + commandLineArguments: [String: Bool] = [:], + preActions: [ExecutionAction] = [], + postActions: [ExecutionAction] = [], + environmentVariables: [XCScheme.EnvironmentVariable] = [], + disableMainThreadChecker: Bool = disableMainThreadCheckerDefault, + language: String? = nil, + region: String? = nil, + debugEnabled: Bool = debugEnabledDefault + ) { + self.config = config + self.commandLineArguments = commandLineArguments + self.preActions = preActions + self.postActions = postActions + self.environmentVariables = environmentVariables + self.disableMainThreadChecker = disableMainThreadChecker + self.language = language + self.region = region + self.debugEnabled = debugEnabled + } + } +} + +extension Scheme.Run: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + config = jsonDictionary.json(atKeyPath: "config") + commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:] + preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] + postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] + environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) + disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Run.disableMainThreadCheckerDefault + language = jsonDictionary.json(atKeyPath: "language") + region = jsonDictionary.json(atKeyPath: "region") + debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Run.debugEnabledDefault + } +} + +extension Scheme.Run: JSONEncodable { + public func toJSONValue() -> Any { + var dict: [String: Any?] = [ + "commandLineArguments": commandLineArguments, + "preActions": preActions.map { $0.toJSONValue() }, + "postActions": postActions.map { $0.toJSONValue() }, + "environmentVariables": environmentVariables.map { $0.toJSONValue() }, + "config": config, + "language": language, + "region": region, + ] + + if disableMainThreadChecker != Scheme.Run.disableMainThreadCheckerDefault { + dict["disableMainThreadChecker"] = disableMainThreadChecker + } + + if debugEnabled != Scheme.Run.debugEnabledDefault { + dict["debugEnabled"] = debugEnabled + } + return dict + } +} diff --git a/Sources/ProjectSpec/Scheme/SchemeTest.swift b/Sources/ProjectSpec/Scheme/SchemeTest.swift new file mode 100644 index 00000000..267fe260 --- /dev/null +++ b/Sources/ProjectSpec/Scheme/SchemeTest.swift @@ -0,0 +1,199 @@ +import Foundation +import JSONUtilities +import XcodeProj + +extension Scheme { + + public struct Test: BuildAction { + public static let gatherCoverageDataDefault = false + public static let disableMainThreadCheckerDefault = false + public static let debugEnabledDefault = true + + public var config: String? + public var gatherCoverageData: Bool + public var coverageTargets: [TargetReference] + public var disableMainThreadChecker: Bool + public var commandLineArguments: [String: Bool] + public var targets: [TestTarget] + public var preActions: [ExecutionAction] + public var postActions: [ExecutionAction] + public var environmentVariables: [XCScheme.EnvironmentVariable] + public var language: String? + public var region: String? + public var debugEnabled: Bool + public var testPlans: [String] + + public struct TestTarget: Equatable, ExpressibleByStringLiteral { + public static let randomExecutionOrderDefault = false + public static let parallelizableDefault = false + + public var name: String { targetReference.name } + public let targetReference: TargetReference + public var randomExecutionOrder: Bool + public var parallelizable: Bool + public var skippedTests: [String] + + public init( + targetReference: TargetReference, + randomExecutionOrder: Bool = randomExecutionOrderDefault, + parallelizable: Bool = parallelizableDefault, + skippedTests: [String] = [] + ) { + self.targetReference = targetReference + self.randomExecutionOrder = randomExecutionOrder + self.parallelizable = parallelizable + self.skippedTests = skippedTests + } + + public init(stringLiteral value: String) { + do { + targetReference = try TargetReference(value) + randomExecutionOrder = false + parallelizable = false + skippedTests = [] + } catch { + fatalError(SpecParsingError.invalidTargetReference(value).description) + } + } + } + + public init( + config: String? = nil, + gatherCoverageData: Bool = gatherCoverageDataDefault, + coverageTargets: [TargetReference] = [], + disableMainThreadChecker: Bool = disableMainThreadCheckerDefault, + randomExecutionOrder: Bool = false, + parallelizable: Bool = false, + commandLineArguments: [String: Bool] = [:], + targets: [TestTarget] = [], + preActions: [ExecutionAction] = [], + postActions: [ExecutionAction] = [], + environmentVariables: [XCScheme.EnvironmentVariable] = [], + testPlans: [String] = [], + language: String? = nil, + region: String? = nil, + debugEnabled: Bool = debugEnabledDefault + ) { + self.config = config + self.gatherCoverageData = gatherCoverageData + self.coverageTargets = coverageTargets + self.disableMainThreadChecker = disableMainThreadChecker + self.commandLineArguments = commandLineArguments + self.targets = targets + self.preActions = preActions + self.postActions = postActions + self.environmentVariables = environmentVariables + self.testPlans = testPlans + self.language = language + self.region = region + self.debugEnabled = debugEnabled + } + + public var shouldUseLaunchSchemeArgsEnv: Bool { + commandLineArguments.isEmpty && environmentVariables.isEmpty + } + } +} + +extension Scheme.Test: PathContainer { + + static var pathProperties: [PathProperty] { + [ + .string("testPlans") + ] + } +} + +extension Scheme.Test: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + config = jsonDictionary.json(atKeyPath: "config") + gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? Scheme.Test.gatherCoverageDataDefault + coverageTargets = try (jsonDictionary.json(atKeyPath: "coverageTargets") ?? []).map { try TargetReference($0) } + disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Test.disableMainThreadCheckerDefault + commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:] + if let targets = jsonDictionary["targets"] as? [Any] { + self.targets = try targets.compactMap { target in + if let string = target as? String { + return try TestTarget(targetReference: TargetReference(string)) + } else if let dictionary = target as? JSONDictionary { + return try TestTarget(jsonDictionary: dictionary) + } else { + return nil + } + } + } else { + targets = [] + } + preActions = jsonDictionary.json(atKeyPath: "preActions") ?? [] + postActions = jsonDictionary.json(atKeyPath: "postActions") ?? [] + environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary) + testPlans = jsonDictionary.json(atKeyPath: "testPlans") ?? [] + language = jsonDictionary.json(atKeyPath: "language") + region = jsonDictionary.json(atKeyPath: "region") + debugEnabled = jsonDictionary.json(atKeyPath: "debugEnabled") ?? Scheme.Test.debugEnabledDefault + } +} + +extension Scheme.Test: JSONEncodable { + public func toJSONValue() -> Any { + var dict: [String: Any?] = [ + "commandLineArguments": commandLineArguments, + "targets": targets.map { $0.toJSONValue() }, + "preActions": preActions.map { $0.toJSONValue() }, + "postActions": postActions.map { $0.toJSONValue() }, + "environmentVariables": environmentVariables.map { $0.toJSONValue() }, + "testPlans": testPlans, + "config": config, + "language": language, + "region": region, + "coverageTargets": coverageTargets.map { $0.reference }, + ] + + if gatherCoverageData != Scheme.Test.gatherCoverageDataDefault { + dict["gatherCoverageData"] = gatherCoverageData + } + + if disableMainThreadChecker != Scheme.Test.disableMainThreadCheckerDefault { + dict["disableMainThreadChecker"] = disableMainThreadChecker + } + + if debugEnabled != Scheme.Run.debugEnabledDefault { + dict["debugEnabled"] = debugEnabled + } + + return dict + } +} + +extension Scheme.Test.TestTarget: JSONObjectConvertible { + + public init(jsonDictionary: JSONDictionary) throws { + targetReference = try TargetReference(jsonDictionary.json(atKeyPath: "name")) + randomExecutionOrder = jsonDictionary.json(atKeyPath: "randomExecutionOrder") ?? Scheme.Test.TestTarget.randomExecutionOrderDefault + parallelizable = jsonDictionary.json(atKeyPath: "parallelizable") ?? Scheme.Test.TestTarget.parallelizableDefault + skippedTests = jsonDictionary.json(atKeyPath: "skippedTests") ?? [] + } +} + +extension Scheme.Test.TestTarget: JSONEncodable { + public func toJSONValue() -> Any { + if randomExecutionOrder == Scheme.Test.TestTarget.randomExecutionOrderDefault, + parallelizable == Scheme.Test.TestTarget.parallelizableDefault { + return targetReference.reference + } + + var dict: JSONDictionary = [ + "name": targetReference.reference, + ] + + if randomExecutionOrder != Scheme.Test.TestTarget.randomExecutionOrderDefault { + dict["randomExecutionOrder"] = randomExecutionOrder + } + if parallelizable != Scheme.Test.TestTarget.parallelizableDefault { + dict["parallelizable"] = parallelizable + } + + return dict + } +}