import * as fs from "fs" import { describe, it, expect } from "vitest" import { parseTodoFile } from "../../src/file.js" import { serializeTodoFile, serializeIssue, serializeSprints, serializeRelationships, } from "../../src/serializer.js" describe("serializeRelationships", () => { it("serializes empty relationships", () => { expect(serializeRelationships({})).toBe("") }) it("serializes single relationship", () => { expect(serializeRelationships({ dependsOn: [3] })).toBe("dependsOn:3") }) it("serializes multiple relationships", () => { const result = serializeRelationships({ dependsOn: [3, 4], blocks: [7] }) expect(result).toContain("dependsOn:3 4") expect(result).toContain("blocks:7") }) }) describe("serializeSprints", () => { it("serializes empty sprints", () => { expect(serializeSprints([])).toBe("Sprints:") }) it("serializes sprint list", () => { const result = serializeSprints([ { name: "Alpha", start: "2026-02-01", end: "2026-02-14" }, ]) expect(result).toContain("Sprints:") expect(result).toContain("- Name: Alpha") expect(result).toContain("Range: 2026-02-01..2026-02-14") }) }) describe("serializeIssue", () => { it("serializes an issue with all fields", () => { const result = serializeIssue({ id: 1, type: "feature", title: "Test", status: "open", priority: "high", created: "2026-02-05", relationships: { dependsOn: [3] }, description: "A test issue", body: "", }) expect(result).toContain("ID: 1") expect(result).toContain("Type: feature") expect(result).toContain("Title: Test") expect(result).toContain("Status: open") expect(result).toContain("Priority: high") expect(result).toContain("Created: 2026-02-05") expect(result).toContain("Relationships: dependsOn:3") expect(result).toContain("Description: A test issue") }) it("serializes multi-line description", () => { const result = serializeIssue({ id: 1, type: "feature", title: "Test", status: "open", priority: "high", created: "2026-02-05", relationships: {}, description: "Line one\nLine two", body: "", }) expect(result).toContain("Description: Line one") expect(result).toContain(" Line two") }) }) describe("round-trip", () => { it("parse → serialize → parse produces equivalent data", async () => { const todo1 = await parseTodoFile("tests/_mocks/todo-basic.txt") const serialized = serializeTodoFile(todo1) // Write to temp location for re-parsing const tmpPath = "tests/_mocks/_roundtrip.txt" fs.writeFileSync(tmpPath, serialized) try { const todo2 = await parseTodoFile(tmpPath) expect(todo2.sprints.length).toBe(todo1.sprints.length) expect(todo2.issues.length).toBe(todo1.issues.length) for (let i = 0; i < todo1.sprints.length; i++) { expect(todo2.sprints[i].name).toBe(todo1.sprints[i].name) expect(todo2.sprints[i].start).toBe(todo1.sprints[i].start) expect(todo2.sprints[i].end).toBe(todo1.sprints[i].end) } for (let i = 0; i < todo1.issues.length; i++) { expect(todo2.issues[i].id).toBe(todo1.issues[i].id) expect(todo2.issues[i].type).toBe(todo1.issues[i].type) expect(todo2.issues[i].title).toBe(todo1.issues[i].title) expect(todo2.issues[i].status).toBe(todo1.issues[i].status) expect(todo2.issues[i].priority).toBe(todo1.issues[i].priority) expect(todo2.issues[i].created).toBe(todo1.issues[i].created) expect(todo2.issues[i].description).toBe(todo1.issues[i].description) } } finally { fs.unlinkSync(tmpPath) } }) it("round-trips issues-only file", async () => { const todo1 = await parseTodoFile("tests/_mocks/todo-issues-only.txt") const serialized = serializeTodoFile(todo1) const tmpPath = "tests/_mocks/_roundtrip2.txt" fs.writeFileSync(tmpPath, serialized) try { const todo2 = await parseTodoFile(tmpPath) expect(todo2.issues.length).toBe(todo1.issues.length) expect(todo2.sprints.length).toBe(0) } finally { fs.unlinkSync(tmpPath) } }) })