Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add handling for Swift Testing Only Parallelization #871

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,12 @@ object.
## References πŸ“š

- [Xcode Project File Format](http://www.monobjc.net/xcode-project-file-format.html)
- [A brief look at the Xcode project format](http://danwright.info/blog/2010/10/xcode-pbxproject-files/)
- [pbexplorer](https://github.com/mjmsmith/pbxplorer)
- [pbxproj identifiers](https://pewpewthespells.com/blog/pbxproj_identifiers.html)
- [mob-pbxproj](https://github.com/kronenthaler/mod-pbxproj)
- [Xcodeproj](https://github.com/CocoaPods/Xcodeproj)
- [Nanaimo](https://github.com/CocoaPods/Nanaimo)
- [Facebook Buck](https://buckbuild.com/javadoc/com/facebook/buck/apple/xcode/xcodeproj/package-summary.html)
- [Swift Package Manager - Xcodeproj](https://github.com/apple/swift-package-manager/tree/main/Sources/Xcodeproj)

## Contributing

Expand Down
12 changes: 12 additions & 0 deletions Sources/XcodeProj/Scheme/XCScheme+TestParallelization.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Foundation

public extension XCScheme {
/// With the introduction of Swift Testing and Xcode 16, you can now choose to run your tests
// in parallel across either the full suite of tests in a target with `.all`, just those created
// under Swift Testing with `.swiftTestingOnly`, or run them serially with the `.none` option.
enum TestParallelization: String {
case all
case swiftTestingOnly
case none
}
}
48 changes: 44 additions & 4 deletions Sources/XcodeProj/Scheme/XCScheme+TestableReference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ public extension XCScheme {
// MARK: - Attributes

public var skipped: Bool
public var parallelizable: Bool
@available(*, deprecated, message: "Please use parallelization property instead")
public var parallelizable: Bool {
get { parallelization == .swiftTestingOnly }
set { parallelization = newValue ? .swiftTestingOnly : .none }
}

public var parallelization: TestParallelization
public var randomExecutionOrdering: Bool
public var useTestSelectionWhitelist: Bool?
public var buildableReference: BuildableReference
Expand All @@ -16,6 +22,25 @@ public extension XCScheme {

// MARK: - Init

public init(skipped: Bool,
parallelization: TestParallelization = .none,
randomExecutionOrdering: Bool = false,
buildableReference: BuildableReference,
locationScenarioReference: LocationScenarioReference? = nil,
skippedTests: [TestItem] = [],
selectedTests: [TestItem] = [],
useTestSelectionWhitelist: Bool? = nil) {
self.skipped = skipped
self.parallelization = parallelization
self.randomExecutionOrdering = randomExecutionOrdering
self.buildableReference = buildableReference
self.locationScenarioReference = locationScenarioReference
self.useTestSelectionWhitelist = useTestSelectionWhitelist
self.selectedTests = selectedTests
self.skippedTests = skippedTests
}

@available(*, deprecated, message: "Use init with Parallelization argument instead")
public init(skipped: Bool,
kelvinharron marked this conversation as resolved.
Show resolved Hide resolved
parallelizable: Bool = false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove the default value, so the deprecation warning is triggered only when parallelizable is specified.

randomExecutionOrdering: Bool = false,
Expand All @@ -25,7 +50,7 @@ public extension XCScheme {
selectedTests: [TestItem] = [],
useTestSelectionWhitelist: Bool? = nil) {
self.skipped = skipped
self.parallelizable = parallelizable
parallelization = parallelizable ? .swiftTestingOnly : .none
self.randomExecutionOrdering = randomExecutionOrdering
self.buildableReference = buildableReference
self.locationScenarioReference = locationScenarioReference
Expand All @@ -36,7 +61,13 @@ public extension XCScheme {

init(element: AEXMLElement) throws {
skipped = element.attributes["skipped"] == "YES"
parallelizable = element.attributes["parallelizable"] == "YES"

if let parallelizableValue = element.attributes["parallelizable"] {
parallelization = parallelizableValue == "YES" ? .all : .none
} else {
parallelization = .swiftTestingOnly
}

useTestSelectionWhitelist = element.attributes["useTestSelectionWhitelist"] == "YES"
randomExecutionOrdering = element.attributes["testExecutionOrdering"] == "random"
buildableReference = try BuildableReference(element: element["BuildableReference"])
Expand All @@ -63,7 +94,16 @@ public extension XCScheme {

func xmlElement() -> AEXMLElement {
var attributes: [String: String] = ["skipped": skipped.xmlString]
attributes["parallelizable"] = parallelizable ? parallelizable.xmlString : nil

switch parallelization {
case .all:
attributes["parallelizable"] = "YES"
case .none:
attributes["parallelizable"] = "NO"
case .swiftTestingOnly:
break // SwiftTesting is inferred by the lack of a value
}

if let useTestSelectionWhitelist {
attributes["useTestSelectionWhitelist"] = useTestSelectionWhitelist.xmlString
}
Expand Down
117 changes: 112 additions & 5 deletions Tests/XcodeProjTests/Scheme/XCSchemeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ final class XCSchemeIntegrationTests: XCTestCase {
func test_write_testableReferenceDefaultAttributesValuesAreOmitted() {
let reference = XCScheme.TestableReference(
skipped: false,
parallelizable: false,
parallelization: .swiftTestingOnly,
randomExecutionOrdering: false,
buildableReference: XCScheme.BuildableReference(
referencedContainer: "",
Expand All @@ -85,10 +85,10 @@ final class XCSchemeIntegrationTests: XCTestCase {
XCTAssertNil(subject.attributes["useTestSelectionWhitelist"])
}

func test_write_testableReferenceAttributesValues() {
func test_write_testableReferenceAttributesValues_allParallelizable() {
let reference = XCScheme.TestableReference(
skipped: false,
parallelizable: true,
parallelization: .all,
randomExecutionOrdering: true,
buildableReference: XCScheme.BuildableReference(
referencedContainer: "",
Expand All @@ -107,11 +107,117 @@ final class XCSchemeIntegrationTests: XCTestCase {
XCTAssertEqual(subject.attributes["testExecutionOrdering"], "random")
}

func test_write_testableReferenceAttributesValues_noneParallelizable() {
let reference = XCScheme.TestableReference(
skipped: false,
parallelization: .none,
randomExecutionOrdering: true,
buildableReference: XCScheme.BuildableReference(
referencedContainer: "",
blueprint: PBXObject(),
buildableName: "",
blueprintName: ""
),
skippedTests: [],
selectedTests: [],
useTestSelectionWhitelist: true
)
let subject = reference.xmlElement()
XCTAssertEqual(subject.attributes["skipped"], "NO")
XCTAssertEqual(subject.attributes["parallelizable"], "NO")
XCTAssertEqual(subject.attributes["useTestSelectionWhitelist"], "YES")
XCTAssertEqual(subject.attributes["testExecutionOrdering"], "random")
}

func test_write_testableReferenceAttributesValues_trueParallelizable() {
let reference = XCScheme.TestableReference(
skipped: false,
parallelizable: true,
randomExecutionOrdering: true,
buildableReference: XCScheme.BuildableReference(
referencedContainer: "",
blueprint: PBXObject(),
buildableName: "",
blueprintName: ""
),
skippedTests: [],
selectedTests: [],
useTestSelectionWhitelist: true
)
let subject = reference.xmlElement()
XCTAssertEqual(subject.attributes["skipped"], "NO")
XCTAssertEqual(subject.attributes["parallelizable"], nil)
XCTAssertEqual(subject.attributes["useTestSelectionWhitelist"], "YES")
XCTAssertEqual(subject.attributes["testExecutionOrdering"], "random")
}

func test_write_testableReferenceAttributesValues_falseParallelizable() {
let reference = XCScheme.TestableReference(
skipped: false,
parallelizable: false,
randomExecutionOrdering: true,
buildableReference: XCScheme.BuildableReference(
referencedContainer: "",
blueprint: PBXObject(),
buildableName: "",
blueprintName: ""
),
skippedTests: [],
selectedTests: [],
useTestSelectionWhitelist: true
)
let subject = reference.xmlElement()
XCTAssertEqual(subject.attributes["skipped"], "NO")
XCTAssertEqual(subject.attributes["parallelizable"], "NO")
XCTAssertEqual(subject.attributes["useTestSelectionWhitelist"], "YES")
XCTAssertEqual(subject.attributes["testExecutionOrdering"], "random")
}

func test_computed_parallelizable_testableReference_false() {
let reference = XCScheme.TestableReference(
skipped: false,
parallelizable: false,
randomExecutionOrdering: true,
buildableReference: XCScheme.BuildableReference(
referencedContainer: "",
blueprint: PBXObject(),
buildableName: "",
blueprintName: ""
),
skippedTests: [],
selectedTests: [],
useTestSelectionWhitelist: true
)

XCTAssertEqual(reference.parallelizable, false)
XCTAssertEqual(reference.parallelization, .none)
}

func test_computed_parallelizable_testableReference_true() {
let reference = XCScheme.TestableReference(
skipped: false,
parallelizable: true,
randomExecutionOrdering: true,
buildableReference: XCScheme.BuildableReference(
referencedContainer: "",
blueprint: PBXObject(),
buildableName: "",
blueprintName: ""
),
skippedTests: [],
selectedTests: [],
useTestSelectionWhitelist: true
)

XCTAssertEqual(reference.parallelizable, true)
XCTAssertEqual(reference.parallelization, .swiftTestingOnly)
}

func test_write_testableReferenceSelectedTests() {
// Given
let reference = XCScheme.TestableReference(
skipped: false,
parallelizable: true,
parallelization: .all,
randomExecutionOrdering: true,
buildableReference: XCScheme.BuildableReference(
referencedContainer: "",
Expand Down Expand Up @@ -397,7 +503,8 @@ final class XCSchemeIntegrationTests: XCTestCase {
XCTAssertEqual(scheme.testAction?.codeCoverageEnabled, true)
XCTAssertEqual(scheme.testAction?.onlyGenerateCoverageForSpecifiedTargets, true)
XCTAssertEqual(scheme.testAction?.testables.first?.skipped, false)
XCTAssertEqual(scheme.testAction?.testables.first?.parallelizable, false)
XCTAssertEqual(scheme.testAction?.testables.first?.parallelizable, true)
XCTAssertEqual(scheme.testAction?.testables.first?.parallelization, .swiftTestingOnly)
XCTAssertEqual(scheme.testAction?.testables.first?.randomExecutionOrdering, false)
XCTAssertEqual(scheme.testAction?.testables.first?.useTestSelectionWhitelist, false)
XCTAssertEqual(scheme.testAction?.testables.first?.buildableReference.buildableIdentifier, "primary")
Expand Down
Loading