diff options
Diffstat (limited to '.ai/scripts/tests')
| -rw-r--r-- | .ai/scripts/tests/task-review-staleness.bats | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/.ai/scripts/tests/task-review-staleness.bats b/.ai/scripts/tests/task-review-staleness.bats new file mode 100644 index 0000000..abb7585 --- /dev/null +++ b/.ai/scripts/tests/task-review-staleness.bats @@ -0,0 +1,149 @@ +#!/usr/bin/env bats +# +# Tests for claude-templates/.ai/scripts/task-review-staleness.sh — +# counts top-level todo.org tasks whose review has gone stale. +# +# Strategy: write a synthetic todo.org into a temp dir per test, with +# LAST_REVIEWED dates generated relative to the real `date` (never +# hardcoded). Run the real script against it and assert the count it +# prints on stdout. +# +# Staleness rule under test: +# - A qualifying task is a depth-2 (**) heading with a TODO/DOING/VERIFY +# keyword and an [#A]/[#B]/[#C] priority cookie. +# - It is stale when LAST_REVIEWED is missing/malformed (NIL → oldest), +# or when its age strictly exceeds the threshold (age > N days). +# - age == N exactly is fresh (the spec's wording is ">N days"). + +# The script under test is always the sibling-of-parent of this test file +# (scripts/task-review-staleness.sh next to scripts/tests/). This holds in +# both the canonical claude-templates/ tree and the rsync'd project mirror, +# so the suite runs identically from either location. +SCRIPT="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)/task-review-staleness.sh" + +setup() { + TEST_DIR="$(mktemp -d -t task-review-bats.XXXXXX)" + TODO="$TEST_DIR/todo.org" + + TODAY="$(date +%F)" + D5="$(date -d '5 days ago' +%F)" + D30="$(date -d '30 days ago' +%F)" + D31="$(date -d '31 days ago' +%F)" + D40="$(date -d '40 days ago' +%F)" +} + +teardown() { + rm -rf "$TEST_DIR" +} + +# Emit a qualifying task with an explicit LAST_REVIEWED date. +task_reviewed() { + local keyword="$1" prio="$2" title="$3" date="$4" + printf '** %s [#%s] %s\n:PROPERTIES:\n:LAST_REVIEWED: %s\n:END:\nBody.\n\n' \ + "$keyword" "$prio" "$title" "$date" >> "$TODO" +} + +# Emit a qualifying task with no PROPERTIES drawer at all. +task_unreviewed() { + local keyword="$1" prio="$2" title="$3" + printf '** %s [#%s] %s\nBody.\n\n' "$keyword" "$prio" "$title" >> "$TODO" +} + +# ---- Normal cases ---------------------------------------------------- + +@test "staleness: empty file reports zero" { + : > "$TODO" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "0" ] +} + +@test "staleness: all tasks fresh reports zero" { + task_reviewed TODO A "Fresh one" "$D5" + task_reviewed TODO B "Fresh two" "$D5" + task_reviewed DOING A "Fresh three" "$TODAY" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "0" ] +} + +@test "staleness: all tasks stale reports full count" { + task_reviewed TODO A "Stale one" "$D40" + task_reviewed TODO B "Stale two" "$D40" + task_reviewed VERIFY C "Stale three" "$D40" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "3" ] +} + +@test "staleness: mixed fresh, stale, and unreviewed counts only the latter two" { + task_reviewed TODO A "Fresh" "$D5" + task_reviewed TODO B "Stale" "$D40" + task_unreviewed DOING A "Never reviewed" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "2" ] +} + +# ---- Boundary cases -------------------------------------------------- + +@test "staleness: age exactly equal to threshold is fresh" { + task_reviewed TODO A "Exactly at cutoff" "$D30" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "0" ] +} + +@test "staleness: age one day past threshold is stale" { + task_reviewed TODO A "One day over" "$D31" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "1" ] +} + +@test "staleness: unreviewed task (no drawer) counts as stale" { + task_unreviewed TODO A "Never reviewed" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "1" ] +} + +@test "staleness: threshold of 7 is softer than 30 on the same list" { + task_reviewed TODO A "Reviewed five days ago" "$D5" + task_reviewed TODO B "Reviewed thirty-one days ago" "$D31" + run bash "$SCRIPT" "$TODO" 7 + [ "$status" -eq 0 ] + [ "$output" = "1" ] +} + +# ---- Error / exclusion cases ----------------------------------------- + +@test "staleness: DONE and CANCELLED tasks are excluded even when old" { + task_reviewed DONE A "Shipped long ago" "$D40" + task_reviewed CANCELLED B "Abandoned long ago" "$D40" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "0" ] +} + +@test "staleness: deeper headings and cookie-less headings are excluded" { + # Depth-3 child with an old review date — not a review unit. + printf '*** TODO [#A] Child task\n:PROPERTIES:\n:LAST_REVIEWED: %s\n:END:\n\n' "$D40" >> "$TODO" + # Depth-2 but no priority cookie — not a review unit. + printf '** TODO Cookie-less task\nBody.\n\n' >> "$TODO" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "0" ] +} + +@test "staleness: malformed LAST_REVIEWED is treated as stale" { + task_reviewed TODO A "Bad date" "not-a-date" + run bash "$SCRIPT" "$TODO" 30 + [ "$status" -eq 0 ] + [ "$output" = "1" ] +} + +@test "staleness: missing todo file exits non-zero" { + run bash "$SCRIPT" "$TEST_DIR/does-not-exist.org" 30 + [ "$status" -ne 0 ] +} |
