From a904543801a0ab21b73ce762ffbb3382bfe67340 Mon Sep 17 00:00:00 2001 From: Yonas Kolb Date: Tue, 3 Mar 2026 22:43:05 +1100 Subject: [PATCH] update to xcodeproj 9.10.1 (#1597) --- Package.resolved | 4 +- Package.swift | 4 +- Sources/ProjectSpec/Linkage.swift | 2 +- Sources/ProjectSpec/Settings.swift | 66 ++++-- Sources/XcodeGenKit/PBXProjGenerator.swift | 106 ++++----- Sources/XcodeGenKit/SettingsBuilder.swift | 33 ++- Sources/XcodeGenKit/SourceGenerator.swift | 10 +- .../Project.xcodeproj/project.pbxproj | 2 + .../SPM/SPM.xcodeproj/project.pbxproj | 2 + .../AnotherProject.xcodeproj/project.pbxproj | 2 + .../TestProject.xcodeproj/project.pbxproj | 2 + Tests/ProjectSpecTests/ProjectSpecTests.swift | 2 +- Tests/ProjectSpecTests/SpecLoadingTests.swift | 28 +-- .../PBXProjGeneratorTests.swift | 6 +- .../ProjectGeneratorTests.swift | 212 +++++++++--------- .../SourceGeneratorTests.swift | 28 +-- 16 files changed, 268 insertions(+), 241 deletions(-) diff --git a/Package.resolved b/Package.resolved index c4dd4b06..b0833fcb 100644 --- a/Package.resolved +++ b/Package.resolved @@ -77,8 +77,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/tuist/XcodeProj.git", "state" : { - "revision" : "b1caa062d4aaab3e3d2bed5fe0ac5f8ce9bf84f4", - "version" : "8.27.7" + "revision" : "01bb77000bc8c23a09ea2058f4954612f03cb705", + "version" : "9.10.1" } }, { diff --git a/Package.swift b/Package.swift index eb1cad2c..cded9e42 100644 --- a/Package.swift +++ b/Package.swift @@ -4,7 +4,7 @@ import PackageDescription let package = Package( name: "XcodeGen", - platforms: [.macOS(.v10_13)], + platforms: [.macOS(.v11)], products: [ .executable(name: "xcodegen", targets: ["XcodeGen"]), .library(name: "XcodeGenKit", targets: ["XcodeGenKit"]), @@ -16,7 +16,7 @@ let package = Package( .package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.2.0"), .package(url: "https://github.com/kylef/Spectre.git", from: "0.9.2"), .package(url: "https://github.com/onevcat/Rainbow.git", from: "4.0.0"), - .package(url: "https://github.com/tuist/XcodeProj.git", exact: "8.27.7"), + .package(url: "https://github.com/tuist/XcodeProj.git", exact: "9.10.1"), .package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.3"), .package(url: "https://github.com/mxcl/Version", from: "2.0.0"), .package(url: "https://github.com/freddi-kit/ArtifactBundleGen", exact: "0.0.8") diff --git a/Sources/ProjectSpec/Linkage.swift b/Sources/ProjectSpec/Linkage.swift index 250f8207..e42cac5c 100644 --- a/Sources/ProjectSpec/Linkage.swift +++ b/Sources/ProjectSpec/Linkage.swift @@ -56,6 +56,6 @@ extension Target { private extension BuildSettings { var machOType: String? { - self["MACH_O_TYPE"] as? String + self["MACH_O_TYPE"]?.stringValue } } diff --git a/Sources/ProjectSpec/Settings.swift b/Sources/ProjectSpec/Settings.swift index b3b366a8..f0a5344a 100644 --- a/Sources/ProjectSpec/Settings.swift +++ b/Sources/ProjectSpec/Settings.swift @@ -15,23 +15,17 @@ public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertibl self.groups = groups } - public init(dictionary: [String: Any]) { - buildSettings = dictionary - configSettings = [:] - groups = [] - } - - public static let empty: Settings = Settings(dictionary: [:]) + public static let empty: Settings = Settings(buildSettings: [:]) public init(jsonDictionary: JSONDictionary) throws { if jsonDictionary["configs"] != nil || jsonDictionary["groups"] != nil || jsonDictionary["base"] != nil { groups = jsonDictionary.json(atKeyPath: "groups") ?? jsonDictionary.json(atKeyPath: "presets") ?? [] let buildSettingsDictionary: JSONDictionary = jsonDictionary.json(atKeyPath: "base") ?? [:] - buildSettings = buildSettingsDictionary + buildSettings = buildSettingsDictionary.mapValues { BuildSetting(any: $0) } self.configSettings = try Self.extractValidConfigs(from: jsonDictionary) } else { - buildSettings = jsonDictionary + buildSettings = jsonDictionary.mapValues { BuildSetting(any: $0) } configSettings = [:] groups = [] } @@ -58,7 +52,7 @@ public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertibl } public static func == (lhs: Settings, rhs: Settings) -> Bool { - NSDictionary(dictionary: lhs.buildSettings).isEqual(to: rhs.buildSettings) && + lhs.buildSettings == rhs.buildSettings && lhs.configSettings == rhs.configSettings && lhs.groups == rhs.groups } @@ -96,14 +90,14 @@ public struct Settings: Equatable, JSONObjectConvertible, CustomStringConvertibl extension Settings: ExpressibleByDictionaryLiteral { - public init(dictionaryLiteral elements: (String, Any)...) { - var dictionary: [String: Any] = [:] - elements.forEach { dictionary[$0.0] = $0.1 } - self.init(dictionary: dictionary) + public init(dictionaryLiteral elements: (String, BuildSetting)...) { + var buildSettings: BuildSettings = [:] + elements.forEach { buildSettings[$0.0] = $0.1 } + self.init(buildSettings: buildSettings) } } -extension Dictionary where Key == String, Value: Any { +extension Dictionary where Key == String { public func merged(_ dictionary: [Key: Value]) -> [Key: Value] { var mergedDictionary = self @@ -116,10 +110,6 @@ extension Dictionary where Key == String, Value: Any { self[key] = value } } - - public func equals(_ dictionary: BuildSettings) -> Bool { - NSDictionary(dictionary: self).isEqual(to: dictionary) - } } public func += (lhs: inout BuildSettings, rhs: BuildSettings?) { @@ -127,15 +117,49 @@ public func += (lhs: inout BuildSettings, rhs: BuildSettings?) { lhs.merge(rhs) } +extension BuildSetting { + + public init(any value: Any) { + if let array = value as? [String] { + self = .array(array) + } else if let bool = value as? Bool { + self = .init(booleanLiteral: bool) + } else { + self = .string("\(value)") + } + } + + public func toAny() -> Any { + switch self { + case let .string(value): return value + case let .array(value): return value + } + } +} + +extension ProjectAttribute { + + public init(any value: Any) { + if let array = value as? [String] { + self = .array(array) + } else if let object = value as? PBXObject { + self = .targetReference(object) + } else { + self = .string("\(value)") + } + } +} + extension Settings: JSONEncodable { public func toJSONValue() -> Any { + let anySettings = buildSettings.mapValues { $0.toAny() } if groups.count > 0 || configSettings.count > 0 { return [ - "base": buildSettings, + "base": anySettings, "groups": groups, "configs": configSettings.mapValues { $0.toJSONValue() }, ] as [String : Any] } - return buildSettings + return anySettings } } diff --git a/Sources/XcodeGenKit/PBXProjGenerator.swift b/Sources/XcodeGenKit/PBXProjGenerator.swift index 8dcad5af..7c7f64f5 100644 --- a/Sources/XcodeGenKit/PBXProjGenerator.swift +++ b/Sources/XcodeGenKit/PBXProjGenerator.swift @@ -294,21 +294,21 @@ public class PBXProjGenerator { }.flatMap { $0 } ).sorted() - let defaultAttributes: [String: Any] = [ + var projectAttributes: [String: ProjectAttribute] = [ "BuildIndependentTargetsInParallel": "YES" ] - var projectAttributes: [String: Any] = defaultAttributes.merged(project.attributes) - - // Set default LastUpgradeCheck if user did not specify - let lastUpgradeKey = "LastUpgradeCheck" - if !projectAttributes.contains(where: { (key, value) -> Bool in - key == lastUpgradeKey && value is String - }) { - projectAttributes[lastUpgradeKey] = project.xcodeVersion + for (key, value) in project.attributes { + projectAttributes[key] = ProjectAttribute(any: value) } - + + // Set default LastUpgradeCheck if user did not specify a valid string value + let lastUpgradeKey = "LastUpgradeCheck" + if !(project.attributes[lastUpgradeKey] is String) { + projectAttributes[lastUpgradeKey] = .string(project.xcodeVersion) + } + if !assetTags.isEmpty { - projectAttributes["knownAssetTags"] = assetTags + projectAttributes["knownAssetTags"] = .array(assetTags) } var knownRegions = Set(sourceGenerator.knownRegions) @@ -483,9 +483,9 @@ public class PBXProjGenerator { let productType: PBXProductType = targetObject.productType ?? .none let buildSettings = defaultConfiguration.buildSettings let settings = Settings(buildSettings: buildSettings, configSettings: [:], groups: []) - let deploymentTargetString = buildSettings[platform.deploymentTargetSetting] as? String + let deploymentTargetString = buildSettings[platform.deploymentTargetSetting]?.stringValue let deploymentTarget = deploymentTargetString == nil ? nil : try Version.parse(deploymentTargetString!) - let requiresObjCLinking = (buildSettings["OTHER_LDFLAGS"] as? String)?.contains("-ObjC") ?? (productType == .staticLibrary) + let requiresObjCLinking = buildSettings["OTHER_LDFLAGS"]?.stringValue?.contains("-ObjC") ?? (productType == .staticLibrary) let dependencyTarget = Target( name: targetObject.name, type: productType, @@ -534,9 +534,9 @@ public class PBXProjGenerator { return addObject(copyFilesBuildPhase) } - func generateTargetAttributes() -> [PBXTarget: [String: Any]] { + func generateTargetAttributes() -> [PBXTarget: [String: ProjectAttribute]] { - var targetAttributes: [PBXTarget: [String: Any]] = [:] + var targetAttributes: [PBXTarget: [String: ProjectAttribute]] = [:] let testTargets = pbxProj.nativeTargets.filter { $0.productType == .uiTestBundle || $0.productType == .unitTestBundle } for testTarget in testTargets { @@ -546,24 +546,24 @@ public class PBXProjGenerator { guard let buildConfigurations = target.buildConfigurationList?.buildConfigurations else { return nil } return buildConfigurations - .compactMap { $0.buildSettings["TEST_TARGET_NAME"] as? String } + .compactMap { $0.buildSettings["TEST_TARGET_NAME"]?.stringValue } .first } guard let name = testTargetName(testTarget) else { continue } guard let target = self.pbxProj.targets(named: name).first else { continue } - targetAttributes[testTarget, default: [:]].merge(["TestTargetID": target]) + targetAttributes[testTarget, default: [:]].merge(["TestTargetID": .targetReference(target)]) } func generateTargetAttributes(_ target: ProjectTarget, pbxTarget: PBXTarget) { if !target.attributes.isEmpty { - targetAttributes[pbxTarget, default: [:]].merge(target.attributes) + targetAttributes[pbxTarget, default: [:]].merge(target.attributes.mapValues { ProjectAttribute(any: $0) }) } func getSingleBuildSetting(_ setting: String) -> String? { let settings = project.configs.compactMap { - project.getCombinedBuildSetting(setting, target: target, config: $0) as? String + project.getCombinedBuildSetting(setting, target: target, config: $0)?.stringValue } guard settings.count == project.configs.count, let firstSetting = settings.first, @@ -575,7 +575,7 @@ public class PBXProjGenerator { func setTargetAttribute(attribute: String, buildSetting: String) { if let setting = getSingleBuildSetting(buildSetting) { - targetAttributes[pbxTarget, default: [:]].merge([attribute: setting]) + targetAttributes[pbxTarget, default: [:]].merge([attribute: .string(setting)]) } } @@ -706,6 +706,7 @@ public class PBXProjGenerator { var systemExtensions: [PBXBuildFile] = [] var appClips: [PBXBuildFile] = [] var carthageFrameworksToEmbed: [String] = [] + var buildFileCopyPhases: [PBXBuildFile: BuildPhaseSpec.CopyFilesSettings] = [:] let targetDependencies = (target.transitivelyLinkDependencies ?? project.options.transitivelyLinkDependencies) ? getAllDependenciesPlusTransitiveNeedingEmbedding(target: target) : target.dependencies @@ -714,7 +715,7 @@ public class PBXProjGenerator { (target.type.isApp || target.type == .watch2Extension)) let directlyEmbedCarthage = target.directlyEmbedCarthageDependencies ?? targetSupportsDirectEmbed - func getEmbedSettings(dependency: Dependency, codeSign: Bool) -> [String: Any] { + func getEmbedSettings(dependency: Dependency, codeSign: Bool) -> [String: BuildFileSetting] { var embedAttributes: [String] = [] if codeSign { embedAttributes.append("CodeSignOnCopy") @@ -722,19 +723,15 @@ public class PBXProjGenerator { if dependency.removeHeaders { embedAttributes.append("RemoveHeadersOnCopy") } - var retval: [String:Any] = ["ATTRIBUTES": embedAttributes] - if let copyPhase = dependency.copyPhase { - retval["COPY_PHASE"] = copyPhase - } - return retval + return ["ATTRIBUTES": .array(embedAttributes)] } - func getDependencyFrameworkSettings(dependency: Dependency) -> [String: Any]? { + func getDependencyFrameworkSettings(dependency: Dependency) -> [String: BuildFileSetting]? { var linkingAttributes: [String] = [] if dependency.weakLink { linkingAttributes.append("Weak") } - return !linkingAttributes.isEmpty ? ["ATTRIBUTES": linkingAttributes] : nil + return !linkingAttributes.isEmpty ? ["ATTRIBUTES": .array(linkingAttributes)] : nil } func processTargetDependency(_ dependency: Dependency, dependencyTarget: Target, embedFileReference: PBXFileElement?, platform: String?, platforms: [String]?) { @@ -766,8 +763,9 @@ public class PBXProjGenerator { pbxBuildFile.platformFilters = platforms let embedFile = addObject(pbxBuildFile) - if dependency.copyPhase != nil { + if let copyPhase = dependency.copyPhase { // custom copy takes precedence + buildFileCopyPhases[embedFile] = copyPhase customCopyDependenciesReferences.append(embedFile) } else if dependencyTarget.type.isExtension { if dependencyTarget.type == .extensionKitExtension { @@ -858,7 +856,8 @@ public class PBXProjGenerator { pbxBuildFile.platformFilters = platforms let embedFile = addObject(pbxBuildFile) - if dependency.copyPhase != nil { + if let copyPhase = dependency.copyPhase { + buildFileCopyPhases[embedFile] = copyPhase customCopyDependenciesReferences.append(embedFile) } else { copyFrameworksReferences.append(embedFile) @@ -916,7 +915,8 @@ public class PBXProjGenerator { pbxBuildFile.platformFilters = platforms let embedFile = addObject(pbxBuildFile) - if dependency.copyPhase != nil { + if let copyPhase = dependency.copyPhase { + buildFileCopyPhases[embedFile] = copyPhase customCopyDependenciesReferences.append(embedFile) } else { copyFrameworksReferences.append(embedFile) @@ -989,7 +989,8 @@ public class PBXProjGenerator { pbxBuildFile.platformFilters = platforms let embedFile = addObject(pbxBuildFile) - if dependency.copyPhase != nil { + if let copyPhase = dependency.copyPhase { + buildFileCopyPhases[embedFile] = copyPhase customCopyDependenciesReferences.append(embedFile) } else { copyFrameworksReferences.append(embedFile) @@ -1052,7 +1053,8 @@ public class PBXProjGenerator { let embedFile = addObject( PBXBuildFile(file: fileReference, settings: getEmbedSettings(dependency: dependency, codeSign: dependency.codeSign ?? true)) ) - if dependency.copyPhase != nil { + if let copyPhase = dependency.copyPhase { + buildFileCopyPhases[embedFile] = copyPhase customCopyDependenciesReferences.append(embedFile) } else { copyFrameworksReferences.append(embedFile) @@ -1107,11 +1109,11 @@ public class PBXProjGenerator { } func splitCopyDepsByDestination(_ references: [PBXBuildFile]) -> [BuildPhaseSpec.CopyFilesSettings : [PBXBuildFile]] { - + var retval = [BuildPhaseSpec.CopyFilesSettings : [PBXBuildFile]]() for reference in references { - - guard let key = reference.settings?["COPY_PHASE"] as? BuildPhaseSpec.CopyFilesSettings else { continue } + + guard let key = buildFileCopyPhases[reference] else { continue } var filesWithSameDestination = retval[key] ?? [PBXBuildFile]() filesWithSameDestination.append(reference) retval[key] = filesWithSameDestination @@ -1162,7 +1164,7 @@ public class PBXProjGenerator { addResourcesBuildPhase() } - let swiftObjCInterfaceHeader = project.getCombinedBuildSetting("SWIFT_OBJC_INTERFACE_HEADER_NAME", target: target, config: project.configs[0]) as? String + let swiftObjCInterfaceHeader = project.getCombinedBuildSetting("SWIFT_OBJC_INTERFACE_HEADER_NAME", target: target, config: project.configs[0])?.stringValue let swiftInstallObjCHeader = project.getBoolBuildSetting("SWIFT_INSTALL_OBJC_HEADER", target: target, config: project.configs[0]) ?? true // Xcode default if target.type == .staticLibrary @@ -1327,12 +1329,12 @@ public class PBXProjGenerator { // Set CODE_SIGN_ENTITLEMENTS if let entitlements = target.entitlements { - buildSettings["CODE_SIGN_ENTITLEMENTS"] = entitlements.path + buildSettings["CODE_SIGN_ENTITLEMENTS"] = .string(entitlements.path) } // Set INFOPLIST_FILE based on the resolved value if let infoPlistFile = infoPlistFiles[config] { - buildSettings["INFOPLIST_FILE"] = infoPlistFile + buildSettings["INFOPLIST_FILE"] = .string(infoPlistFile) } // automatically calculate bundle id @@ -1343,7 +1345,7 @@ public class PBXProjGenerator { .replacingOccurrences(of: "_", with: "-") .components(separatedBy: characterSet) .joined(separator: "") - buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] = bundleIdPrefix + "." + escapedTargetName + buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] = .string(bundleIdPrefix + "." + escapedTargetName) } // automatically set test target name @@ -1353,7 +1355,7 @@ public class PBXProjGenerator { if dependency.type == .target, let dependencyTarget = project.getTarget(dependency.reference), dependencyTarget.type.isApp { - buildSettings["TEST_TARGET_NAME"] = dependencyTarget.name + buildSettings["TEST_TARGET_NAME"] = .string(dependencyTarget.name) break } } @@ -1380,13 +1382,13 @@ public class PBXProjGenerator { if anyDependencyRequiresObjCLinking { let otherLinkingFlags = "OTHER_LDFLAGS" let objCLinking = "-ObjC" - if var array = buildSettings[otherLinkingFlags] as? [String] { + if var array = buildSettings[otherLinkingFlags]?.arrayValue { array.append(objCLinking) - buildSettings[otherLinkingFlags] = array - } else if let string = buildSettings[otherLinkingFlags] as? String { - buildSettings[otherLinkingFlags] = [string, objCLinking] + buildSettings[otherLinkingFlags] = .array(array) + } else if let string = buildSettings[otherLinkingFlags]?.stringValue { + buildSettings[otherLinkingFlags] = .array([string, objCLinking]) } else { - buildSettings[otherLinkingFlags] = ["$(inherited)", objCLinking] + buildSettings[otherLinkingFlags] = .array(["$(inherited)", objCLinking]) } } @@ -1410,13 +1412,13 @@ public class PBXProjGenerator { // set framework search paths if !configFrameworkBuildPaths.isEmpty { let frameworkSearchPaths = "FRAMEWORK_SEARCH_PATHS" - if var array = buildSettings[frameworkSearchPaths] as? [String] { + if var array = buildSettings[frameworkSearchPaths]?.arrayValue { array.append(contentsOf: configFrameworkBuildPaths) - buildSettings[frameworkSearchPaths] = array - } else if let string = buildSettings[frameworkSearchPaths] as? String { - buildSettings[frameworkSearchPaths] = [string] + configFrameworkBuildPaths + buildSettings[frameworkSearchPaths] = .array(array) + } else if let string = buildSettings[frameworkSearchPaths]?.stringValue { + buildSettings[frameworkSearchPaths] = .array([string] + configFrameworkBuildPaths) } else { - buildSettings[frameworkSearchPaths] = ["$(inherited)"] + configFrameworkBuildPaths + buildSettings[frameworkSearchPaths] = .array(["$(inherited)"] + configFrameworkBuildPaths) } } @@ -1506,7 +1508,7 @@ public class PBXProjGenerator { let values: [(Config, String)] = project.configs.compactMap { config in // First, if the plist path was defined by `INFOPLIST_FILE`, use that let buildSettings = project.getTargetBuildSettings(target: target, config: config) - if let value = buildSettings["INFOPLIST_FILE"] as? String { + if let value = buildSettings["INFOPLIST_FILE"]?.stringValue { return (config, value) } diff --git a/Sources/XcodeGenKit/SettingsBuilder.swift b/Sources/XcodeGenKit/SettingsBuilder.swift index b65079b9..53a5b867 100644 --- a/Sources/XcodeGenKit/SettingsBuilder.swift +++ b/Sources/XcodeGenKit/SettingsBuilder.swift @@ -14,7 +14,7 @@ extension Project { if let firstPlatform = targets.first?.platform, targets.allSatisfy({ $0.platform == firstPlatform }) { - buildSettings["SDKROOT"] = firstPlatform.sdkRoot + buildSettings["SDKROOT"] = .string(firstPlatform.sdkRoot) } if let type = config.type, options.settingPresets.applyProject { @@ -25,7 +25,7 @@ extension Project { // apply custom platform version for platform in Platform.allCases { if let version = options.deploymentTarget.version(for: platform) { - buildSettings[platform.deploymentTargetSetting] = version.deploymentTarget + buildSettings[platform.deploymentTargetSetting] = .string(version.deploymentTarget) } } @@ -63,7 +63,7 @@ extension Project { if target.platform == .auto { // this fix is necessary because the platform preset overrides the original value - buildSettings["SDKROOT"] = Platform.auto.rawValue + buildSettings["SDKROOT"] = .string(Platform.auto.rawValue) } } @@ -75,16 +75,16 @@ extension Project { let supportedPlatformBuildSettings = SettingsPresetFile.supportedDestination(supportedDestination).getBuildSettings() buildSettings += supportedPlatformBuildSettings - if let value = supportedPlatformBuildSettings?["SUPPORTED_PLATFORMS"] as? String { + if let value = supportedPlatformBuildSettings?["SUPPORTED_PLATFORMS"]?.stringValue { supportedPlatforms += value.components(separatedBy: " ") } - if let value = supportedPlatformBuildSettings?["TARGETED_DEVICE_FAMILY"] as? String { + if let value = supportedPlatformBuildSettings?["TARGETED_DEVICE_FAMILY"]?.stringValue { targetedDeviceFamily += value.components(separatedBy: ",") } } - buildSettings["SUPPORTED_PLATFORMS"] = supportedPlatforms.joined(separator: " ") - buildSettings["TARGETED_DEVICE_FAMILY"] = targetedDeviceFamily.joined(separator: ",") + buildSettings["SUPPORTED_PLATFORMS"] = .string(supportedPlatforms.joined(separator: " ")) + buildSettings["TARGETED_DEVICE_FAMILY"] = .string(targetedDeviceFamily.joined(separator: ",")) } // apply custom platform version @@ -92,11 +92,11 @@ extension Project { if !specSupportedDestinations.isEmpty { for supportedDestination in specSupportedDestinations { if let platform = Platform(rawValue: supportedDestination.rawValue) { - buildSettings[platform.deploymentTargetSetting] = version.deploymentTarget + buildSettings[platform.deploymentTargetSetting] = .string(version.deploymentTarget) } } } else { - buildSettings[target.platform.deploymentTargetSetting] = version.deploymentTarget + buildSettings[target.platform.deploymentTargetSetting] = .string(version.deploymentTarget) } } @@ -140,7 +140,7 @@ extension Project { } // combines all levels of a target's settings: target, target config, project, project config - public func getCombinedBuildSetting(_ setting: String, target: ProjectTarget, config: Config) -> Any? { + public func getCombinedBuildSetting(_ setting: String, target: ProjectTarget, config: Config) -> BuildSetting? { if let target = target as? Target, let value = getTargetBuildSettings(target: target, config: config)[setting] { return value @@ -160,15 +160,7 @@ extension Project { } public func getBoolBuildSetting(_ setting: String, target: ProjectTarget, config: Config) -> Bool? { - guard let value = getCombinedBuildSetting(setting, target: target, config: config) else { return nil } - - if let boolValue = value as? Bool { - return boolValue - } else if let stringValue = value as? String { - return stringValue == "YES" - } - - return nil + getCombinedBuildSetting(setting, target: target, config: config)?.boolValue } public func targetHasBuildSetting(_ setting: String, target: Target, config: Config) -> Bool { @@ -264,10 +256,11 @@ extension SettingsPresetFile { return nil } - guard let buildSettings = try? loadYamlDictionary(path: settingsPath) else { + guard let dictionary = try? loadYamlDictionary(path: settingsPath) else { print("Error parsing \"\(name)\" settings") return nil } + let buildSettings: BuildSettings = dictionary.mapValues { BuildSetting(any: $0) } settingPresetSettings[path] = .cached(buildSettings) return buildSettings } diff --git a/Sources/XcodeGenKit/SourceGenerator.swift b/Sources/XcodeGenKit/SourceGenerator.swift index e6c9948f..35c914fc 100644 --- a/Sources/XcodeGenKit/SourceGenerator.swift +++ b/Sources/XcodeGenKit/SourceGenerator.swift @@ -121,7 +121,7 @@ class SourceGenerator { func generateSourceFile(targetType: PBXProductType, targetSource: TargetSource, path: Path, fileReference: PBXFileElement? = nil, buildPhases: [Path: BuildPhaseSpec]) -> SourceFile { let fileReference = fileReference ?? fileReferencesByPath[path.string.lowercased()]! - var settings: [String: Any] = [:] + var settings: [String: BuildFileSetting] = [:] let fileType = getFileType(path: path) var attributes: [String] = targetSource.attributes + (fileType?.attributes ?? []) var chosenBuildPhase: BuildPhaseSpec? @@ -173,15 +173,15 @@ class SourceGenerator { } if chosenBuildPhase == .sources && !compilerFlags.isEmpty { - settings["COMPILER_FLAGS"] = compilerFlags + settings["COMPILER_FLAGS"] = .string(compilerFlags) } if !attributes.isEmpty { - settings["ATTRIBUTES"] = attributes + settings["ATTRIBUTES"] = .array(attributes) } - + if chosenBuildPhase == .resources && !assetTags.isEmpty { - settings["ASSET_TAGS"] = assetTags + settings["ASSET_TAGS"] = .array(assetTags) } let platforms = makeDestinationFilters(for: path, with: targetSource.destinationFilters, or: targetSource.inferDestinationFiltersByPath) diff --git a/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.pbxproj index 5b62b813..8b2ad988 100644 --- a/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/CarthageProject/Project.xcodeproj/project.pbxproj @@ -322,6 +322,8 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1430; + TargetAttributes = { + }; }; buildConfigurationList = D91E14E36EC0B415578456F2 /* Build configuration list for PBXProject "Project" */; compatibilityVersion = "Xcode 14.0"; diff --git a/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj b/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj index eef5a9d7..f9320a9d 100644 --- a/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/SPM/SPM.xcodeproj/project.pbxproj @@ -242,6 +242,8 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1430; + TargetAttributes = { + }; }; buildConfigurationList = 425866ADA259DB93FC4AF1E3 /* Build configuration list for PBXProject "SPM" */; compatibilityVersion = "Xcode 14.0"; diff --git a/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj index 50593a11..d86f4027 100644 --- a/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj @@ -120,6 +120,8 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1430; + TargetAttributes = { + }; }; buildConfigurationList = 3DFC1105373EDB6483D4BC5D /* Build configuration list for PBXProject "AnotherProject" */; compatibilityVersion = "Xcode 14.0"; diff --git a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.pbxproj b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.pbxproj index baed78ca..5c0229f7 100644 --- a/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/scheme_test/TestProject.xcodeproj/project.pbxproj @@ -72,6 +72,8 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1430; + TargetAttributes = { + }; }; buildConfigurationList = E903F6E8184E2A86CEC31778 /* Build configuration list for PBXProject "TestProject" */; compatibilityVersion = "Xcode 14.0"; diff --git a/Tests/ProjectSpecTests/ProjectSpecTests.swift b/Tests/ProjectSpecTests/ProjectSpecTests.swift index 3ae878ac..7d7d3c0b 100644 --- a/Tests/ProjectSpecTests/ProjectSpecTests.swift +++ b/Tests/ProjectSpecTests/ProjectSpecTests.swift @@ -442,7 +442,7 @@ class ProjectSpecTests: XCTestCase { $0.it("validates config settings format") { var project = baseProject project.configs = Config.defaultConfigs - project.settings.buildSettings = ["Debug": ["SETTING": "VALUE"], "Release": ["SETTING": "VALUE"]] + project.settings.buildSettings = ["Debug": "VALUE", "Release": "VALUE"] try expectValidationError(project, .invalidPerConfigSettings) } diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index c0bbb281..d3db0d9c 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -33,9 +33,9 @@ class SpecLoadingTests: XCTestCase { try expect(project.name) == "NewName" try expect(project.settingGroups) == [ - "test": Settings(dictionary: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}"]), - "new": Settings(dictionary: ["MY_SETTING": "VALUE"]), - "toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]), + "test": Settings(buildSettings: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}"]), + "new": Settings(buildSettings: ["MY_SETTING": "VALUE"]), + "toReplace": Settings(buildSettings: ["MY_SETTING2": "VALUE2"]), ] try expect(project.targets) == [ Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(products: []), reference: "Yams")]), @@ -49,9 +49,9 @@ class SpecLoadingTests: XCTestCase { try expect(project.name) == "NewName" try expect(project.settingGroups) == [ - "test": Settings(dictionary: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}", "MY_SETTING5": "ADDITIONAL"]), - "new": Settings(dictionary: ["MY_SETTING": "VALUE"]), - "toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]), + "test": Settings(buildSettings: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}", "MY_SETTING5": "ADDITIONAL"]), + "new": Settings(buildSettings: ["MY_SETTING": "VALUE"]), + "toReplace": Settings(buildSettings: ["MY_SETTING2": "VALUE2"]), ] try expect(project.targets) == [ Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(products: []), reference: "SwiftPM"), Dependency(type: .package(products: []), reference: "Yams")]), @@ -65,9 +65,9 @@ class SpecLoadingTests: XCTestCase { try expect(project.name) == "NewName" try expect(project.settingGroups) == [ - "test": Settings(dictionary: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}"]), - "new": Settings(dictionary: ["MY_SETTING": "VALUE"]), - "toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]), + "test": Settings(buildSettings: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}"]), + "new": Settings(buildSettings: ["MY_SETTING": "VALUE"]), + "toReplace": Settings(buildSettings: ["MY_SETTING2": "VALUE2"]), ] try expect(project.targets) == [ Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(products: []), reference: "Yams")]), @@ -286,8 +286,8 @@ class SpecLoadingTests: XCTestCase { try expect(project.name) == "NewName" try expect(project.settingGroups) == [ - "test": Settings(dictionary: ["MY_SETTING1": "ENV VALUE1", "MY_SETTING2": "VALUE2", "MY_SETTING4": "ENV VALUE4"]), - "toReplace": Settings(dictionary: ["MY_SETTING1": "VALUE1"]), + "test": Settings(buildSettings: ["MY_SETTING1": "ENV VALUE1", "MY_SETTING2": "VALUE2", "MY_SETTING4": "ENV VALUE4"]), + "toReplace": Settings(buildSettings: ["MY_SETTING1": "VALUE1"]), ] try expect(project.targets.last?.sources) == ["SomeTarget", "doesWin", "templateVariable"] } @@ -302,9 +302,9 @@ class SpecLoadingTests: XCTestCase { try expect(project.name) == "NewName" try expect(project.settingGroups) == [ - "test": Settings(dictionary: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}"]), - "new": Settings(dictionary: ["MY_SETTING": "VALUE"]), - "toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]), + "test": Settings(buildSettings: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}"]), + "new": Settings(buildSettings: ["MY_SETTING": "VALUE"]), + "toReplace": Settings(buildSettings: ["MY_SETTING2": "VALUE2"]), ] try expect(project.targets) == [ Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"]), diff --git a/Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift b/Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift index 31873cdc..3af4148d 100644 --- a/Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/PBXProjGeneratorTests.swift @@ -361,7 +361,7 @@ class PBXProjGeneratorTests: XCTestCase { let pbxProj = try projGenerator.generate() for pbxProject in pbxProj.projects { - XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, project.xcodeVersion) + XCTAssertEqual(pbxProject.attributes[lastUpgradeKey]?.stringValue, project.xcodeVersion) } } @@ -375,7 +375,7 @@ class PBXProjGeneratorTests: XCTestCase { let pbxProj = try projGenerator.generate() for pbxProject in pbxProj.projects { - XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, lastUpgradeValue) + XCTAssertEqual(pbxProject.attributes[lastUpgradeKey]?.stringValue, lastUpgradeValue) } } @@ -387,7 +387,7 @@ class PBXProjGeneratorTests: XCTestCase { let pbxProj = try projGenerator.generate() for pbxProject in pbxProj.projects { - XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, project.xcodeVersion) + XCTAssertEqual(pbxProject.attributes[lastUpgradeKey]?.stringValue, project.xcodeVersion) } } diff --git a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift index 7a42dcb9..872dcd60 100644 --- a/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/ProjectGeneratorTests.swift @@ -54,7 +54,7 @@ class ProjectGeneratorTests: XCTestCase { let buildConfig = buildConfigList.buildConfigurations.first else { throw failure("Build Config not found") } - try expect(buildConfig.buildSettings["PRODUCT_BUNDLE_IDENTIFIER"] as? String) == "com.test.MyFramework" + try expect(buildConfig.buildSettings["PRODUCT_BUNDLE_IDENTIFIER"]?.stringValue) == "com.test.MyFramework" } $0.it("clears setting presets") { @@ -188,7 +188,7 @@ class ProjectGeneratorTests: XCTestCase { "SETTING 5": "value 5", "SETTING 6": "value 6", ] - try expect(debugProjectSettings.equals(buildSettings)).beTrue() + try expect(debugProjectSettings == buildSettings).beTrue() var expectedTargetDebugSettings = BuildSettings() expectedTargetDebugSettings += SettingsPresetFile.platform(.iOS).getBuildSettings() @@ -196,7 +196,7 @@ class ProjectGeneratorTests: XCTestCase { expectedTargetDebugSettings += SettingsPresetFile.productPlatform(.application, .iOS).getBuildSettings() expectedTargetDebugSettings += ["SETTING 2": "value 2", "SETTING 3": "value 3", "SETTING": "value"] - try expect(targetDebugSettings.equals(expectedTargetDebugSettings)).beTrue() + try expect(targetDebugSettings == expectedTargetDebugSettings).beTrue() } $0.it("applies partial config settings") { @@ -215,8 +215,8 @@ class ProjectGeneratorTests: XCTestCase { ) var buildSettings = project.getProjectBuildSettings(config: project.configs[1]) - try expect(buildSettings["SETTING1"] as? String) == "VALUE1" - try expect(buildSettings["SETTING2"] as? String) == "VALUE2" + try expect(buildSettings["SETTING1"]?.stringValue) == "VALUE1" + try expect(buildSettings["SETTING2"]?.stringValue) == "VALUE2" // don't apply partial when exact match buildSettings = project.getProjectBuildSettings(config: project.configs[2]) @@ -232,7 +232,7 @@ class ProjectGeneratorTests: XCTestCase { ] ) var buildSettings = project.getProjectBuildSettings(config: project.configs.first!) - try expect(buildSettings["SDKROOT"] as? String) == "iphoneos" + try expect(buildSettings["SDKROOT"]?.stringValue) == "iphoneos" project.targets.append(Target(name: "3", type: .application, platform: .tvOS)) buildSettings = project.getProjectBuildSettings(config: project.configs.first!) @@ -314,10 +314,14 @@ class ProjectGeneratorTests: XCTestCase { let appTarget = try unwrap(pbxProject.targets(named: app.name).first) let uiTestTarget = try unwrap(pbxProject.targets(named: uiTest.name).first) - try expect((targetAttributes[uiTestTarget]?["TestTargetID"] as? PBXNativeTarget)?.name) == app.name - try expect(targetAttributes[uiTestTarget]?["ProvisioningStyle"] as? String) == "Manual" - try expect(targetAttributes[appTarget]?["ProvisioningStyle"] as? String) == "Automatic" - try expect(targetAttributes[appTarget]?["DevelopmentTeam"] as? String) == "123" + if case let .targetReference(object) = targetAttributes[uiTestTarget]?["TestTargetID"] { + try expect((object as? PBXNativeTarget)?.name) == app.name + } else { + throw failure("Expected TestTargetID to be a target reference") + } + try expect(targetAttributes[uiTestTarget]?["ProvisioningStyle"]?.stringValue) == "Manual" + try expect(targetAttributes[appTarget]?["ProvisioningStyle"]?.stringValue) == "Automatic" + try expect(targetAttributes[appTarget]?["DevelopmentTeam"]?.stringValue) == "123" } $0.it("generates platform version") { @@ -328,12 +332,12 @@ class ProjectGeneratorTests: XCTestCase { let projectConfig = try unwrap(pbxProject.projects.first?.buildConfigurationList?.buildConfigurations.first) let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(projectConfig.buildSettings["IPHONEOS_DEPLOYMENT_TARGET"] as? String) == "10.0" - try expect(projectConfig.buildSettings["WATCHOS_DEPLOYMENT_TARGET"] as? String) == "3.0" + try expect(projectConfig.buildSettings["IPHONEOS_DEPLOYMENT_TARGET"]?.stringValue) == "10.0" + try expect(projectConfig.buildSettings["WATCHOS_DEPLOYMENT_TARGET"]?.stringValue) == "3.0" try expect(projectConfig.buildSettings["TVOS_DEPLOYMENT_TARGET"]).beNil() try expect(targetConfig.buildSettings["IPHONEOS_DEPLOYMENT_TARGET"]).beNil() - try expect(targetConfig.buildSettings["WATCHOS_DEPLOYMENT_TARGET"] as? String) == "2.0" + try expect(targetConfig.buildSettings["WATCHOS_DEPLOYMENT_TARGET"]?.stringValue) == "2.0" try expect(targetConfig.buildSettings["TVOS_DEPLOYMENT_TARGET"]).beNil() } @@ -344,16 +348,16 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator appletvos appletvsimulator" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,3" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "iphoneos iphonesimulator appletvos appletvsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "1,2,3" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true - try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] - try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" - try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"]?.stringValue) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"]?.stringValue) == "iPhone Developer" } $0.it("supportedDestinations merges settings - iOS, visionOS") { @@ -363,16 +367,16 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator xros xrsimulator" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,7" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "iphoneos iphonesimulator xros xrsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "1,2,7" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false - try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] - try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" - try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"]?.stringValue) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"]?.stringValue) == "iPhone Developer" } $0.it("supportedDestinations merges settings - iOS, tvOS, macOS") { @@ -382,16 +386,16 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator appletvos appletvsimulator macosx" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,3" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "iphoneos iphonesimulator appletvos appletvsimulator macosx" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "1,2,3" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true - try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] - try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" - try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"]?.stringValue) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"]?.stringValue) == "iPhone Developer" } $0.it("supportedDestinations merges settings - iOS, tvOS, macCatalyst") { @@ -401,16 +405,16 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator appletvos appletvsimulator" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,3" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == true - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "iphoneos iphonesimulator appletvos appletvsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "1,2,3" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == true + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true - try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] - try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" - try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"]?.stringValue) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"]?.stringValue) == "iPhone Developer" } $0.it("supportedDestinations merges settings - iOS, macOS") { @@ -420,16 +424,16 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator macosx" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "iphoneos iphonesimulator macosx" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "1,2" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true - try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] - try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" - try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"]?.stringValue) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"]?.stringValue) == "iPhone Developer" } $0.it("supportedDestinations merges settings - tvOS, macOS") { @@ -439,15 +443,15 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "appletvos appletvsimulator macosx" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "3" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "appletvos appletvsimulator macosx" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "3" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false - try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] - try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "App Icon & Top Shelf Image" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME"] as? String) == "LaunchImage" + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"]?.stringValue) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "App Icon & Top Shelf Image" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME"]?.stringValue) == "LaunchImage" } $0.it("supportedDestinations merges settings - visionOS, macOS") { @@ -457,14 +461,14 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "xros xrsimulator macosx" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "7" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "xros xrsimulator macosx" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "7" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false - try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" + try expect(targetConfig1.buildSettings["SDKROOT"]?.stringValue) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "AppIcon" } $0.it("supportedDestinations merges settings - iOS, macCatalyst") { @@ -474,16 +478,16 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == true - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "iphoneos iphonesimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "1,2" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == true + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true - try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "@executable_path/Frameworks"] - try expect(targetConfig1.buildSettings["SDKROOT"] as? String) == "auto" - try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"] as? String) == "AppIcon" - try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"] as? String) == "iPhone Developer" + try expect(targetConfig1.buildSettings["LD_RUNPATH_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "@executable_path/Frameworks"] + try expect(targetConfig1.buildSettings["SDKROOT"]?.stringValue) == "auto" + try expect(targetConfig1.buildSettings["ASSETCATALOG_COMPILER_APPICON_NAME"]?.stringValue) == "AppIcon" + try expect(targetConfig1.buildSettings["CODE_SIGN_IDENTITY"]?.stringValue) == "iPhone Developer" } $0.it("supportedDestinations merges settings - iOS, watchOS (framework)") { @@ -493,11 +497,11 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "iphoneos iphonesimulator watchos watchsimulator" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "1,2,4" - try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"] as? Bool) == false - try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == true + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "iphoneos iphonesimulator watchos watchsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "1,2,4" + try expect(targetConfig1.buildSettings["SUPPORTS_MACCATALYST"]?.boolValue) == false + try expect(targetConfig1.buildSettings["SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == true } $0.it("supportedDestinations merges settings - visionOS, watchOS (framework)") { @@ -507,9 +511,9 @@ class ProjectGeneratorTests: XCTestCase { let pbxProject = try project.generatePbxProj() let targetConfig1 = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"] as? String) == "watchos watchsimulator xros xrsimulator" - try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"] as? String) == "4,7" - try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"] as? Bool) == false + try expect(targetConfig1.buildSettings["SUPPORTED_PLATFORMS"]?.stringValue) == "watchos watchsimulator xros xrsimulator" + try expect(targetConfig1.buildSettings["TARGETED_DEVICE_FAMILY"]?.stringValue) == "4,7" + try expect(targetConfig1.buildSettings["SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD"]?.boolValue) == false } $0.it("generates dependencies") { @@ -1232,10 +1236,10 @@ class ProjectGeneratorTests: XCTestCase { return buildConfig.buildSettings } - let frameworkOtherLinkerSettings = try buildSettings(for: framework)["OTHER_LDFLAGS"] as? [String] ?? [] - let app1OtherLinkerSettings = try buildSettings(for: app1)["OTHER_LDFLAGS"] as? [String] ?? [] - let app2OtherLinkerSettings = try buildSettings(for: app2)["OTHER_LDFLAGS"] as? [String] ?? [] - let app3OtherLinkerSettings = try buildSettings(for: app3)["OTHER_LDFLAGS"] as? [String] ?? [] + let frameworkOtherLinkerSettings = try buildSettings(for: framework)["OTHER_LDFLAGS"]?.arrayValue ?? [] + let app1OtherLinkerSettings = try buildSettings(for: app1)["OTHER_LDFLAGS"]?.arrayValue ?? [] + let app2OtherLinkerSettings = try buildSettings(for: app2)["OTHER_LDFLAGS"]?.arrayValue ?? [] + let app3OtherLinkerSettings = try buildSettings(for: app3)["OTHER_LDFLAGS"]?.arrayValue ?? [] try expect(frameworkOtherLinkerSettings.contains("-ObjC")) == false try expect(app1OtherLinkerSettings.contains("-ObjC")) == true @@ -1531,7 +1535,7 @@ class ProjectGeneratorTests: XCTestCase { try expect(frameworkBuildFiles.count) == 2 try expect(buildFileSettings.compactMap { $0 }.count) == 1 try expect(buildFileSettings.compactMap { $0?["ATTRIBUTES"] }.count) == 1 - try expect(buildFileSettings.compactMap { $0?["ATTRIBUTES"] as? [String] }.first) == ["Weak"] + try expect(buildFileSettings.compactMap { $0?["ATTRIBUTES"]?.arrayValue }.first) == ["Weak"] } $0.it("generates swift packages") { @@ -1767,7 +1771,7 @@ class ProjectGeneratorTests: XCTestCase { let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig.buildSettings["INFOPLIST_FILE"] as? String) == plist.path + try expect(targetConfig.buildSettings["INFOPLIST_FILE"]?.stringValue) == plist.path let infoPlistFile = tempPath + plist.path let data: Data = try infoPlistFile.read() @@ -1793,14 +1797,14 @@ class ProjectGeneratorTests: XCTestCase { let plist = Plist(path: "Info.plist", attributes: ["UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationLandscapeLeft"]]) let tempPath = Path.temporary + "info" // create project with a predefined plist - let project = Project(basePath: tempPath, name: "", targets: [Target(name: "", type: .application, platform: .iOS, settings: Settings(buildSettings: ["INFOPLIST_FILE": predefinedPlistPath]), info: plist)]) + let project = Project(basePath: tempPath, name: "", targets: [Target(name: "", type: .application, platform: .iOS, settings: Settings(buildSettings: ["INFOPLIST_FILE": .string(predefinedPlistPath)]), info: plist)]) let pbxProject = try project.generatePbxProj() let writer = FileWriter(project: project) try writer.writePlists() let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) // generated plist should not be in buildsettings - try expect(targetConfig.buildSettings["INFOPLIST_FILE"] as? String) == predefinedPlistPath + try expect(targetConfig.buildSettings["INFOPLIST_FILE"]?.stringValue) == predefinedPlistPath } describe("Carthage dependencies") { @@ -1819,7 +1823,7 @@ class ProjectGeneratorTests: XCTestCase { let target = pbxProject.nativeTargets.first! let configuration = target.buildConfigurationList!.buildConfigurations.first! - try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] + try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] let frameworkBuildPhase = try target.frameworksBuildPhase() guard let files = frameworkBuildPhase?.files, let file = files.first else { return XCTFail("frameworkBuildPhase should have files") @@ -1847,7 +1851,7 @@ class ProjectGeneratorTests: XCTestCase { let target = pbxProject.nativeTargets.first! let configuration = target.buildConfigurationList!.buildConfigurations.first! - try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] + try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] let frameworkBuildPhase = try target.frameworksBuildPhase() guard let files = frameworkBuildPhase?.files else { return XCTFail("frameworkBuildPhase should have files") @@ -1880,7 +1884,7 @@ class ProjectGeneratorTests: XCTestCase { let targetConfig = try unwrap(pbxProject.nativeTargets.first?.buildConfigurationList?.buildConfigurations.first) - try expect(targetConfig.buildSettings["INFOPLIST_FILE"] as? String) == plist.path + try expect(targetConfig.buildSettings["INFOPLIST_FILE"]?.stringValue) == plist.path let infoPlistFile = tempPath + plist.path let data: Data = try infoPlistFile.read() @@ -1970,7 +1974,7 @@ class ProjectGeneratorTests: XCTestCase { let project = Project(name: "test", targets: [frameworkWithSources]) let generator = ProjectGenerator(project: project) let generatedProject = try generator.generateXcodeProject(in: destinationPath, userName: "someUser") - let plists = generatedProject.pbxproj.buildConfigurations.compactMap { $0.buildSettings["INFOPLIST_FILE"] as? String } + let plists = generatedProject.pbxproj.buildConfigurations.compactMap { $0.buildSettings["INFOPLIST_FILE"]?.stringValue } try expect(plists.count) == 2 for plist in plists { try expect(plist) == "TestProject/App_iOS/Info.plist" @@ -1994,7 +1998,7 @@ class ProjectGeneratorTests: XCTestCase { let target = pbxProject.nativeTargets.first! let configuration = target.buildConfigurationList!.buildConfigurations.first! - try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] + try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] let frameworkBuildPhase = try target.frameworksBuildPhase() guard let files = frameworkBuildPhase?.files, let file = files.first else { return XCTFail("frameworkBuildPhase should have files") @@ -2023,7 +2027,7 @@ class ProjectGeneratorTests: XCTestCase { let target = pbxProject.nativeTargets.first! let configuration = target.buildConfigurationList!.buildConfigurations.first! - try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"] as? [String]) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] + try expect(configuration.buildSettings["FRAMEWORK_SEARCH_PATHS"]?.arrayValue) == ["$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", "$(PROJECT_DIR)/Carthage/Build/iOS/Static"] let frameworkBuildPhase = try target.frameworksBuildPhase() guard let files = frameworkBuildPhase?.files else { diff --git a/Tests/XcodeGenKitTests/SourceGeneratorTests.swift b/Tests/XcodeGenKitTests/SourceGeneratorTests.swift index 4e109ab2..3712f42e 100644 --- a/Tests/XcodeGenKitTests/SourceGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SourceGeneratorTests.swift @@ -745,7 +745,7 @@ class SourceGeneratorTests: XCTestCase { name: "C", type: .application, platform: .iOS, - settings: Settings(dictionary: [ + settings: Settings(buildSettings: [ "INFOPLIST_FILE": "C/Info-Production.plist" ]), sources: ["C"] @@ -756,7 +756,7 @@ class SourceGeneratorTests: XCTestCase { name: "D", type: .application, platform: .iOS, - settings: Settings(dictionary: [ + settings: Settings(buildSettings: [ "ENVIRONMENT": "Production", "INFOPLIST_FILE": "D/Info-${ENVIRONMENT}.plist" ]), @@ -812,20 +812,16 @@ class SourceGeneratorTests: XCTestCase { do { let fileReference = try unwrap(pbxProj.getFileReference(paths: ["A", "file.resource1"], names: ["A", "file.resource1"])) let buildFile = try unwrap(pbxProj.buildFiles.first(where: { $0.file === fileReference })) - let settings = NSDictionary(dictionary: buildFile.settings ?? [:]) - try expect(settings) == [ - "ATTRIBUTES": ["a1", "a2"], - "ASSET_TAGS": ["r1", "r2"], - ] + let settings = buildFile.settings ?? [:] + try expect(settings["ATTRIBUTES"]?.arrayValue) == ["a1", "a2"] + try expect(settings["ASSET_TAGS"]?.arrayValue) == ["r1", "r2"] } do { let fileReference = try unwrap(pbxProj.getFileReference(paths: ["A", "file.source1"], names: ["A", "file.source1"])) let buildFile = try unwrap(pbxProj.buildFiles.first(where: { $0.file === fileReference })) - let settings = NSDictionary(dictionary: buildFile.settings ?? [:]) - try expect(settings) == [ - "ATTRIBUTES": ["a1", "a2"], - "COMPILER_FLAGS": "-c1 -c2", - ] + let settings = buildFile.settings ?? [:] + try expect(settings["ATTRIBUTES"]?.arrayValue) == ["a1", "a2"] + try expect(settings["COMPILER_FLAGS"]?.stringValue) == "-c1 -c2" } } @@ -1041,7 +1037,7 @@ class SourceGeneratorTests: XCTestCase { try pbxProj.expectFile(paths: ["A", definition], buildPhase: .sources) - if (buildFile.settings! as NSDictionary) != (["ATTRIBUTES": ["no_codegen"]] as NSDictionary) { + if buildFile.settings?["ATTRIBUTES"]?.arrayValue != ["no_codegen"] { throw failure("File does not contain no_codegen attribute") } } @@ -1266,11 +1262,11 @@ class SourceGeneratorTests: XCTestCase { let resourceBuildFile2 = try unwrap(pbxProj.buildFiles.first(where: { $0.file == resourceFileReference2 })) let sourceBuildFile = try unwrap(pbxProj.buildFiles.first(where: { $0.file == sourceFileReference })) - if (resourceBuildFile.settings! as NSDictionary) != (["ASSET_TAGS": ["tag1", "tag2"]] as NSDictionary) { + if resourceBuildFile.settings?["ASSET_TAGS"]?.arrayValue != ["tag1", "tag2"] { throw failure("File does not contain tag1 and tag2 ASSET_TAGS") } - if (resourceBuildFile2.settings! as NSDictionary) != (["ASSET_TAGS": ["tag2", "tag3"]] as NSDictionary) { + if resourceBuildFile2.settings?["ASSET_TAGS"]?.arrayValue != ["tag2", "tag3"] { throw failure("File does not contain tag2 and tag3 ASSET_TAGS") } @@ -1282,7 +1278,7 @@ class SourceGeneratorTests: XCTestCase { throw failure("PBXProject does not contain knownAssetTags") } - try expect(pbxProj.rootObject!.attributes["knownAssetTags"] as? [String]) == ["tag1", "tag2", "tag3"] + try expect(pbxProj.rootObject!.attributes["knownAssetTags"]?.arrayValue) == ["tag1", "tag2", "tag3"] } $0.it("Detects all locales present in a String Catalog") {