"""Кооперативный дедлайн разбора (design D-8, ruling R-3): проверка между шагами, часы подменяются в тестах.""" import inspect import time import pytest from src.parser.deadline import Deadline from src.parser.errors import ParseTimeoutError class FakeClock: """Часы-заглушка: время двигается только вручную.""" def __init__(self) -> None: self.now = 1000.0 def __call__(self) -> float: return self.now def test_check_passes_within_limit() -> None: clock = FakeClock() deadline = Deadline(10, clock=clock) clock.now += 10 deadline.check("иерархия") # ровно на границе лимита — ещё не превышен def test_check_raises_after_limit_with_step_name() -> None: clock = FakeClock() deadline = Deadline(120, clock=clock) clock.now += 120.5 with pytest.raises(ParseTimeoutError) as raised: deadline.check("иерархия (outline)") assert raised.value.message == "превышен лимит 120 с на шаге иерархия (outline)" def test_limit_is_counted_from_creation() -> None: clock = FakeClock() clock.now += 500 deadline = Deadline(1, clock=clock) deadline.check("старт") def test_default_clock_is_monotonic() -> None: default = inspect.signature(Deadline).parameters["clock"].default assert default is time.monotonic def test_default_clock_measures_real_time() -> None: Deadline(60).check("сразу") # монотонные часы: свежий лимит не превышен with pytest.raises(ParseTimeoutError): Deadline(-1).check("уже в прошлом") # граница раньше «сейчас» по тем же часам