mirror of
https://github.com/kuhyx/steam-backlog-enforcer.git
synced 2026-11-11 18:33:49 +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>
77 lines
2.9 KiB
Python
77 lines
2.9 KiB
Python
"""Tests for _command_gate: the lock rules shared by the CLI and web jobs."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from contextlib import contextmanager
|
|
from typing import TYPE_CHECKING
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from steam_backlog_enforcer import _command_gate as _gate
|
|
from steam_backlog_enforcer.config import Config, State
|
|
from steam_backlog_enforcer.tests._main_helpers import locked_state
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Iterator
|
|
|
|
_PKG = "steam_backlog_enforcer._command_gate"
|
|
_CONFIGURED = Config(steam_api_key="k", steam_id="i")
|
|
|
|
|
|
@contextmanager
|
|
def _block(*, active: bool, days: float = 3.5) -> Iterator[None]:
|
|
"""Patch the total-block status the gate reads."""
|
|
status = MagicMock(days_remaining=days)
|
|
with (
|
|
patch(f"{_PKG}.is_total_block_active", return_value=active),
|
|
patch(f"{_PKG}.get_total_block_status", return_value=status),
|
|
):
|
|
yield
|
|
|
|
|
|
class TestLockReason:
|
|
"""Which commands the gate refuses, and why."""
|
|
|
|
def test_unconfigured_is_refused(self) -> None:
|
|
"""An unconfigured install refuses normal commands."""
|
|
assert _gate.lock_reason("status", Config(), State()) == (
|
|
_gate.NOT_CONFIGURED_MSG
|
|
)
|
|
|
|
@pytest.mark.parametrize("command", ["setup", "add-exception", "serve"])
|
|
def test_setup_commands_need_no_key(self, command: str) -> None:
|
|
"""Setup commands run without an API key."""
|
|
with _block(active=False):
|
|
assert _gate.lock_reason(command, Config(), State()) is None
|
|
|
|
def test_total_block_names_days_and_allowed_commands(self) -> None:
|
|
"""A total block names the time left and the allowed commands."""
|
|
with _block(active=True):
|
|
reason = _gate.lock_reason("scan", _CONFIGURED, State())
|
|
assert reason is not None
|
|
assert "Total gaming block active (3d 12h left)" in reason
|
|
assert "Allowed:" in reason
|
|
|
|
def test_exempt_commands_pass_the_total_block(self) -> None:
|
|
"""Exempt commands pass a total block."""
|
|
with _block(active=True):
|
|
assert _gate.lock_reason("status", _CONFIGURED, State()) is None
|
|
|
|
def test_manual_pick_lock_names_the_picks(self) -> None:
|
|
"""The manual pick lock names the locked picks."""
|
|
with _block(active=False):
|
|
reason = _gate.lock_reason("scan", _CONFIGURED, locked_state())
|
|
assert reason is not None
|
|
assert "Manual pick lock active (TestGame)" in reason
|
|
|
|
def test_exempt_commands_pass_the_pick_lock(self) -> None:
|
|
"""Exempt commands pass the pick lock."""
|
|
with _block(active=False):
|
|
assert _gate.lock_reason("status", _CONFIGURED, locked_state()) is None
|
|
|
|
def test_no_state_skips_the_pick_check(self) -> None:
|
|
"""Without state the pick lock is not checked."""
|
|
with _block(active=False):
|
|
assert _gate.lock_reason("scan", _CONFIGURED, None) is None
|