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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Xcodes/Backend/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ class AppState: ObservableObject {
try await uninstallXcodeAsync(path: installedXcodePath)
try Task.checkCancellation()
await updateSelectedXcodePathAsync()
await updateInstalledXcodesAsync()
} catch is CancellationError {
} catch {
self.error = error
Expand Down Expand Up @@ -881,11 +882,13 @@ class AppState: ObservableObject {
// MARK: - Private

private func uninstallXcodeAsync(path: Path) async throws {
let xcode = InstalledXcode(
guard let xcode = InstalledXcode(
path: path,
contentsAtPath: { path in Current.files.contents(atPath: path) },
loadArchitectures: Current.shell.archs
)!
) else {
throw FileError.fileNotFound(path.string)
}
_ = try XcodeUninstallService(
removeItem: { url in try Current.files.removeItem(at: url) },
trashItem: { url in try Current.files.trashItem(at: url) }
Expand Down
46 changes: 46 additions & 0 deletions XcodesTests/AppStateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,52 @@ class AppStateTests: XCTestCase {
XCTAssertEqual(subject.selectedXcodePath, secondPath.string)
}

func test_Uninstall_MissingXcodePresentsFileNotFoundError() async throws {
let missingPath = try XCTUnwrap(Path("/Applications/Xcode-Missing.app"))
let xcode = Xcode(version: Version("15.0.0")!, installState: .installed(missingPath), selected: false, icon: nil)
let didTryToTrashItem = TestLockedBox(false)
Current.files.contentsAtPath = { _ in nil }
Current.files.trashItem = { _ in
didTryToTrashItem.withValue { $0 = true }
return URL(fileURLWithPath: "\(NSHomeDirectory())/.Trash")
}

subject.uninstall(xcode: xcode)
let uninstallTask = try XCTUnwrap(subject.uninstallTask)
await uninstallTask.value

guard case let .generic(title, message) = subject.presentedAlert else {
return XCTFail("Expected generic uninstall error alert")
}
XCTAssertEqual(title, localizeString("Alert.Uninstall.Error.Title"))
XCTAssertEqual(
message,
String(format: localizeString("Alert.Uninstall.Error.Message.FileNotFound"), missingPath.string)
)
XCTAssertFalse(didTryToTrashItem.read { $0 })
}

func test_Uninstall_RefreshesInstalledXcodeList() async throws {
let installedPath = try XCTUnwrap(Path("/Applications/Xcode-0.0.0.app"))
let version = try XCTUnwrap(Version("0.0.0"))
subject.availableXcodes = [
AvailableXcode(version: version, url: URL(string: "https://apple.com/xcode.xip")!, filename: "mock.xip", releaseDate: nil)
]
subject.allXcodes = [
Xcode(version: version, installState: .installed(installedPath), selected: true, icon: nil)
]
Current.files.installedXcodes = { _ in [] }
Current.shell.xcodeSelectPrintPath = {
ProcessOutput(status: 0, out: "", err: "")
}

subject.uninstall(xcode: subject.allXcodes[0])
let uninstallTask = try XCTUnwrap(subject.uninstallTask)
await uninstallTask.value

XCTAssertEqual(subject.allXcodes[0].installState, .notInstalled)
}

func test_Signout_RemovesCookiesFromDownloadSession() throws {
let session = URLSession(configuration: .ephemeral)
Current.network.session = session
Expand Down
Loading