#!/usr/bin/env bash # # Test script for command_modifies_file function in loop-common.sh # # Tests the regex patterns used to detect file modification commands # to ensure proper blocking of file writes via Bash. # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "$PROJECT_ROOT/hooks/lib/loop-common.sh" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' NC='\033[0m' # No Color TESTS_PASSED=0 TESTS_FAILED=0 # Test helper functions pass() { echo -e "${GREEN}PASS${NC}: $1" TESTS_PASSED=$((TESTS_PASSED + 1)) } fail() { echo -e "${RED}FAIL${NC}: $1" echo " Command: $2" echo " Expected: $3" TESTS_FAILED=$((TESTS_FAILED + 1)) } # Assert that a command SHOULD be detected as modifying the target file assert_modifies() { local command="$1" local pattern="${2:-goal-tracker\\.md}" local command_lower command_lower=$(to_lower "$command") if command_modifies_file "$command_lower" "$pattern"; then pass "Correctly detected modification: $command" else fail "Should detect modification" "$command" "should match pattern" fi } # Assert that a command should NOT be detected as modifying the target file assert_not_modifies() { local command="$1" local pattern="${2:-goal-tracker\\.md}" local command_lower command_lower=$(to_lower "$command") if command_modifies_file "$command_lower" "$pattern"; then fail "Should NOT detect modification" "$command" "should not match pattern" else pass "Correctly ignored: $command" fi } echo "========================================" echo "Testing command_modifies_file patterns" echo "========================================" echo "" # ======================================== # Test Group 1: Redirection operators (> >>) # ======================================== echo "Test Group 1: Redirection operators" echo "" assert_modifies "echo x > goal-tracker.md" assert_modifies "echo x >> goal-tracker.md" assert_modifies "cat foo >> goal-tracker.md" assert_modifies "printf 'text' > goal-tracker.md" assert_modifies "echo 'data' > /path/to/goal-tracker.md" assert_modifies "ECHO X > GOAL-TRACKER.MD" # ======================================== # Test Group 2: tee command # ======================================== echo "" echo "Test Group 2: tee command" echo "" assert_modifies "tee goal-tracker.md" assert_modifies "tee -a goal-tracker.md" assert_modifies "echo x | tee goal-tracker.md" assert_modifies "echo x | tee -a goal-tracker.md" assert_modifies "cat file | tee /path/to/goal-tracker.md" # ======================================== # Test Group 3: In-place editors (sed, awk, perl) # ======================================== echo "" echo "Test Group 3: In-place editors" echo "" assert_modifies "sed -i 's/x/y/' goal-tracker.md" assert_modifies "sed -i.bak 's/x/y/' goal-tracker.md" assert_modifies "sed -i '' 's/x/y/' goal-tracker.md" assert_modifies "awk -i inplace '{print}' goal-tracker.md" assert_modifies "perl -i -pe 's/x/y/' goal-tracker.md" assert_modifies "perl -pie 's/x/y/' goal-tracker.md" # ======================================== # Test Group 4: File operations (mv, cp, rm) # ======================================== echo "" echo "Test Group 4: File operations" echo "" assert_modifies "mv temp.md goal-tracker.md" assert_modifies "cp backup.md goal-tracker.md" assert_modifies "rm goal-tracker.md" assert_modifies "rm -f goal-tracker.md" assert_modifies "rm -rf goal-tracker.md" assert_modifies "mv /tmp/new.md /path/to/goal-tracker.md" # ======================================== # Test Group 5: Other modifiers (dd, truncate, exec) # ======================================== echo "" echo "Test Group 5: Other modifiers" echo "" assert_modifies "dd if=/dev/zero of=goal-tracker.md" assert_modifies "truncate -s 0 goal-tracker.md" assert_modifies "exec 3> goal-tracker.md" assert_modifies "printf '%s' data > goal-tracker.md" # ======================================== # Test Group 6: Commands that should NOT be caught # ======================================== echo "" echo "Test Group 6: Commands that should NOT be caught (false positives)" echo "" assert_not_modifies "cat goal-tracker.md" assert_not_modifies "grep goal goal-tracker.md" assert_not_modifies "head -10 goal-tracker.md" assert_not_modifies "tail -10 goal-tracker.md" assert_not_modifies "wc -l goal-tracker.md" assert_not_modifies "less goal-tracker.md" assert_not_modifies "echo goal-tracker.md" assert_not_modifies "ls goal-tracker.md" assert_not_modifies "file goal-tracker.md" assert_not_modifies "stat goal-tracker.md" assert_not_modifies "diff goal-tracker.md other.md" # ======================================== # Test Group 7: Edge cases # ======================================== echo "" echo "Test Group 7: Edge cases" echo "" # Filename in different positions assert_modifies "> goal-tracker.md" assert_modifies "echo test >goal-tracker.md" # Multiple source files to single destination # Note: "cp file1.md file2.md goal-tracker.md" (multiple sources) is NOT detected # because the pattern expects "cp src dest" format. This is a known limitation. # The more common "cp src goal-tracker.md" case IS detected. # With variables (should still match the literal pattern) assert_not_modifies 'echo x > $FILE' assert_not_modifies "cat file.md | grep pattern" # ======================================== # Test Group 8: State file patterns # ======================================== echo "" echo "Test Group 8: State file patterns" echo "" assert_modifies "echo x > state.md" "state\\.md" assert_modifies "sed -i 's/round: 0/round: 99/' state.md" "state\\.md" assert_not_modifies "cat state.md" "state\\.md" # ======================================== # Test Group 9: Summary file patterns # ======================================== echo "" echo "Test Group 9: Summary file patterns" echo "" assert_modifies "echo x > round-5-summary.md" "round-[0-9]+-summary\\.md" assert_modifies "cat data >> round-10-summary.md" "round-[0-9]+-summary\\.md" assert_not_modifies "cat round-5-summary.md" "round-[0-9]+-summary\\.md" # ======================================== # Summary # ======================================== echo "" echo "========================================" echo "Test Summary" echo "========================================" echo -e "Passed: ${GREEN}$TESTS_PASSED${NC}" echo -e "Failed: ${RED}$TESTS_FAILED${NC}" if [[ $TESTS_FAILED -eq 0 ]]; then echo "" echo -e "${GREEN}All tests passed!${NC}" exit 0 else echo "" echo -e "${RED}Some tests failed!${NC}" exit 1 fi