import Foundation import Testing @Test func installationRefusesToReplaceAnUnrelatedApplication() throws { let manager = FileManager.default let root = manager.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true) defer { try? manager.removeItem(at: root) } let source = root.appendingPathComponent("Source/Conjure.app", isDirectory: true) let contents = source.appendingPathComponent("Contents", isDirectory: true) let executables = contents.appendingPathComponent("MacOS", isDirectory: true) try manager.createDirectory(at: executables, withIntermediateDirectories: true) try manager.copyItem(at: URL(fileURLWithPath: "/usr/bin/true"), to: executables.appendingPathComponent("Conjure")) let info: [String: Any] = [ "CFBundleIdentifier": "dev.conjure.launcher", "CFBundleExecutable": "Conjure", "CFBundlePackageType": "APPL", "CFBundleName": "Conjure", ] try PropertyListSerialization.data(fromPropertyList: info, format: .xml, options: 0) .write(to: contents.appendingPathComponent("Info.plist")) let signing = try installationCommand("/usr/bin/codesign", ["--force", "--sign", "-", source.path]) guard signing.status == 0 else { throw InstallationFixtureError(output: signing.output) } let directory = root.appendingPathComponent("Applications", isDirectory: true) let unrelated = directory.appendingPathComponent("Conjure.app", isDirectory: true) let unrelatedContents = unrelated.appendingPathComponent("Contents", isDirectory: true) try manager.createDirectory(at: unrelatedContents, withIntermediateDirectories: true) try PropertyListSerialization.data(fromPropertyList: ["CFBundleIdentifier": "example.unrelated"], format: .xml, options: 0) .write(to: unrelatedContents.appendingPathComponent("Info.plist")) let marker = unrelated.appendingPathComponent("UserData.txt") try Data("Keep this unrelated app".utf8).write(to: marker) let repository = URL(fileURLWithPath: #filePath).deletingLastPathComponent() .deletingLastPathComponent().deletingLastPathComponent() let result = try installationCommand("/usr/bin/swift", [repository.appendingPathComponent("Scripts/install.swift").path, source.path, directory.path]) #expect(result.status != 0) #expect(try String(contentsOf: marker, encoding: .utf8) == "Keep this unrelated app") #expect(Bundle(url: unrelated)?.bundleIdentifier == "example.unrelated") } private struct InstallationFixtureError: Error { let output: String } private func installationCommand(_ executable: String, _ arguments: [String]) throws -> (status: Int32, output: String) { let process = Process() process.executableURL = URL(fileURLWithPath: executable) process.arguments = arguments let output = Pipe() process.standardOutput = output process.standardError = output try process.run() let data = output.fileHandleForReading.readDataToEndOfFile() process.waitUntilExit() return (process.terminationStatus, String(decoding: data, as: UTF8.self)) }