#!/usr/bin/env bats # vendor_playbook.sh 测试套件 # 测试辅助函数 setup() { # 创建临时测试目录 export TEST_DIR="$(mktemp -d)" export PLAYBOOK_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)" export SCRIPT_PATH="$PLAYBOOK_ROOT/scripts/vendor_playbook.sh" # 创建目标项目目录 export TARGET_DIR="$(mktemp -d)" cd "$TARGET_DIR" git init -b main git config user.name "Test User" git config user.email "test@example.com" } teardown() { # 清理测试目录 if [ -n "$TEST_DIR" ] && [ -d "$TEST_DIR" ]; then chmod -R u+w "$TEST_DIR" 2>/dev/null || true rm -rf "$TEST_DIR" fi if [ -n "$TARGET_DIR" ] && [ -d "$TARGET_DIR" ]; then chmod -R u+w "$TARGET_DIR" 2>/dev/null || true rm -rf "$TARGET_DIR" fi } # ============================================== # 基础功能测试 # ============================================== @test "vendor_playbook.sh 脚本存在且可执行" { [ -f "$SCRIPT_PATH" ] } @test "vendor_playbook.sh - 无参数时显示用法" { cd "$TARGET_DIR" run sh "$SCRIPT_PATH" [ "$status" -ne 0 ] } @test "vendor_playbook.sh - 单语言 vendoring (tsl)" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 验证快照目录结构 [ -d "docs/standards/playbook" ] [ -d "docs/standards/playbook/docs/common" ] [ -d "docs/standards/playbook/docs/tsl" ] [ -d "docs/standards/playbook/rulesets/tsl" ] [ -f "docs/standards/playbook/scripts/sync_standards.sh" ] } @test "vendor_playbook.sh - 多语言 vendoring (tsl cpp)" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl cpp # 验证包含两种语言的文档 [ -d "docs/standards/playbook/docs/tsl" ] [ -d "docs/standards/playbook/docs/cpp" ] [ -d "docs/standards/playbook/rulesets/tsl" ] [ -d "docs/standards/playbook/rulesets/cpp" ] } # ============================================== # 自动同步测试 # ============================================== @test "vendor_playbook.sh - 自动执行 sync_standards" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 验证根目录已同步规则集 [ -d ".agents/tsl" ] [ -f ".agents/tsl/index.md" ] [ -f ".gitattributes" ] } @test "vendor_playbook.sh - 多语言自动同步" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl cpp # 验证两个规则集都已同步 [ -d ".agents/tsl" ] [ -d ".agents/cpp" ] [ -f ".agents/index.md" ] } # ============================================== # SOURCE.md 生成测试 # ============================================== @test "vendor_playbook.sh - 生成 SOURCE.md" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl [ -f "docs/standards/playbook/SOURCE.md" ] grep -q "Source:" docs/standards/playbook/SOURCE.md grep -q "Commit:" docs/standards/playbook/SOURCE.md } @test "vendor_playbook.sh - SOURCE.md 包含 commit hash" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 验证包含 commit hash(40个十六进制字符) grep -E "[0-9a-f]{40}" docs/standards/playbook/SOURCE.md } @test "vendor_playbook.sh - SOURCE.md 包含时间戳" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 验证包含日期格式 YYYY-MM-DD grep -E "[0-9]{4}-[0-9]{2}-[0-9]{2}" docs/standards/playbook/SOURCE.md } # ============================================== # 裁剪功能测试 # ============================================== @test "裁剪 - 仅包含指定语言的文档" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 验证包含 TSL 文档 [ -d "docs/standards/playbook/docs/tsl" ] # 验证不包含其他语言(如果原本有 Python) if [ -d "$PLAYBOOK_ROOT/docs/python" ]; then [ ! -d "docs/standards/playbook/docs/python" ] fi } @test "裁剪 - 始终包含 common 目录" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl [ -d "docs/standards/playbook/docs/common" ] [ -f "docs/standards/playbook/docs/common/commit_message.md" ] } @test "裁剪 - 包含对应的模板文件" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" cpp # 验证包含 C++ 模板 [ -d "docs/standards/playbook/templates/cpp" ] # 验证不包含 Python 模板(如果指定了 cpp) if [ -d "$PLAYBOOK_ROOT/templates/python" ]; then [ ! -d "docs/standards/playbook/templates/python" ] fi } @test "裁剪 - 包含通用 CI 模板" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl [ -d "docs/standards/playbook/templates/ci" ] } # ============================================== # 目标目录处理测试 # ============================================== @test "目标目录 - 已存在时覆盖更新" { cd "$TARGET_DIR" # 首次 vendor sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 在快照中添加标记文件 touch docs/standards/playbook/OLD_MARKER # 再次 vendor sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 验证旧标记不存在(已被覆盖) [ ! -f "docs/standards/playbook/OLD_MARKER" ] } @test "目标目录 - 创建必要的父目录" { cd "$TARGET_DIR" # 确保 docs/standards 不存在 [ ! -d "docs/standards" ] sh "$SCRIPT_PATH" "$TARGET_DIR" tsl [ -d "docs/standards/playbook" ] } # ============================================== # 错误处理测试 # ============================================== @test "错误处理 - 目标目录不存在时报错" { cd "$TARGET_DIR" missing_dir="$TEST_DIR/missing-project" rm -rf "$missing_dir" run sh "$SCRIPT_PATH" "$missing_dir" tsl [ "$status" -ne 0 ] } @test "错误处理 - 无效语言参数时报错" { cd "$TARGET_DIR" run sh "$SCRIPT_PATH" "$TARGET_DIR" invalid_lang [ "$status" -ne 0 ] } @test "错误处理 - 目标目录不是 git 仓库时警告" { cd "$TARGET_DIR" rm -rf .git run sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 应该给出警告但不失败 [ "$status" -eq 0 ] } # ============================================== # 完整性测试 # ============================================== @test "完整性 - 验证所有必要文件已复制" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 验证关键文件 [ -f "docs/standards/playbook/README.md" ] [ -f "docs/standards/playbook/docs/index.md" ] [ -f "docs/standards/playbook/.gitattributes" ] [ -f "docs/standards/playbook/scripts/sync_standards.sh" ] [ -f "docs/standards/playbook/SOURCE.md" ] } @test "完整性 - 验证脚本可执行性" { cd "$TARGET_DIR" sh "$SCRIPT_PATH" "$TARGET_DIR" tsl # 验证同步脚本可执行 run sh docs/standards/playbook/scripts/sync_standards.sh tsl [ "$status" -eq 0 ] } # ============================================== # 多次执行测试 # ============================================== @test "幂等性 - 多次 vendor 结果一致" { cd "$TARGET_DIR" # 第一次 vendor sh "$SCRIPT_PATH" "$TARGET_DIR" tsl CHECKSUM1=$(find docs/standards/playbook -type f -name "*.md" ! -name "SOURCE.md" -exec md5sum {} \; | sort | md5sum) # 第二次 vendor sh "$SCRIPT_PATH" "$TARGET_DIR" tsl CHECKSUM2=$(find docs/standards/playbook -type f -name "*.md" ! -name "SOURCE.md" -exec md5sum {} \; | sort | md5sum) [ "$CHECKSUM1" = "$CHECKSUM2" ] }