claude-code/docs/test-plans/08-git-utils.md
2026-04-01 21:19:41 +08:00

4.4 KiB
Raw Blame History

Git 工具测试计划

概述

Git 工具模块提供 git 远程 URL 规范化、仓库根目录查找、裸仓库安全检测等功能。测试重点是纯函数的 URL 规范化和需要文件系统 mock 的仓库发现逻辑。

被测文件

文件 关键导出
src/utils/git.ts normalizeGitRemoteUrl, findGitRoot, findCanonicalGitRoot, getIsGit, isAtGitRoot, getRepoRemoteHash, isCurrentDirectoryBareGitRepo, gitExe, getGitState, stashToCleanState, preserveGitStateForIssue

测试用例

describe('normalizeGitRemoteUrl')(纯函数)

SSH 格式

  • test('normalizes SSH URL') — 'git@github.com:owner/repo.git''github.com/owner/repo'
  • test('normalizes SSH URL without .git suffix') — 'git@github.com:owner/repo''github.com/owner/repo'
  • test('handles GitLab SSH') — 'git@gitlab.com:group/subgroup/repo.git''gitlab.com/group/subgroup/repo'

HTTPS 格式

  • test('normalizes HTTPS URL') — 'https://github.com/owner/repo.git''github.com/owner/repo'
  • test('normalizes HTTPS URL without .git suffix') — 'https://github.com/owner/repo''github.com/owner/repo'
  • test('normalizes HTTP URL') — 'http://github.com/owner/repo.git''github.com/owner/repo'

SSH:// 协议格式

  • test('normalizes ssh:// URL') — 'ssh://git@github.com/owner/repo''github.com/owner/repo'
  • test('handles user prefix in ssh://') — 'ssh://user@host/path''host/path'

代理 URLCCR git proxy

  • test('normalizes legacy proxy URL') — 'http://local_proxy@127.0.0.1:16583/git/owner/repo''github.com/owner/repo'
  • test('normalizes GHE proxy URL') — 'http://user@127.0.0.1:8080/git/ghe.company.com/owner/repo''ghe.company.com/owner/repo'

边界情况

  • test('returns null for empty string') — '' → null
  • test('returns null for whitespace') — ' ' → null
  • test('returns null for unrecognized format') — 'not-a-url' → null
  • test('output is lowercase') — 'git@GitHub.com:Owner/Repo.git''github.com/owner/repo'
  • test('SSH and HTTPS for same repo produce same result') — 相同仓库不同协议 → 相同输出

describe('findGitRoot')(需文件系统 Mock

  • test('finds git root from nested directory') — /project/src/utils//project/(假设 /project/.git 存在)
  • test('finds git root from root directory') — /project//project/
  • test('returns null for non-git directory') — 无 .git → null
  • test('handles worktree .git file') — .git 为文件时也识别
  • test('memoizes results') — 同一路径不重复查找

describe('findCanonicalGitRoot')

  • test('returns same as findGitRoot for regular repo')
  • test('resolves worktree to main repo root') — worktree 路径 → 主仓库根目录
  • test('returns null for non-git directory')

describe('gitExe')

  • test('returns git path string') — 返回字符串
  • test('memoizes the result') — 多次调用返回同一值

describe('getRepoRemoteHash')(需 Mock

  • test('returns 16-char hex hash') — 返回值为 16 位十六进制字符串
  • test('returns null when no remote') — 无 remote URL 时返回 null
  • test('same repo SSH/HTTPS produce same hash') — 不同协议同一仓库 hash 相同

describe('isCurrentDirectoryBareGitRepo')(需文件系统 Mock

  • test('detects bare git repo attack vector') — 目录含 HEAD + objects/ + refs/ 但无有效 .git/HEAD → true
  • test('returns false for normal directory') — 普通目录 → false
  • test('returns false for regular git repo') — 有效 .git 目录 → false

Mock 需求

依赖 Mock 方式 说明
statSync mock module findGitRoot 中的 .git 检测
readFileSync mock module worktree .git 文件读取
realpathSync mock module 路径解析
execFileNoThrow mock module git 命令执行
whichSync mock module gitExe 中的 git 路径查找
getCwd mock module 当前工作目录
getRemoteUrl mock module getRepoRemoteHash 依赖
临时目录 mkdtemp 集成测试中创建临时 git 仓库

集成测试场景

describe('Git repo discovery')(放在 tests/integration/

  • test('findGitRoot works in actual git repo') — 在临时 git init 的目录中验证
  • test('normalizeGitRemoteUrl + getRepoRemoteHash produces stable hash') — URL → hash 端到端验证