import asyncio import re import unittest from pathlib import Path from jinja2 import ChainableUndefined, Environment from core.template import TemplateRepository ROOT = Path(__file__).parent.parent TEMPLATE_ROOT = ROOT / "templates" class TemplateRepositoryTests(unittest.TestCase): def setUp(self): self.repository = TemplateRepository(TEMPLATE_ROOT) def test_all_pages_compose_to_valid_jinja_documents(self): pages = sorted((TEMPLATE_ROOT / "pages").glob("*.html")) page_styles = sorted((TEMPLATE_ROOT / "styles" / "pages").glob("*.css")) self.assertEqual(46, len(pages)) self.assertEqual( {page.stem for page in pages}, {style.stem for style in page_styles}, ) environment = Environment(undefined=ChainableUndefined) empty_context = { "data": {}, "icons": {"img": {}, "sect": {}, "serendipity": {}}, "items": [], "summary": {}, } for page in pages: with self.subTest(page=page.name): fragment = page.read_text(encoding="utf-8") for document_tag in ("!DOCTYPE", "html", "head", "style", "body"): self.assertIsNone( re.search(rf"<{document_tag}(?:\s|>)", fragment, re.IGNORECASE) ) template = asyncio.run(self.repository.get(page.name)) self.assertIn("", template) self.assertIn("
", template) self.assertNotIn("", template) self.assertNotIn("/*__PAGE_CSS__*/", template) rendered = environment.from_string(template).render(empty_context) self.assertIn("", rendered) def test_cache_returns_same_template_instance(self): first = asyncio.run(self.repository.get("helps.html")) second = asyncio.run(self.repository.get("helps.html")) self.assertIs(first, second) def test_rejects_path_traversal(self): with self.assertRaises(ValueError): asyncio.run(self.repository.get("../helps.html")) def test_help_page_catalogue_structure(self): fragment = (TEMPLATE_ROOT / "pages" / "helps.html").read_text( encoding="utf-8" ) categories = re.findall( r'