mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 18:07:22 +01:00
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RHwVPyiiQMPh4M3JQwQku
88 lines
3.0 KiB
Python
88 lines
3.0 KiB
Python
"""A sandbox poke is verified and answered, but writes and credits nothing."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from screen_locker import _poke_credit, _poke_server
|
|
from screen_locker._poke_credit import PokeLocker
|
|
from screen_locker._poke_wire import PokeRequest
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
_LOCKER_STEPS = (
|
|
"start_the_day",
|
|
"credit_written",
|
|
"_write_shutdown_config",
|
|
"_adjust_shutdown_time_later",
|
|
"_apply_credit_for_written_entry",
|
|
)
|
|
|
|
|
|
def _request(*, sandbox: bool) -> PokeRequest:
|
|
return PokeRequest(
|
|
sent_at_ms=1,
|
|
nonce="n",
|
|
sandbox=sandbox,
|
|
record_id="rec-1",
|
|
payload={"date": "2026-10-09"},
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def pc(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> dict[str, MagicMock]:
|
|
"""A real PokeLocker on a tmp log with every state-changing step spied."""
|
|
|
|
def headless(locker_cls: type[PokeLocker]) -> PokeLocker:
|
|
locker = object.__new__(locker_cls)
|
|
locker.log_file = tmp_path / "log.json"
|
|
return locker
|
|
|
|
spies = {name: MagicMock() for name in (*_LOCKER_STEPS, "ingest", "credit")}
|
|
for name in _LOCKER_STEPS:
|
|
monkeypatch.setattr(PokeLocker, name, spies[name])
|
|
monkeypatch.setattr(_poke_credit, "_headless_locker", headless)
|
|
monkeypatch.setattr(_poke_credit, "ingest_session_records", spies["ingest"])
|
|
monkeypatch.setattr(_poke_credit, "credit_session", spies["credit"])
|
|
monkeypatch.setattr(_poke_credit, "current_shutdown", lambda: "20:30")
|
|
monkeypatch.setattr(_poke_credit, "current_gaming_minutes", lambda _p: 75)
|
|
return spies
|
|
|
|
|
|
def test_sandbox_replies_ok_with_the_snapshot_and_nothing_credited(
|
|
pc: dict[str, MagicMock],
|
|
) -> None:
|
|
reply = _poke_server._process(_request(sandbox=True))
|
|
assert reply["ok"] is True
|
|
assert reply["sandbox"] is True
|
|
assert reply["credited"] is False
|
|
assert reply["duplicate"] is False
|
|
assert reply["shutdown"] == "20:30"
|
|
assert reply["gaming_budget_minutes"] == 75
|
|
assert "nothing written or credited" in str(reply["reason"])
|
|
|
|
|
|
def test_sandbox_never_logs_credits_or_touches_the_shutdown_config(
|
|
pc: dict[str, MagicMock], tmp_path: Path
|
|
) -> None:
|
|
before = sorted(p.name for p in tmp_path.iterdir())
|
|
_poke_server._process(_request(sandbox=True))
|
|
for name, spy in pc.items():
|
|
assert not spy.called, name
|
|
assert sorted(p.name for p in tmp_path.iterdir()) == before
|
|
assert not (tmp_path / "log.json").exists()
|
|
|
|
|
|
def test_a_real_poke_does_reach_the_credit_step(pc: dict[str, MagicMock]) -> None:
|
|
"""Guards the guard: the spies above are wired to the path a real poke takes."""
|
|
pc["credit"].return_value = _poke_credit.PokeOutcome(
|
|
ok=True, credited=True, duplicate=False, reason="workout credited"
|
|
)
|
|
reply = _poke_server._process(_request(sandbox=False))
|
|
assert reply["credited"] is True
|
|
pc["credit"].assert_called_once_with("rec-1", {"date": "2026-10-09"})
|