steam-backlog-enforcer/steam_backlog_enforcer/tests/_polls_helpers.py
Krzysztof kuhy Rudnicki d2565416aa Pylint gate covers tests, no suppressions
Tests are now linted by the 10.00 gate (ignore-paths dropped), with no
per-test disables. CtlServer/DaemonControl members the tests drive are
public (renamed, behaviour unchanged); SteamAPIClient._get takes its
params explicitly, as every caller already did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 12:17:07 +01:00

131 lines
4.1 KiB
Python

"""Shared builders and patches for the HLTB poll-count tracking tests."""
from __future__ import annotations
from contextlib import contextmanager
import json
from typing import TYPE_CHECKING
from unittest.mock import MagicMock, patch
from steam_backlog_enforcer._cmd_done import _report_assigned_confidence
from steam_backlog_enforcer.config import State
from steam_backlog_enforcer.scanning import _report_poll_confidence
from steam_backlog_enforcer.steam_api import GameInfo
if TYPE_CHECKING:
from collections.abc import Callable, Iterator
from pathlib import Path
TYPES = "steam_backlog_enforcer._hltb_types"
CMD = "steam_backlog_enforcer._cmd_done"
SCAN = "steam_backlog_enforcer.scanning"
SCANCONF = "steam_backlog_enforcer._scanning_confidence"
POLLS = "steam_backlog_enforcer._polls_reporting"
FETCH_CONFIDENCE = "steam_backlog_enforcer._hltb_confidence.fetch_hltb_confidence"
def poll_state(finished: list[int], current: int | None = None) -> State:
"""Return a state with the given finished games and current pick."""
s = State()
s.finished_app_ids = list(finished)
s.current_app_id = current
s.current_game_name = ""
return s
def make_game(
app_id: int,
name: str,
*,
total: int = 10,
unlocked: int = 0,
polls: tuple[int, int] = (0, 0),
) -> GameInfo:
"""Return an unplayed GameInfo; ``polls`` is (comp_100_count, count_comp)."""
comp_100_count, count_comp = polls
return GameInfo(
app_id,
name,
total,
unlocked,
playtime_minutes=0,
comp_100_count=comp_100_count,
count_comp=count_comp,
)
def write_cache(tmp_path: Path, data: dict[str, object]) -> Path:
"""Write ``data`` as the HLTB cache file under ``tmp_path`` and return it."""
cache_file = tmp_path / "hltb_cache.json"
cache_file.write_text(json.dumps(data), encoding="utf-8")
return cache_file
def filling_fetch(
hours: float, polls_n: int, count_comp_n: int = 0
) -> Callable[..., list[object]]:
"""Return a fake HLTB search that writes the same row for every game asked."""
def fake_fetch(
games: list[tuple[int, str]],
cache: dict[int, float],
polls: dict[int, int],
count_comp: dict[int, int],
**_kw: object,
) -> list[object]:
"""Write into the caches it is handed."""
for aid, _name in games:
cache[aid], polls[aid], count_comp[aid] = hours, polls_n, count_comp_n
return []
return fake_fetch
@contextmanager
def hltb_cache_patched(
cache_file: Path, tmp_path: Path, fetch: Callable[..., list[object]]
) -> Iterator[MagicMock]:
"""Point the HLTB cache at ``cache_file``; route confidence fetches to ``fetch``."""
with (
patch(f"{TYPES}.HLTB_CACHE_FILE", cache_file),
patch(f"{TYPES}.CONFIG_DIR", tmp_path),
patch(FETCH_CONFIDENCE, side_effect=fetch) as mock_fetch,
):
yield mock_fetch
@contextmanager
def echo_sink(target: str, echoed: list[str]) -> Iterator[MagicMock]:
"""Patch ``target._echo`` so each echoed first arg lands in ``echoed``."""
with patch(
f"{target}._echo", side_effect=lambda *a, **_: echoed.append(a[0])
) as mock_echo:
yield mock_echo
def poll_confidence_echoes(
chosen: GameInfo, games: list[GameInfo], polls: dict[int, int], state: State
) -> list[str]:
"""Run ``_report_poll_confidence`` with backfilled ``polls``; return its echoes."""
echoed: list[str] = []
with (
patch(f"{POLLS}._backfill_polls_for_finished", return_value=polls),
echo_sink(POLLS, echoed),
):
_report_poll_confidence(chosen, games, state)
return echoed
def assigned_confidence_echoes(
polls: dict[int, int], snapshot: list[dict[str, object]], state: State
) -> list[str]:
"""Run ``_report_assigned_confidence`` for app 1; return its echoes."""
echoed: list[str] = []
with (
patch(f"{CMD}._backfill_polls_for_finished", return_value=polls),
patch(f"{CMD}.load_snapshot", return_value=snapshot),
echo_sink(CMD, echoed),
):
_report_assigned_confidence(1, state)
return echoed