import { describe, it, expect } from "vitest"; import { findNextPendingIndex, countByStatus, buildTaskPrompt, normalizeToUnixPath, type TaskLoopTask, } from "./taskLoop"; const makeTask = (id: string, status: TaskLoopTask["status"] = "pending"): TaskLoopTask => ({ id, title: `Task ${id}`, prompt: `Do the thing for ${id}`, priority: "medium", status, }); describe("findNextPendingIndex", () => { it("returns -1 for an empty list", () => { expect(findNextPendingIndex([])).toBe(-1); }); it("returns 0 when the first task is pending", () => { const tasks = [makeTask("1", "pending"), makeTask("2", "pending")]; expect(findNextPendingIndex(tasks)).toBe(0); }); it("skips completed and failed tasks to find the next pending", () => { const tasks = [ makeTask("1", "completed"), makeTask("2", "failed"), makeTask("3", "pending"), makeTask("4", "pending"), ]; expect(findNextPendingIndex(tasks)).toBe(2); }); it("returns -1 when all tasks are completed", () => { const tasks = [makeTask("1", "completed"), makeTask("2", "completed")]; expect(findNextPendingIndex(tasks)).toBe(-1); }); it("skips running tasks", () => { const tasks = [makeTask("1", "running"), makeTask("2", "pending")]; expect(findNextPendingIndex(tasks)).toBe(1); }); }); describe("countByStatus", () => { it("returns 0 for an empty list", () => { expect(countByStatus([], "pending")).toBe(0); }); it("counts only tasks with the specified status", () => { const tasks = [ makeTask("1", "pending"), makeTask("2", "completed"), makeTask("3", "pending"), makeTask("4", "failed"), ]; expect(countByStatus(tasks, "pending")).toBe(2); expect(countByStatus(tasks, "completed")).toBe(1); expect(countByStatus(tasks, "failed")).toBe(1); expect(countByStatus(tasks, "running")).toBe(0); }); it("counts all tasks when all have the same status", () => { const tasks = [makeTask("1", "completed"), makeTask("2", "completed")]; expect(countByStatus(tasks, "completed")).toBe(2); }); }); describe("buildTaskPrompt", () => { it("includes the task number and total", () => { const task = makeTask("1"); const result = buildTaskPrompt(task, 1, 5); expect(result).toContain("1/5"); }); it("includes the task title", () => { const task = makeTask("abc"); const result = buildTaskPrompt(task, 2, 3); expect(result).toContain("Task abc"); }); it("includes the task prompt", () => { const task = makeTask("x"); const result = buildTaskPrompt(task, 1, 1); expect(result).toContain("Do the thing for x"); }); it("labels the output as an automated task loop entry", () => { const task = makeTask("1"); const result = buildTaskPrompt(task, 1, 1); expect(result).toContain("Automated Task Loop"); }); }); describe("normalizeToUnixPath", () => { it("converts a WSL UNC path with wsl.localhost to a Unix path", () => { expect( normalizeToUnixPath("\\\\wsl.localhost\\Ubuntu\\home\\naomi\\code\\temp\\file.json") ).toBe("/home/naomi/code/temp/file.json"); }); it("converts a WSL UNC path with wsl$ (legacy) to a Unix path", () => { expect(normalizeToUnixPath("\\\\wsl$\\Ubuntu\\home\\naomi\\file.json")).toBe( "/home/naomi/file.json" ); }); it("handles forward-slash UNC paths produced by some tools", () => { expect(normalizeToUnixPath("//wsl.localhost/Ubuntu/home/naomi/file.json")).toBe( "/home/naomi/file.json" ); }); it("leaves a plain Unix path unchanged", () => { expect(normalizeToUnixPath("/home/naomi/code/temp/file.json")).toBe( "/home/naomi/code/temp/file.json" ); }); it("leaves an empty string unchanged", () => { expect(normalizeToUnixPath("")).toBe(""); }); });