/** * Unit tests for parseWorktreeList parser. * * Tests cover normal output, edge cases, malformed input, and path normalization. */ import { describe, it, expect } from "bun:test"; import { parseWorktreeList } from "./pi-worktree-parser"; describe("parseWorktreeList", () => { describe("normal output", () => { it("parses a single worktree entry with branch in brackets", () => { const rawOutput = "/home/user/project abc1234 [main]"; const result = parseWorktreeList(rawOutput, "/home/user/project"); expect(result).toHaveLength(1); expect(result[0].path).toBe("/home/user/project"); expect(result[0].commit).toBe("abc1234"); expect(result[0].branch).toBe("main"); expect(result[0].isCurrent).toBe(true); }); it("parses multiple worktree entries", () => { const rawOutput = `/home/user/project abc1234 [main] /home/user/feature-x def5678 [feature-x]`; const result = parseWorktreeList(rawOutput, "/home/user/project"); expect(result).toHaveLength(2); expect(result[0].branch).toBe("main"); expect(result[0].isCurrent).toBe(true); expect(result[1].branch).toBe("feature-x"); expect(result[1].isCurrent).toBe(false); }); it("handles detached HEAD entries", () => { const rawOutput = "/home/user/detached fedcba9 HEAD"; const result = parseWorktreeList(rawOutput, "/other/path"); expect(result).toHaveLength(1); expect(result[0].branch).toBe("(detached)"); expect(result[0].commit).toBe("fedcba9"); }); }); describe("path normalization (Task 001)", () => { it("marks isCurrent=true when paths match with trailing slash difference", () => { const rawOutput = "/home/user/project abc1234 [main]"; const result = parseWorktreeList(rawOutput, "/home/user/project/"); expect(result[0].isCurrent).toBe(true); }); it("marks isCurrent=true when paths match with different casing in components", () => { const rawOutput = "/home/user/Project abc1234 [main]"; // On Linux, path.resolve preserves case — this tests normalization of slashes const result = parseWorktreeList(rawOutput, "/home/user/Project/"); expect(result[0].isCurrent).toBe(true); }); }); describe("malformed input validation (Task 002)", () => { it("skips lines with fewer than 3 tokens", () => { const rawOutput = `/home/user/project abc1234 [main] /incomplete/path`; const result = parseWorktreeList(rawOutput, "/other"); expect(result).toHaveLength(1); expect(result[0].path).toBe("/home/user/project"); }); it("skips lines with only 2 tokens (missing branch)", () => { const rawOutput = `/home/user/project abc1234 [main] /incomplete/path def5678`; const result = parseWorktreeList(rawOutput, "/other"); expect(result).toHaveLength(1); }); it("returns empty array for completely malformed input", () => { const rawOutput = `just some random text`; const result = parseWorktreeList(rawOutput, "/any/path"); expect(result).toHaveLength(0); }); }); describe("empty input (Task 006)", () => { it("returns empty array for empty string", () => { const result = parseWorktreeList("", "/some/path"); expect(result).toHaveLength(0); }); it("returns empty array for whitespace-only input", () => { const result = parseWorktreeList(" \n \n ", "/some/path"); expect(result).toHaveLength(0); }); }); describe("branch names with special characters", () => { it("handles branch names with hyphens and slashes", () => { const rawOutput = "/home/user/feature abc1234 [feature/my-branch-name]"; const result = parseWorktreeList(rawOutput, "/other"); expect(result).toHaveLength(1); expect(result[0].branch).toBe("feature/my-branch-name"); }); it("handles branch names with underscores", () => { const rawOutput = "/home/user/feature abc1234 [issue_42_fix]"; const result = parseWorktreeList(rawOutput, "/other"); expect(result).toHaveLength(1); expect(result[0].branch).toBe("issue_42_fix"); }); }); });