test-sdd-workspace.sh 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #!/usr/bin/env bash
  2. # Tests for the SDD workspace: scripts/sdd-workspace resolves a self-ignoring
  3. # working-tree directory for SDD artifacts, and the SDD scripts write into it.
  4. set -euo pipefail
  5. SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  6. REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
  7. SDD_SCRIPTS="$REPO_ROOT/skills/subagent-driven-development/scripts"
  8. FAILURES=0
  9. TEST_ROOT=""
  10. pass() { echo " [PASS] $1"; }
  11. fail() {
  12. echo " [FAIL] $1"
  13. FAILURES=$((FAILURES + 1))
  14. }
  15. cleanup() {
  16. if [[ -n "$TEST_ROOT" && -d "$TEST_ROOT" ]]; then
  17. rm -rf "$TEST_ROOT"
  18. fi
  19. }
  20. main() {
  21. echo "=== Test: sdd-workspace ==="
  22. TEST_ROOT="$(mktemp -d)"
  23. trap cleanup EXIT
  24. # Resolve repo to its physical path so string comparisons match the
  25. # helper's output (git rev-parse --show-toplevel resolves symlinks; on
  26. # macOS mktemp lives under /var -> /private/var).
  27. git init -q -b main "$TEST_ROOT/repo"
  28. local repo
  29. repo="$(cd "$TEST_ROOT/repo" && git rev-parse --show-toplevel)"
  30. local dir
  31. dir="$(cd "$repo" && "$SDD_SCRIPTS/sdd-workspace")"
  32. if [[ "$dir" == "$repo/.superpowers/sdd" ]]; then
  33. pass "prints <repo-root>/.superpowers/sdd"
  34. else
  35. fail "prints <repo-root>/.superpowers/sdd"
  36. echo " got: $dir"
  37. fi
  38. if [[ -f "$repo/.superpowers/sdd/.gitignore" && "$(cat "$repo/.superpowers/sdd/.gitignore")" == "*" ]]; then
  39. pass "self-ignoring .gitignore created with '*'"
  40. else
  41. fail "self-ignoring .gitignore created with '*'"
  42. fi
  43. printf 'x\n' > "$repo/.superpowers/sdd/artifact.md"
  44. local status
  45. status="$(cd "$repo" && git status --porcelain)"
  46. if [[ -z "$status" ]]; then
  47. pass "workspace invisible to git status"
  48. else
  49. fail "workspace invisible to git status"
  50. echo " status: $status"
  51. fi
  52. ( cd "$repo" && git add -A )
  53. local staged
  54. staged="$(cd "$repo" && git diff --cached --name-only)"
  55. if [[ -z "$staged" ]]; then
  56. pass "git add -A does not stage the workspace"
  57. else
  58. fail "git add -A does not stage the workspace"
  59. echo " staged: $staged"
  60. fi
  61. cat > "$repo/plan.md" <<'PLAN'
  62. # Plan
  63. ## Task 1: First thing
  64. Do the first thing.
  65. PLAN
  66. local brief_out brief_path
  67. brief_out="$(cd "$repo" && "$SDD_SCRIPTS/task-brief" plan.md 1)"
  68. brief_path="$(printf '%s\n' "$brief_out" | sed -n 's/^wrote \(.*\): [0-9][0-9]* lines$/\1/p')"
  69. case "$brief_path" in
  70. "$repo/.superpowers/sdd/"*) pass "task-brief writes its brief under the workspace" ;;
  71. *)
  72. fail "task-brief writes its brief under the workspace"
  73. echo " got: $brief_path"
  74. ;;
  75. esac
  76. local git_id=(-c user.email=t@example.com -c user.name=t -c commit.gpgsign=false)
  77. ( cd "$repo" \
  78. && git add plan.md \
  79. && git "${git_id[@]}" commit -qm c1 \
  80. && printf 'y\n' > f && git add f \
  81. && git "${git_id[@]}" commit -qm c2 )
  82. local rp_out rp_path
  83. rp_out="$(cd "$repo" && "$SDD_SCRIPTS/review-package" HEAD~1 HEAD)"
  84. rp_path="$(printf '%s\n' "$rp_out" | sed -n 's/^wrote \(.*\): [0-9].*$/\1/p')"
  85. case "$rp_path" in
  86. "$repo/.superpowers/sdd/"*) pass "review-package writes its diff under the workspace" ;;
  87. *)
  88. fail "review-package writes its diff under the workspace"
  89. echo " got: $rp_path"
  90. ;;
  91. esac
  92. # --- Worktree isolation: a linked worktree resolves its own workspace ---
  93. local wt="$TEST_ROOT/wt"
  94. ( cd "$repo" && git worktree add -q "$wt" -b wt-feature )
  95. local wt_root wt_dir
  96. wt_root="$(cd "$wt" && git rev-parse --show-toplevel)"
  97. wt_dir="$(cd "$wt" && "$SDD_SCRIPTS/sdd-workspace")"
  98. if [[ "$wt_dir" == "$wt_root/.superpowers/sdd" && "$wt_dir" != "$dir" ]]; then
  99. pass "linked worktree resolves its own distinct workspace"
  100. else
  101. fail "linked worktree resolves its own distinct workspace"
  102. echo " main: $dir"
  103. echo " wt: $wt_dir"
  104. fi
  105. printf 'y\n' > "$wt/.superpowers/sdd/artifact.md"
  106. local wt_status
  107. wt_status="$(cd "$wt" && git status --porcelain)"
  108. if [[ -z "$wt_status" ]]; then
  109. pass "worktree workspace invisible to git status"
  110. else
  111. fail "worktree workspace invisible to git status"
  112. echo " status: $wt_status"
  113. fi
  114. echo ""
  115. if [[ "$FAILURES" -ne 0 ]]; then
  116. echo "FAILED: $FAILURES assertion(s)."
  117. exit 1
  118. fi
  119. echo "PASS"
  120. }
  121. main "$@"