diff --git a/Sources/Zero/Services/RunProfileService.swift b/Sources/Zero/Services/RunProfileService.swift index 86db0ce..60bad6b 100644 --- a/Sources/Zero/Services/RunProfileService.swift +++ b/Sources/Zero/Services/RunProfileService.swift @@ -56,11 +56,15 @@ class FileBasedRunProfileService: RunProfileService { return [:] } - guard let store = try? JSONDecoder().decode(RunProfileStore.self, from: data) else { + do { + let store = try JSONDecoder().decode(RunProfileStore.self, from: data) + return store.commandsByRepository + } catch { + AppLogStore.shared.append( + "RunProfileService decode failed for \(configPath): \(error.localizedDescription)" + ) return [:] } - - return store.commandsByRepository } private func writeCommands(_ commands: [String: String]) throws { diff --git a/Tests/ZeroTests/RunProfileServiceTests.swift b/Tests/ZeroTests/RunProfileServiceTests.swift index 3bc533b..4a35b48 100644 --- a/Tests/ZeroTests/RunProfileServiceTests.swift +++ b/Tests/ZeroTests/RunProfileServiceTests.swift @@ -7,11 +7,13 @@ final class RunProfileServiceTests: XCTestCase { override func setUp() { super.setUp() + AppLogStore.shared.clear() testConfigPath = "/tmp/test-zero-run-profiles-\(UUID().uuidString).json" service = FileBasedRunProfileService(configPath: testConfigPath) } override func tearDown() { + AppLogStore.shared.clear() if let testConfigPath { try? FileManager.default.removeItem(atPath: testConfigPath) } @@ -72,4 +74,24 @@ final class RunProfileServiceTests: XCTestCase { // Then XCTAssertEqual(try service.loadCommand(for: repositoryURL), "swift run") } + + func testLoadCommandFromCorruptedStoreAppendsDecodeFailureToAppLogStore() throws { + // Given + let repositoryURL = URL(string: "https://github.com/zero-ide/Zero.git")! + try "{not-valid-json".write( + to: URL(fileURLWithPath: testConfigPath), + atomically: true, + encoding: .utf8 + ) + + // When + let command = try service.loadCommand(for: repositoryURL) + + // Then + XCTAssertNil(command) + let logEntries = AppLogStore.shared.recentEntries() + XCTAssertTrue(logEntries.contains { entry in + entry.contains("RunProfileService decode failed") && entry.contains(testConfigPath) + }) + } }