test(templates): add template coverage

This commit is contained in:
csh 2026-01-21 10:51:48 +08:00
parent fc230b7ff9
commit b2eb475a6d
6 changed files with 288 additions and 2 deletions

View File

@ -137,6 +137,7 @@ jobs:
}
run_bats "sync_standards" "test_sync_standards.bats"
run_bats "sync_templates" "test_sync_templates.bats"
run_bats "vendor_playbook" "test_vendor_playbook.bats"
run_bats "install_codex_skills" "test_install_codex_skills.bats"
@ -171,6 +172,7 @@ jobs:
run_validator "python" "validate_python_templates.sh"
run_validator "cpp" "validate_cpp_templates.sh"
run_validator "ci" "validate_ci_templates.sh"
run_validator "project_templates" "validate_project_templates.sh"
echo "========================================"
echo "🔗 集成测试"

View File

@ -9,12 +9,14 @@ tests/
├── README.md # 本文件:测试文档
├── scripts/ # Shell 脚本测试bats
│ ├── test_sync_standards.bats # sync_standards.sh 测试
│ ├── test_sync_templates.bats # sync_templates.sh 测试
│ ├── test_vendor_playbook.bats # vendor_playbook.sh 测试
│ └── test_install_codex_skills.bats # install_codex_skills.sh 测试
├── templates/ # 模板验证测试
│ ├── validate_python_templates.sh # Python 模板验证
│ ├── validate_cpp_templates.sh # C++ 模板验证
│ └── validate_ci_templates.sh # CI 模板验证
│ ├── validate_ci_templates.sh # CI 模板验证
│ └── validate_project_templates.sh # 项目模板验证
└── integration/ # 集成测试
└── check_doc_links.sh # 文档链接有效性检查
```
@ -31,6 +33,7 @@ cd /path/to/playbook
sudo apt-get install bats # Ubuntu/Debian
cd tests/scripts
bats test_sync_standards.bats
bats test_sync_templates.bats
bats test_vendor_playbook.bats
bats test_install_codex_skills.bats
@ -39,6 +42,7 @@ cd tests/templates
sh validate_python_templates.sh
sh validate_cpp_templates.sh
sh validate_ci_templates.sh
sh validate_project_templates.sh
# 3. 运行集成测试
cd tests/integration
@ -88,6 +92,21 @@ sh check_doc_links.sh
- **幂等性**
- 多次执行结果一致
#### test_sync_templates.bats
测试 `scripts/sync_templates.sh` 脚本的功能:
- **基础同步**
- 同步 memory-bank/ 与 docs/prompts/
- 创建 AGENTS.md / AGENT_RULES.md / TODO.md / CONFIRM.md
- **占位符替换**
- `{{PROJECT_NAME}}``{{DATE}}`
- **目录覆盖策略**
- 无 `--force` 时不覆盖已有目录
- `--force` 时覆盖并备份
- **AGENTS.md 更新**
- `--full` 更新 framework 区块
#### test_vendor_playbook.bats
测试 `scripts/vendor_playbook.sh` 脚本的功能:
@ -227,6 +246,22 @@ sh check_doc_links.sh
- 包含 README 说明文档
- 包含使用说明
#### validate_project_templates.sh
验证项目通用模板:
- **核心模板**
- `templates/AGENTS.template.md`
- `templates/AGENT_RULES.template.md`
- `templates/README.md`
- **memory-bank 模板**
- 项目定位/技术栈/架构/进度/决策/实施计划
- **prompts 模板**
- `prompts/README.md`
- `prompts/system/agent-behavior.template.md`
- `prompts/coding/clarify.template.md`
- `prompts/coding/verify.template.md`
### 3. 集成测试 (integration/)
端到端测试,验证整体功能。
@ -236,7 +271,7 @@ sh check_doc_links.sh
检查所有 Markdown 文档中的链接有效性:
- **扫描范围**
- 所有 `*.md` 文件
- 所有 `*.md` 文件(排除 `*.template.md`
- 排除 node_modules, .git, build, dist 等目录
- **链接类型**
- Markdown 链接:`[text](link)`
@ -296,6 +331,7 @@ pip3 install yamllint
# Shell 脚本测试
cd tests/scripts
bats test_sync_standards.bats --tap # TAP 格式输出
bats test_sync_templates.bats
bats test_vendor_playbook.bats --formatter junit # JUnit 格式
# 模板验证测试
@ -303,6 +339,7 @@ cd tests/templates
sh validate_python_templates.sh
sh validate_cpp_templates.sh
sh validate_ci_templates.sh
sh validate_project_templates.sh
# 集成测试
cd tests/integration

View File

@ -127,6 +127,7 @@ echo "🔍 扫描 Markdown 文件..."
cd "$PLAYBOOK_ROOT"
MD_FILES=$(find . -name "*.md" \
-not -name "*.template.md" \
-not -path "*/node_modules/*" \
-not -path "*/.git/*" \
-not -path "*/build/*" \

View File

@ -0,0 +1,86 @@
#!/usr/bin/env bats
# sync_templates.sh 测试套件
setup() {
export PLAYBOOK_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)"
export SCRIPT_PATH="$PLAYBOOK_ROOT/scripts/sync_templates.sh"
export TARGET_DIR="$(mktemp -d)"
}
teardown() {
if [ -n "$TARGET_DIR" ] && [ -d "$TARGET_DIR" ]; then
chmod -R u+w "$TARGET_DIR" 2>/dev/null || true
rm -rf "$TARGET_DIR"
fi
}
# ==============================================
# 基础功能测试
# ==============================================
@test "sync_templates.sh 脚本存在且可执行" {
[ -f "$SCRIPT_PATH" ]
}
@test "sync_templates.sh - 基础同步与占位符替换" {
sh "$SCRIPT_PATH" --project-name "DemoProject" --date "2026-02-03" "$TARGET_DIR"
[ -d "$TARGET_DIR/memory-bank" ]
[ -f "$TARGET_DIR/memory-bank/project-brief.md" ]
[ -f "$TARGET_DIR/docs/prompts/coding/clarify.md" ]
[ -f "$TARGET_DIR/AGENTS.md" ]
[ -f "$TARGET_DIR/AGENT_RULES.md" ]
[ -f "$TARGET_DIR/TODO.md" ]
[ -f "$TARGET_DIR/CONFIRM.md" ]
grep -q "DemoProject" "$TARGET_DIR/memory-bank/project-brief.md"
! grep -q "{{DATE}}" "$TARGET_DIR/TODO.md"
[ -z "$(find "$TARGET_DIR" -name '*.template.md' -print -quit)" ]
}
@test "sync_templates.sh - 已存在目录不覆盖 (无 --force)" {
mkdir -p "$TARGET_DIR/memory-bank"
mkdir -p "$TARGET_DIR/docs/prompts"
echo "keep" > "$TARGET_DIR/memory-bank/keep.md"
echo "keep" > "$TARGET_DIR/docs/prompts/keep.md"
sh "$SCRIPT_PATH" "$TARGET_DIR"
[ -f "$TARGET_DIR/memory-bank/keep.md" ]
[ ! -f "$TARGET_DIR/memory-bank/project-brief.md" ]
[ -f "$TARGET_DIR/docs/prompts/keep.md" ]
[ ! -f "$TARGET_DIR/docs/prompts/README.md" ]
}
@test "sync_templates.sh - --force 覆盖并备份" {
mkdir -p "$TARGET_DIR/memory-bank"
echo "marker" > "$TARGET_DIR/memory-bank/marker.txt"
sh "$SCRIPT_PATH" --force "$TARGET_DIR"
[ -f "$TARGET_DIR/memory-bank/project-brief.md" ]
[ ! -f "$TARGET_DIR/memory-bank/marker.txt" ]
backup_dir="$(ls -d "$TARGET_DIR"/memory-bank.bak.* 2>/dev/null | head -n 1)"
[ -n "$backup_dir" ]
[ -f "$backup_dir/marker.txt" ]
}
@test "sync_templates.sh - --full 更新 framework 区块" {
cat > "$TARGET_DIR/AGENTS.md" << 'EOF'
# Agent Instructions
<!-- playbook:framework:start -->
OLD_FRAMEWORK
<!-- playbook:framework:end -->
Footer
EOF
sh "$SCRIPT_PATH" --full "$TARGET_DIR"
! grep -q "OLD_FRAMEWORK" "$TARGET_DIR/AGENTS.md"
grep -q "<!-- playbook:framework:start -->" "$TARGET_DIR/AGENTS.md"
grep -q "Footer" "$TARGET_DIR/AGENTS.md"
}

View File

@ -176,6 +176,20 @@ teardown() {
[ -d "docs/standards/playbook/templates/ci" ]
}
@test "vendor_playbook.sh - --apply-templates 应用模板到项目根目录" {
cd "$TARGET_DIR"
sh "$SCRIPT_PATH" "$TARGET_DIR" cpp --apply-templates
if [ -f "$PLAYBOOK_ROOT/templates/cpp/.clang-format" ]; then
[ -f ".clang-format" ]
fi
if [ -f "$PLAYBOOK_ROOT/templates/ci/gitea/.gitea/workflows/standards-check.yml" ]; then
[ -f ".gitea/workflows/standards-check.yml" ]
fi
}
# ==============================================
# 目标目录处理测试
# ==============================================

View File

@ -0,0 +1,146 @@
#!/usr/bin/env sh
# 项目模板验证脚本
set -eu
echo "========================================"
echo "🧩 项目模板验证"
echo "========================================"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PLAYBOOK_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
TEMPLATES_DIR="$PLAYBOOK_ROOT/templates"
VALIDATION_PASSED=0
VALIDATION_FAILED=0
ERRORS_FILE="/tmp/project_template_validation_errors.txt"
REPORT_FILE="$SCRIPT_DIR/project_templates_report.txt"
> "$ERRORS_FILE"
> "$REPORT_FILE"
echo "📁 模板目录: $TEMPLATES_DIR"
echo ""
# ============================================
# 辅助函数
# ============================================
validate_file_exists() {
local file="$1"
local description="$2"
if [ -f "$file" ]; then
echo "$description: $(basename "$file")"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
return 0
else
echo "$description: $(basename "$file") - 文件不存在"
echo "文件不存在: $file" >> "$ERRORS_FILE"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
return 1
fi
}
validate_contains() {
local file="$1"
local needle="$2"
local description="$3"
if grep -Fq "$needle" "$file"; then
echo "$description"
VALIDATION_PASSED=$((VALIDATION_PASSED + 1))
else
echo "$description"
echo "缺少内容: $needle in $file" >> "$ERRORS_FILE"
VALIDATION_FAILED=$((VALIDATION_FAILED + 1))
fi
}
echo "🔍 验证核心模板文件"
AGENTS_TEMPLATE="$TEMPLATES_DIR/AGENTS.template.md"
AGENT_RULES_TEMPLATE="$TEMPLATES_DIR/AGENT_RULES.template.md"
README_TEMPLATE="$TEMPLATES_DIR/README.md"
if validate_file_exists "$AGENTS_TEMPLATE" "AGENTS.template.md"; then
validate_contains "$AGENTS_TEMPLATE" "<!-- playbook:templates:start -->" "包含 templates 标记"
validate_contains "$AGENTS_TEMPLATE" "<!-- playbook:framework:start -->" "包含 framework 标记"
validate_contains "$AGENTS_TEMPLATE" "{{DATE}}" "包含 {{DATE}} 占位符"
fi
if validate_file_exists "$AGENT_RULES_TEMPLATE" "AGENT_RULES.template.md"; then
validate_contains "$AGENT_RULES_TEMPLATE" "AGENT_RULES" "包含 AGENT_RULES 标题"
validate_contains "$AGENT_RULES_TEMPLATE" "{{DATE}}" "包含 {{DATE}} 占位符"
fi
validate_file_exists "$README_TEMPLATE" "templates/README.md"
echo ""
echo "🔍 验证 memory-bank 模板"
MEMORY_BANK_DIR="$TEMPLATES_DIR/memory-bank"
for name in project-brief tech-stack architecture progress decisions implementation-plan; do
validate_file_exists "$MEMORY_BANK_DIR/$name.template.md" "memory-bank/$name.template.md"
done
echo ""
echo "🔍 验证 prompts 模板"
PROMPTS_DIR="$TEMPLATES_DIR/prompts"
validate_file_exists "$PROMPTS_DIR/README.md" "prompts/README.md"
validate_file_exists "$PROMPTS_DIR/system/agent-behavior.template.md" "prompts/system/agent-behavior.template.md"
validate_file_exists "$PROMPTS_DIR/coding/clarify.template.md" "prompts/coding/clarify.template.md"
validate_file_exists "$PROMPTS_DIR/coding/verify.template.md" "prompts/coding/verify.template.md"
echo ""
# ============================================
# 生成验证报告
# ============================================
echo "========================================"
echo "📊 验证结果统计"
echo "========================================"
echo "✅ 通过: $VALIDATION_PASSED"
echo "❌ 失败: $VALIDATION_FAILED"
if [ $((VALIDATION_PASSED + VALIDATION_FAILED)) -gt 0 ]; then
echo "📈 通过率: $(awk "BEGIN {printf \"%.1f\", ($VALIDATION_PASSED * 100.0) / ($VALIDATION_PASSED + $VALIDATION_FAILED)}")%"
else
echo "📈 通过率: N/A (无测试项)"
fi
echo ""
{
echo "项目模板验证报告"
echo "===================="
echo ""
echo "验证时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "模板目录: $TEMPLATES_DIR"
echo ""
echo "统计结果:"
echo " 通过: $VALIDATION_PASSED"
echo " 失败: $VALIDATION_FAILED"
if [ $((VALIDATION_PASSED + VALIDATION_FAILED)) -gt 0 ]; then
echo " 通过率: $(awk "BEGIN {printf \"%.1f\", ($VALIDATION_PASSED * 100.0) / ($VALIDATION_PASSED + $VALIDATION_FAILED)}")%"
fi
echo ""
if [ -s "$ERRORS_FILE" ]; then
echo "错误详情:"
cat "$ERRORS_FILE"
fi
} > "$REPORT_FILE"
echo "📄 详细报告: $REPORT_FILE"
echo "========================================"
rm -f "$ERRORS_FILE"
if [ "$VALIDATION_FAILED" -eq 0 ]; then
echo "✅ 所有项目模板验证通过"
exit 0
else
echo "❌ 项目模板验证失败 ($VALIDATION_FAILED 个错误)"
exit 1
fi