GLEGram 12.5 — Initial public release

Based on Swiftgram 12.5 (Telegram iOS 12.5).
All GLEGram features ported and organized in GLEGram/ folder.

Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass,
Font Replacement, Fake Profile, Chat Export, Plugin System, and more.

See CHANGELOG_12.5.md for full details.
This commit is contained in:
Leeksov
2026-04-06 09:48:12 +03:00
commit 4647310322
39685 changed files with 11052678 additions and 0 deletions
@@ -0,0 +1,20 @@
import ProjectSpec
import Spectre
import TestSupport
import XCTest
class BreakpointGeneratorTests: XCTestCase {
func testBreakpoints() {
describe {
$0.it("generates breakpoint") {
let breakpoint = Breakpoint(type: .exception(.init()))
let project = Project(basePath: "", name: "test", targets: [], breakpoints: [breakpoint])
let xcodeProject = try project.generateXcodeProject()
let xcbreakpoint = try unwrap(xcodeProject.sharedData?.breakpoints?.breakpoints.first)
try expect(xcbreakpoint.breakpointExtensionID.rawValue) == "Xcode.Breakpoint.ExceptionBreakpoint"
}
}
}
}
@@ -0,0 +1,180 @@
import ProjectSpec
import Spectre
import XCTest
import PathKit
@testable import XcodeGenKit
import TestSupport
class CarthageDependencyResolverTests: XCTestCase {
override func setUp() {}
func testBaseBuildPath() {
describe {
$0.it("provides the default base build path") {
let resolver = CarthageDependencyResolver(project: makeTestProject())
try expect(resolver.buildPath) == "Carthage/Build"
}
$0.it("provides the base build path specified by the project specs") {
let customPath = "MyCustomBuildPath/Test"
let options = SpecOptions(carthageBuildPath: customPath)
let resolver = CarthageDependencyResolver(project: makeTestProject(options: options))
try expect(resolver.buildPath) == customPath
}
}
}
func testExecutablePath() {
describe {
$0.it("provides the default executable path for carthage") {
let resolver = CarthageDependencyResolver(project: makeTestProject())
try expect(resolver.executable) == "carthage"
}
$0.it("provides the executable path for carthage as specified by the project specs") {
let customPath = "MyCustomBuildPath/Test/carthage"
let options = SpecOptions(carthageExecutablePath: customPath)
let resolver = CarthageDependencyResolver(project: makeTestProject(options: options))
try expect(resolver.executable) == customPath
}
}
}
func testBuildPathForPlatform() {
describe {
$0.it("generates the build path for a given platform") {
let resolver = CarthageDependencyResolver(project: makeTestProject())
let allPlatforms = Platform.allCases
let expectedByPlatform: [Platform: String] = allPlatforms.reduce(into: [:]) { result, next in
result[next] = "\(resolver.buildPath)/\(next.carthageName)"
}
try allPlatforms.forEach { platform in
try expect(expectedByPlatform[platform]) == resolver.buildPath(for: platform, linkType: .dynamic)
}
}
}
}
func testRelatedDependenciesForPlatform() {
let carthageBuildPath = fixturePath + "CarthageProject/Carthage/Build"
describe {
$0.it("fetches related dependencies for a given platform, sorted alphabetically") {
let options = SpecOptions(carthageBuildPath: carthageBuildPath.string)
let resolver = CarthageDependencyResolver(project: makeTestProject(options: options))
let dependency = Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "CarthageTestFixture")
let expectedDependencies: [Platform: [String]] = [
.macOS: ["DependencyFixtureB", "DependencyFixtureA", "CarthageTestFixture"],
.watchOS: ["DependencyFixtureA", "DependencyFixtureB", "CarthageTestFixture"],
.tvOS: ["CarthageTestFixture", "DependencyFixtureA", "DependencyFixtureB"],
.iOS: ["CarthageTestFixture", "DependencyFixtureA", "DependencyFixtureB"],
]
try Platform.allCases.forEach { platform in
let expected = expectedDependencies[platform] ?? []
let related = resolver.relatedDependencies(for: dependency, in: platform)
try expect(related.map { $0.reference }) == expected.sorted(by: { $0 < $1 })
}
}
$0.it("returns the main dependency when no related dependencies are found") {
let resolver = CarthageDependencyResolver(project: makeTestProject())
let dependency = Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "RandomDependency")
let related = resolver.relatedDependencies(for: dependency, in: .iOS)
try expect(related.map { $0.reference }) == ["RandomDependency"]
}
$0.it("de-duplicates dependencies") {
let resolver = CarthageDependencyResolver(project: makeTestProject())
let dependency = Dependency(type: .carthage(findFrameworks: true, linkType: .dynamic), reference: "ReactiveSwift")
let related = resolver.relatedDependencies(for: dependency, in: .iOS)
try expect(related.map { $0.reference }) == ["ReactiveSwift"]
}
}
}
func testDependenciesForTopLevelTarget() {
let dependencyFixtureName = "CarthageTestFixture"
let carthageBuildPath = fixturePath + "TestProject/Carthage/Build"
describe {
$0.it("overrides the findFrameworks dependency global flag when specified") {
let options = SpecOptions(carthageBuildPath: carthageBuildPath.string, findCarthageFrameworks: true)
let dependency = Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: dependencyFixtureName)
let resolver = CarthageDependencyResolver(project: makeTestProject(options: options))
let target = Target(name: "1", type: .application, platform: .iOS, dependencies: [dependency])
let dependencies = resolver.dependencies(for: target)
let expectedDependencies = [dependency].map {
ResolvedCarthageDependency(dependency: $0, isFromTopLevelTarget: true)
}
try expect(dependencies) == expectedDependencies
}
$0.it("fetches all carthage dependencies for a given target, sorted alphabetically") {
let unsortedDependencyReferences = ["RxSwift", "RxCocoa", "RxBlocking", "RxTest", "RxAtomic"]
let dependencies = unsortedDependencyReferences.map {
Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: $0)
}
let nonCarthageDependencies = unsortedDependencyReferences.map { Dependency(type: .target, reference: $0) }
let target = Target(name: "1", type: .application, platform: .iOS, dependencies: dependencies + nonCarthageDependencies)
let resolver = CarthageDependencyResolver(project: makeTestProject(with: [target]))
let related = resolver.dependencies(for: target)
let expectedDependencies = dependencies
.sorted(by: { $0.reference < $1.reference })
.map {
ResolvedCarthageDependency(dependency: $0, isFromTopLevelTarget: true)
}
try expect(related) == expectedDependencies
}
$0.it("skips dependencies which are not embedded") {
let resolver = CarthageDependencyResolver(project: makeTestProject())
let target = Target(name: "1", type: .application, platform: .iOS, dependencies: [
Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: dependencyFixtureName, embed: false, link: false)
])
try expect(resolver.dependencies(for: target)) == []
}
$0.it("skips dependencies nested in targets which are not embedded") {
let nestedTarget = Target(name: "1", type: .framework, platform: .iOS, dependencies: [
Dependency(type: .carthage(findFrameworks: false, linkType: .dynamic), reference: dependencyFixtureName)
])
let resolver = CarthageDependencyResolver(project: makeTestProject(with: [nestedTarget]))
let target = Target(name: "2", type: .application, platform: .iOS, dependencies: [
Dependency(type: .target, reference: "1", embed: false, link: false)
])
try expect(resolver.dependencies(for: target)) == []
}
}
}
}
private func makeTestProject(with targets: [Target] = [], options: SpecOptions = SpecOptions()) -> Project {
Project(name: "Test Project", targets: targets, options: options)
}
@@ -0,0 +1,508 @@
import Yams
import XCTest
import Spectre
import PathKit
import XcodeProj
import ProjectSpec
import XcodeGenKit
import TestSupport
extension Project {
func generateXcodeProject(validate: Bool = true, file: String = #file, line: Int = #line) throws -> XcodeProj {
try doThrowing(file: file, line: line) {
if validate {
try self.validate()
}
let generator = ProjectGenerator(project: self)
return try generator.generateXcodeProject(userName: "someUser")
}
}
func generatePbxProj(specValidate: Bool = true, projectValidate: Bool = true, file: String = #file, line: Int = #line) throws -> PBXProj {
try doThrowing(file: file, line: line) {
let xcodeProject = try generateXcodeProject(validate: specValidate).pbxproj
if projectValidate {
try xcodeProject.validate()
}
return xcodeProject
}
}
}
extension PBXProj {
// validates that a PBXProj is correct
// TODO: Use xclint?
func validate() throws {
let mainGroup = try getMainGroup()
func validateGroup(_ group: PBXGroup) throws {
// check for duplicte children
let dictionary = Dictionary(grouping: group.children) { $0.hashValue }
let mostChildren = dictionary.sorted { $0.value.count > $1.value.count }
if let first = mostChildren.first, first.value.count > 1 {
throw failure("Group \"\(group.nameOrPath)\" has duplicated children:\n - \(group.children.map { $0.nameOrPath }.joined(separator: "\n - "))")
}
for child in group.children {
if let group = child as? PBXGroup {
try validateGroup(group)
}
}
}
try validateGroup(mainGroup)
}
func getMainGroup(function: String = #function, file: String = #file, line: Int = #line) throws -> PBXGroup {
guard let mainGroup = projects.first?.mainGroup else {
throw failure("Couldn't find main group", file: file, line: line)
}
return mainGroup
}
}
class PBXProjGeneratorTests: XCTestCase {
func testGroupOrdering() {
describe {
let directoryPath = Path("TestDirectory")
func createDirectories(_ directories: String) throws {
let yaml = try Yams.load(yaml: directories)!
func getFiles(_ file: Any, path: Path) -> [Path] {
if let array = file as? [Any] {
return array.flatMap { getFiles($0, path: path) }
} else if let string = file as? String {
return [path + string]
} else if let dictionary = file as? [String: Any] {
var array: [Path] = []
for (key, value) in dictionary {
array += getFiles(value, path: path + key)
}
return array
} else {
return []
}
}
let files = getFiles(yaml, path: directoryPath).filter { $0.extension != nil }
for file in files {
try file.parent().mkpath()
try file.write("")
}
}
func removeDirectories() {
try? directoryPath.delete()
}
$0.before {
removeDirectories()
}
$0.after {
removeDirectories()
}
$0.it("setups group ordering with groupSortPosition = .top") {
var options = SpecOptions()
options.groupSortPosition = .top
options.groupOrdering = [
GroupOrdering(
order: [
"Sources",
"Resources",
"Tests",
"Support files",
"Configurations",
]
),
GroupOrdering(
pattern: "^.*Screen$",
order: [
"View",
"Presenter",
"Interactor",
"Entities",
"Assembly",
]
),
]
let directories = """
Configurations:
- file.swift
Resources:
- file.swift
Sources:
- MainScreen:
- mainScreen1.swift
- mainScreen2.swift
- Assembly:
- file.swift
- Entities:
- file.swift
- Interactor:
- file.swift
- Presenter:
- file.swift
- View:
- file.swift
Support files:
- file.swift
Tests:
- file.swift
UITests:
- file.swift
"""
try createDirectories(directories)
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Configurations", "Resources", "Sources", "Support files", "Tests", "UITests"])
let project = Project(basePath: directoryPath, name: "Test", targets: [target], options: options)
let projGenerator = PBXProjGenerator(project: project)
let pbxProj = try project.generatePbxProj()
let group = try pbxProj.getMainGroup()
projGenerator.setupGroupOrdering(group: group)
let mainGroups = group.children.map { $0.nameOrPath }
try expect(mainGroups) == ["Sources", "Resources", "Tests", "Support files", "Configurations", "UITests", "Products"]
let screenGroups = group.children
.first { $0.nameOrPath == "Sources" }
.flatMap { $0 as? PBXGroup }?
.children
.first { $0.nameOrPath == "MainScreen" }
.flatMap { $0 as? PBXGroup }?
.children
.map { $0.nameOrPath }
try expect(screenGroups) == ["View", "Presenter", "Interactor", "Entities", "Assembly", "mainScreen1.swift", "mainScreen2.swift"]
}
$0.it("setups group ordering with groupSortPosition = .bottom") {
var options = SpecOptions()
options.groupSortPosition = .bottom
options.groupOrdering = [
GroupOrdering(
order: [
"Sources",
"Resources",
"Tests",
"Support files",
"Configurations",
]
),
GroupOrdering(
pattern: "^.*Screen$",
order: [
"View",
"Presenter",
"Interactor",
"Entities",
"Assembly",
]
),
]
let directories = """
Configurations:
- file.swift
Resources:
- file.swift
Sources:
- MainScreen:
- mainScreen1.swift
- mainScreen2.swift
- Assembly:
- file.swift
- Entities:
- file.swift
- Interactor:
- file.swift
- Presenter:
- file.swift
- View:
- file.swift
Support files:
- file.swift
Tests:
- file.swift
UITests:
- file.swift
"""
try createDirectories(directories)
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Configurations", "Resources", "Sources", "Support files", "Tests", "UITests"])
let project = Project(basePath: directoryPath, name: "Test", targets: [target], options: options)
let projGenerator = PBXProjGenerator(project: project)
let pbxProj = try project.generatePbxProj()
let group = try pbxProj.getMainGroup()
projGenerator.setupGroupOrdering(group: group)
let mainGroups = group.children.map { $0.nameOrPath }
try expect(mainGroups) == ["Sources", "Resources", "Tests", "Support files", "Configurations", "UITests", "Products"]
let screenGroups = group.children
.first { $0.nameOrPath == "Sources" }
.flatMap { $0 as? PBXGroup }?
.children
.first { $0.nameOrPath == "MainScreen" }
.flatMap { $0 as? PBXGroup }?
.children
.map { $0.nameOrPath }
try expect(screenGroups) == ["mainScreen1.swift", "mainScreen2.swift", "View", "Presenter", "Interactor", "Entities", "Assembly"]
}
$0.it("sorts SPM packages") {
var options = SpecOptions()
options.groupSortPosition = .top
options.groupOrdering = [
GroupOrdering(
order: [
"Sources",
"Resources",
"Tests",
"Packages",
"Support files",
"Configurations",
]
),
GroupOrdering(
pattern: "Packages",
order: [
"FeatureA",
"FeatureB",
"Common",
]
),
]
let directories = """
Configurations:
- file.swift
Resources:
- file.swift
Sources:
- MainScreen:
- mainScreen1.swift
- mainScreen2.swift
- Assembly:
- file.swift
- Entities:
- file.swift
- Interactor:
- file.swift
- Presenter:
- file.swift
- View:
- file.swift
Support files:
- file.swift
Packages:
- Common:
- Package.swift
- FeatureA:
- Package.swift
- FeatureB:
- Package.swift
Tests:
- file.swift
UITests:
- file.swift
"""
try createDirectories(directories)
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Configurations", "Resources", "Sources", "Support files", "Tests", "UITests"])
let project = Project(
basePath: directoryPath,
name: "Test",
targets: [target],
packages: [
"Common": .local(path: "Packages/Common", group: nil, excludeFromProject: false),
"FeatureA": .local(path: "Packages/FeatureA", group: nil, excludeFromProject: false),
"FeatureB": .local(path: "Packages/FeatureB", group: nil, excludeFromProject: false),
],
options: options
)
let projGenerator = PBXProjGenerator(project: project)
let pbxProj = try project.generatePbxProj()
let group = try pbxProj.getMainGroup()
projGenerator.setupGroupOrdering(group: group)
let mainGroups = group.children.map { $0.nameOrPath }
try expect(mainGroups) == ["Sources", "Resources", "Tests", "Packages", "Support files", "Configurations", "UITests", "Products"]
let packages = group.children
.first { $0.nameOrPath == "Packages" }
.flatMap { $0 as? PBXGroup }?
.children
.map(\.nameOrPath)
try expect(packages) == ["FeatureA", "FeatureB", "Common"]
}
}
}
func testDefaultLastUpgradeCheckWhenUserDidSpecifyInvalidValue() throws {
let lastUpgradeKey = "LastUpgradeCheck"
let attributes: [String: Any] = [lastUpgradeKey: 1234]
let project = Project(name: "Test", attributes: attributes)
let projGenerator = PBXProjGenerator(project: project)
let pbxProj = try projGenerator.generate()
for pbxProject in pbxProj.projects {
XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, project.xcodeVersion)
}
}
func testOverrideLastUpgradeCheckWhenUserDidSpecifyValue() throws {
let lastUpgradeKey = "LastUpgradeCheck"
let lastUpgradeValue = "1234"
let attributes: [String: Any] = [lastUpgradeKey: lastUpgradeValue]
let project = Project(name: "Test", attributes: attributes)
let projGenerator = PBXProjGenerator(project: project)
let pbxProj = try projGenerator.generate()
for pbxProject in pbxProj.projects {
XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, lastUpgradeValue)
}
}
func testDefaultLastUpgradeCheckWhenUserDidNotSpecifyValue() throws {
let lastUpgradeKey = "LastUpgradeCheck"
let project = Project(name: "Test")
let projGenerator = PBXProjGenerator(project: project)
let pbxProj = try projGenerator.generate()
for pbxProject in pbxProj.projects {
XCTAssertEqual(pbxProject.attributes[lastUpgradeKey] as? String, project.xcodeVersion)
}
}
func testPlatformDependencies() {
describe {
let directoryPath = Path("TestDirectory")
func createDirectories(_ directories: String) throws {
let yaml = try Yams.load(yaml: directories)!
func getFiles(_ file: Any, path: Path) -> [Path] {
if let array = file as? [Any] {
return array.flatMap { getFiles($0, path: path) }
} else if let string = file as? String {
return [path + string]
} else if let dictionary = file as? [String: Any] {
var array: [Path] = []
for (key, value) in dictionary {
array += getFiles(value, path: path + key)
}
return array
} else {
return []
}
}
let files = getFiles(yaml, path: directoryPath).filter { $0.extension != nil }
for file in files {
try file.parent().mkpath()
try file.write("")
}
}
func removeDirectories() {
try? directoryPath.delete()
}
$0.before {
removeDirectories()
}
$0.after {
removeDirectories()
}
$0.it("setups target with different dependencies") {
let directories = """
Sources:
- MainScreen:
- Entities:
- file.swift
"""
try createDirectories(directories)
let target1 = Target(name: "TestAll", type: .application, platform: .iOS, sources: ["Sources"])
let target2 = Target(name: "TestiOS", type: .application, platform: .iOS, sources: ["Sources"])
let target3 = Target(name: "TestmacOS", type: .application, platform: .iOS, sources: ["Sources"])
let dependency1 = Dependency(type: .target, reference: "TestAll", platformFilter: .all)
let dependency2 = Dependency(type: .target, reference: "TestiOS", platformFilter: .iOS)
let dependency3 = Dependency(type: .target, reference: "TestmacOS", platformFilter: .macOS)
let dependency4 = Dependency(type: .package(products: ["Swinject"]), reference: "Swinject", platformFilter: .iOS)
let target = Target(name: "Test", type: .application, platform: .iOS, sources: ["Sources"], dependencies: [dependency1, dependency2, dependency3, dependency4])
let swinjectPackage = SwiftPackage.remote(url: "https://github.com/Swinject/Swinject", versionRequirement: .exact("2.8.0"))
let project = Project(basePath: directoryPath, name: "Test", targets: [target, target1, target2, target3], packages: ["Swinject": swinjectPackage])
let pbxProj = try project.generatePbxProj()
let targets = pbxProj.projects.first?.targets
let testTarget = pbxProj.projects.first?.targets.first(where: { $0.name == "Test" })
let testTargetDependencies = testTarget?.dependencies
try expect(targets?.count) == 4
try expect(testTargetDependencies?.count) == 3
try expect(testTargetDependencies?[0].platformFilter).beNil()
try expect(testTargetDependencies?[1].platformFilter) == "ios"
try expect(testTargetDependencies?[2].platformFilter) == "maccatalyst"
try expect(testTarget?.frameworksBuildPhase()?.files?.count) == 1
try expect(testTarget?.frameworksBuildPhase()?.files?[0].platformFilter) == "ios"
}
$0.it("places resources before sources buildPhase") {
let directories = """
Sources:
- MainScreen:
- Entities:
- file.swift
- image.jpg
"""
try createDirectories(directories)
let target1 = Target(
name: "TestAll",
type: .application,
platform: .iOS,
sources: ["Sources"],
putResourcesBeforeSourcesBuildPhase: true
)
let target2 = Target(
name: "TestiOS",
type: .application,
platform: .iOS,
sources: ["Sources"],
putResourcesBeforeSourcesBuildPhase: false
)
let project = Project(basePath: directoryPath, name: "Test", targets: [target1, target2])
let pbxProj = try project.generatePbxProj()
let targets = pbxProj.projects.first?.targets
try expect(targets?.count) == 2
try expect(targets?.first?.buildPhases.first).to.beOfType(PBXResourcesBuildPhase.self)
try expect(targets?.first?.buildPhases.last).to.beOfType(PBXSourcesBuildPhase.self)
try expect(targets?.last?.buildPhases.first).to.beOfType(PBXSourcesBuildPhase.self)
try expect(targets?.last?.buildPhases.last).to.beOfType(PBXResourcesBuildPhase.self)
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,771 @@
import PathKit
import ProjectSpec
import Spectre
import XcodeGenKit
import XcodeProj
import XCTest
import Yams
import TestSupport
private let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
dependencies: [Dependency(type: .target, reference: "MyFramework")]
)
private let framework = Target(
name: "MyFramework",
type: .framework,
platform: .iOS
)
private let frameworkTest = Target(
name: "MyFrameworkTests",
type: .unitTestBundle,
platform: .iOS
)
private let optionalFramework = Target(
name: "MyOptionalFramework",
type: .framework,
platform: .iOS
)
private let uiTest = Target(
name: "MyAppUITests",
type: .uiTestBundle,
platform: .iOS,
dependencies: [Dependency(type: .target, reference: "MyApp")]
)
class SchemeGeneratorTests: XCTestCase {
func testSchemes() throws {
try skipIfNecessary()
describe {
let buildTarget = Scheme.BuildTarget(target: .local(app.name))
$0.it("generates scheme") {
let preAction = Scheme.ExecutionAction(name: "Script", script: "echo Starting", settingsTarget: app.name)
let simulateLocation = Scheme.SimulateLocation(allow: true, defaultLocation: "New York, NY, USA")
let storeKitConfiguration = "Configuration.storekit"
let scheme = try Scheme(
name: "MyScheme",
build: Scheme.Build(targets: [buildTarget], preActions: [preAction]),
run: Scheme.Run(config: "Debug", enableGPUFrameCaptureMode: .metal, askForAppToLaunch: true, launchAutomaticallySubstyle: "2", simulateLocation: simulateLocation, storeKitConfiguration: storeKitConfiguration, customLLDBInit: "/sample/.lldbinit"),
test: Scheme.Test(config: "Debug", targets: [
Scheme.Test.TestTarget(targetReference: TestableTargetReference(framework.name), location: "test.gpx"),
Scheme.Test.TestTarget(targetReference: TestableTargetReference(framework.name), location: "New York, NY, USA")
], customLLDBInit: "/test/.lldbinit"),
profile: Scheme.Profile(config: "Release", askForAppToLaunch: true)
)
let project = Project(
name: "test",
targets: [app, framework],
schemes: [scheme],
options: .init(schemePathPrefix: "../")
)
let xcodeProject = try project.generateXcodeProject()
let target = try unwrap(xcodeProject.pbxproj.nativeTargets
.first(where: { $0.name == app.name }))
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(scheme.name) == "MyScheme"
try expect(xcscheme.buildAction?.buildImplicitDependencies) == true
try expect(xcscheme.buildAction?.parallelizeBuild) == true
try expect(xcscheme.buildAction?.runPostActionsOnFailure) == false
try expect(xcscheme.buildAction?.preActions.first?.title) == "Script"
try expect(xcscheme.buildAction?.preActions.first?.scriptText) == "echo Starting"
try expect(xcscheme.buildAction?.preActions.first?.environmentBuildable?.buildableName) == "MyApp.app"
try expect(xcscheme.buildAction?.preActions.first?.environmentBuildable?.blueprintName) == "MyApp"
let buildActionEntry = try unwrap(xcscheme.buildAction?.buildActionEntries.first)
try expect(buildActionEntry.buildFor) == BuildType.all
let buildableReferences: [XCScheme.BuildableReference] = [
buildActionEntry.buildableReference,
xcscheme.launchAction?.runnable?.buildableReference,
xcscheme.profileAction?.buildableProductRunnable?.buildableReference,
xcscheme.testAction?.macroExpansion,
].compactMap { $0 }
for buildableReference in buildableReferences {
// FIXME: try expect(buildableReference.blueprintIdentifier) == target.reference
try expect(buildableReference.blueprintName) == target.name
try expect(buildableReference.buildableName) == "\(target.name).\(target.productType!.fileExtension!)"
}
try expect(xcscheme.launchAction?.buildConfiguration) == "Debug"
try expect(xcscheme.testAction?.buildConfiguration) == "Debug"
try expect(xcscheme.profileAction?.buildConfiguration) == "Release"
try expect(xcscheme.analyzeAction?.buildConfiguration) == "Debug"
try expect(xcscheme.archiveAction?.buildConfiguration) == "Release"
try expect(xcscheme.launchAction?.selectedDebuggerIdentifier) == XCScheme.defaultDebugger
try expect(xcscheme.testAction?.selectedDebuggerIdentifier) == XCScheme.defaultDebugger
try expect(xcscheme.launchAction?.askForAppToLaunch) == true
try expect(xcscheme.profileAction?.askForAppToLaunch) == true
try expect(xcscheme.launchAction?.launchAutomaticallySubstyle) == "2"
try expect(xcscheme.launchAction?.allowLocationSimulation) == true
try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../Configuration.storekit"
try expect(xcscheme.launchAction?.locationScenarioReference?.referenceType) == Scheme.SimulateLocation.ReferenceType.predefined.rawValue
try expect(xcscheme.launchAction?.locationScenarioReference?.identifier) == "New York, NY, USA"
try expect(xcscheme.launchAction?.customLLDBInitFile) == "/sample/.lldbinit"
try expect(xcscheme.launchAction?.enableGPUFrameCaptureMode) == .metal
try expect(xcscheme.testAction?.customLLDBInitFile) == "/test/.lldbinit"
try expect(xcscheme.testAction?.systemAttachmentLifetime).to.beNil()
try expect(xcscheme.testAction?.testables[0].locationScenarioReference?.referenceType) == "0"
try expect(xcscheme.testAction?.testables[0].locationScenarioReference?.identifier) == "../test.gpx"
try expect(xcscheme.testAction?.testables[1].locationScenarioReference?.referenceType) == "1"
try expect(xcscheme.testAction?.testables[1].locationScenarioReference?.identifier) == "New York, NY, USA"
}
let frameworkTarget = Scheme.BuildTarget(target: .local(framework.name), buildTypes: [.archiving])
$0.it("generates a scheme with the first runnable selected") {
let scheme = Scheme(
name: "MyScheme",
build: Scheme.Build(targets: [frameworkTarget, buildTarget])
)
let project = Project(
name: "test",
targets: [framework, app],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
let buildableReference = xcscheme.launchAction?.runnable?.buildableReference
try expect(buildableReference?.buildableName) == "MyApp.app"
}
$0.it("generates scheme with multiple configs") {
let configs: [Config] = [
Config(name: "Beta", type: .debug),
Config(name: "Debug", type: .debug),
Config(name: "Production", type: .release),
Config(name: "Release", type: .release),
]
let framework = Target(
name: "MyFramework",
type: .application,
platform: .iOS,
scheme: TargetScheme(testTargets: ["MyFrameworkTests"], storeKitConfiguration: "Configuration.storekit")
)
let project = Project(
name: "test",
configs: configs,
targets: [framework, frameworkTest],
options: .init(schemePathPrefix: "../../")
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.launchAction?.buildConfiguration) == "Debug"
try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../../Configuration.storekit"
try expect(xcscheme.testAction?.buildConfiguration) == "Debug"
try expect(xcscheme.profileAction?.buildConfiguration) == "Release"
try expect(xcscheme.analyzeAction?.buildConfiguration) == "Debug"
try expect(xcscheme.archiveAction?.buildConfiguration) == "Release"
}
$0.it("sets environment variables for a scheme") {
let runVariables: [XCScheme.EnvironmentVariable] = [
XCScheme.EnvironmentVariable(variable: "RUN_ENV", value: "ENABLED", enabled: true),
XCScheme.EnvironmentVariable(variable: "OTHER_RUN_ENV", value: "DISABLED", enabled: false),
]
let scheme = Scheme(
name: "EnvironmentVariablesScheme",
build: Scheme.Build(targets: [buildTarget]),
run: Scheme.Run(config: "Debug", environmentVariables: runVariables, simulateLocation: .init(allow: true, defaultLocation: "File.gpx"), storeKitConfiguration: "Configuration.storekit"),
test: Scheme.Test(config: "Debug"),
profile: Scheme.Profile(config: "Debug")
)
let project = Project(
name: "test",
targets: [app, framework],
schemes: [scheme],
options: .init(schemePathPrefix: "../")
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(
xcodeProject.pbxproj.nativeTargets
.contains(where: { $0.name == app.name })
).beTrue()
try expect(xcscheme.launchAction?.environmentVariables) == runVariables
try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../Configuration.storekit"
try expect(xcscheme.launchAction?.locationScenarioReference?.referenceType) == Scheme.SimulateLocation.ReferenceType.gpx.rawValue
try expect(xcscheme.launchAction?.locationScenarioReference?.identifier) == "../File.gpx"
try expect(xcscheme.testAction?.environmentVariables).to.beNil()
try expect(xcscheme.profileAction?.environmentVariables).to.beNil()
}
$0.it("generates target schemes from config variant") {
let configVariants = ["Test", "PreProd", "Prod"]
var target = app
target.scheme = TargetScheme(configVariants: configVariants)
// Including here a double test for custom upper/lowercase, and dash delimited in config types
let configs: [Config] = [
Config(name: "Test-Debug", type: .debug),
Config(name: "PreProd debug", type: .debug),
Config(name: "Prod-Debug", type: .debug),
Config(name: "Test Release", type: .release),
Config(name: "PreProd release", type: .release),
Config(name: "Prod Release", type: .release),
]
let project = Project(name: "test", configs: configs, targets: [target, framework])
let xcodeProject = try project.generateXcodeProject()
try expect(xcodeProject.sharedData?.schemes.count) == 3
try configVariants.forEach { variantName in
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes
.first(where: { $0.name == "\(target.name) \(variantName)" }))
let buildActionEntry = try unwrap(xcscheme.buildAction?.buildActionEntries.first)
try expect((buildActionEntry.buildableReference.blueprintIdentifier?.count ?? 0) > 0) == true
if variantName == "PreProd" {
try expect(xcscheme.launchAction?.buildConfiguration) == "\(variantName) debug"
try expect(xcscheme.testAction?.buildConfiguration) == "\(variantName) debug"
try expect(xcscheme.profileAction?.buildConfiguration) == "\(variantName) release"
try expect(xcscheme.analyzeAction?.buildConfiguration) == "\(variantName) debug"
try expect(xcscheme.archiveAction?.buildConfiguration) == "\(variantName) release"
} else {
try expect(xcscheme.launchAction?.buildConfiguration) == "\(variantName)-Debug"
try expect(xcscheme.testAction?.buildConfiguration) == "\(variantName)-Debug"
try expect(xcscheme.profileAction?.buildConfiguration) == "\(variantName) Release"
try expect(xcscheme.analyzeAction?.buildConfiguration) == "\(variantName)-Debug"
try expect(xcscheme.archiveAction?.buildConfiguration) == "\(variantName) Release"
}
}
}
$0.it("generates environment variables for target schemes") {
let variables: [XCScheme.EnvironmentVariable] = [XCScheme.EnvironmentVariable(variable: "env", value: "var", enabled: false)]
var target = app
target.scheme = TargetScheme(environmentVariables: variables)
let project = Project(name: "test", targets: [target, framework])
let xcodeProject = try project.generateXcodeProject()
try expect(xcodeProject.sharedData?.schemes.count) == 1
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.launchAction?.environmentVariables) == variables
try expect(xcscheme.testAction?.environmentVariables) == variables
try expect(xcscheme.profileAction?.environmentVariables) == variables
}
$0.it("generate scheme without debugger - run") {
let scheme = Scheme(
name: "TestScheme",
build: Scheme.Build(targets: [buildTarget]),
run: Scheme.Run(config: "Debug", enableGPUFrameCaptureMode: .metal, debugEnabled: false, simulateLocation: .init(allow: true, defaultLocation: "File.gpx"), storeKitConfiguration: "Configuration.storekit")
)
let project = Project(
name: "test",
targets: [app, framework],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.launchAction?.selectedDebuggerIdentifier) == ""
try expect(xcscheme.launchAction?.selectedLauncherIdentifier) == "Xcode.IDEFoundation.Launcher.PosixSpawn"
try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../../Configuration.storekit"
try expect(xcscheme.launchAction?.locationScenarioReference?.referenceType) == Scheme.SimulateLocation.ReferenceType.gpx.rawValue
try expect(xcscheme.launchAction?.locationScenarioReference?.identifier) == "../../File.gpx"
try expect(xcscheme.launchAction?.enableGPUFrameCaptureMode) == .metal
}
$0.it("generate scheme without debugger - test") {
let scheme = Scheme(
name: "TestScheme",
build: Scheme.Build(targets: [buildTarget]),
test: Scheme.Test(config: "Debug", debugEnabled: false)
)
let project = Project(
name: "test",
targets: [app, framework],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.selectedDebuggerIdentifier) == ""
try expect(xcscheme.testAction?.selectedLauncherIdentifier) == "Xcode.IDEFoundation.Launcher.PosixSpawn"
}
$0.it("generates pre and post actions for target schemes") {
var target = app
target.scheme = TargetScheme(
preActions: [.init(name: "Run", script: "do")],
postActions: [.init(name: "Run2", script: "post", settingsTarget: "MyApp")]
)
let project = Project(name: "test", targets: [target, framework])
let xcodeProject = try project.generateXcodeProject()
try expect(xcodeProject.sharedData?.schemes.count) == 1
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.buildAction?.preActions.count) == 1
try expect(xcscheme.buildAction?.preActions.first?.title) == "Run"
try expect(xcscheme.buildAction?.preActions.first?.scriptText) == "do"
try expect(xcscheme.buildAction?.postActions.first?.environmentBuildable?.blueprintName) == "MyApp"
try expect(xcscheme.launchAction?.preActions.count) == 0
try expect(xcscheme.testAction?.postActions.count) == 0
}
$0.it("generates target schemes with code coverage options") {
var target = app
target.scheme = try TargetScheme(
gatherCoverageData: true,
coverageTargets: [
TestableTargetReference(framework.name),
]
)
let project = Project(name: "test", targets: [target, framework])
let xcodeProject = try project.generateXcodeProject()
try expect(xcodeProject.sharedData?.schemes.count) == 1
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.codeCoverageEnabled) == true
try expect(xcscheme.testAction?.codeCoverageTargets.count) == 1
try expect(xcscheme.testAction?.codeCoverageTargets.first?.blueprintName) == framework.name
}
$0.it("generates scheme using external project file") {
prepareXcodeProj: do {
let project = try! Project(path: fixturePath + "scheme_test/test_project.yml")
let generator = ProjectGenerator(project: project)
let writer = FileWriter(project: project)
let xcodeProject = try! generator.generateXcodeProject(userName: "someUser")
try! writer.writeXcodeProject(xcodeProject)
try! writer.writePlists()
}
let externalProjectPath = fixturePath + "scheme_test/TestProject.xcodeproj"
let projectReference = ProjectReference(name: "ExternalProject", path: externalProjectPath.string)
let target = Scheme.BuildTarget(target: .init(name: "ExternalTarget", location: .project("ExternalProject")))
let scheme = Scheme(
name: "ExternalProjectScheme",
build: Scheme.Build(targets: [target])
)
let project = Project(
name: "test",
targets: [],
schemes: [scheme],
projectReferences: [projectReference]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.buildAction?.buildActionEntries.count) == 1
let buildableReference = xcscheme.buildAction?.buildActionEntries.first?.buildableReference
try expect(buildableReference?.blueprintName) == "ExternalTarget"
try expect(buildableReference?.referencedContainer) == "container:\(externalProjectPath.string)"
}
$0.it("generate scheme with code coverage options") {
prepareXcodeProj: do {
let project = try! Project(path: fixturePath + "scheme_test/test_project.yml")
let generator = ProjectGenerator(project: project)
let writer = FileWriter(project: project)
let xcodeProject = try! generator.generateXcodeProject(userName: "someUser")
try! writer.writeXcodeProject(xcodeProject)
try! writer.writePlists()
}
let externalProject = fixturePath + "scheme_test/TestProject.xcodeproj"
let externalTarget = Scheme.BuildTarget(target: .init(name: "ExternalTarget", location: .project("TestProject")))
let scheme = try Scheme(
name: "CodeCoverageScheme",
build: Scheme.Build(targets: [externalTarget]),
test: Scheme.Test(
config: "Debug",
gatherCoverageData: true,
coverageTargets: [
"TestProject/ExternalTarget",
TestableTargetReference(framework.name),
TestableTargetReference(name: "XcodeGenKitTests", location: .package("XcodeGen"))
]
)
)
let project = Project(
name: "test",
targets: [framework],
schemes: [scheme],
packages: ["XcodeGen": .local(path: "../", group: nil, excludeFromProject: false)],
projectReferences: [
ProjectReference(name: "TestProject", path: externalProject.string),
]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.codeCoverageEnabled) == true
try expect(xcscheme.testAction?.codeCoverageTargets.count) == 3
let buildableReference = xcscheme.testAction?.codeCoverageTargets.first
try expect(buildableReference?.blueprintName) == "ExternalTarget"
try expect(buildableReference?.referencedContainer) == "container:\(externalProject.string)"
}
$0.it("generates scheme with buildable product runnable for ios app target") {
let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
scheme: TargetScheme()
)
let project = Project(name: "ios_test", targets: [app])
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.launchAction?.runnable).beOfType(XCScheme.BuildableProductRunnable.self)
}
$0.it("generates scheme with remote runnable for watch app target") {
let xcscheme = try self.makeWatchScheme(appType: .watch2App, extensionType: .watch2Extension)
try expect(xcscheme.launchAction?.runnable).beOfType(XCScheme.RemoteRunnable.self)
try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../Configuration.storekit"
}
$0.it("generates scheme with host target build action for watch") {
let xcscheme = try self.makeWatchScheme(appType: .watch2App, extensionType: .watch2Extension)
let buildEntries = xcscheme.buildAction?.buildActionEntries ?? []
try expect(buildEntries.count) == 2
try expect(buildEntries.first?.buildableReference.blueprintName) == "WatchApp"
try expect(buildEntries.last?.buildableReference.blueprintName) == "HostApp"
try expect(xcscheme.launchAction?.storeKitConfigurationFileReference?.identifier) == "../Configuration.storekit"
}
$0.it("generates scheme with extension target and specify macroExpansion") {
let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
dependencies: [Dependency(type: .target, reference: "MyAppExtension", embed: false)]
)
let `extension` = Target(
name: "MyAppExtension",
type: .appExtension,
platform: .iOS
)
let appTarget = Scheme.BuildTarget(target: .local(app.name), buildTypes: [.running])
let extensionTarget = Scheme.BuildTarget(target: .local(`extension`.name), buildTypes: [.running])
let scheme = Scheme(
name: "TestScheme",
build: Scheme.Build(targets: [appTarget, extensionTarget]),
run: Scheme.Run(config: "Debug", macroExpansion: "MyApp")
)
let project = Project(
name: "test",
targets: [app, `extension`],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.macroExpansion?.buildableName) == "MyApp.app"
try expect(xcscheme.launchAction?.macroExpansion?.buildableName) == "MyApp.app"
}
$0.it("allows to override test macroExpansion") {
let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
dependencies: [Dependency(type: .target, reference: "MyAppExtension", embed: false)]
)
let `extension` = Target(
name: "MyAppExtension",
type: .appExtension,
platform: .iOS
)
let appTarget = Scheme.BuildTarget(target: .local(app.name), buildTypes: [.running])
let extensionTarget = Scheme.BuildTarget(target: .local(`extension`.name), buildTypes: [.running])
let scheme = Scheme(
name: "TestScheme",
build: Scheme.Build(targets: [appTarget, extensionTarget]),
run: Scheme.Run(config: "Debug", macroExpansion: "MyApp"),
test: .init(macroExpansion: "MyAppExtension")
)
let project = Project(
name: "test",
targets: [app, `extension`],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.macroExpansion?.buildableName) == "MyAppExtension.appex"
try expect(xcscheme.launchAction?.macroExpansion?.buildableName) == "MyApp.app"
}
$0.it("generates scheme with macroExpansion from tests when the main target is not part of the scheme") {
let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
dependencies: []
)
let mockApp = Target(
name: "MockApp",
type: .application,
platform: .iOS,
dependencies: []
)
let testBundle = Target(
name: "TestBundle",
type: .unitTestBundle,
platform: .iOS
)
let appTarget = Scheme.BuildTarget(target: .local(app.name), buildTypes: [.running])
let mockAppTarget = Scheme.BuildTarget(target: .local(mockApp.name), buildTypes: [.testing])
let testBundleTarget = Scheme.BuildTarget(target: .local(testBundle.name), buildTypes: [.testing])
let scheme = Scheme(
name: "TestScheme",
build: Scheme.Build(targets: [appTarget, mockAppTarget, testBundleTarget]),
run: Scheme.Run(config: "Debug", macroExpansion: "MyApp")
)
let project = Project(
name: "test",
targets: [app, mockApp, testBundle],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.macroExpansion?.buildableName) == "MockApp.app"
}
$0.it("generates scheme with test target of local swift package") {
let targetScheme = TargetScheme(
testTargets: [Scheme.Test.TestTarget(targetReference: TestableTargetReference(name: "XcodeGenKitTests", location: .package("XcodeGen")))])
let app = Target(
name: "MyApp",
type: .application,
platform: .iOS,
dependencies: [
Dependency(type: .package(products: []), reference: "XcodeGen")
],
scheme: targetScheme
)
let project = Project(
name: "ios_test",
targets: [app],
packages: ["XcodeGen": .local(path: "../", group: nil, excludeFromProject: false)]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
let buildableReference = try unwrap(xcscheme.testAction?.testables.first?.buildableReference)
try expect(buildableReference.blueprintIdentifier) == "XcodeGenKitTests"
try expect(buildableReference.blueprintName) == "XcodeGenKitTests"
try expect(buildableReference.buildableName) == "XcodeGenKitTests"
try expect(buildableReference.referencedContainer) == "container:../"
}
$0.it("generates scheme capturing screenshots automatically and deleting on success") {
let xcscheme = try self.makeSnapshotScheme(
buildTarget: buildTarget,
captureScreenshotsAutomatically: true,
deleteScreenshotsWhenEachTestSucceeds: true)
try expect(xcscheme.testAction?.systemAttachmentLifetime).to.beNil()
}
$0.it("generates scheme capturing screenshots and not deleting") {
let xcscheme = try self.makeSnapshotScheme(
buildTarget: buildTarget,
captureScreenshotsAutomatically: true,
deleteScreenshotsWhenEachTestSucceeds: false)
try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepAlways
}
$0.it("generates scheme not capturing screenshots") {
let xcscheme = try self.makeSnapshotScheme(
buildTarget: buildTarget,
captureScreenshotsAutomatically: false,
deleteScreenshotsWhenEachTestSucceeds: false)
try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepNever
}
$0.it("ignores screenshot delete preference when not capturing screenshots") {
let xcscheme = try self.makeSnapshotScheme(
buildTarget: buildTarget,
captureScreenshotsAutomatically: false,
deleteScreenshotsWhenEachTestSucceeds: true)
try expect(xcscheme.testAction?.systemAttachmentLifetime) == .keepNever
}
$0.it("generate test plans ") {
let testPlanPath1 = "\(fixturePath.string)/TestProject/App_iOS/App_iOS.xctestplan"
let testPlanPath2 = "\(fixturePath.string)/TestProject/App_iOS/App_iOS.xctestplan"
let scheme = Scheme(
name: "TestScheme",
build: Scheme.Build(targets: [buildTarget]),
test: Scheme.Test(config: "Debug", testPlans: [
.init(path: testPlanPath1, defaultPlan: false),
.init(path: testPlanPath2, defaultPlan: true),
])
)
let project = Project(
name: "test",
targets: [app, framework],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.testPlans) == [
.init(reference: "container:\(testPlanPath1)", default: false),
.init(reference: "container:\(testPlanPath2)", default: true),
]
}
$0.it("generates scheme with screenshots as preferred screen capture format") {
let scheme = Scheme(
name: "MyScheme",
build: Scheme.Build(targets: [buildTarget]),
run: Scheme.Run(config: "Debug"),
test: Scheme.Test(config: "Debug", preferredScreenCaptureFormat: .screenshots)
)
let project = Project(
name: "test",
targets: [app, framework],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.preferredScreenCaptureFormat) == .screenshots
}
$0.it("generates scheme with screen recording as preferred screen capture format") {
let scheme = Scheme(
name: "MyScheme",
build: Scheme.Build(targets: [buildTarget]),
run: Scheme.Run(config: "Debug"),
test: Scheme.Test(config: "Debug", preferredScreenCaptureFormat: .screenRecording)
)
let project = Project(
name: "test",
targets: [app, framework],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
try expect(xcscheme.testAction?.preferredScreenCaptureFormat) == .screenRecording
}
}
}
func testOverrideLastUpgradeVersionWhenUserDidSpecify() throws {
var target = app
target.scheme = TargetScheme()
let lastUpgradeKey = "LastUpgradeCheck"
let lastUpgradeValue = "1234"
let attributes: [String: Any] = [lastUpgradeKey: lastUpgradeValue]
let project = Project(name: "test", targets: [target, framework], attributes: attributes)
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
XCTAssertEqual(xcscheme.lastUpgradeVersion, lastUpgradeValue)
}
func testDefaultLastUpgradeVersionWhenUserDidNotSpecify() throws {
var target = app
target.scheme = TargetScheme()
let project = Project(name: "test", targets: [target, framework])
let xcodeProject = try project.generateXcodeProject()
let xcscheme = try unwrap(xcodeProject.sharedData?.schemes.first)
XCTAssertEqual(xcscheme.lastUpgradeVersion, project.xcodeVersion)
}
func testGenerateSchemeManagementOnHiddenTargetScheme() throws {
var target = app
target.scheme = TargetScheme(management: Scheme.Management(isShown: false))
let project = Project(name: "test", targets: [target, framework])
let xcodeProject = try project.generateXcodeProject()
let xcSchemeManagement = try XCTUnwrap(xcodeProject.userData.first?.schemeManagement)
XCTAssertEqual(xcSchemeManagement.schemeUserState![0].name, "MyApp.xcscheme")
XCTAssertEqual(xcSchemeManagement.schemeUserState![0].shared, true)
XCTAssertEqual(xcSchemeManagement.schemeUserState![0].isShown, false)
XCTAssertEqual(xcSchemeManagement.schemeUserState![0].orderHint, nil)
}
// MARK: - Helpers
private func makeWatchScheme(appType: PBXProductType, extensionType: PBXProductType) throws -> XCScheme {
let watchExtension = Target(
name: "WatchExtension",
type: extensionType,
platform: .watchOS
)
let watchApp = Target(
name: "WatchApp",
type: appType,
platform: .watchOS,
dependencies: [Dependency(type: .target, reference: watchExtension.name)],
scheme: TargetScheme(storeKitConfiguration: "Configuration.storekit")
)
let hostApp = Target(
name: "HostApp",
type: .application,
platform: .iOS,
dependencies: [Dependency(type: .target, reference: watchApp.name)]
)
let project = Project(
name: "watch_test",
targets: [hostApp, watchApp, watchExtension],
options: .init(schemePathPrefix: "../")
)
let xcodeProject = try project.generateXcodeProject()
return try unwrap(xcodeProject.sharedData?.schemes.first)
}
private func makeSnapshotScheme(buildTarget: Scheme.BuildTarget, captureScreenshotsAutomatically: Bool, deleteScreenshotsWhenEachTestSucceeds: Bool) throws -> XCScheme {
let scheme = Scheme(
name: "MyScheme",
build: Scheme.Build(targets: [buildTarget]),
run: Scheme.Run(config: "Debug"),
test: Scheme.Test(config: "Debug", captureScreenshotsAutomatically: captureScreenshotsAutomatically, deleteScreenshotsWhenEachTestSucceeds: deleteScreenshotsWhenEachTestSucceeds)
)
let project = Project(
name: "test",
targets: [app, framework],
schemes: [scheme]
)
let xcodeProject = try project.generateXcodeProject()
return try unwrap(xcodeProject.sharedData?.schemes.first)
}
}
File diff suppressed because it is too large Load Diff