Full rearchitecture using Claude
- event bus systen - all components are independent - preparation for web frontend
This commit is contained in:
108
python-backend/tests/test_clock.py
Normal file
108
python-backend/tests/test_clock.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
from musicmouse.clock import FakeClock, RealClock
|
||||
|
||||
|
||||
async def test_fake_clock_starts_at_zero_and_advances() -> None:
|
||||
clock = FakeClock()
|
||||
assert clock.now() == 0.0
|
||||
|
||||
await clock.advance(2.5)
|
||||
|
||||
assert clock.now() == 2.5
|
||||
|
||||
|
||||
async def test_sleep_blocks_until_time_is_advanced_past_the_deadline() -> None:
|
||||
clock = FakeClock()
|
||||
woken = asyncio.Event()
|
||||
|
||||
async def sleeper() -> None:
|
||||
await clock.sleep(10)
|
||||
woken.set()
|
||||
|
||||
task = asyncio.create_task(sleeper())
|
||||
await clock.advance(9)
|
||||
assert not woken.is_set()
|
||||
|
||||
await clock.advance(2)
|
||||
assert woken.is_set()
|
||||
await task
|
||||
|
||||
|
||||
async def test_sleepers_wake_in_deadline_order_regardless_of_start_order() -> None:
|
||||
clock = FakeClock()
|
||||
woken: list[str] = []
|
||||
|
||||
async def sleeper(name: str, delay: float) -> None:
|
||||
await clock.sleep(delay)
|
||||
woken.append(name)
|
||||
|
||||
tasks = [
|
||||
asyncio.create_task(sleeper("late", 30)),
|
||||
asyncio.create_task(sleeper("early", 10)),
|
||||
asyncio.create_task(sleeper("middle", 20)),
|
||||
]
|
||||
await clock.advance(60)
|
||||
|
||||
assert woken == ["early", "middle", "late"]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
|
||||
async def test_time_at_wake_up_is_the_deadline_not_the_target() -> None:
|
||||
clock = FakeClock()
|
||||
observed: list[float] = []
|
||||
|
||||
async def sleeper() -> None:
|
||||
await clock.sleep(5)
|
||||
observed.append(clock.now())
|
||||
|
||||
task = asyncio.create_task(sleeper())
|
||||
await clock.advance(100)
|
||||
|
||||
assert observed == [5.0]
|
||||
assert clock.now() == 100.0
|
||||
await task
|
||||
|
||||
|
||||
async def test_idle_hook_runs_after_each_wake_up() -> None:
|
||||
calls: list[int] = []
|
||||
|
||||
async def idle() -> None:
|
||||
calls.append(1)
|
||||
|
||||
clock = FakeClock(idle=idle)
|
||||
|
||||
async def sleeper() -> None:
|
||||
await clock.sleep(1)
|
||||
|
||||
task = asyncio.create_task(sleeper())
|
||||
await clock.advance(2)
|
||||
|
||||
assert calls # the bus got a chance to drain between virtual ticks
|
||||
await task
|
||||
|
||||
|
||||
async def test_pending_timers_is_visible() -> None:
|
||||
clock = FakeClock()
|
||||
task = asyncio.create_task(clock.sleep(5))
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert clock.pending_timers == 1
|
||||
await clock.advance(5)
|
||||
assert clock.pending_timers == 0
|
||||
await task
|
||||
|
||||
|
||||
async def test_zero_sleep_just_yields() -> None:
|
||||
clock = FakeClock()
|
||||
await clock.sleep(0)
|
||||
assert clock.now() == 0.0
|
||||
|
||||
|
||||
async def test_real_clock_measures_real_elapsed_time() -> None:
|
||||
clock = RealClock()
|
||||
before = clock.now()
|
||||
await clock.advance(0.01)
|
||||
assert clock.now() - before >= 0.005
|
||||
Reference in New Issue
Block a user