ctx / src /tests /test_feature_user_story_tracker.py
Stevesolun's picture
Sync ctx 0d3237d (part 3)
e8a8059 verified
Raw
History Blame Contribute Delete
4.45 kB
from __future__ import annotations
import csv
import sys
import tomllib
from pathlib import Path
repo_root = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(repo_root / "src"))
from ctx.monitor import routes as monitor_routes # noqa: E402
TRACKER = repo_root / "docs" / "qa" / "feature-user-story-status.csv"
README = repo_root / "README.md"
PASS_STATUSES = {"Tested Pass", "Retested Pass"}
VALIDATION_STATUSES = {"Needs Validation"}
FIX_STATUSES = {"Needs Fix"}
ACTIONABLE_STATUSES = PASS_STATUSES | VALIDATION_STATUSES | FIX_STATUSES
def _tracker_rows() -> list[dict[str, str]]:
with TRACKER.open(newline="", encoding="utf-8") as f:
return list(csv.DictReader(f))
def _tracker_text() -> str:
return "\n".join(" ".join(row.values()) for row in _tracker_rows())
def test_feature_user_story_tracker_has_no_empty_core_fields() -> None:
rows = _tracker_rows()
assert rows
required = (
"feature_id",
"surface",
"feature",
"entrypoint_or_route",
"user_story",
"expected_behavior",
"test_command_or_steps",
"status",
"first_test_result",
"last_verified_at",
)
for row in rows:
for key in required:
assert row[key].strip(), f"{row.get('feature_id', '<unknown>')} missing {key}"
assert row["status"] in ACTIONABLE_STATUSES
if row["status"] in FIX_STATUSES:
for key in ("error_id", "error_summary", "fix_status"):
assert row[key].strip(), (
f"{row.get('feature_id', '<unknown>')} has "
f"{row['status']} without {key}"
)
if row["status"] in VALIDATION_STATUSES:
assert row["notes"].strip(), (
f"{row.get('feature_id', '<unknown>')} needs validation "
"without a validation note"
)
def test_feature_user_story_tracker_covers_all_console_scripts() -> None:
pyproject = tomllib.loads((repo_root / "pyproject.toml").read_text(encoding="utf-8"))
scripts = sorted(pyproject["project"]["scripts"])
tracker = _tracker_text()
assert scripts
assert [script for script in scripts if script not in tracker] == []
def test_feature_user_story_tracker_covers_monitor_route_inventory() -> None:
route_patterns: list[str] = []
route_patterns.extend(href for _key, _label, href in monitor_routes.NAV_ROUTES)
route_patterns.extend(sorted(monitor_routes.PAGE_ROUTES))
route_patterns.extend(sorted(monitor_routes.GET_API_ROUTES))
route_patterns.extend(monitor_routes.GET_API_PATTERNS)
route_patterns.extend(sorted(monitor_routes.POST_API_ROUTES))
route_patterns.extend(("/session/<session_id>", "/skill/<slug>"))
route_patterns = list(dict.fromkeys(route_patterns))
tracker = _tracker_text()
assert route_patterns
assert [route for route in route_patterns if route not in tracker] == []
def test_feature_user_story_tracker_covers_distribution_workflows() -> None:
workflows = (
".github/workflows/test.yml",
".github/workflows/docs.yml",
".github/workflows/huggingface-sync.yml",
".github/workflows/publish.yml",
".github/workflows/clean-host-contract.yml",
".github/workflows/xdist-experiment.yml",
)
tracker = _tracker_text()
assert [workflow for workflow in workflows if workflow not in tracker] == []
def test_feature_user_story_tracker_covers_maintainer_scripts() -> None:
scripts = sorted((repo_root / "scripts").glob("*.py"))
tracker = _tracker_text()
script_paths = [script.relative_to(repo_root).as_posix() for script in scripts]
assert scripts
assert [path for path in script_paths if path not in tracker] == []
def test_feature_user_story_tracker_covers_public_docs_assets() -> None:
assets = sorted((repo_root / "docs" / "assets" / "javascripts").glob("*.js"))
tracker = _tracker_text()
asset_paths = [asset.relative_to(repo_root).as_posix() for asset in assets]
assert assets
assert [path for path in asset_paths if path not in tracker] == []
def test_readme_shows_user_story_examples_from_tracker() -> None:
readme = README.read_text(encoding="utf-8")
assert "## Example user stories" in readme
assert "docs/qa/feature-user-story-status.csv" in readme
for feature_id in ("CLI-002", "CLI-026", "API-011"):
assert feature_id in readme