import pytest from engine.timing import GameClock, Scheduler def test_game_clock_yields_whole_ticks_and_keeps_remainder(): clock = GameClock(tick_interval=1.0) assert clock.advance(0.4) == 0 assert clock.advance(0.4) == 0 assert clock.advance(0.4) == 1 # 1.2s total -> 1 whole tick, 0.2s carried over assert clock.tick_count == 1 assert clock.total_time == pytest.approx(1.2) def test_game_clock_handles_multiple_ticks_in_one_advance(): clock = GameClock(tick_interval=0.5) assert clock.advance(1.7) == 3 assert clock.tick_count == 3 def test_scheduler_runs_one_off_event_once_due(): scheduler = Scheduler() calls = [] scheduler.schedule_in(now=0.0, delay=5.0, event_id="e1", callback=lambda: calls.append("e1")) assert scheduler.run_due(4.9) == [] assert scheduler.run_due(5.0) == ["e1"] assert calls == ["e1"] assert scheduler.run_due(100.0) == [] # already consumed, doesn't fire again def test_scheduler_reschedules_repeating_event(): scheduler = Scheduler() calls = [] scheduler.schedule_in(now=0.0, delay=1.0, event_id="tick", callback=lambda: calls.append("tick"), interval=1.0) assert scheduler.run_due(1.0) == ["tick"] assert scheduler.run_due(1.9) == [] assert scheduler.run_due(2.0) == ["tick"] assert calls == ["tick", "tick"] assert scheduler.pending_count() == 1 def test_scheduler_runs_multiple_due_events_in_run_at_order(): scheduler = Scheduler() calls = [] scheduler.schedule_at(2.0, "second", lambda: calls.append("second")) scheduler.schedule_at(1.0, "first", lambda: calls.append("first")) assert scheduler.run_due(2.0) == ["first", "second"] assert calls == ["first", "second"]