utils/focus_project/focus_project/tests/conftest.py
Krzysztof kuhy Rudnicki 4c1ffd900b focus_project: interview milestones, evidence
Project.kind (focus default; old rows load unchanged) plus interview
fields test_at, invite_url, trips, weekend_answers. Interview budget
30 min weekdays / 120 Sat-Sun, exempt from daily_floor, unlock clamped
after the 0.7.0 history ratchet. Milestones are generated (rules,
trip_ask, phone, mock, slot), never stored. Append-only evidence store
behind the _paths seam. Calendar dropped: slot = slot entry + slot_confirm.

Failure paths:
- unanswered trip question: fail closed (reads as a trip, phone due)
- late no-trip answer cannot erase an overdue phone milestone: closed
- phone source missing/stale/crashed: unknown, locks: fail closed
- trip_ask answer: evidence row first, then registry; a crash between
  leaves the question open: fail closed
- add_trip/answer_weekend loosening: ValueError, nothing written
- owed_lock with unreadable registry or evidence: fail open, logged
  (focus-guard's unreadable-registry rule); test day never locks
- status() milestones with unreadable evidence: empty list, logged
- torn or non-utf8 evidence lines: skipped and logged

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWZUTC9Zzdzsx7VW7dm
2026-11-10 15:39:30 +01:00

56 lines
1.9 KiB
Python

# Copyright (c) 2026 Krzysztof Rudnicki
"""Redirect the data directory away from the real one, for every test.
Every path resolves through :func:`focus_project._paths.data_dir`, which
honours ``FOCUS_PROJECT_DATA``, so one env var moves all of them.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from focus_project import _clock, _paths, checks
if TYPE_CHECKING:
from pathlib import Path
@pytest.fixture(autouse=True)
def _redirect_state(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
"""Point the data directory at ``tmp_path`` before any test runs."""
monkeypatch.setenv("FOCUS_PROJECT_DATA", str(tmp_path / "data"))
# Read-only evidence files and the signing key: never the real ones.
monkeypatch.setenv("FOCUS_PROJECT_LEETCODE_LEDGER", str(tmp_path / "lc.json"))
monkeypatch.setenv("KUHYTRACK_ENV", str(tmp_path / "no-kuhytrack-env"))
monkeypatch.setenv("FOCUS_PROJECT_KEY", str(tmp_path / "hmac.key"))
@pytest.fixture(autouse=True)
def _far_future_clock(monkeypatch: pytest.MonkeyPatch) -> None:
"""Pin "now" to 2030 so fixture days of 2026 are past, never in the future.
Tests about the clock itself set ``_clock.now`` explicitly.
"""
monkeypatch.setattr(_clock, "now", lambda: 1_893_456_000.0)
@pytest.fixture
def data(tmp_path: Path) -> Path:
"""The redirected data directory (may not exist yet)."""
return tmp_path / "data"
@pytest.fixture(autouse=True)
def _interview_isolation(
monkeypatch: pytest.MonkeyPatch, tmp_path: Path, _redirect_state: None
) -> None:
"""Evidence lives under the redirected data dir; sources are a private copy.
Fails closed (R3): if the path seam ever resolves outside ``tmp_path`` the
test errors before it can write a production evidence row.
"""
assert _paths.evidence_dir().is_relative_to(tmp_path)
monkeypatch.setattr(checks, "SOURCES", dict(checks.SOURCES))