Files
orca/src/relay/git-handler-worktree-paths.test.ts
T

104 lines
3.3 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import * as path from 'path'
import type { GitExec } from './git-handler-ops'
import { removeWorktreeOp } from './git-handler-worktree-ops'
function lineWorktreeList(...entries: { path: string; branch?: string }[]): string {
return entries
.map((entry, index) =>
[
`worktree ${entry.path}`,
`HEAD ${index}`,
...(entry.branch ? [`branch refs/heads/${entry.branch}`] : [])
].join('\n')
)
.join('\n\n')
}
function nulWorktreeList(...entries: { path: string; branch?: string }[]): string {
return entries
.map((entry, index) =>
[
`worktree ${entry.path}`,
`HEAD ${index}`,
...(entry.branch ? [`branch refs/heads/${entry.branch}`] : []),
''
].join('\0')
)
.join('\0')
}
function resolvedRepoPath(): string {
return path.posix.resolve('/repo-feature', '/repo/.git', '..')
}
describe('relay worktree path parsing', () => {
it('deletes the matching branch for SSH worktrees whose paths contain newlines', async () => {
const worktreePath = '/repo-feature\nremote'
let listCount = 0
const git = vi.fn<GitExec>(async (args) => {
if (args[0] === 'rev-parse') {
return { stdout: '/repo/.git\n', stderr: '' }
}
if (args[0] === 'worktree' && args[1] === 'list') {
listCount += 1
return {
stdout:
listCount === 1
? nulWorktreeList(
{ path: '/repo', branch: 'main' },
{ path: worktreePath, branch: 'feature/newline' }
)
: nulWorktreeList({ path: '/repo', branch: 'main' }),
stderr: ''
}
}
return { stdout: '', stderr: '' }
})
await removeWorktreeOp(git, { worktreePath })
expect(git).toHaveBeenCalledWith(['branch', '-d', '--', 'feature/newline'], resolvedRepoPath())
})
it('falls back to line-block worktree listing when remote Git rejects -z', async () => {
const calls: string[] = []
let listCount = 0
const git = vi.fn<GitExec>(async (args, cwd) => {
calls.push(`${cwd}$ ${args.join(' ')}`)
if (args[0] === 'rev-parse') {
return { stdout: '/repo/.git\n', stderr: '' }
}
if (args[0] === 'worktree' && args[1] === 'list' && args.includes('-z')) {
throw Object.assign(new Error("unknown switch `z'"), {
stderr: "error: unknown switch `z'"
})
}
if (args[0] === 'worktree' && args[1] === 'list') {
listCount += 1
return {
stdout:
listCount === 1
? lineWorktreeList(
{ path: '/repo', branch: 'main' },
{ path: '/repo-feature', branch: 'feature/test' }
)
: lineWorktreeList({ path: '/repo', branch: 'main' }),
stderr: ''
}
}
return { stdout: '', stderr: '' }
})
await removeWorktreeOp(git, { worktreePath: '/repo-feature' })
expect(calls).toEqual([
'/repo-feature$ rev-parse --git-common-dir',
`${resolvedRepoPath()}$ worktree list --porcelain -z`,
`${resolvedRepoPath()}$ worktree list --porcelain`,
`${resolvedRepoPath()}$ worktree remove /repo-feature`,
`${resolvedRepoPath()}$ branch -d -- feature/test`
])
})
})