diff --git a/.changeset/fix-3056-worktree-path-assertion.md b/.changeset/fix-3056-worktree-path-assertion.md new file mode 100644 index 000000000..fffe00081 --- /dev/null +++ b/.changeset/fix-3056-worktree-path-assertion.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 3117 +--- +**Worktree prune regression checks are now path-normalized** — pruning safety tests now parse `git worktree list --porcelain` and assert structured normalized paths, preventing path-separator false negatives across platforms while preserving non-destructive prune guarantees. \ No newline at end of file diff --git a/tests/prune-orphaned-worktrees.test.cjs b/tests/prune-orphaned-worktrees.test.cjs index 18756e8f4..bcc14a982 100644 --- a/tests/prune-orphaned-worktrees.test.cjs +++ b/tests/prune-orphaned-worktrees.test.cjs @@ -21,6 +21,24 @@ function getPruneOrphanedWorktrees() { } // Create a minimal git repo with an initial commit on main. +function canonicalPath(p) { + try { + return fs.realpathSync.native(path.resolve(p)); + } catch { + return path.resolve(p); + } +} + +function listedWorktreePaths(repoDir) { + const out = execSync('git worktree list --porcelain', { cwd: repoDir, encoding: 'utf8' }); + return new Set( + out + .split('\n') + .filter((line) => line.startsWith('worktree ')) + .map((line) => canonicalPath(line.slice('worktree '.length).trim())) + ); +} + function createGitRepo(dir) { fs.mkdirSync(dir, { recursive: true }); execSync('git init', { cwd: dir, stdio: 'pipe' }); @@ -79,10 +97,10 @@ describe('pruneOrphanedWorktrees', () => { ); // Assert: git worktree list still shows it - const listOut = execSync('git worktree list', { cwd: repoDir, encoding: 'utf8' }); + const listed = listedWorktreePaths(repoDir); assert.ok( - listOut.includes(worktreeDir), - 'git worktree list should still reference merged worktree:\n' + listOut + listed.has(canonicalPath(worktreeDir)), + 'git worktree list should still reference merged worktree' ); });