/** * Unit tests for git_worktree_switch validation and resolution functions. * * Tests cover input validation, target resolution, already-there check, * and the integrated tool execute path. */ import { describe, it, expect } from "bun:test"; import { validateSwitchInput, resolveWorktreeTarget, isAlreadyInWorktree, } from "./pi-worktree-switch"; import type { WorktreeEntry } from "./pi-worktree-parser"; // ─── validateSwitchInput ────────────────────────────────────────────── describe("validateSwitchInput (Issue #6)", () => { it("returns null for valid absolute path", () => { const result = validateSwitchInput("/tmp/worktrees/feature-x"); expect(result).toBeNull(); }); it("returns null for valid relative path", () => { const result = validateSwitchInput("../worktrees/feature-x"); expect(result).toBeNull(); }); it("returns null for valid branch name", () => { const result = validateSwitchInput("feature-x"); expect(result).toBeNull(); }); it("returns null for branch name with slashes", () => { const result = validateSwitchInput("feature/my-branch"); expect(result).toBeNull(); }); it("returns error for empty target", () => { const result = validateSwitchInput(""); expect(result).not.toBeNull(); if (result) expect(result.message).toContain("cannot be empty"); }); it("returns error for whitespace-only target", () => { const result = validateSwitchInput(" "); expect(result).not.toBeNull(); }); it("includes suggestion in error for empty target", () => { const result = validateSwitchInput(""); expect(result).not.toBeNull(); if (result) expect(result.suggestion).toBeDefined(); }); }); // ─── resolveWorktreeTarget ──────────────────────────────────────────── describe("resolveWorktreeTarget (Issue #6)", () => { const worktrees: WorktreeEntry[] = [ { path: "/home/user/project", commit: "abc1234", branch: "main", isCurrent: true }, { path: "/tmp/feature-x", commit: "def5678", branch: "feature-x", isCurrent: false }, { path: "/tmp/bugfix", commit: "fedcba9", branch: "bugfix/issue-42", isCurrent: false }, ]; it("resolves by exact path match", () => { const result = resolveWorktreeTarget("/tmp/feature-x", worktrees); expect(result).toBe("/tmp/feature-x"); }); it("resolves by branch name", () => { const result = resolveWorktreeTarget("feature-x", worktrees); expect(result).toBe("/tmp/feature-x"); }); it("resolves branch name with slashes", () => { const result = resolveWorktreeTarget("bugfix/issue-42", worktrees); expect(result).toBe("/tmp/bugfix"); }); it("returns undefined for unknown target", () => { const result = resolveWorktreeTarget("nonexistent", worktrees); expect(result).toBeUndefined(); }); it("returns undefined for unknown path", () => { const result = resolveWorktreeTarget("/tmp/does-not-exist", worktrees); expect(result).toBeUndefined(); }); it("resolves main repo by path", () => { const result = resolveWorktreeTarget("/home/user/project", worktrees); expect(result).toBe("/home/user/project"); }); it("resolves main repo by branch name", () => { const result = resolveWorktreeTarget("main", worktrees); expect(result).toBe("/home/user/project"); }); it("prefers exact path match over branch name match", () => { // If a target matches both a path and a branch name, path wins const result = resolveWorktreeTarget("/tmp/feature-x", worktrees); expect(result).toBe("/tmp/feature-x"); }); it("returns undefined for empty worktree list", () => { const result = resolveWorktreeTarget("anything", []); expect(result).toBeUndefined(); }); }); // ─── isAlreadyInWorktree ────────────────────────────────────────────── describe("isAlreadyInWorktree (Issue #6)", () => { it("returns true when cwd matches target path exactly", () => { const result = isAlreadyInWorktree("/tmp/feature-x", "/tmp/feature-x"); expect(result).toBe(true); }); it("returns false when cwd differs from target path", () => { const result = isAlreadyInWorktree("/tmp/feature-x", "/home/user/project"); expect(result).toBe(false); }); it("returns true when paths match with trailing slash difference", () => { const result = isAlreadyInWorktree("/tmp/feature-x/", "/tmp/feature-x"); expect(result).toBe(true); }); it("returns true when both have trailing slashes", () => { const result = isAlreadyInWorktree("/tmp/feature-x/", "/tmp/feature-x/"); expect(result).toBe(true); }); it("handles relative target path resolved against cwd", () => { // If target is relative and resolves to same as cwd, already there const result = isAlreadyInWorktree(".", "/tmp/feature-x"); expect(result).toBe(true); }); });