from __future__ import annotations from datetime import datetime, timezone from digital_pet_import import load_module state_mod = load_module("state.py", "digital_pet_state") PetState = state_mod.PetState apply_event = state_mod.apply_event def at(second: int = 0): return datetime(2026, 1, 1, 12, 0, second, tzinfo=timezone.utc) def test_click_summons_hidden_pet_deterministically(): state = PetState() next_state = apply_event("click", state=state, now=at()) assert next_state.enabled is True assert next_state.mode == "idle" assert next_state.last_mode == "hidden" assert next_state.message == "Station companion online." assert next_state.revision == 1 def test_hover_hold_sends_active_pet_to_sleep(): state = apply_event("summon", state=PetState(), now=at()) next_state = apply_event("hover_hold", state=state, now=at(1)) assert next_state.enabled is True assert next_state.mode == "sleeping" assert next_state.last_mode == "idle" assert next_state.message == "Going quiet." def test_sleeping_click_wakes_then_wake_complete_returns_idle(): state = apply_event("summon", state=PetState(), now=at()) state = apply_event("hover_hold", state=state, now=at(1)) waking = apply_event("click", state=state, now=at(2)) assert waking.mode == "waking" assert waking.message == "Back online." idle = apply_event("wake_complete", state=waking, now=at(3)) assert idle.mode == "idle" assert idle.message is None def test_reaction_and_prompt_complete_return_to_idle(): state = apply_event("summon", state=PetState(), now=at()) reacting = apply_event("click", state=state, now=at(1)) assert reacting.mode == "reacting" idle = apply_event("reaction_complete", state=reacting, now=at(2)) assert idle.mode == "idle" idle.prompt_cooldown_until = None prompting = apply_event("prompt_tick", state=idle, now=at(3)) assert prompting.mode == "prompting" completed = apply_event("prompt_complete", state=prompting, now=at(4)) assert completed.mode == "idle" def test_hidden_and_sleeping_ignore_prompt_and_reacting_completion(): hidden = PetState() after_prompt = apply_event("prompt_tick", state=hidden, now=at()) after_reaction_complete = apply_event("reaction_complete", state=after_prompt, now=at(1)) assert after_prompt.mode == "hidden" assert after_reaction_complete.mode == "hidden" sleeping = apply_event("sleep", state=PetState(enabled=True, mode="idle"), now=at(2)) still_sleeping = apply_event("prompt_tick", state=sleeping, now=at(3)) assert still_sleeping.mode == "sleeping"