diff --git a/Fixtures/Schemes/DebugAsRoot.xcscheme b/Fixtures/Schemes/DebugAsRoot.xcscheme
index 17c540ce6..d6e1ae611 100644
--- a/Fixtures/Schemes/DebugAsRoot.xcscheme
+++ b/Fixtures/Schemes/DebugAsRoot.xcscheme
@@ -28,8 +28,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
-
-
+
+
+
+ CFBundleIdentifier
+ com.example.XPCService
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ XPCService
+ CFBundlePackageType
+ XPC!
+ XPCService
+
+ ServiceType
+ Application
+
+
+
diff --git a/Fixtures/iOS/Project.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme b/Fixtures/iOS/Project.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme
index 5ec735651..7cc8ee447 100644
--- a/Fixtures/iOS/Project.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme
+++ b/Fixtures/iOS/Project.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme
@@ -81,12 +81,6 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ allowLocationSimulation = "YES">
@@ -180,10 +179,6 @@
ReferencedContainer = "container:Project.xcodeproj">
-
-
+
+
diff --git a/Fixtures/iOS/Project.xcodeproj/xcuserdata/username1.xcuserdatad/xcschemes/iOS-debug.xcscheme b/Fixtures/iOS/Project.xcodeproj/xcuserdata/username1.xcuserdatad/xcschemes/iOS-debug.xcscheme
index 7cb38d44f..04d801fc8 100644
--- a/Fixtures/iOS/Project.xcodeproj/xcuserdata/username1.xcuserdatad/xcschemes/iOS-debug.xcscheme
+++ b/Fixtures/iOS/Project.xcodeproj/xcuserdata/username1.xcuserdatad/xcschemes/iOS-debug.xcscheme
@@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
-
-
-
-
-
-
+ skipped = "NO">
-
-
PBXTarget? {
+ guard let projectObjects = try? objects() else { return nil }
+ let allTargets: [PBXTarget] = Array(projectObjects.nativeTargets.values)
+ + Array(projectObjects.legacyTargets.values)
+ + Array(projectObjects.aggregateTargets.values)
+ return allTargets.first { $0.buildPhaseReferences.map(\.value).contains(reference.value) }
+ }
+
+ /// Human-readable display name, used in descriptive comment strings.
+ ///
+ /// - Returns: display name matching Xcode's comment format.
+ func displayName() -> String? {
+ if let phase = self as? PBXCopyFilesBuildPhase {
+ return phase.name ?? "Copy Files"
+ } else if let phase = self as? PBXShellScriptBuildPhase {
+ return phase.name ?? "Run Script"
+ }
+ return name()
+ }
+
/// Build phase name.
///
/// - Returns: build phase name.
diff --git a/Sources/XcodeProj/Objects/Files/PBXFileElement.swift b/Sources/XcodeProj/Objects/Files/PBXFileElement.swift
index 5f3e80dca..6d623dc50 100644
--- a/Sources/XcodeProj/Objects/Files/PBXFileElement.swift
+++ b/Sources/XcodeProj/Objects/Files/PBXFileElement.swift
@@ -139,6 +139,16 @@ public class PBXFileElement: PBXContainerItem, PlistSerializable {
guard let rhs = object as? PBXFileElement else { return false }
return isEqual(to: rhs)
}
+
+ // This method is needed to recursively set the parent to all elements.
+ // This allows us to more quickly find the full path to the elements.
+ func assignParentToChildren() {
+ guard let group = self as? PBXGroup else { return }
+ for child in group.children {
+ child.parent = self
+ child.assignParentToChildren()
+ }
+ }
}
// MARK: - Helpers
@@ -206,14 +216,4 @@ public extension PBXFileElement {
.first(where: { $0.name == "Base" }) else { return nil }
return baseReference.path
}
-
- // This method is needed to recursively set the parent to all elements.
- // This allows us to more quickly find the full path to the elements.
- func assignParentToChildren() {
- guard let group = self as? PBXGroup else { return }
- for child in group.children {
- child.parent = self
- child.assignParentToChildren()
- }
- }
}
diff --git a/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedBuildFileExceptionSet.swift b/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedBuildFileExceptionSet.swift
index e007bb879..d1623ded4 100644
--- a/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedBuildFileExceptionSet.swift
+++ b/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedBuildFileExceptionSet.swift
@@ -96,6 +96,11 @@ public class PBXFileSystemSynchronizedBuildFileExceptionSet: PBXFileSystemSynchr
// MARK: - PlistSerializable
+ override var plistComment: String {
+ let folder = synchronizedRootGroup?.fileName() ?? ""
+ return "Exceptions for \"\(folder)\" folder in \"\(target.name)\" target"
+ }
+
func plistKeyAndValue(proj _: PBXProj, reference: String) throws -> (key: CommentedString, value: PlistValue) {
var dictionary: [CommentedString: PlistValue] = [:]
dictionary["isa"] = .string(CommentedString(PBXFileSystemSynchronizedBuildFileExceptionSet.isa))
@@ -124,6 +129,6 @@ public class PBXFileSystemSynchronizedBuildFileExceptionSet: PBXFileSystemSynchr
}))
}
dictionary["target"] = .string(CommentedString(target.reference.value, comment: target.name))
- return (key: CommentedString(reference, comment: "PBXFileSystemSynchronizedBuildFileExceptionSet"), value: .dictionary(dictionary))
+ return (key: CommentedString(reference, comment: plistComment), value: .dictionary(dictionary))
}
}
diff --git a/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedExceptionSet.swift b/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedExceptionSet.swift
index 095bd24e9..7b141471a 100644
--- a/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedExceptionSet.swift
+++ b/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedExceptionSet.swift
@@ -1,4 +1,10 @@
import Foundation
/// Common class for exception sets, such as `PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet` and `PBXFileSystemSynchronizedBuildFileExceptionSet`
-public class PBXFileSystemSynchronizedExceptionSet: PBXObject {}
+public class PBXFileSystemSynchronizedExceptionSet: PBXObject {
+ /// The synchronized root group this exception set belongs to.
+ public internal(set) weak var synchronizedRootGroup: PBXFileSystemSynchronizedRootGroup?
+
+ /// The comment string used when this object is referenced in a plist.
+ var plistComment: String { type(of: self).isa }
+}
diff --git a/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet.swift b/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet.swift
index b2326893e..d18671fcb 100644
--- a/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet.swift
+++ b/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet.swift
@@ -66,6 +66,14 @@ public class PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet: PBX
// MARK: - PlistSerializable
+ override var plistComment: String {
+ guard let group = synchronizedRootGroup else { return type(of: self).isa }
+ let folder = group.fileName() ?? ""
+ let phase = buildPhase.displayName() ?? ""
+ let target = buildPhase.target()?.name ?? ""
+ return "Exceptions for \"\(folder)\" folder in \"\(phase)\" phase from \"\(target)\" target"
+ }
+
func plistKeyAndValue(proj _: PBXProj, reference: String) throws -> (key: CommentedString, value: PlistValue) {
var dictionary: [CommentedString: PlistValue] = [:]
dictionary["isa"] = .string(CommentedString(type(of: self).isa))
@@ -78,6 +86,6 @@ public class PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet: PBX
}))
}
dictionary["buildPhase"] = .string(CommentedString(buildPhase.reference.value, comment: buildPhase.name() ?? "CopyFiles"))
- return (key: CommentedString(reference, comment: "PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet"), value: .dictionary(dictionary))
+ return (key: CommentedString(reference, comment: plistComment), value: .dictionary(dictionary))
}
}
diff --git a/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedRootGroup.swift b/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedRootGroup.swift
index 43e090eff..5917e08db 100644
--- a/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedRootGroup.swift
+++ b/Sources/XcodeProj/Objects/Files/PBXFileSystemSynchronizedRootGroup.swift
@@ -15,6 +15,7 @@ public class PBXFileSystemSynchronizedRootGroup: PBXFileElement {
public var exceptions: [PBXFileSystemSynchronizedExceptionSet]? {
set {
exceptionsReferences = newValue?.references()
+ newValue?.forEach { $0.synchronizedRootGroup = self }
}
get {
exceptionsReferences?.objects()
@@ -83,24 +84,30 @@ public class PBXFileSystemSynchronizedRootGroup: PBXFileElement {
// MARK: - PlistSerializable
- override var multiline: Bool { (exceptions?.count ?? 0) < 2 }
+ override func assignParentToChildren() {
+ super.assignParentToChildren()
+ exceptions?.forEach { $0.synchronizedRootGroup = self }
+ }
override func plistKeyAndValue(proj: PBXProj, reference: String) throws -> (key: CommentedString, value: PlistValue) {
var dictionary: [CommentedString: PlistValue] = try super.plistKeyAndValue(proj: proj, reference: reference).value.dictionary ?? [:]
dictionary["isa"] = .string(CommentedString(type(of: self).isa))
if let exceptions, !exceptions.isEmpty {
dictionary["exceptions"] = .array(exceptions.map { exception in
- .string(CommentedString(exception.reference.value, comment: type(of: exception).isa))
+ .string(CommentedString(exception.reference.value, comment: exception.plistComment))
})
}
- if let explicitFileTypes {
+ if let explicitFileTypes, !explicitFileTypes.isEmpty {
dictionary["explicitFileTypes"] = .dictionary(Dictionary(uniqueKeysWithValues: explicitFileTypes.map { relativePath, fileType in
(CommentedString(relativePath), .string(CommentedString(fileType)))
}))
}
- if let explicitFolders {
+ if let explicitFolders, !explicitFolders.isEmpty {
dictionary["explicitFolders"] = .array(explicitFolders.map { .string(CommentedString($0)) })
}
+ if name == path {
+ dictionary["name"] = nil
+ }
return (key: CommentedString(reference,
comment: name ?? path),
value: .dictionary(dictionary))
diff --git a/Sources/XcodeProj/Project/Xcode.swift b/Sources/XcodeProj/Project/Xcode.swift
index 44ab18058..cd0b3e51e 100644
--- a/Sources/XcodeProj/Project/Xcode.swift
+++ b/Sources/XcodeProj/Project/Xcode.swift
@@ -328,6 +328,7 @@ public enum Xcode {
"xcsynspec": "text.plist.xcsynspec",
"xctarget": "wrapper.pb-target",
"xctest": "wrapper.cfbundle",
+ "xctestplan": "text",
"xctxtmacro": "text.plist.xctxtmacro",
"xcworkspace": "wrapper.workspace",
"xhtml": "text.xml",
diff --git a/Sources/XcodeProj/Scheme/XCScheme+BuildAction.swift b/Sources/XcodeProj/Scheme/XCScheme+BuildAction.swift
index 8cc9ed15a..00b3e9d3b 100644
--- a/Sources/XcodeProj/Scheme/XCScheme+BuildAction.swift
+++ b/Sources/XcodeProj/Scheme/XCScheme+BuildAction.swift
@@ -158,8 +158,8 @@ public extension XCScheme {
attributes["buildArchitectures"] = buildArchitecturesXMLString
}
- if let runPostActionsOnFailure {
- attributes["runPostActionsOnFailure"] = runPostActionsOnFailure.xmlString
+ if runPostActionsOnFailure == true {
+ attributes["runPostActionsOnFailure"] = "YES"
}
let element = AEXMLElement(name: "BuildAction",
diff --git a/Sources/XcodeProj/Scheme/XCScheme+LaunchAction.swift b/Sources/XcodeProj/Scheme/XCScheme+LaunchAction.swift
index 5f73777bc..d51c944b8 100644
--- a/Sources/XcodeProj/Scheme/XCScheme+LaunchAction.swift
+++ b/Sources/XcodeProj/Scheme/XCScheme+LaunchAction.swift
@@ -436,6 +436,14 @@ public extension XCScheme {
element.addChild(runnable.xmlElement())
}
+ if let commandlineArguments, !commandlineArguments.arguments.isEmpty {
+ element.addChild(commandlineArguments.xmlElement())
+ }
+
+ if let environmentVariables {
+ element.addChild(EnvironmentVariable.xmlElement(from: environmentVariables))
+ }
+
if let locationScenarioReference {
element.addChild(locationScenarioReference.xmlElement())
}
@@ -445,14 +453,6 @@ public extension XCScheme {
macro.addChild(macroExpansion.xmlElement())
}
- if let commandlineArguments {
- element.addChild(commandlineArguments.xmlElement())
- }
-
- if let environmentVariables {
- element.addChild(EnvironmentVariable.xmlElement(from: environmentVariables))
- }
-
if let language {
element.attributes["language"] = language
}
diff --git a/Sources/XcodeProj/Scheme/XCScheme+TestAction.swift b/Sources/XcodeProj/Scheme/XCScheme+TestAction.swift
index 735e699b1..4d014e86d 100644
--- a/Sources/XcodeProj/Scheme/XCScheme+TestAction.swift
+++ b/Sources/XcodeProj/Scheme/XCScheme+TestAction.swift
@@ -167,8 +167,8 @@ public extension XCScheme {
if codeCoverageEnabled {
attributes["codeCoverageEnabled"] = codeCoverageEnabled.xmlString
}
- if let onlyGenerateCoverageForSpecifiedTargets {
- attributes["onlyGenerateCoverageForSpecifiedTargets"] = onlyGenerateCoverageForSpecifiedTargets.xmlString
+ if onlyGenerateCoverageForSpecifiedTargets == true {
+ attributes["onlyGenerateCoverageForSpecifiedTargets"] = "YES"
}
if enableAddressSanitizer {
attributes["enableAddressSanitizer"] = enableAddressSanitizer.xmlString
@@ -204,24 +204,12 @@ public extension XCScheme {
let element = AEXMLElement(name: "TestAction", value: nil, attributes: attributes)
super.writeXML(parent: element)
- if let testPlans {
- let testPlansElement = element.addChild(name: "TestPlans")
- for testPlan in testPlans {
- testPlansElement.addChild(testPlan.xmlElement())
- }
- }
-
if let macroExpansion {
let macro = element.addChild(name: "MacroExpansion")
macro.addChild(macroExpansion.xmlElement())
}
- let testablesElement = element.addChild(name: "Testables")
- for testable in testables {
- testablesElement.addChild(testable.xmlElement())
- }
-
- if let commandlineArguments {
+ if let commandlineArguments, !commandlineArguments.arguments.isEmpty {
element.addChild(commandlineArguments.xmlElement())
}
@@ -229,6 +217,20 @@ public extension XCScheme {
element.addChild(EnvironmentVariable.xmlElement(from: environmentVariables))
}
+ if let testPlans {
+ let testPlansElement = element.addChild(name: "TestPlans")
+ for testPlan in testPlans {
+ testPlansElement.addChild(testPlan.xmlElement())
+ }
+ }
+
+ if !testables.isEmpty {
+ let testablesElement = element.addChild(name: "Testables")
+ for testable in testables {
+ testablesElement.addChild(testable.xmlElement())
+ }
+ }
+
if !additionalOptions.isEmpty {
let additionalOptionsElement = element.addChild(AEXMLElement(name: "AdditionalOptions"))
for additionalOption in additionalOptions {
diff --git a/Sources/XcodeProj/Scheme/XCScheme+TestableReference.swift b/Sources/XcodeProj/Scheme/XCScheme+TestableReference.swift
index f6b6a4b42..4d1a7dfa2 100644
--- a/Sources/XcodeProj/Scheme/XCScheme+TestableReference.swift
+++ b/Sources/XcodeProj/Scheme/XCScheme+TestableReference.swift
@@ -43,7 +43,7 @@ public extension XCScheme {
parallelization = .swiftTestingOnly
}
- useTestSelectionWhitelist = element.attributes["useTestSelectionWhitelist"] == "YES"
+ useTestSelectionWhitelist = element.attributes["useTestSelectionWhitelist"].map { $0 == "YES" }
randomExecutionOrdering = element.attributes["testExecutionOrdering"] == "random"
buildableReference = try BuildableReference(element: element["BuildableReference"])
@@ -79,8 +79,8 @@ public extension XCScheme {
break // SwiftTesting is inferred by the lack of a value
}
- if let useTestSelectionWhitelist {
- attributes["useTestSelectionWhitelist"] = useTestSelectionWhitelist.xmlString
+ if useTestSelectionWhitelist == true {
+ attributes["useTestSelectionWhitelist"] = "YES"
}
attributes["testExecutionOrdering"] = randomExecutionOrdering ? "random" : nil
let element = AEXMLElement(name: "TestableReference",
diff --git a/Tests/XcodeProjTests/Objects/Files/PBXFileSystemSynchronizedBuildFileExceptionSetTests.swift b/Tests/XcodeProjTests/Objects/Files/PBXFileSystemSynchronizedBuildFileExceptionSetTests.swift
index 0ef9fda58..7620895fc 100644
--- a/Tests/XcodeProjTests/Objects/Files/PBXFileSystemSynchronizedBuildFileExceptionSetTests.swift
+++ b/Tests/XcodeProjTests/Objects/Files/PBXFileSystemSynchronizedBuildFileExceptionSetTests.swift
@@ -75,4 +75,25 @@ final class PBXFileSystemSynchronizedBuildFileExceptionSetTests: XCTestCase {
XCTAssertNil(plistValue.dictionary?[CommentedString("platformFiltersByRelativePath")])
}
+
+ func test_plistComment_withSynchronizedRootGroup_returnsDescriptiveComment() {
+ let group = PBXFileSystemSynchronizedRootGroup(sourceTree: .group, path: "Sources", exceptions: [subject])
+ XCTAssertEqual(subject.plistComment, "Exceptions for \"Sources\" folder in \"Test\" target")
+ withExtendedLifetime(group) {}
+ }
+
+ func test_plistComment_exceptionsAssignedViaSetter_returnsDescriptiveComment() {
+ let group = PBXFileSystemSynchronizedRootGroup(sourceTree: .group, path: "Sources")
+ group.exceptions = [subject]
+ XCTAssertEqual(subject.plistComment, "Exceptions for \"Sources\" folder in \"Test\" target")
+ withExtendedLifetime(group) {}
+ }
+
+ func test_plistKeyAndValue_keyComment_matchesPlistComment() throws {
+ let proj = PBXProj()
+ let group = PBXFileSystemSynchronizedRootGroup(sourceTree: .group, path: "Sources", exceptions: [subject])
+ let (key, _) = try subject.plistKeyAndValue(proj: proj, reference: "ref")
+ XCTAssertEqual(key.comment, subject.plistComment)
+ withExtendedLifetime(group) {}
+ }
}
diff --git a/Tests/XcodeProjTests/Objects/Files/PBXFileSystemSynchronizedRootGroupTests.swift b/Tests/XcodeProjTests/Objects/Files/PBXFileSystemSynchronizedRootGroupTests.swift
index 374156104..aae5a178e 100644
--- a/Tests/XcodeProjTests/Objects/Files/PBXFileSystemSynchronizedRootGroupTests.swift
+++ b/Tests/XcodeProjTests/Objects/Files/PBXFileSystemSynchronizedRootGroupTests.swift
@@ -48,4 +48,46 @@ final class PBXFileSystemSynchronizedRootGroupTests: XCTestCase {
explicitFolders: [])
XCTAssertEqual(subject, another)
}
+
+ // MARK: - plistKeyAndValue
+
+ func test_plistKeyAndValue_explicitFileTypes_serializedOnlyWhenNonEmpty() throws {
+ let (_, nonEmpty) = try subject.plistKeyAndValue(proj: PBXProj(), reference: "ref")
+ XCTAssertNotNil(nonEmpty.dictionary?[CommentedString("explicitFileTypes")])
+
+ subject.explicitFileTypes = [:]
+ let (_, empty) = try subject.plistKeyAndValue(proj: PBXProj(), reference: "ref")
+ XCTAssertNil(empty.dictionary?[CommentedString("explicitFileTypes")])
+ }
+
+ func test_plistKeyAndValue_explicitFolders_serializedOnlyWhenNonEmpty() throws {
+ let (_, empty) = try subject.plistKeyAndValue(proj: PBXProj(), reference: "ref")
+ XCTAssertNil(empty.dictionary?[CommentedString("explicitFolders")])
+
+ subject.explicitFolders = ["SubFolder"]
+ let (_, nonEmpty) = try subject.plistKeyAndValue(proj: PBXProj(), reference: "ref")
+ XCTAssertNotNil(nonEmpty.dictionary?[CommentedString("explicitFolders")])
+ }
+
+ func test_plistKeyAndValue_name_serializedOnlyWhenDifferentFromPath() throws {
+ let (_, same) = try subject.plistKeyAndValue(proj: PBXProj(), reference: "ref")
+ XCTAssertNil(same.dictionary?[CommentedString("name")])
+
+ subject.name = "Display Name"
+ let (_, different) = try subject.plistKeyAndValue(proj: PBXProj(), reference: "ref")
+ XCTAssertEqual(different.dictionary?[CommentedString("name")], .string(CommentedString("Display Name")))
+ }
+
+ func test_plistKeyAndValue_exceptionReference_usesDescriptiveComment() throws {
+ let (_, value) = try subject.plistKeyAndValue(proj: PBXProj(), reference: "ref")
+ let exceptionsArray = try XCTUnwrap(value.dictionary?[CommentedString("exceptions")]?.array)
+ let entry = try XCTUnwrap(exceptionsArray.first?.string)
+ XCTAssertEqual(entry.comment, "Exceptions for \"synchronized\" folder in \"Test\" target")
+ }
+
+ // MARK: - assignParentToChildren
+
+ func test_assignParentToChildren_wiresSynchronizedRootGroup() {
+ XCTAssertIdentical(exception.synchronizedRootGroup, subject)
+ }
}
diff --git a/Tests/XcodeProjTests/Objects/Project/PBXProjEncoderTests.swift b/Tests/XcodeProjTests/Objects/Project/PBXProjEncoderTests.swift
index af5233ce0..f2a4980a9 100644
--- a/Tests/XcodeProjTests/Objects/Project/PBXProjEncoderTests.swift
+++ b/Tests/XcodeProjTests/Objects/Project/PBXProjEncoderTests.swift
@@ -294,7 +294,15 @@
let lines = lines(fromFile: encodeProject(settings: settings))
let beginGroup = lines.findLine("/* Begin PBXFileSystemSynchronizedRootGroup section */")
- var line = lines.validate(line: "6CF05B9D2C53F64800EF267F /* SynchronizedRootGroups */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (6CF05BA32C53F97F00EF267F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, F841A9D12D63B00A00059ED6 /* PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = SynchronizedRootGroups; sourceTree = \"\"; };", after: beginGroup)
+ var line = lines.validate(line: "6CF05B9D2C53F64800EF267F /* SynchronizedRootGroups */ = {", after: beginGroup)
+ line = lines.validate(line: "isa = PBXFileSystemSynchronizedRootGroup;", after: line)
+ line = lines.validate(line: "exceptions = (", after: line)
+ line = lines.validate(line: "6CF05BA32C53F97F00EF267F /* Exceptions for \"SynchronizedRootGroups\" folder in \"SynchronizedRootGroups\" target */,", after: line)
+ line = lines.validate(line: "F841A9D12D63B00A00059ED6 /* Exceptions for \"SynchronizedRootGroups\" folder in \"Copy Files\" phase from \"SynchronizedRootGroups\" target */,", after: line)
+ line = lines.validate(line: ");", after: line)
+ line = lines.validate(line: "path = SynchronizedRootGroups;", after: line)
+ line = lines.validate(line: "sourceTree = \"\";", after: line)
+ line = lines.validate(line: "};", after: line)
line = lines.validate(line: "/* End PBXFileSystemSynchronizedRootGroup section */", after: line)
}
@@ -307,7 +315,7 @@
let lines = lines(fromFile: encodeProject(settings: settings))
let beginGroup = lines.findLine("/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */")
- var line = lines.validate(line: "6CF05BA32C53F97F00EF267F /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {", after: beginGroup)
+ var line = lines.validate(line: "6CF05BA32C53F97F00EF267F /* Exceptions for \"SynchronizedRootGroups\" folder in \"SynchronizedRootGroups\" target */ = {", after: beginGroup)
line = lines.validate(line: "isa = PBXFileSystemSynchronizedBuildFileExceptionSet;", after: line)
line = lines.validate(line: "membershipExceptions = (", after: line)
line = lines.validate(line: "Exception/Exception.swift,", after: line)
@@ -326,7 +334,7 @@
let lines = lines(fromFile: encodeProject(settings: settings))
let beginGroup = lines.findLine("/* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */")
- var line = lines.validate(line: "F841A9D12D63B00A00059ED6 /* PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet */ = {", after: beginGroup)
+ var line = lines.validate(line: "F841A9D12D63B00A00059ED6 /* Exceptions for \"SynchronizedRootGroups\" folder in \"Copy Files\" phase from \"SynchronizedRootGroups\" target */ = {", after: beginGroup)
line = lines.validate(line: "isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;", after: line)
line = lines.validate(line: "attributesByRelativePath = {", after: line)
line = lines.validate(line: "XPCService.xpc = (", after: line)
diff --git a/Tests/XcodeProjTests/Scheme/XCSchemeTests.swift b/Tests/XcodeProjTests/Scheme/XCSchemeTests.swift
index 160d1f78c..2deb7d2cd 100644
--- a/Tests/XcodeProjTests/Scheme/XCSchemeTests.swift
+++ b/Tests/XcodeProjTests/Scheme/XCSchemeTests.swift
@@ -491,7 +491,7 @@ final class XCSchemeIntegrationTests: XCTestCase {
XCTAssertEqual(scheme.testAction?.testables.first?.skipped, false)
XCTAssertEqual(scheme.testAction?.testables.first?.parallelization, .swiftTestingOnly)
XCTAssertEqual(scheme.testAction?.testables.first?.randomExecutionOrdering, false)
- XCTAssertEqual(scheme.testAction?.testables.first?.useTestSelectionWhitelist, false)
+ XCTAssertNil(scheme.testAction?.testables.first?.useTestSelectionWhitelist)
XCTAssertEqual(scheme.testAction?.testables.first?.buildableReference.buildableIdentifier, "primary")
XCTAssertEqual(scheme.testAction?.testables.first?.buildableReference.blueprintIdentifier, "23766C251EAA3484007A9026")
XCTAssertEqual(scheme.testAction?.testables.first?.buildableReference.buildableName, "iOSTests.xctest")