test(m1): add conftest fixtures and golden helpers

This commit is contained in:
Kjell Tore Guttormsen 2026-09-04 19:30:58 +02:00
commit d0be8fba11
5 changed files with 369 additions and 0 deletions

100
tests/conftest.py Normal file
View file

@ -0,0 +1,100 @@
"""Shared fixtures for the whole suite (plan Step 6).
Determinism here is a property of the interface, not of the harness. Tests get
`frozen_today` and pass it to scripts as `--today`; nothing monkeypatches
`datetime`. The difference matters: a script that only behaves deterministically
because a test patched the clock is a script whose callers cannot make it
behave deterministically at all, and `dagens` (build-brief 5.8) has to be
reproducible from the command line.
The autouse `fixtures_are_pristine` guard exists because the failure it catches
does not announce itself. A test that writes into `tests/fixtures/` leaves
every later run reading a corpus that no longer matches what it says it is, and
the eventual failure surfaces in some unrelated test hours later. Catching it
at the end of the offending test names the culprit.
"""
import os
import shutil
import pytest
from helpers import golden as golden_helper
from helpers import workspace as workspace_helper
from jobbsok_lib import paths
FIXTURES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures")
#: Every date in the corpus is relative to this. 2026-09-15 is a Tuesday, so
#: weekday-sensitive output does not accidentally land on a weekend.
FROZEN_TODAY = workspace_helper.FROZEN_TODAY
def pytest_addoption(parser):
parser.addoption(
"--update-golden",
action="store_true",
default=False,
help="rewrite golden files instead of comparing against them",
)
@pytest.fixture
def fixtures_dir():
"""Absolute path to the read-only fixture corpus."""
return FIXTURES_DIR
@pytest.fixture
def frozen_today():
"""The date the suite reasons from, passed to scripts as ``--today``."""
return FROZEN_TODAY
@pytest.fixture
def empty_workspace(tmp_path):
"""A scaffolded but empty build-brief section 5 workspace."""
root = str(tmp_path / "workspace")
paths.scaffold(root)
return root
@pytest.fixture
def workspace(empty_workspace):
"""A workspace with the fixture corpus copied in, when there is one.
The populated corpus arrives in plan Step 19; until then this is the
scaffolded tree, so tests written against it now keep working when the
corpus lands rather than being rewritten then.
"""
source = os.path.join(FIXTURES_DIR, "workspace")
if os.path.isdir(source):
shutil.copytree(source, empty_workspace, dirs_exist_ok=True)
return empty_workspace
@pytest.fixture
def golden(request):
"""`assert_golden` with the ``--update-golden`` flag already bound."""
update = request.config.getoption("--update-golden")
def compare(path, actual):
return golden_helper.assert_golden(path, actual, update=update)
return compare
@pytest.fixture(autouse=True)
def fixtures_are_pristine(request):
"""Fail the test that mutated the read-only corpus, at that test."""
if not os.path.isdir(FIXTURES_DIR):
yield
return
if request.config.getoption("--update-golden"):
# Golden regeneration is the one sanctioned write into the corpus.
yield
return
before = workspace_helper.snapshot_tree(FIXTURES_DIR)
yield
workspace_helper.assert_tree_unchanged(FIXTURES_DIR, before)