#!/bin/bash # autotest.sh - Automated testing script for gwatch # Tests various scenarios and validates behavior set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Test counters TESTS_PASSED=0 TESTS_FAILED=0 # Paths GWATCH="./build/gwatch" SAMPLE_PROGRAM="./sample_program" SAMPLE_SOURCE="./sample_program.c" # Helper function to print test results print_result() { local test_name="$1" local result="$2" if [ "$result" = "PASS" ]; then echo -e "${GREEN}[PASS]${NC} $test_name" ((TESTS_PASSED++)) else echo -e "${RED}[FAIL]${NC} $test_name" ((TESTS_FAILED++)) fi } # Helper function to run test run_test() { local test_name="$1" echo -e "\n${YELLOW}Running:${NC} $test_name" } # Compile sample program echo "=== Preparing Test Environment ===" if [ ! -f "$SAMPLE_SOURCE" ]; then echo "Error: $SAMPLE_SOURCE not found" exit 1 fi echo "Compiling sample program..." gcc -g -O0 -o "$SAMPLE_PROGRAM" "$SAMPLE_SOURCE" if [ $? -ne 0 ]; then echo "Error: Failed to compile sample program" exit 1 fi echo "Sample program compiled successfully" if [ ! -f "$GWATCH" ]; then echo "Error: $GWATCH not found. Build the project first." exit 1 fi echo -e "\n=== Starting Tests ===\n" # Test 1: Monitor global_int with successful writes run_test "Test 1: Monitor global_int (4 bytes)" OUTPUT=$(timeout 3 $GWATCH --var global_int --exec $SAMPLE_PROGRAM 2>&1) EXIT_CODE=$? # timeout returns 124 if killed, but gwatch itself returns 0 if echo "$OUTPUT" | grep -q "global_int.*write.*0->42" && echo "$OUTPUT" | grep -q "Process exited"; then print_result "Test 1" "PASS" else print_result "Test 1" "FAIL" echo "Exit code: $EXIT_CODE" fi # Test 2: Monitor global_long (8 bytes) run_test "Test 2: Monitor global_long (8 bytes)" OUTPUT=$(timeout 3 $GWATCH --var global_long --exec $SAMPLE_PROGRAM 2>&1) EXIT_CODE=$? if echo "$OUTPUT" | grep -q "global_long.*write.*1000->5000" && echo "$OUTPUT" | grep -q "Process exited"; then print_result "Test 2" "PASS" else print_result "Test 2" "FAIL" fi # Test 3: Monitor global_uint (unsigned 4 bytes) run_test "Test 3: Monitor global_uint (unsigned 4 bytes)" OUTPUT=$(timeout 3 $GWATCH --var global_uint --exec $SAMPLE_PROGRAM 2>&1) EXIT_CODE=$? if echo "$OUTPUT" | grep -q "global_uint.*write.*0->999" && echo "$OUTPUT" | grep -q "Process exited"; then print_result "Test 3" "PASS" else print_result "Test 3" "FAIL" fi # Test 4: Nonexistent variable run_test "Test 4: Nonexistent variable (should fail)" OUTPUT=$($GWATCH --var nonexistent_var --exec $SAMPLE_PROGRAM 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ] && echo "$OUTPUT" | grep -q "not found"; then print_result "Test 4" "PASS" else print_result "Test 4" "FAIL" echo "Exit code: $EXIT_CODE, Output: $OUTPUT" fi # Test 5: Missing executable run_test "Test 5: Missing executable (should fail)" OUTPUT=$($GWATCH --var global_int --exec /nonexistent/file 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ] && echo "$OUTPUT" | grep -q "Cannot open"; then print_result "Test 5" "PASS" else print_result "Test 5" "FAIL" echo "Exit code: $EXIT_CODE, Output: $OUTPUT" fi # Test 6: Missing arguments run_test "Test 6: Missing required arguments (should fail)" OUTPUT=$($GWATCH 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ] && echo "$OUTPUT" | grep -q "required"; then print_result "Test 6" "PASS" else print_result "Test 6" "FAIL" echo "Exit code: $EXIT_CODE, Output: $OUTPUT" fi # Test 7: Help message run_test "Test 7: Help message" OUTPUT=$($GWATCH --help 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -eq 0 ] && echo "$OUTPUT" | grep -q "exec" && echo "$OUTPUT" | grep -q "var"; then print_result "Test 7" "PASS" else print_result "Test 7" "FAIL" echo "Exit code: $EXIT_CODE, Output: $OUTPUT" fi # Test 8: Command-line argument passing run_test "Test 8: Command-line arguments to traced program" OUTPUT=$(timeout 3 $GWATCH --var global_int --exec $SAMPLE_PROGRAM -- 777 2>&1) EXIT_CODE=$? if echo "$OUTPUT" | grep -q "777" && echo "$OUTPUT" | grep -q "Process exited"; then print_result "Test 8" "PASS" else print_result "Test 8" "FAIL" fi # Test 9: Unsupported type (char - 1 byte) run_test "Test 9: Unsupported type - char (1 byte, should fail)" cat > /tmp/test_char_gwatch.c <<'EOF' #include char global_char = 'A'; int main() { global_char = 'B'; printf("Char: %c\n", global_char); return 0; } EOF gcc -g -O0 -o /tmp/test_char_gwatch /tmp/test_char_gwatch.c 2>/dev/null OUTPUT=$($GWATCH --var global_char --exec /tmp/test_char_gwatch 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ] && echo "$OUTPUT" | grep -q "unsupported size"; then print_result "Test 9" "PASS" else print_result "Test 9" "FAIL" echo "Exit code: $EXIT_CODE, Output: $OUTPUT" fi # Test 10: Unsupported type (short - 2 bytes) run_test "Test 10: Unsupported type - short (2 bytes, should fail)" cat > /tmp/test_short_gwatch.c <<'EOF' #include short global_short = 10; int main() { global_short = 20; printf("Short: %d\n", global_short); return 0; } EOF gcc -g -O0 -o /tmp/test_short_gwatch /tmp/test_short_gwatch.c 2>/dev/null OUTPUT=$($GWATCH --var global_short --exec /tmp/test_short_gwatch 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ] && echo "$OUTPUT" | grep -q "unsupported size"; then print_result "Test 10" "PASS" else print_result "Test 10" "FAIL" echo "Exit code: $EXIT_CODE, Output: $OUTPUT" fi # Test 11: Unsupported type (float) run_test "Test 11: Unsupported type - float (should fail)" cat > /tmp/test_float_gwatch.c <<'EOF' #include float global_float = 3.14f; int main() { global_float = 6.28f; printf("Float: %f\n", global_float); return 0; } EOF gcc -g -O0 -o /tmp/test_float_gwatch /tmp/test_float_gwatch.c 2>/dev/null OUTPUT=$($GWATCH --var global_float --exec /tmp/test_float_gwatch 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ] && echo "$OUTPUT" | grep -q "not found or is not a supported integer type"; then print_result "Test 11" "PASS" else print_result "Test 11" "FAIL" echo "Exit code: $EXIT_CODE, Output: $OUTPUT" fi # Test 12: Output format validation (tab-delimited) run_test "Test 12: Output format validation (tab-delimited)" OUTPUT=$(timeout 3 $GWATCH --var global_int --exec $SAMPLE_PROGRAM 2>&1) EXIT_CODE=$? # Check if output contains tabs between fields if echo "$OUTPUT" | grep -P "global_int\twrite\t\d+->\d+" >/dev/null && echo "$OUTPUT" | grep -q "Process exited"; then print_result "Test 12" "PASS" else print_result "Test 12" "FAIL" fi # Test 13: Multiple writes detection run_test "Test 13: Multiple writes detection" OUTPUT=$(timeout 3 $GWATCH --var global_int --exec $SAMPLE_PROGRAM 2>&1) EXIT_CODE=$? # Count number of write events (should be at least 5) WRITE_COUNT=$(echo "$OUTPUT" | grep -c "global_int.*write" || true) if [ "$WRITE_COUNT" -ge 5 ] && echo "$OUTPUT" | grep -q "Process exited"; then print_result "Test 13" "PASS" else print_result "Test 13" "FAIL" echo "Expected at least 5 writes, got $WRITE_COUNT" fi # Cleanup rm -f /tmp/test_char_gwatch /tmp/test_char_gwatch.c rm -f /tmp/test_short_gwatch /tmp/test_short_gwatch.c rm -f /tmp/test_float_gwatch /tmp/test_float_gwatch.c # Summary echo -e "\n=== Test Summary ===" echo -e "Tests passed: ${GREEN}$TESTS_PASSED${NC}" echo -e "Tests failed: ${RED}$TESTS_FAILED${NC}" echo -e "Total tests: $((TESTS_PASSED + TESTS_FAILED))" if [ $TESTS_FAILED -eq 0 ]; then echo -e "\n${GREEN}All tests passed!${NC}" exit 0 else echo -e "\n${RED}Some tests failed!${NC}" exit 1 fi