philosophers_prep/testers/test_8_simple_philosophers.sh

193 lines
5.7 KiB
Bash
Executable File

#!/bin/bash
# Tester for simple_philosophers exercise
# Tests basic philosophers implementation
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
EXERCISE="simple_philosophers"
PASSED=0
FAILED=0
echo "========================================"
echo "Testing: $EXERCISE"
echo "========================================"
if [ ! -f "./$EXERCISE" ]; then
echo -e "${RED}✗ Executable ./$EXERCISE not found${NC}"
echo "Please compile: gcc -Wall -Wextra -Werror -pthread simple_philosophers.c -o simple_philosophers"
exit 1
fi
# Test 1: Program runs for approximately 10 seconds
echo -n "Test 1: Program duration (~10 seconds)... "
START_TIME=$(date +%s)
timeout 15 ./$EXERCISE > /tmp/simple_philo_output.txt 2>&1
EXIT_CODE=$?
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
if [ $EXIT_CODE -eq 0 ] && [ $DURATION -ge 9 ] && [ $DURATION -le 12 ]; then
echo -e "${GREEN}✓ PASSED${NC} (ran for ${DURATION}s)"
((PASSED++))
elif [ $EXIT_CODE -eq 0 ]; then
echo -e "${YELLOW}⚠ PARTIAL${NC} (ran for ${DURATION}s, expected ~10s)"
((PASSED++))
else
echo -e "${RED}✗ FAILED${NC}"
echo "Program should run for approximately 10 seconds"
((FAILED++))
fi
OUTPUT=$(cat /tmp/simple_philo_output.txt 2>/dev/null)
# Test 2: Three philosophers present
echo -n "Test 2: Three philosophers... "
PHILO_COUNT=$(echo "$OUTPUT" | grep -oE "Philosopher [0-9]+" | sort -u | wc -l)
if [ "$PHILO_COUNT" -eq 3 ]; then
echo -e "${GREEN}✓ PASSED${NC}"
((PASSED++))
else
echo -e "${RED}✗ FAILED${NC}"
echo "Expected 3 philosophers, found: $PHILO_COUNT"
((FAILED++))
fi
# Test 3: Thinking action present
echo -n "Test 3: Thinking actions... "
THINKING_COUNT=$(echo "$OUTPUT" | grep -ci "thinking")
if [ "$THINKING_COUNT" -gt 0 ]; then
echo -e "${GREEN}✓ PASSED${NC} ($THINKING_COUNT occurrences)"
((PASSED++))
else
echo -e "${RED}✗ FAILED${NC}"
echo "No thinking actions detected"
((FAILED++))
fi
# Test 4: Eating action present
echo -n "Test 4: Eating actions... "
EATING_COUNT=$(echo "$OUTPUT" | grep -ci "eating")
if [ "$EATING_COUNT" -gt 0 ]; then
echo -e "${GREEN}✓ PASSED${NC} ($EATING_COUNT occurrences)"
((PASSED++))
else
echo -e "${RED}✗ FAILED${NC}"
echo "No eating actions detected"
((FAILED++))
fi
# Test 5: Timestamps present
echo -n "Test 5: Timestamps... "
if echo "$OUTPUT" | grep -qE "\[[0-9]+\]"; then
echo -e "${GREEN}✓ PASSED${NC}"
((PASSED++))
else
echo -e "${RED}✗ FAILED${NC}"
echo "Expected timestamps in format [timestamp]"
((FAILED++))
fi
# Test 6: Each philosopher eats multiple times
echo -n "Test 6: All philosophers eat... "
PHILO_0_EATS=$(echo "$OUTPUT" | grep -ciE "(philosopher 0|philo 0).*eat")
PHILO_1_EATS=$(echo "$OUTPUT" | grep -ciE "(philosopher 1|philo 1).*eat")
PHILO_2_EATS=$(echo "$OUTPUT" | grep -ciE "(philosopher 2|philo 2).*eat")
if [ "$PHILO_0_EATS" -gt 0 ] && [ "$PHILO_1_EATS" -gt 0 ] && [ "$PHILO_2_EATS" -gt 0 ]; then
echo -e "${GREEN}✓ PASSED${NC} (P0:$PHILO_0_EATS, P1:$PHILO_1_EATS, P2:$PHILO_2_EATS)"
((PASSED++))
else
echo -e "${RED}✗ FAILED${NC}"
echo "Not all philosophers are eating"
echo "P0:$PHILO_0_EATS, P1:$PHILO_1_EATS, P2:$PHILO_2_EATS"
((FAILED++))
fi
# Test 7: No philosopher dies
echo -n "Test 7: No deaths... "
if echo "$OUTPUT" | grep -qiE "(die|death|dead)"; then
echo -e "${RED}✗ FAILED${NC}"
echo "A philosopher died - check your timing and fork management"
((FAILED++))
else
echo -e "${GREEN}✓ PASSED${NC}"
((PASSED++))
fi
# Test 8: Thread sanitizer check
if command -v gcc &> /dev/null; then
echo -n "Test 8: Data race detection... "
gcc -Wall -Wextra -Werror -pthread -fsanitize=thread -g simple_philosophers.c -o simple_philosophers_tsan 2>/dev/null
if [ $? -eq 0 ]; then
TSAN_OUTPUT=$(timeout 12 ./simple_philosophers_tsan 2>&1)
if echo "$TSAN_OUTPUT" | grep -q "WARNING: ThreadSanitizer: data race"; then
echo -e "${RED}✗ FAILED${NC}"
echo "Data race detected!"
echo "$TSAN_OUTPUT" | grep -A 3 "data race" | head -10
((FAILED++))
else
echo -e "${GREEN}✓ PASSED${NC}"
((PASSED++))
fi
rm -f simple_philosophers_tsan
else
echo -e "${YELLOW}⊘ Could not compile with thread sanitizer${NC}"
fi
else
echo -e "${YELLOW}⊘ Test 8: gcc not available, skipping${NC}"
fi
# Test 9: No deadlock (run multiple times)
echo -n "Test 9: No deadlock (3 runs)... "
DEADLOCK_DETECTED=false
for i in {1..3}; do
timeout 15 ./$EXERCISE > /dev/null 2>&1
if [ $? -eq 124 ]; then
DEADLOCK_DETECTED=true
break
fi
done
if [ "$DEADLOCK_DETECTED" = false ]; then
echo -e "${GREEN}✓ PASSED${NC}"
((PASSED++))
else
echo -e "${RED}✗ FAILED${NC}"
echo "Program appears to deadlock on run $i"
((FAILED++))
fi
# Test 10: Memory leak check
if command -v valgrind &> /dev/null; then
echo -n "Test 10: Memory leak check... "
VALGRIND_OUTPUT=$(timeout 15 valgrind --leak-check=full --error-exitcode=42 ./$EXERCISE 2>&1)
VALGRIND_EXIT=$?
if [ $VALGRIND_EXIT -eq 0 ]; then
echo -e "${GREEN}✓ PASSED${NC}"
((PASSED++))
elif [ $VALGRIND_EXIT -eq 124 ]; then
echo -e "${YELLOW}⚠ TIMEOUT${NC} (likely OK)"
((PASSED++))
else
echo -e "${RED}✗ FAILED${NC}"
echo "Memory leaks detected!"
((FAILED++))
fi
else
echo -e "${YELLOW}⊘ Test 10: Valgrind not installed, skipping${NC}"
fi
# Cleanup
rm -f /tmp/simple_philo_output.txt
# Summary
echo "========================================"
echo -e "Results: ${GREEN}$PASSED passed${NC}, ${RED}$FAILED failed${NC}"
echo "========================================"
[ $FAILED -eq 0 ] && exit 0 || exit 1