summaryrefslogtreecommitdiff
path: root/tools/tests/test_check_docs.py
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-18 20:28:09 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-18 20:28:09 +0200
commit2071e2beda763137416ac386d4bb953711ec995d (patch)
treebdcf840cb457f8286c1d967410f98972eb99b50a /tools/tests/test_check_docs.py
parenta9b1dc8bd9354973eabd72f56d82b2eab6f48d56 (diff)
test(tools): add test-log judge, docs and policy checks with tests
- ciq_test_report.py: decides pass/fail from Run No Evil output instead of monkeydo's unreliable exit code; writes JUnit XML. - check_docs.py: offline check of relative links and GitHub anchors. - lint_project.py: project rules (headers, no logging outside Diag, no secret-like literals, no network APIs or permissions). - check_budgets.py with budgets.json: perf and memory gates. - make_icon.py: reproducible launcher icon. - 31 pytest tests, including Hypothesis fuzzing of the log parser and integration checks against the real docs and sources; ruff and mypy (strict) clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/tests/test_check_docs.py')
-rw-r--r--tools/tests/test_check_docs.py68
1 files changed, 68 insertions, 0 deletions
diff --git a/tools/tests/test_check_docs.py b/tools/tests/test_check_docs.py
new file mode 100644
index 0000000..67404c9
--- /dev/null
+++ b/tools/tests/test_check_docs.py
@@ -0,0 +1,68 @@
+"""Tests for tools/check_docs.py, the offline Markdown link checker."""
+
+from __future__ import annotations
+
+import re
+from pathlib import Path
+
+import check_docs as cd
+import pytest
+from conftest import PROJECT_ROOT
+from hypothesis import given
+from hypothesis import strategies as st
+
+
+@pytest.mark.parametrize(
+ ("heading", "anchor"),
+ [
+ ("12.4 How each symbology is proven scannable", "124-how-each-symbology-is-proven-scannable"),
+ ("3e. Writing values back: unknown", "3e-writing-values-back-unknown"),
+ ("1. Scope", "1-scope"),
+ ("`make sim` and noVNC", "make-sim-and-novnc"),
+ ("A — B", "a--b"),
+ ("[Link](x.md) text", "link-text"),
+ ],
+)
+def test_slugify_matches_github(heading: str, anchor: str) -> None:
+ assert cd.slugify(heading) == anchor
+
+
+@given(st.text())
+def test_slugify_output_is_anchor_safe(heading: str) -> None:
+ assert re.fullmatch(r"[\w\-]*", cd.slugify(heading))
+
+
+def write(tmp_path: Path, name: str, text: str) -> Path:
+ path = tmp_path / name
+ path.write_text(text, encoding="utf-8")
+ return path
+
+
+def test_repeated_headings_get_numbered_anchors(tmp_path: Path) -> None:
+ doc = write(tmp_path, "a.md", "# Notes\n\n## Notes\n\n```\n# not a heading\n```\n")
+ assert cd.anchors_of(doc) == {"notes", "notes-1"}
+
+
+def test_broken_links_are_reported(tmp_path: Path) -> None:
+ write(tmp_path, "other.md", "# Present\n")
+ doc = write(
+ tmp_path,
+ "a.md",
+ "# Top\n"
+ "[ok](#top) [ok2](other.md#present) [web](https://example.com/x)\n"
+ "[missing file](nope.md)\n"
+ "[missing anchor](other.md#absent)\n"
+ "`[inline code](ignored.md)`\n"
+ "```\n[fenced](ignored.md)\n```\n",
+ )
+ problems = cd.check_file(doc, tmp_path, {})
+ assert [(p.line, p.message) for p in problems] == [
+ (3, "missing file 'nope.md'"),
+ (4, "no heading for anchor '#absent' in other.md"),
+ ]
+
+
+def test_project_docs_have_no_broken_links() -> None:
+ cache: dict[Path, set[str]] = {}
+ problems = [p for f in cd.markdown_files(PROJECT_ROOT) for p in cd.check_file(f, PROJECT_ROOT, cache)]
+ assert problems == [], "\n".join(map(str, problems))