diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-25 15:35:14 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-25 15:35:14 -0500 |
| commit | f2609d9f9ad33486bef43211d753ba53e1e24181 (patch) | |
| tree | 561f0514866570d47c446816daa131ce13064639 /scripts/tests/git-worktree-gate.bats | |
| parent | 3203bd803b6a05d10781634e7e18742879c1046a (diff) | |
| download | rulesets-main.tar.gz rulesets-main.zip | |
Centralize repository-state checks, bind teardown to a certified clean HEAD, and allow inbox-only refreshes. Guard installed symlinks from cross-project writes and add regression coverage.
Diffstat (limited to 'scripts/tests/git-worktree-gate.bats')
| -rwxr-xr-x | scripts/tests/git-worktree-gate.bats | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/scripts/tests/git-worktree-gate.bats b/scripts/tests/git-worktree-gate.bats new file mode 100755 index 0000000..7d0d8a1 --- /dev/null +++ b/scripts/tests/git-worktree-gate.bats @@ -0,0 +1,146 @@ +#!/usr/bin/env bats + +setup() { + REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)" + GATE="$REPO_ROOT/claude-templates/bin/git-worktree-gate" + WORK="$(mktemp -d)" + REPO="$WORK/repo" + git init -q "$REPO" + git -C "$REPO" config user.email test@example.com + git -C "$REPO" config user.name tester + printf 'base\n' >"$REPO/tracked" + git -C "$REPO" add tracked + git -C "$REPO" commit -qm init +} + +teardown() { + rm -rf "$WORK" +} + +@test "strict accepts a completely clean worktree" { + run bash "$GATE" strict "$REPO" + [ "$status" -eq 0 ] + [ -z "$output" ] +} + +@test "strict rejects unstaged, staged, and untracked changes with paths" { + printf 'changed\n' >>"$REPO/tracked" + printf 'new\n' >"$REPO/staged" + git -C "$REPO" add staged + printf 'loose\n' >"$REPO/loose" + + run bash "$GATE" strict "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"wrap blocked"* ]] + [[ "$output" == *"tracked"* ]] + [[ "$output" == *"staged"* ]] + [[ "$output" == *"loose"* ]] +} + +@test "sync-safe permits untracked inbox deliveries and strict still rejects them" { + mkdir -p "$REPO/inbox/nested" + printf 'handoff\n' >"$REPO/inbox/nested/from-home.org" + + run bash "$GATE" sync-safe "$REPO" + [ "$status" -eq 0 ] + + run bash "$GATE" strict "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"inbox/nested/from-home.org"* ]] +} + +@test "sync-safe rejects tracked changes even inside inbox" { + mkdir -p "$REPO/inbox" + printf 'tracked\n' >"$REPO/inbox/tracked.org" + git -C "$REPO" add inbox/tracked.org + git -C "$REPO" commit -qm inbox + printf 'changed\n' >>"$REPO/inbox/tracked.org" + + run bash "$GATE" sync-safe "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"inbox/tracked.org"* ]] +} + +@test "sync-safe rejects untracked files outside inbox" { + printf 'scratch\n' >"$REPO/scratch" + run bash "$GATE" sync-safe "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"scratch"* ]] +} + +@test "ignored files do not block either policy" { + printf 'cache/\n' >"$REPO/.gitignore" + git -C "$REPO" add .gitignore + git -C "$REPO" commit -qm ignore + mkdir -p "$REPO/cache" + printf 'generated\n' >"$REPO/cache/output" + + run bash "$GATE" strict "$REPO" + [ "$status" -eq 0 ] + run bash "$GATE" sync-safe "$REPO" + [ "$status" -eq 0 ] +} + +@test "reports unusual filenames without losing the entry" { + odd=$'line break\nname' + printf 'odd\n' >"$REPO/$odd" + run bash "$GATE" strict "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"line"* ]] + [[ "$output" == *"name"* ]] +} + +@test "certify and verify bind a clean worktree to its current HEAD" { + run bash "$GATE" certify "$REPO" + [ "$status" -eq 0 ] + run bash "$GATE" verify "$REPO" + [ "$status" -eq 0 ] + + git -C "$REPO" commit -q --allow-empty -m later + run bash "$GATE" verify "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"HEAD changed"* ]] +} + +@test "verify rejects changes made after certification" { + run bash "$GATE" certify "$REPO" + [ "$status" -eq 0 ] + printf 'late\n' >>"$REPO/tracked" + run bash "$GATE" verify "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"tracked"* ]] +} + +@test "dirty submodule blocks strict and sync-safe" { + CHILD="$WORK/child" + git init -q "$CHILD" + git -C "$CHILD" config user.email test@example.com + git -C "$CHILD" config user.name tester + printf 'child\n' >"$CHILD/file" + git -C "$CHILD" add file + git -C "$CHILD" commit -qm init + git -C "$REPO" -c protocol.file.allow=always submodule add -q "$CHILD" sub + git -C "$REPO" commit -qam submodule + printf 'dirty\n' >>"$REPO/sub/file" + + run bash "$GATE" strict "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"sub"* ]] + run bash "$GATE" sync-safe "$REPO" + [ "$status" -eq 1 ] +} + +@test "a low-level git status failure blocks instead of looking clean" { + printf 'not an index\n' >"$WORK/bad-index" + run env GIT_INDEX_FILE="$WORK/bad-index" bash "$GATE" strict "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"git status failed"* ]] +} + +@test "an in-progress sequencer operation blocks a clean-looking tree" { + gitdir="$(git -C "$REPO" rev-parse --absolute-git-dir)" + mkdir -p "$gitdir/sequencer" + run bash "$GATE" strict "$REPO" + [ "$status" -eq 1 ] + [[ "$output" == *"sequencer"* ]] +} |
