2026-03-10 02:28:16 -04:00
|
|
|
import pytest
|
|
|
|
|
from cursor_flasher.state import FlasherState, StateMachine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestStateMachine:
|
|
|
|
|
def test_initial_state_is_idle(self):
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
assert sm.state == FlasherState.IDLE
|
|
|
|
|
|
|
|
|
|
def test_idle_to_agent_working(self):
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
changed = sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
assert sm.state == FlasherState.AGENT_WORKING
|
|
|
|
|
assert changed is True
|
|
|
|
|
|
|
|
|
|
def test_agent_working_to_waiting(self):
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
changed = sm.update(agent_working=False, approval_needed=False)
|
|
|
|
|
assert sm.state == FlasherState.WAITING_FOR_USER
|
|
|
|
|
assert changed is True
|
|
|
|
|
|
|
|
|
|
def test_approval_needed_triggers_waiting(self):
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
changed = sm.update(agent_working=False, approval_needed=True)
|
|
|
|
|
assert sm.state == FlasherState.WAITING_FOR_USER
|
|
|
|
|
assert changed is True
|
|
|
|
|
|
|
|
|
|
def test_idle_does_not_jump_to_waiting(self):
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
changed = sm.update(agent_working=False, approval_needed=False)
|
|
|
|
|
assert sm.state == FlasherState.IDLE
|
|
|
|
|
assert changed is False
|
|
|
|
|
|
|
|
|
|
def test_waiting_to_user_interacting(self):
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
sm.update(agent_working=False, approval_needed=False)
|
|
|
|
|
assert sm.state == FlasherState.WAITING_FOR_USER
|
|
|
|
|
changed = sm.dismiss()
|
|
|
|
|
assert sm.state == FlasherState.IDLE
|
|
|
|
|
assert changed is True
|
|
|
|
|
|
|
|
|
|
def test_waiting_to_agent_working(self):
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
sm.update(agent_working=False, approval_needed=False)
|
|
|
|
|
changed = sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
assert sm.state == FlasherState.AGENT_WORKING
|
|
|
|
|
assert changed is True
|
|
|
|
|
|
|
|
|
|
def test_no_change_returns_false(self):
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
changed = sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
assert changed is False
|
|
|
|
|
|
|
|
|
|
def test_cooldown_prevents_immediate_retrigger(self):
|
|
|
|
|
sm = StateMachine(cooldown=5.0)
|
|
|
|
|
sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
sm.update(agent_working=False, approval_needed=False)
|
|
|
|
|
assert sm.state == FlasherState.WAITING_FOR_USER
|
|
|
|
|
sm.dismiss()
|
|
|
|
|
sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
changed = sm.update(agent_working=False, approval_needed=False)
|
|
|
|
|
assert sm.cooldown == 5.0
|
|
|
|
|
|
2026-03-10 03:17:34 -04:00
|
|
|
def test_stale_approval_from_idle_ignored(self):
|
|
|
|
|
"""Approval buttons in IDLE state (stale chat history) must not trigger flash."""
|
2026-03-10 02:28:16 -04:00
|
|
|
sm = StateMachine()
|
|
|
|
|
changed = sm.update(agent_working=False, approval_needed=True)
|
2026-03-10 03:17:34 -04:00
|
|
|
assert sm.state == FlasherState.IDLE
|
|
|
|
|
assert changed is False
|
|
|
|
|
|
|
|
|
|
def test_approval_after_working_triggers(self):
|
|
|
|
|
"""Approval buttons after seeing agent work should trigger flash."""
|
|
|
|
|
sm = StateMachine()
|
|
|
|
|
sm.update(agent_working=True, approval_needed=False)
|
|
|
|
|
changed = sm.update(agent_working=False, approval_needed=True)
|
2026-03-10 02:28:16 -04:00
|
|
|
assert sm.state == FlasherState.WAITING_FOR_USER
|
|
|
|
|
assert changed is True
|