steam-backlog-enforcer/steam_backlog_enforcer/tests/test_total_block.py
Krzysztof kuhy Rudnicki 356530a01c
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (push) Waiting to run
Grade against 3.14 too, not just run on it
`requires-python` and the CI pin already said 3.14, but ruff, mypy and pylint
were still grading against 3.10 -- three tools judging an interpreter nothing
runs any more, and ruff withholding the pyupgrade fixes that only become safe
at the newer target. `pin_ci_python.py` rewrites exactly these three knobs.

What the stale target was hiding: `datetime.timezone.utc` where `datetime.UTC`
is now correct (UP017), `socket.timeout` where `TimeoutError` is (UP041),
deprecated `typing` imports (UP035), PEP 695 `type` aliases (UP040), and ruff's
stable formatter applying PEP 758 -- `except (A, B):` becomes `except A, B:`.
That last one makes the source 3.14-only at the syntax level, which is what
`requires-python = ">=3.14"` already promised; kuhy chose it deliberately over
holding ruff a release back (2026-08-29).

ruff, ruff-format, mypy --strict and pylint all clean at the new target. The
two modified web/ TypeScript files are another session's in-flight work and
are deliberately left unstaged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfnJmxxsZ534AKk16rC2Gr
2026-08-29 11:44:25 +02:00

137 lines
5.4 KiB
Python

"""Tests for the lock file and the status derived from it."""
from __future__ import annotations
from datetime import UTC, datetime
import json
from steam_backlog_enforcer._total_block import (
get_total_block_status,
is_total_block_active,
total_block_needs_cleanup,
)
from steam_backlog_enforcer.tests._total_block_paths import (
Paths,
write_lock,
)
PKG = "steam_backlog_enforcer._total_block"
_NOW = datetime.now(UTC).timestamp()
class TestIsTotalBlockActive:
"""Tests for is total block active."""
def test_no_lock_file(self) -> None:
"""Test that no lock file."""
assert is_total_block_active() is False
def test_active_lock(self, total_block_paths: Paths) -> None:
"""Test that active lock."""
write_lock(total_block_paths, _NOW, _NOW + 3600)
assert is_total_block_active() is True
def test_expired_lock(self, total_block_paths: Paths) -> None:
"""Test that expired lock."""
write_lock(total_block_paths, _NOW - 3600, _NOW - 1)
assert is_total_block_active() is False
def test_malformed_json(self, total_block_paths: Paths) -> None:
"""Test that malformed json."""
total_block_paths.lock_file.parent.mkdir(parents=True, exist_ok=True)
total_block_paths.lock_file.write_text("not json", encoding="utf-8")
assert is_total_block_active() is False
def test_non_dict_json(self, total_block_paths: Paths) -> None:
"""Test that non dict json."""
total_block_paths.lock_file.parent.mkdir(parents=True, exist_ok=True)
total_block_paths.lock_file.write_text("[1, 2, 3]", encoding="utf-8")
assert is_total_block_active() is False
def test_missing_until_key(self, total_block_paths: Paths) -> None:
"""Test that missing until key."""
total_block_paths.lock_file.parent.mkdir(parents=True, exist_ok=True)
total_block_paths.lock_file.write_text(
json.dumps({"days": 1}), encoding="utf-8"
)
assert is_total_block_active() is False
def test_non_numeric_until(self, total_block_paths: Paths) -> None:
"""Test that non numeric until."""
total_block_paths.lock_file.parent.mkdir(parents=True, exist_ok=True)
total_block_paths.lock_file.write_text(
json.dumps({"until": "not-a-number"}), encoding="utf-8"
)
assert is_total_block_active() is False
class TestTotalBlockNeedsCleanup:
"""Tests for total block needs cleanup."""
def test_no_lock_file(self) -> None:
"""Test that no lock file."""
assert total_block_needs_cleanup() is False
def test_active_lock_no_cleanup_needed(self, total_block_paths: Paths) -> None:
"""Test that active lock no cleanup needed."""
write_lock(total_block_paths, _NOW, _NOW + 3600)
assert total_block_needs_cleanup() is False
def test_expired_lock_needs_cleanup(self, total_block_paths: Paths) -> None:
"""Test that expired lock needs cleanup."""
write_lock(total_block_paths, _NOW - 3600, _NOW - 1)
assert total_block_needs_cleanup() is True
class TestGetTotalBlockStatus:
"""Tests for get total block status."""
def test_no_lock(self) -> None:
"""Test that no lock."""
status = get_total_block_status()
assert status.active is False
assert status.started_at is None
assert status.until is None
assert status.days == 0
assert status.days_remaining == 0.0
def test_active_lock(self, total_block_paths: Paths) -> None:
"""Test that active lock."""
write_lock(total_block_paths, _NOW, _NOW + 86400, days=1)
status = get_total_block_status()
assert status.active is True
assert status.days == 1
assert 0.0 < status.days_remaining <= 1.0
assert status.started_at is not None
assert status.until is not None
def test_expired_lock(self, total_block_paths: Paths) -> None:
"""Test that expired lock."""
write_lock(total_block_paths, _NOW - 7200, _NOW - 3600, days=1)
status = get_total_block_status()
assert status.active is False
assert status.days_remaining == 0.0
def test_malformed_json_returns_inactive(self, total_block_paths: Paths) -> None:
"""Test that malformed json returns inactive."""
total_block_paths.lock_file.parent.mkdir(parents=True, exist_ok=True)
total_block_paths.lock_file.write_text("garbage", encoding="utf-8")
status = get_total_block_status()
assert status.active is False
def test_non_int_days_defaults_to_zero(self, total_block_paths: Paths) -> None:
"""Test that non int days defaults to zero."""
total_block_paths.lock_file.parent.mkdir(parents=True, exist_ok=True)
total_block_paths.lock_file.write_text(
json.dumps({"started_at": _NOW, "until": _NOW + 3600, "days": "one"}),
encoding="utf-8",
)
status = get_total_block_status()
assert status.days == 0
# ──────────────────────────────────────────────────────────────
# Process killing
# ──────────────────────────────────────────────────────────────