62 lines
2.2 KiB
Python
62 lines
2.2 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
DOCS = ROOT / "docs"
|
|
MARKDOWN_LINK = re.compile(
|
|
r"!?\[[^\n]*?\]\((?P<destination><[^>]+>|[^)\s]+)"
|
|
)
|
|
|
|
|
|
class DocumentationStructureTests(unittest.TestCase):
|
|
def test_documentation_root_has_one_human_entry_point(self) -> None:
|
|
self.assertEqual(
|
|
[path.name for path in sorted(DOCS.glob("*.md"))],
|
|
["README.md"],
|
|
)
|
|
|
|
def test_documentation_front_doors_exist(self) -> None:
|
|
expected = (
|
|
DOCS / "strategy" / "PLATFORM_CORE_IDEAS.md",
|
|
DOCS / "strategy" / "ROADMAP.md",
|
|
DOCS / "strategy" / "STRATEGY_STATUS.md",
|
|
DOCS / "strategy" / "REFERENCE_JOURNEY_PROGRAM.md",
|
|
)
|
|
self.assertFalse([path for path in expected if not path.is_file()])
|
|
|
|
def test_local_markdown_links_resolve(self) -> None:
|
|
broken: list[str] = []
|
|
sources = [ROOT / "README.md", *sorted(DOCS.rglob("*.md"))]
|
|
for source in sources:
|
|
for line_number, line in enumerate(
|
|
source.read_text(encoding="utf-8").splitlines(),
|
|
start=1,
|
|
):
|
|
for match in MARKDOWN_LINK.finditer(line):
|
|
destination = match.group("destination")
|
|
if destination.startswith("<") and destination.endswith(">"):
|
|
destination = destination[1:-1]
|
|
path_text = destination.split("#", 1)[0]
|
|
if (
|
|
not path_text
|
|
or path_text.startswith(("/", "mailto:", "data:"))
|
|
or "://" in path_text
|
|
):
|
|
continue
|
|
target = (source.parent / path_text).resolve()
|
|
if not target.is_relative_to(ROOT):
|
|
continue
|
|
if not target.exists():
|
|
broken.append(
|
|
f"{source.relative_to(ROOT)}:{line_number}: {destination}"
|
|
)
|
|
self.assertEqual(broken, [])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|