diff --git a/Sources/Zero/Services/GitService.swift b/Sources/Zero/Services/GitService.swift index 7b321f1..91930aa 100644 --- a/Sources/Zero/Services/GitService.swift +++ b/Sources/Zero/Services/GitService.swift @@ -15,6 +15,11 @@ struct GitFileChange: Codable, Identifiable { let id = UUID() let path: String let changeType: ChangeType + + enum CodingKeys: String, CodingKey { + case path + case changeType + } enum ChangeType: String, Codable { case added = "A" @@ -43,6 +48,14 @@ struct GitBranch: Codable, Identifiable { let isRemote: Bool let commitHash: String? let commitMessage: String? + + enum CodingKeys: String, CodingKey { + case name + case isCurrent + case isRemote + case commitHash + case commitMessage + } } struct GitStash: Codable, Identifiable { @@ -50,6 +63,12 @@ struct GitStash: Codable, Identifiable { let index: Int let hash: String let message: String + + enum CodingKeys: String, CodingKey { + case index + case hash + case message + } } // MARK: - Git Service diff --git a/Tests/ZeroTests/GitServiceTests.swift b/Tests/ZeroTests/GitServiceTests.swift index d46144a..fe37348 100644 --- a/Tests/ZeroTests/GitServiceTests.swift +++ b/Tests/ZeroTests/GitServiceTests.swift @@ -259,4 +259,61 @@ final class GitServiceTests: XCTestCase { // Then XCTAssertEqual(mockRunner.executedScript, "cd /workspace && git commit -m 'feat: it'\"'\"'s done'") } + + func testGitFileChangeEncodingExcludesUIOnlyID() throws { + // Given + let model = GitFileChange(path: "Sources/Zero/main.swift", changeType: .modified) + + // When + let encoded = try JSONEncoder().encode(model) + let payload = try jsonObject(from: encoded) + + // Then + XCTAssertNil(payload["id"]) + XCTAssertEqual(payload["path"] as? String, "Sources/Zero/main.swift") + XCTAssertEqual(payload["changeType"] as? String, "M") + } + + func testGitBranchEncodingExcludesUIOnlyID() throws { + // Given + let model = GitBranch( + name: "main", + isCurrent: true, + isRemote: false, + commitHash: "abc123", + commitMessage: "initial" + ) + + // When + let encoded = try JSONEncoder().encode(model) + let payload = try jsonObject(from: encoded) + + // Then + XCTAssertNil(payload["id"]) + XCTAssertEqual(payload["name"] as? String, "main") + XCTAssertEqual(payload["isCurrent"] as? Bool, true) + } + + func testGitStashEncodingExcludesUIOnlyID() throws { + // Given + let model = GitStash(index: 0, hash: "def456", message: "WIP") + + // When + let encoded = try JSONEncoder().encode(model) + let payload = try jsonObject(from: encoded) + + // Then + XCTAssertNil(payload["id"]) + XCTAssertEqual(payload["index"] as? Int, 0) + XCTAssertEqual(payload["hash"] as? String, "def456") + } + + private func jsonObject(from data: Data) throws -> [String: Any] { + let object = try JSONSerialization.jsonObject(with: data) + guard let dictionary = object as? [String: Any] else { + XCTFail("Expected dictionary JSON object") + return [:] + } + return dictionary + } }