70
tests/test_readme_runtime_map.py
Normal file
70
tests/test_readme_runtime_map.py
Normal file
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
Regression test: README file map must stay in sync with scripts loaded by index.html.
|
||||
|
||||
Catches stale references (e.g. the old game.js) and missing documentation for
|
||||
any new modules added to the runtime.
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
INDEX_HTML = REPO_ROOT / "index.html"
|
||||
README_MD = REPO_ROOT / "README.md"
|
||||
|
||||
|
||||
def _scripts_from_index_html() -> set[str]:
|
||||
"""Return the set of .js paths referenced in <script src="..."> tags."""
|
||||
html = INDEX_HTML.read_text(encoding="utf-8")
|
||||
return set(re.findall(r'<script\s+src="([^"]+\.js)"', html))
|
||||
|
||||
|
||||
def _scripts_from_readme() -> set[str]:
|
||||
"""Return the set of js/ paths mentioned in the README Files section."""
|
||||
text = README_MD.read_text(encoding="utf-8")
|
||||
# Grab everything between "## Files" and the next "## " heading
|
||||
m = re.search(r"## Files\n(.*?)(?=\n## |\Z)", text, re.DOTALL)
|
||||
assert m, "README is missing a '## Files' section"
|
||||
files_section = m.group(1)
|
||||
return set(re.findall(r"`(js/[^`]+\.js)`", files_section))
|
||||
|
||||
|
||||
def test_no_stale_game_js_reference():
|
||||
"""README must not reference the old monolithic game.js."""
|
||||
text = README_MD.read_text(encoding="utf-8")
|
||||
# Only flag if game.js appears *inside* the Files section (not elsewhere in prose)
|
||||
m = re.search(r"## Files\n(.*?)(?=\n## |\Z)", text, re.DOTALL)
|
||||
assert m, "README is missing a '## Files' section"
|
||||
files_section = m.group(1)
|
||||
assert "game.js" not in files_section, (
|
||||
"Stale reference to game.js found in README Files section"
|
||||
)
|
||||
|
||||
|
||||
def test_readme_covers_all_runtime_scripts():
|
||||
"""Every <script> in index.html must be documented in the README."""
|
||||
loaded = _scripts_from_index_html()
|
||||
documented = _scripts_from_readme()
|
||||
undocumented = loaded - documented
|
||||
assert not undocumented, (
|
||||
f"Scripts loaded by index.html but missing from README: {undocumented}"
|
||||
)
|
||||
|
||||
|
||||
def test_readme_has_no_extra_scripts():
|
||||
"""README should not document scripts that index.html does not load."""
|
||||
loaded = _scripts_from_index_html()
|
||||
documented = _scripts_from_readme()
|
||||
extra = documented - loaded
|
||||
assert not extra, (
|
||||
f"Scripts documented in README but not loaded by index.html: {extra}"
|
||||
)
|
||||
|
||||
|
||||
def test_main_js_is_entry_point():
|
||||
"""README should identify js/main.js as the entry / bootstrap point."""
|
||||
text = README_MD.read_text(encoding="utf-8")
|
||||
m = re.search(r"## Files\n(.*?)(?=\n## |\Z)", text, re.DOTALL)
|
||||
assert m, "README is missing a '## Files' section"
|
||||
files_section = m.group(1)
|
||||
assert "main.js" in files_section, "README Files section should mention js/main.js"
|
||||
Reference in New Issue
Block a user