eyeguard-20-20-20 / test_eyeguard_synthetic.py
HarshCode's picture
Upload synthetic test suite
1fe2781 verified
"""Synthetic test suite for EyeGuard 20-20-20. No webcam required."""
import time, sys
sys.path.insert(0, '/app')
from eye_guard_2020 import EyeGuard2020, Status, update_eye_state
from eye_guard_2020 import REST_DURATION_SECONDS, SCREEN_TIME_ALERT_SECONDS, MIN_CONSECUTIVE_CLOSED_FRAMES
def run_state_machine(guard, ear_l, ear_r, now_override=None):
now = now_override if now_override is not None else time.time()
state = guard.state
ear_left = guard._smooth_ear(state.ear_history_left, ear_l)
ear_right = guard._smooth_ear(state.ear_history_right, ear_r)
state.left_eye = update_eye_state(state.left_eye, ear_left, guard.ear_open, guard.ear_closed)
state.right_eye = update_eye_state(state.right_eye, ear_right, guard.ear_open, guard.ear_closed)
screen_elapsed = now - state.screen_timer_start
both_eyes_closed = state.left_eye.is_closed and state.right_eye.is_closed
one_eye_closed = (state.left_eye.is_closed and not state.right_eye.is_closed) or \
(not state.left_eye.is_closed and state.right_eye.is_closed)
if state.status == Status.RESTING and one_eye_closed:
state.spoofing_detected_at = now
state.spoofing_count += 1
state.status = Status.SPOOFING
state.failed_rests += 1
state.rest_start_time = None
return
if state.status == Status.ALERT and one_eye_closed:
state.spoofing_detected_at = now
state.spoofing_count += 1
if state.status == Status.SCREENING:
if screen_elapsed >= SCREEN_TIME_ALERT_SECONDS:
state.status = Status.ALERT
elif state.status == Status.ALERT:
if both_eyes_closed and state.left_eye.closed_frames >= MIN_CONSECUTIVE_CLOSED_FRAMES:
state.status = Status.RESTING
state.rest_start_time = now
elif state.status == Status.RESTING:
if not both_eyes_closed:
state.failed_rests += 1
state.status = Status.ALERT
state.rest_start_time = None
else:
rest_elapsed = now - state.rest_start_time
if rest_elapsed >= REST_DURATION_SECONDS:
state.status = Status.REST_COMPLETE
state.rest_completed_time = now
state.total_rests_completed += 1
state.total_rest_seconds += rest_elapsed
state.screen_timer_start = now
elif state.status == Status.REST_COMPLETE:
if now - state.rest_completed_time > 3.0:
state.status = Status.SCREENING
elif state.status == Status.SPOOFING:
if now - state.spoofing_detected_at > 3.0:
state.status = Status.ALERT
elif state.status == Status.NO_FACE:
if screen_elapsed >= SCREEN_TIME_ALERT_SECONDS:
state.status = Status.ALERT
else:
state.status = Status.SCREENING
def print_frame(i, guard, desc):
le = "C" if guard.state.left_eye.is_closed else "O"
re = "C" if guard.state.right_eye.is_closed else "O"
print(f" Frame {i:3d}: Eyes=({le},{re}) Status={guard.state.status.name:<12} | {desc}")
def test_normal_rest():
print("\n" + "=" * 60)
print("TEST 1: Normal rest cycle (both eyes closed)")
print("=" * 60)
guard = EyeGuard2020()
guard.ear_open = 0.20
guard.ear_closed = 0.15
t0 = 1000.0
guard.state.screen_timer_start = t0 - SCREEN_TIME_ALERT_SECONDS - 1
guard.state.status = Status.SCREENING
for i in range(5):
run_state_machine(guard, 0.25, 0.25, t0 + i * 0.033)
print_frame(i, guard, "eyes open")
assert guard.state.status == Status.ALERT, f"Expected ALERT, got {guard.state.status.name}"
print(" -> ALERT triggered correctly")
for i in range(5, 30):
run_state_machine(guard, 0.10, 0.10, t0 + i * 0.033)
assert guard.state.status == Status.RESTING
print(" -> RESTING entered correctly")
for i in range(30, 650):
run_state_machine(guard, 0.10, 0.10, t0 + i * 0.033)
if i == 35:
print_frame(i, guard, "resting...")
assert guard.state.status == Status.REST_COMPLETE
assert guard.state.total_rests_completed >= 1
print(f" -> REST_COMPLETE! rests={guard.state.total_rests_completed}")
print(" PASS")
def test_spoofing():
print("\n" + "=" * 60)
print("TEST 2: Spoofing detection (one eye closed)")
print("=" * 60)
guard = EyeGuard2020()
guard.ear_open = 0.20
guard.ear_closed = 0.15
t0 = 2000.0
guard.state.screen_timer_start = t0 - SCREEN_TIME_ALERT_SECONDS - 1
guard.state.status = Status.ALERT
for i in range(20):
run_state_machine(guard, 0.10, 0.10, t0 + i * 0.033)
if i < 3:
print_frame(i, guard, "entering rest")
assert guard.state.status == Status.RESTING
print(" -> RESTING entered")
for i in range(20, 50):
run_state_machine(guard, 0.25, 0.10, t0 + i * 0.033)
if i < 23:
print_frame(i, guard, "SPOOFING: left eye open!")
assert guard.state.status == Status.SPOOFING
assert guard.state.spoofing_count >= 1
print(f" -> SPOOFING detected! count={guard.state.spoofing_count}")
for i in range(50, 200):
run_state_machine(guard, 0.25, 0.25, t0 + i * 0.033)
if i == 150:
print_frame(i, guard, "after spoof penalty")
assert guard.state.status == Status.ALERT
print(" -> Back to ALERT after penalty")
print(" PASS")
def test_blink_filter():
print("\n" + "=" * 60)
print("TEST 3: Blink filtering (brief closures ignored)")
print("=" * 60)
guard = EyeGuard2020()
guard.ear_open = 0.20
guard.ear_closed = 0.15
t0 = 3000.0
guard.state.screen_timer_start = t0 - SCREEN_TIME_ALERT_SECONDS - 1
guard.state.status = Status.ALERT
for i in range(5):
run_state_machine(guard, 0.10, 0.10, t0 + i * 0.033)
print_frame(i, guard, "blink!")
for i in range(5, 20):
run_state_machine(guard, 0.25, 0.25, t0 + i * 0.033)
if i < 7:
print_frame(i, guard, "eyes open again")
assert guard.state.status == Status.ALERT, f"Expected ALERT, got {guard.state.status.name}"
print(" -> Blink correctly filtered, still in ALERT")
for i in range(20, 650):
run_state_machine(guard, 0.10, 0.10, t0 + i * 0.033)
if i == 30:
print_frame(i, guard, "proper rest...")
assert guard.state.status == Status.REST_COMPLETE
assert guard.state.total_rests_completed >= 1
print(f" -> Rest completed after blink! rests={guard.state.total_rests_completed}")
print(" PASS")
def test_interruption():
print("\n" + "=" * 60)
print("TEST 4: Rest interruption (early opening)")
print("=" * 60)
guard = EyeGuard2020()
guard.ear_open = 0.20
guard.ear_closed = 0.15
t0 = 4000.0
guard.state.screen_timer_start = t0 - SCREEN_TIME_ALERT_SECONDS - 1
guard.state.status = Status.ALERT
for i in range(30):
run_state_machine(guard, 0.10, 0.10, t0 + i * 0.033)
if i < 3:
print_frame(i, guard, "starting rest")
assert guard.state.status == Status.RESTING
print(" -> RESTING entered")
for i in range(30, 350):
run_state_machine(guard, 0.25, 0.25, t0 + i * 0.033)
if i == 35:
print_frame(i, guard, "REST INTERRUPTED!")
assert guard.state.status == Status.ALERT
assert guard.state.failed_rests >= 1
print(f" -> Rest failed (interrupted). failed={guard.state.failed_rests}")
guard.state.status = Status.ALERT
for i in range(350, 1000):
run_state_machine(guard, 0.10, 0.10, t0 + i * 0.033)
if i == 360:
print_frame(i, guard, "retry rest...")
assert guard.state.status == Status.REST_COMPLETE
assert guard.state.total_rests_completed >= 1
print(f" -> Retry succeeded! rests={guard.state.total_rests_completed}")
print(" PASS")
def test_no_face():
print("\n" + "=" * 60)
print("TEST 5: No face visible during rest")
print("=" * 60)
guard = EyeGuard2020()
guard.ear_open = 0.20
guard.ear_closed = 0.15
t0 = 5000.0
guard.state.screen_timer_start = t0 - SCREEN_TIME_ALERT_SECONDS - 1
guard.state.status = Status.ALERT
for i in range(20):
run_state_machine(guard, 0.10, 0.10, t0 + i * 0.033)
if i < 3:
print_frame(i, guard, "entering rest")
assert guard.state.status == Status.RESTING
print(" -> RESTING entered")
guard.state.status = Status.NO_FACE
guard.state.failed_rests += 1
guard.state.rest_start_time = None
assert guard.state.status == Status.NO_FACE
print(" -> NO_FACE detected, rest failed")
assert guard.state.failed_rests >= 1
print(f" -> failed={guard.state.failed_rests}")
print(" PASS")
def test_one_eye_alert():
print("\n" + "=" * 60)
print("TEST 6: One-eye trick during ALERT phase")
print("=" * 60)
guard = EyeGuard2020()
guard.ear_open = 0.20
guard.ear_closed = 0.15
t0 = 6000.0
guard.state.screen_timer_start = t0 - SCREEN_TIME_ALERT_SECONDS - 1
guard.state.status = Status.ALERT
for i in range(50):
run_state_machine(guard, 0.10, 0.25, t0 + i * 0.033)
if i < 3:
print_frame(i, guard, "one-eye trick (left closed)")
assert guard.state.spoofing_count >= 1
print(f" -> Spoofing detected during ALERT! count={guard.state.spoofing_count}")
print(f" -> Final status: {guard.state.status.name}")
print(" PASS")
if __name__ == "__main__":
print("=" * 60)
print("EyeGuard 20-20-20 Synthetic Test Suite")
print("=" * 60)
test_normal_rest()
test_spoofing()
test_blink_filter()
test_interruption()
test_no_face()
test_one_eye_alert()
print("\n" + "=" * 60)
print("ALL TESTS PASSED!")
print("=" * 60)