mirror of
https://github.com/kuhyx/steam-backlog-enforcer.git
synced 2026-11-11 22:13:48 +01:00
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>
131 lines
4.1 KiB
Python
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
|