code-stats.sh 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #!/bin/bash
  2. # Functional tests for code-stats skill
  3. # Tests tokei and difft CLI tools
  4. set -euo pipefail
  5. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  6. FIXTURES="$SCRIPT_DIR/../fixtures"
  7. PROJECT_ROOT="$SCRIPT_DIR/../../.."
  8. # Colors
  9. RED='\033[0;31m'
  10. GREEN='\033[0;32m'
  11. YELLOW='\033[1;33m'
  12. NC='\033[0m'
  13. PASSED=0
  14. FAILED=0
  15. SKIPPED=0
  16. pass() { ((PASSED++)); echo -e "${GREEN}✓${NC} $1"; }
  17. fail() { ((FAILED++)); echo -e "${RED}✗${NC} $1: $2"; }
  18. skip() { ((SKIPPED++)); echo -e "${YELLOW}○${NC} $1 (skipped: $2)"; }
  19. check_prereqs() {
  20. local missing=()
  21. command -v tokei >/dev/null 2>&1 || missing+=("tokei")
  22. command -v difft >/dev/null 2>&1 || missing+=("difft")
  23. if [[ ${#missing[@]} -gt 0 ]]; then
  24. echo -e "${YELLOW}Missing tools: ${missing[*]}${NC}"
  25. echo "Install with: brew install ${missing[*]}"
  26. echo "Some tests will be skipped."
  27. echo ""
  28. fi
  29. }
  30. # === tokei Tests ===
  31. test_tokei_basic() {
  32. if ! command -v tokei >/dev/null 2>&1; then
  33. skip "tokei: basic line count" "tokei not installed"
  34. return
  35. fi
  36. local result
  37. result=$(tokei "$PROJECT_ROOT" --compact 2>/dev/null | head -5)
  38. if [[ -n "$result" ]]; then
  39. pass "tokei: basic line count"
  40. else
  41. fail "tokei: basic line count" "no output"
  42. fi
  43. }
  44. test_tokei_json_output() {
  45. if ! command -v tokei >/dev/null 2>&1; then
  46. skip "tokei: JSON output" "tokei not installed"
  47. return
  48. fi
  49. local result
  50. result=$(tokei "$PROJECT_ROOT" -o json 2>/dev/null | jq 'keys | length')
  51. if [[ "$result" -gt 0 ]]; then
  52. pass "tokei: JSON output with languages"
  53. else
  54. fail "tokei: JSON output" "no languages found"
  55. fi
  56. }
  57. test_tokei_exclude() {
  58. if ! command -v tokei >/dev/null 2>&1; then
  59. skip "tokei: exclude directories" "tokei not installed"
  60. return
  61. fi
  62. local with_node without_node
  63. with_node=$(tokei "$PROJECT_ROOT" -o json 2>/dev/null | jq '.Total.code // 0')
  64. without_node=$(tokei "$PROJECT_ROOT" -e node_modules -o json 2>/dev/null | jq '.Total.code // 0')
  65. # Both should be valid numbers
  66. if [[ "$with_node" =~ ^[0-9]+$ && "$without_node" =~ ^[0-9]+$ ]]; then
  67. pass "tokei: exclude directories works"
  68. else
  69. fail "tokei: exclude directories" "invalid output"
  70. fi
  71. }
  72. # === difft Tests ===
  73. test_difft_basic() {
  74. if ! command -v difft >/dev/null 2>&1; then
  75. skip "difft: basic diff" "difft not installed"
  76. return
  77. fi
  78. # Create temp files
  79. local file1 file2
  80. file1=$(mktemp)
  81. file2=$(mktemp)
  82. echo 'function hello() { console.log("hello"); }' > "$file1"
  83. echo 'function hello() { console.log("world"); }' > "$file2"
  84. local result
  85. result=$(difft "$file1" "$file2" 2>/dev/null || true)
  86. rm -f "$file1" "$file2"
  87. if [[ -n "$result" ]]; then
  88. pass "difft: basic file comparison"
  89. else
  90. fail "difft: basic file comparison" "no diff output"
  91. fi
  92. }
  93. test_difft_identical() {
  94. if ! command -v difft >/dev/null 2>&1; then
  95. skip "difft: identical files" "difft not installed"
  96. return
  97. fi
  98. local file1 file2
  99. file1=$(mktemp)
  100. file2=$(mktemp)
  101. echo 'const x = 1;' > "$file1"
  102. echo 'const x = 1;' > "$file2"
  103. local result
  104. result=$(difft "$file1" "$file2" 2>/dev/null || true)
  105. rm -f "$file1" "$file2"
  106. # Identical files should have minimal or no output
  107. if [[ -z "$result" || "$result" == *"No changes"* || ${#result} -lt 50 ]]; then
  108. pass "difft: identical files show no changes"
  109. else
  110. fail "difft: identical files" "unexpected output"
  111. fi
  112. }
  113. test_difft_syntax_aware() {
  114. if ! command -v difft >/dev/null 2>&1; then
  115. skip "difft: syntax-aware diff" "difft not installed"
  116. return
  117. fi
  118. local file1 file2
  119. file1=$(mktemp)
  120. file2=$(mktemp)
  121. mv "$file1" "${file1}.js"; file1="${file1}.js"
  122. mv "$file2" "${file2}.js"; file2="${file2}.js"
  123. cat > "$file1" << 'EOF'
  124. function add(a, b) {
  125. return a + b;
  126. }
  127. EOF
  128. cat > "$file2" << 'EOF'
  129. function add(a, b) {
  130. // Added comment
  131. return a + b;
  132. }
  133. EOF
  134. local result
  135. result=$(difft "$file1" "$file2" 2>/dev/null || true)
  136. rm -f "$file1" "$file2"
  137. if [[ -n "$result" ]]; then
  138. pass "difft: syntax-aware JavaScript diff"
  139. else
  140. fail "difft: syntax-aware diff" "no output"
  141. fi
  142. }
  143. # === Run Tests ===
  144. main() {
  145. echo "=== code-stats functional tests ==="
  146. echo ""
  147. check_prereqs
  148. echo "--- tokei tests ---"
  149. test_tokei_basic
  150. test_tokei_json_output
  151. test_tokei_exclude
  152. echo ""
  153. echo "--- difft tests ---"
  154. test_difft_basic
  155. test_difft_identical
  156. test_difft_syntax_aware
  157. echo ""
  158. echo "=== Results ==="
  159. echo -e "Passed: ${GREEN}$PASSED${NC}"
  160. echo -e "Failed: ${RED}$FAILED${NC}"
  161. echo -e "Skipped: ${YELLOW}$SKIPPED${NC}"
  162. [[ $FAILED -eq 0 ]]
  163. }
  164. main "$@"