Merge pull request #434 from yonaskolb/test_target

Add TestTarget with parallelizable and randomExecutionOrder
This commit is contained in:
Yonas Kolb 2018-11-04 20:31:32 +11:00 committed by GitHub
commit e96c91eecf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 237 additions and 16 deletions

View File

@ -6,6 +6,7 @@
- Added `weak` linking setting for dependencies [#411](https://github.com/yonaskolb/XcodeGen/pull/411) @alvarhansen
- Added `info` to targets for generating an `Info.plist` [#415](https://github.com/yonaskolb/XcodeGen/pull/415) @yonaskolb
- Added `entitlements` to targets for generating an `.entitlement` file [#415](https://github.com/yonaskolb/XcodeGen/pull/415) @yonaskolb
- Added `parallelizable` and `randomExecutionOrder` to `Scheme` test targets in an expanded form [#434](https://github.com/yonaskolb/XcodeGen/pull/434) @yonaskolb
- Validate incorrect config setting definitions [#431](https://github.com/yonaskolb/XcodeGen/pull/431) @yonaskolb
- Automatically set project `SDKROOT` if there is only a single platform within the project [#433](https://github.com/yonaskolb/XcodeGen/pull/433) @yonaskolb

View File

@ -454,7 +454,7 @@ targets:
This is a convenience used to automatically generate schemes for a target based on different configs or included tests. If you want more control check out the top level [Scheme](#scheme).
- [x] **configVariants**: **[String]** - This generates a scheme for each entry, using configs that contain the name with debug and release variants. This is useful for having different environment schemes.
- [ ] **testTargets**: **[String]** - a list of test targets that should be included in the scheme. These will be added to the build targets and the test entries
- [ ] **testTargets**: **[[Test Target](#test-target)]** - a list of test targets that should be included in the scheme. These will be added to the build targets and the test entries. Each entry can either be a simple string, or a [Test Target](#test-target)
- [ ] **gatherCoverageData**: **Bool** - a boolean that indicates if this scheme should gather coverage data. This defaults to false
- [ ] **commandLineArguments**: **[String:Bool]** - a dictionary from the argument name (`String`) to if it is enabled (`Bool`). These arguments will be added to the Test, Profile and Run scheme actions
- [ ] **environmentVariables**: **[[Environment Variable](#environment-variable)]** or **[String:String]** - environment variables for Run, Test and Profile scheme actions. When passing a dictionary, every key-value entry maps to a corresponding variable that is enabled.
@ -578,7 +578,12 @@ A multiline script can be written using the various YAML multiline methods, for
### Test Action
- [ ] **gatherCoverageData**: **Bool** - a boolean that indicates if this scheme should gather coverage data. This defaults to false
- [ ] **targets**: **[String]** - a list of targets to test
- [ ] **targets**: **[[Test Target](#test-target)]** - a list of targets to test. Each entry can either be a simple string, or a [Test Target](#test-target)
#### Test Target
- [x] **name**: **String** - The name of the target
- [ ] **parallelizable**: **Bool** - Whether to run tests in parallel. Defaults to false
- [ ] **randomExecutionOrder**: **Bool** - Whether to run tests in a random order. Defaults to false
### Archive Action

View File

@ -89,15 +89,40 @@ public struct Scheme: Equatable {
public var config: String?
public var gatherCoverageData: Bool
public var commandLineArguments: [String: Bool]
public var targets: [String]
public var targets: [TestTarget]
public var preActions: [ExecutionAction]
public var postActions: [ExecutionAction]
public var environmentVariables: [XCScheme.EnvironmentVariable]
public struct TestTarget: Equatable, ExpressibleByStringLiteral {
public let name: String
public var randomExecutionOrder: Bool
public var parallelizable: Bool
public init(
name: String,
randomExecutionOrder: Bool = false,
parallelizable: Bool = false
) {
self.name = name
self.randomExecutionOrder = randomExecutionOrder
self.parallelizable = parallelizable
}
public init(stringLiteral value: String) {
name = value
randomExecutionOrder = false
parallelizable = false
}
}
public init(
config: String,
gatherCoverageData: Bool = false,
randomExecutionOrder: Bool = false,
parallelizable: Bool = false,
commandLineArguments: [String: Bool] = [:],
targets: [String] = [],
targets: [TestTarget] = [],
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = [],
environmentVariables: [XCScheme.EnvironmentVariable] = []
@ -210,13 +235,34 @@ extension Scheme.Test: JSONObjectConvertible {
config = jsonDictionary.json(atKeyPath: "config")
gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? false
commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:]
targets = jsonDictionary.json(atKeyPath: "targets") ?? []
if let targets = jsonDictionary["targets"] as? [Any] {
self.targets = try targets.compactMap { target in
if let string = target as? String {
return TestTarget(name: 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)
}
}
extension Scheme.Test.TestTarget: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
name = try jsonDictionary.json(atKeyPath: "name")
randomExecutionOrder = jsonDictionary.json(atKeyPath: "randomExecutionOrder") ?? false
parallelizable = jsonDictionary.json(atKeyPath: "parallelizable") ?? false
}
}
extension Scheme.Profile: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {

View File

@ -110,8 +110,8 @@ extension Project {
}
for testTarget in scheme.testTargets {
if getTarget(testTarget) == nil {
errors.append(.invalidTargetSchemeTest(target: target.name, testTarget: testTarget))
if getTarget(testTarget.name) == nil {
errors.append(.invalidTargetSchemeTest(target: target.name, testTarget: testTarget.name))
}
}
}

View File

@ -3,7 +3,7 @@ import JSONUtilities
import xcodeproj
public struct TargetScheme: Equatable {
public var testTargets: [String]
public var testTargets: [Scheme.Test.TestTarget]
public var configVariants: [String]
public var gatherCoverageData: Bool
public var commandLineArguments: [String: Bool]
@ -12,7 +12,7 @@ public struct TargetScheme: Equatable {
public var postActions: [Scheme.ExecutionAction]
public init(
testTargets: [String] = [],
testTargets: [Scheme.Test.TestTarget] = [],
configVariants: [String] = [],
gatherCoverageData: Bool = false,
commandLineArguments: [String: Bool] = [:],
@ -33,7 +33,19 @@ public struct TargetScheme: Equatable {
extension TargetScheme: JSONObjectConvertible {
public init(jsonDictionary: JSONDictionary) throws {
testTargets = jsonDictionary.json(atKeyPath: "testTargets") ?? []
if let targets = jsonDictionary["testTargets"] as? [Any] {
self.testTargets = try targets.compactMap { target in
if let string = target as? String {
return .init(name: string)
} else if let dictionary = target as? JSONDictionary {
return try .init(jsonDictionary: dictionary)
} else {
return nil
}
}
} else {
testTargets = []
}
configVariants = jsonDictionary.json(atKeyPath: "configVariants") ?? []
gatherCoverageData = jsonDictionary.json(atKeyPath: "gatherCoverageData") ?? false
commandLineArguments = jsonDictionary.json(atKeyPath: "commandLineArguments") ?? [:]

View File

@ -95,9 +95,9 @@ public class SchemeGenerator {
return XCScheme.BuildAction.Entry(buildableReference: buildableReference, buildFor: buildTarget.buildTypes)
}
let testTargetNames = scheme.test?.targets ?? []
let testBuildTargets = testTargetNames.map {
Scheme.BuildTarget(target: $0, buildTypes: BuildType.testOnly)
let testTargets = scheme.test?.targets ?? []
let testBuildTargets = testTargets.map {
Scheme.BuildTarget(target: $0.name, buildTypes: BuildType.testOnly)
}
let testBuildTargetEntries = testBuildTargets.map(getBuildEntry)
@ -128,8 +128,11 @@ public class SchemeGenerator {
buildImplicitDependencies: scheme.build.buildImplicitDependencies
)
let testables = testBuildTargetEntries.map {
XCScheme.TestableReference(skipped: false, buildableReference: $0.buildableReference)
let testables = zip(testTargets, testBuildTargetEntries).map { testTarget, testBuilEntries in
XCScheme.TestableReference(skipped: false,
parallelizable: testTarget.parallelizable,
randomExecutionOrdering: testTarget.randomExecutionOrder,
buildableReference: testBuilEntries.buildableReference)
}
let testCommandLineArgs = scheme.test.map { XCScheme.CommandLineArguments($0.commandLineArguments) }

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
BuildableName = "App_iOS.app"
BlueprintName = "App_iOS"
ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Production Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NT_D4BAEEEC88124103C8DFF41FCE206DCE"
BuildableName = "App_iOS_UITests.xctest"
BlueprintName = "App_iOS_UITests"
ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES"
testExecutionOrdering = "random">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NT_193BAF154270D1C21E269EDF2A1BD3F6"
BuildableName = "App_iOS_Tests.xctest"
BlueprintName = "App_iOS_Tests"
ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
BuildableName = "App_iOS.app"
BlueprintName = "App_iOS"
ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Production Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
BuildableName = "App_iOS.app"
BlueprintName = "App_iOS"
ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Production Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "NT_BEB0891E36797FE2214A0A9D516D408D"
BuildableName = "App_iOS.app"
BlueprintName = "App_iOS"
ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Production Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Production Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -44,6 +44,7 @@
buildConfiguration = "Production Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -56,6 +57,8 @@
ReferencedContainer = "container:Project.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>

View File

@ -217,6 +217,19 @@ schemes:
commandLineArguments:
argument: YES
argument.with.dot: YES
test:
gatherCoverageData: true
App_Scheme:
build:
targets:
App_iOS: all
test:
gatherCoverageData: true
targets:
- App_iOS_UITests
- name: App_iOS_Tests
parallelizable: true
randomExecutionOrder: true
targetTemplates:
MyTemplate:
scheme: {}

View File

@ -253,7 +253,7 @@ class SpecLoadingTests: XCTestCase {
$0.it("parses target schemes") {
var targetDictionary = validTarget
targetDictionary["scheme"] = [
"testTargets": ["t1", "t2"],
"testTargets": ["t1", ["name": "t2"]],
"configVariants": ["dev", "app-store"],
"commandLineArguments": [
"ENV1": true,
@ -312,6 +312,18 @@ class SpecLoadingTests: XCTestCase {
],
],
],
"test": [
"config": "debug",
"targets": [
"Target1",
[
"name": "Target2",
"parallelizable": true,
"randomExecutionOrder": true,
],
],
"gatherCoverageData": true,
]
]
let scheme = try Scheme(name: "Scheme", jsonDictionary: schemeDictionary)
let expectedTargets: [Scheme.BuildTarget] = [
@ -330,6 +342,16 @@ class SpecLoadingTests: XCTestCase {
try expect(scheme.build.parallelizeBuild) == false
try expect(scheme.build.buildImplicitDependencies) == false
let expectedTest = Scheme.Test(config: "debug",
gatherCoverageData: true,
targets: [
"Target1",
Scheme.Test.TestTarget(name: "Target2",
randomExecutionOrder: true,
parallelizable: true)
])
try expect(scheme.test) == expectedTest
}
$0.it("parses schemes variables") {