#!/usr/bin/env python3 """Deterministic structural tests for the committed desfoto.de build in site/. Run after `python3 scripts/build-site.py`: python3 -m unittest discover -s tests -v The tests only read generated files, so they are fast and side-effect free. """ from __future__ import annotations import json import re import sys import unittest from html import unescape from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SITE = ROOT / "site" SRC = ROOT / "src" sys.path.insert(0, str(SRC)) import pages # noqa: E402 from content import CONTACT, LEGAL, SITE as META # noqa: E402 ROUTE_PATHS = [route[0] for route in pages.ROUTES] HTML_FILES = [SITE / route[1] for route in pages.ROUTES] + [SITE / "404.html"] GTIN_HTML = SITE / "gtin" / "index.html" GTIN_IMPRESSUM = SITE / "gtin" / "impressum" / "index.html" GTIN_DATENSCHUTZ = SITE / "gtin" / "datenschutz" / "index.html" def read(path: Path) -> str: return path.read_text(encoding="utf-8") def visible_text(html_text: str) -> str: body = re.search(r"
", html_text, re.S) chunk = body.group(0) if body else html_text chunk = re.sub(r"<(script|style)\b.*?\1>", " ", chunk, flags=re.S) return unescape(re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", chunk))).strip() class BuildLayout(unittest.TestCase): def test_every_route_is_built(self): for route in pages.ROUTES: _path, rel = route[0], route[1] with self.subTest(route=route[0]): self.assertTrue((SITE / rel).is_file(), f"missing {rel}") def test_no_stray_html_files(self): expected = {route[1] for route in pages.ROUTES} | { "404.html", "gtin/index.html", "gtin/impressum/index.html", "gtin/datenschutz/index.html", "gtin/aktualisieren/index.html", } actual = {str(f.relative_to(SITE)) for f in SITE.rglob("*.html")} self.assertEqual(expected, actual) def test_site_files_are_world_readable(self): """The nginx worker is not root: 0600 build output would 403 in production.""" for path in SITE.rglob("*"): if path.is_dir(): continue with self.subTest(asset=str(path.relative_to(SITE))): self.assertTrue(path.stat().st_mode & 0o044, f"{path} is not world readable") def test_meta_files_exist(self): for rel in ( "sitemap.xml", "robots.txt", "site.webmanifest", "favicon.svg", ".well-known/security.txt", "assets/site.css", "assets/site.js", "assets/fonts.css", ): with self.subTest(rel=rel): self.assertTrue((SITE / rel).is_file(), f"missing {rel}") class HeadTags(unittest.TestCase): def test_titles_descriptions_and_canonicals(self): for path in ROUTE_PATHS: rel = dict((r[0], r[1]) for r in pages.ROUTES)[path] with self.subTest(route=path): text = read(SITE / rel) self.assertIn('', text) title = re.search(r"