"""Unit: `Clock`, `SystemClock` and `FakeClock` — the injectable time contract. `FakeClock` is the test clock every time-dependent server object is driven with (phase 05: "no test sleeps — all time via `FakeClock`"); these tests lock its behaviour so that contract is honest. """ from __future__ import annotations import pytest from undercooked.server.clock import Clock, FakeClock, SystemClock pytestmark = pytest.mark.unit def test_system_clock_reads_a_monotonic_clock() -> None: clock = SystemClock() first = clock.now() second = clock.now() assert second >= first def test_system_clock_accepts_a_substitute_time_function() -> None: values = iter([1.0, 2.5, 7.25]) clock = SystemClock(lambda: next(values)) assert clock.now() == 1.0 assert clock.now() == 2.5 assert clock.now() == 7.25 def test_fake_clock_starts_at_the_given_instant() -> None: assert FakeClock().now() == 0.0 assert FakeClock(start=12.5).now() == 12.5 def test_fake_clock_advances_and_reports_the_new_instant() -> None: clock = FakeClock(start=10.0) assert clock.advance(5.0) == 15.0 assert clock.now() == 15.0 assert clock.advance(0.5) == 15.5 assert clock.advance(0) == 15.5 def test_fake_clock_never_goes_backwards() -> None: clock = FakeClock() with pytest.raises(ValueError, match="cannot go backwards"): clock.advance(-1.0) assert clock.now() == 0.0 def test_both_clocks_satisfy_the_protocol() -> None: """The `Clock` protocol is a structural contract: both implementations must be usable anywhere a `Clock` is demanded.""" clocks: list[Clock] = [SystemClock(), FakeClock()] for clock in clocks: assert isinstance(clock.now(), float)