91 lines
2.9 KiB
Python
91 lines
2.9 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from html.parser import HTMLParser
|
|
from pathlib import Path
|
|
from urllib.parse import urlparse
|
|
|
|
SITE_ROOT = Path(__file__).parents[1] / "docs" / "site"
|
|
ALLOWED_STATUSES = {"baseline", "validated", "backlog"}
|
|
|
|
|
|
class SiteParser(HTMLParser):
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self.ids: set[str] = set()
|
|
self.references: list[str] = []
|
|
|
|
def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
|
|
values = dict(attrs)
|
|
if values.get("id"):
|
|
self.ids.add(values["id"])
|
|
attribute = "href" if tag in {"a", "link"} else "src" if tag in {"script", "img"} else None
|
|
if attribute and values.get(attribute):
|
|
self.references.append(values[attribute])
|
|
|
|
|
|
def _parser() -> SiteParser:
|
|
parser = SiteParser()
|
|
parser.feed((SITE_ROOT / "index.html").read_text())
|
|
return parser
|
|
|
|
|
|
def test_docs_site_required_files_are_present() -> None:
|
|
for relative_path in ("index.html", "styles.css", "app.js", "experiments.json", "og.png"):
|
|
path = SITE_ROOT / relative_path
|
|
assert path.is_file(), relative_path
|
|
assert path.stat().st_size > 0, relative_path
|
|
assert (SITE_ROOT / "og.png").read_bytes().startswith(b"\x89PNG\r\n\x1a\n")
|
|
|
|
|
|
def test_docs_site_local_links_and_anchors_resolve() -> None:
|
|
parser = _parser()
|
|
for reference in parser.references:
|
|
if reference.startswith("#"):
|
|
assert reference[1:] in parser.ids, reference
|
|
continue
|
|
|
|
parsed = urlparse(reference)
|
|
if parsed.scheme or parsed.netloc or reference.startswith("/"):
|
|
continue
|
|
if reference == "../static/favicon.svg":
|
|
continue
|
|
|
|
local_path = (SITE_ROOT / parsed.path).resolve()
|
|
assert local_path.is_relative_to(SITE_ROOT.resolve()), reference
|
|
assert local_path.is_file(), reference
|
|
|
|
|
|
def test_docs_site_navigation_targets_every_top_level_section() -> None:
|
|
parser = _parser()
|
|
html = (SITE_ROOT / "index.html").read_text()
|
|
expected_sections = {
|
|
"overview",
|
|
"architecture",
|
|
"agent-loop",
|
|
"workspace",
|
|
"models",
|
|
"experiments",
|
|
"operations",
|
|
"timeline",
|
|
"repository",
|
|
}
|
|
assert expected_sections <= parser.ids
|
|
for section_id in expected_sections:
|
|
assert f'href="#{section_id}"' in html
|
|
|
|
|
|
def test_experiment_ledger_has_unique_stable_records() -> None:
|
|
experiments = json.loads((SITE_ROOT / "experiments.json").read_text())
|
|
assert len(experiments) >= 5
|
|
|
|
ids = [item["id"] for item in experiments]
|
|
assert len(ids) == len(set(ids))
|
|
for item in experiments:
|
|
assert item["status"] in ALLOWED_STATUSES
|
|
assert item["title"].strip()
|
|
assert item["summary"].strip()
|
|
assert item["area"].strip()
|
|
assert item["version"].strip()
|
|
assert isinstance(item["metrics"], list)
|