test-helpers.sh 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #!/usr/bin/env bash
  2. # Helper functions for Claude Code skill tests
  3. # Run Claude Code with a prompt and capture output
  4. # Usage: run_claude "prompt text" [timeout_seconds]
  5. run_claude() {
  6. local prompt="$1"
  7. local timeout="${2:-60}"
  8. local output_file=$(mktemp)
  9. # Run Claude in headless mode with timeout
  10. if timeout "$timeout" claude -p "$prompt" > "$output_file" 2>&1; then
  11. cat "$output_file"
  12. rm -f "$output_file"
  13. return 0
  14. else
  15. local exit_code=$?
  16. cat "$output_file" >&2
  17. rm -f "$output_file"
  18. return $exit_code
  19. fi
  20. }
  21. # Check if output contains a pattern
  22. # Usage: assert_contains "output" "pattern" "test name"
  23. assert_contains() {
  24. local output="$1"
  25. local pattern="$2"
  26. local test_name="${3:-test}"
  27. if echo "$output" | grep -q "$pattern"; then
  28. echo " [PASS] $test_name"
  29. return 0
  30. else
  31. echo " [FAIL] $test_name"
  32. echo " Expected to find: $pattern"
  33. echo " In output:"
  34. echo "$output" | sed 's/^/ /'
  35. return 1
  36. fi
  37. }
  38. # Check if output does NOT contain a pattern
  39. # Usage: assert_not_contains "output" "pattern" "test name"
  40. assert_not_contains() {
  41. local output="$1"
  42. local pattern="$2"
  43. local test_name="${3:-test}"
  44. if echo "$output" | grep -q "$pattern"; then
  45. echo " [FAIL] $test_name"
  46. echo " Did not expect to find: $pattern"
  47. echo " In output:"
  48. echo "$output" | sed 's/^/ /'
  49. return 1
  50. else
  51. echo " [PASS] $test_name"
  52. return 0
  53. fi
  54. }
  55. # Check if output matches a count
  56. # Usage: assert_count "output" "pattern" expected_count "test name"
  57. assert_count() {
  58. local output="$1"
  59. local pattern="$2"
  60. local expected="$3"
  61. local test_name="${4:-test}"
  62. local actual=$(echo "$output" | grep -c "$pattern" || echo "0")
  63. if [ "$actual" -eq "$expected" ]; then
  64. echo " [PASS] $test_name (found $actual instances)"
  65. return 0
  66. else
  67. echo " [FAIL] $test_name"
  68. echo " Expected $expected instances of: $pattern"
  69. echo " Found $actual instances"
  70. echo " In output:"
  71. echo "$output" | sed 's/^/ /'
  72. return 1
  73. fi
  74. }
  75. # Check if pattern A appears before pattern B
  76. # Usage: assert_order "output" "pattern_a" "pattern_b" "test name"
  77. assert_order() {
  78. local output="$1"
  79. local pattern_a="$2"
  80. local pattern_b="$3"
  81. local test_name="${4:-test}"
  82. # Get line numbers where patterns appear
  83. local line_a=$(echo "$output" | grep -n "$pattern_a" | head -1 | cut -d: -f1)
  84. local line_b=$(echo "$output" | grep -n "$pattern_b" | head -1 | cut -d: -f1)
  85. if [ -z "$line_a" ]; then
  86. echo " [FAIL] $test_name: pattern A not found: $pattern_a"
  87. return 1
  88. fi
  89. if [ -z "$line_b" ]; then
  90. echo " [FAIL] $test_name: pattern B not found: $pattern_b"
  91. return 1
  92. fi
  93. if [ "$line_a" -lt "$line_b" ]; then
  94. echo " [PASS] $test_name (A at line $line_a, B at line $line_b)"
  95. return 0
  96. else
  97. echo " [FAIL] $test_name"
  98. echo " Expected '$pattern_a' before '$pattern_b'"
  99. echo " But found A at line $line_a, B at line $line_b"
  100. return 1
  101. fi
  102. }
  103. # Create a temporary test project directory
  104. # Usage: test_project=$(create_test_project)
  105. create_test_project() {
  106. local test_dir=$(mktemp -d)
  107. echo "$test_dir"
  108. }
  109. # Cleanup test project
  110. # Usage: cleanup_test_project "$test_dir"
  111. cleanup_test_project() {
  112. local test_dir="$1"
  113. if [ -d "$test_dir" ]; then
  114. rm -rf "$test_dir"
  115. fi
  116. }
  117. # Create a simple plan file for testing
  118. # Usage: create_test_plan "$project_dir" "$plan_name"
  119. create_test_plan() {
  120. local project_dir="$1"
  121. local plan_name="${2:-test-plan}"
  122. local plan_file="$project_dir/docs/plans/$plan_name.md"
  123. mkdir -p "$(dirname "$plan_file")"
  124. cat > "$plan_file" <<'EOF'
  125. # Test Implementation Plan
  126. ## Task 1: Create Hello Function
  127. Create a simple hello function that returns "Hello, World!".
  128. **File:** `src/hello.js`
  129. **Implementation:**
  130. ```javascript
  131. export function hello() {
  132. return "Hello, World!";
  133. }
  134. ```
  135. **Tests:** Write a test that verifies the function returns the expected string.
  136. **Verification:** `npm test`
  137. ## Task 2: Create Goodbye Function
  138. Create a goodbye function that takes a name and returns a goodbye message.
  139. **File:** `src/goodbye.js`
  140. **Implementation:**
  141. ```javascript
  142. export function goodbye(name) {
  143. return `Goodbye, ${name}!`;
  144. }
  145. ```
  146. **Tests:** Write tests for:
  147. - Default name
  148. - Custom name
  149. - Edge cases (empty string, null)
  150. **Verification:** `npm test`
  151. EOF
  152. echo "$plan_file"
  153. }
  154. # Export functions for use in tests
  155. export -f run_claude
  156. export -f assert_contains
  157. export -f assert_not_contains
  158. export -f assert_count
  159. export -f assert_order
  160. export -f create_test_project
  161. export -f cleanup_test_project
  162. export -f create_test_plan