test: add bats test suite for lib/ helper scripts
110 tests across 10 test files covering all lib/ scripts: - archeflow-event.sh: JSONL format, seq numbering, parent fields, validation - archeflow-memory.sh: add/list/decay/forget/inject/extract commands - archeflow-git.sh: branch creation, commit format, merge strategies, safety - archeflow-report.sh: markdown output, summary mode, in-progress handling - archeflow-progress.sh: progress.md generation, JSON mode, error handling - archeflow-score.sh: archetype scoring, effectiveness report, validation - archeflow-dag.sh: DAG rendering, color flags, tree structure - archeflow-rollback.sh: arg parsing, phase validation, mutual exclusivity - archeflow-init.sh: template listing, clone from project, arg validation - archeflow-review.sh: diff modes, stats, branch/commit range review Includes test_helper.bash (shared setup/teardown with temp git repos) and scripts/run-tests.sh runner.
This commit is contained in:
212
tests/archeflow-git.bats
Normal file
212
tests/archeflow-git.bats
Normal file
@@ -0,0 +1,212 @@
|
||||
# Tests for archeflow-git.sh — git branch/commit strategy for ArcheFlow runs.
|
||||
#
|
||||
# Validates: branch creation with correct naming, commit formatting,
|
||||
# merge strategies, input validation, and safety guards.
|
||||
|
||||
setup() {
|
||||
load test_helper
|
||||
_common_setup
|
||||
}
|
||||
|
||||
teardown() {
|
||||
_common_teardown
|
||||
}
|
||||
|
||||
# --- Usage ---
|
||||
|
||||
@test "git: exits 1 with usage when called with fewer than 2 args" {
|
||||
run "$LIB_DIR/archeflow-git.sh"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Usage"* ]]
|
||||
}
|
||||
|
||||
@test "git: exits 1 for unknown command" {
|
||||
run "$LIB_DIR/archeflow-git.sh" nonexistent test-run
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Unknown command"* ]]
|
||||
}
|
||||
|
||||
# --- init ---
|
||||
|
||||
@test "git init: creates branch with archeflow/ prefix" {
|
||||
run "$LIB_DIR/archeflow-git.sh" init test-run
|
||||
[ "$status" -eq 0 ]
|
||||
local current
|
||||
current=$(git branch --show-current)
|
||||
[ "$current" = "archeflow/test-run" ]
|
||||
}
|
||||
|
||||
@test "git init: stores base branch in .archeflow/runs/<run_id>/base-branch" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
[ -f ".archeflow/runs/test-run/base-branch" ]
|
||||
local base
|
||||
base=$(cat ".archeflow/runs/test-run/base-branch")
|
||||
[ "$base" = "main" ]
|
||||
}
|
||||
|
||||
@test "git init: fails if branch already exists" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
git checkout main --quiet
|
||||
run "$LIB_DIR/archeflow-git.sh" init test-run
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"already exists"* ]]
|
||||
}
|
||||
|
||||
# --- commit ---
|
||||
|
||||
@test "git commit: uses conventional commit format by default" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
# Create a file to commit
|
||||
mkdir -p .archeflow/events
|
||||
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||
"$LIB_DIR/archeflow-git.sh" commit test-run plan "initial plan" 2>/dev/null
|
||||
local msg
|
||||
msg=$(git log -1 --format=%s)
|
||||
[[ "$msg" == "archeflow(plan): initial plan" ]]
|
||||
}
|
||||
|
||||
@test "git commit: stages event file automatically" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
mkdir -p .archeflow/events
|
||||
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||
"$LIB_DIR/archeflow-git.sh" commit test-run plan "test commit" 2>/dev/null
|
||||
|
||||
# Verify the event file was committed
|
||||
local committed_files
|
||||
committed_files=$(git diff-tree --no-commit-id --name-only -r HEAD)
|
||||
[[ "$committed_files" == *"test-run.jsonl"* ]]
|
||||
}
|
||||
|
||||
@test "git commit: stages extra files passed as arguments" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
echo "extra content" > extra.txt
|
||||
"$LIB_DIR/archeflow-git.sh" commit test-run do "with extras" extra.txt 2>/dev/null
|
||||
local committed_files
|
||||
committed_files=$(git diff-tree --no-commit-id --name-only -r HEAD)
|
||||
[[ "$committed_files" == *"extra.txt"* ]]
|
||||
}
|
||||
|
||||
@test "git commit: reports nothing to commit when no changes" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
# Commit the init artifacts first so there's a clean state
|
||||
git add -A && git commit -m "init artifacts" --quiet 2>/dev/null || true
|
||||
run bash -c "cd '$BATS_TEST_TMPDIR' && '$LIB_DIR/archeflow-git.sh' commit test-run plan 'empty' 2>&1"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Nothing to commit"* ]]
|
||||
}
|
||||
|
||||
@test "git commit: fails if not on the run branch" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
git checkout main --quiet
|
||||
run "$LIB_DIR/archeflow-git.sh" commit test-run plan "wrong branch"
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Expected to be on branch"* ]]
|
||||
}
|
||||
|
||||
# --- phase-commit ---
|
||||
|
||||
@test "git phase-commit: creates commit with phase transition message" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
mkdir -p .archeflow/events
|
||||
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||
"$LIB_DIR/archeflow-git.sh" phase-commit test-run plan 2>/dev/null
|
||||
local msg
|
||||
msg=$(git log -1 --format=%s)
|
||||
# Should contain the phase transition arrow
|
||||
[[ "$msg" == *"plan"* ]]
|
||||
[[ "$msg" == *"do"* ]]
|
||||
}
|
||||
|
||||
# --- merge ---
|
||||
|
||||
@test "git merge: squash merge is the default strategy" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
mkdir -p .archeflow/events
|
||||
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||
"$LIB_DIR/archeflow-git.sh" commit test-run plan "test" 2>/dev/null
|
||||
"$LIB_DIR/archeflow-git.sh" merge test-run 2>/dev/null
|
||||
|
||||
local current
|
||||
current=$(git branch --show-current)
|
||||
[ "$current" = "main" ]
|
||||
|
||||
local msg
|
||||
msg=$(git log -1 --format=%s)
|
||||
[[ "$msg" == *"archeflow run test-run"* ]]
|
||||
}
|
||||
|
||||
@test "git merge: --no-ff creates a merge commit" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
mkdir -p .archeflow/events
|
||||
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||
"$LIB_DIR/archeflow-git.sh" commit test-run plan "test" 2>/dev/null
|
||||
"$LIB_DIR/archeflow-git.sh" merge test-run --no-ff 2>/dev/null
|
||||
|
||||
local current
|
||||
current=$(git branch --show-current)
|
||||
[ "$current" = "main" ]
|
||||
|
||||
# no-ff merge commit should have 2 parents
|
||||
local parent_count
|
||||
parent_count=$(git cat-file -p HEAD | grep -c '^parent')
|
||||
[ "$parent_count" -eq 2 ]
|
||||
}
|
||||
|
||||
@test "git merge: rejects unknown merge strategy" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
mkdir -p .archeflow/events
|
||||
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||
"$LIB_DIR/archeflow-git.sh" commit test-run plan "test" 2>/dev/null
|
||||
run "$LIB_DIR/archeflow-git.sh" merge test-run --fast-forward
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Unknown merge strategy"* ]]
|
||||
}
|
||||
|
||||
@test "git merge: fails with uncommitted changes" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
echo "dirty" > dirty.txt
|
||||
git add dirty.txt
|
||||
run "$LIB_DIR/archeflow-git.sh" merge test-run
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Uncommitted changes"* ]]
|
||||
}
|
||||
|
||||
# --- format_message ---
|
||||
|
||||
@test "git commit: simple style uses 'phase: msg' format" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
# Create config with simple style
|
||||
mkdir -p .archeflow
|
||||
echo "commit_style: simple" > .archeflow/config.yaml
|
||||
mkdir -p .archeflow/events
|
||||
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||
"$LIB_DIR/archeflow-git.sh" commit test-run plan "simple test" 2>/dev/null
|
||||
local msg
|
||||
msg=$(git log -1 --format=%s)
|
||||
[ "$msg" = "plan: simple test" ]
|
||||
}
|
||||
|
||||
# --- status ---
|
||||
|
||||
@test "git status: shows branch info for existing run" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
run "$LIB_DIR/archeflow-git.sh" status test-run
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Branch: archeflow/test-run"* ]]
|
||||
[[ "$output" == *"Base: main"* ]]
|
||||
}
|
||||
|
||||
@test "git status: fails for nonexistent branch" {
|
||||
run "$LIB_DIR/archeflow-git.sh" status nonexistent
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"does not exist"* ]]
|
||||
}
|
||||
|
||||
# --- cleanup ---
|
||||
|
||||
@test "git cleanup: fails if currently on the run branch" {
|
||||
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||
run "$LIB_DIR/archeflow-git.sh" cleanup test-run
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"Cannot delete"* ]]
|
||||
}
|
||||
Reference in New Issue
Block a user