"""IMP-45 (#74) u2 — frontmatter ``slide_overrides`` surfacing. Covers ``src.mdx_normalizer.normalize_mdx_content`` and the helper ``_extract_slide_overrides``. The Stage 2 plan enumerates four cases: 1. Present — nested ``slide_overrides.css`` survives normalization verbatim. 2. Absent — return dict carries an empty ``slide_overrides`` mapping. 3. Non-string ``css`` — dropped (fail-closed against typo'd YAML shapes). 4. Title-only frontmatter — no ``slide_overrides`` key in metadata → ``{}``. Scope-lock: this unit only adds the new key to the return dict. The four pre-existing return keys (``clean_text``/``title``/``images``/``popups``/ ``tables``/``sections``) are asserted unchanged at the structural level. """ from __future__ import annotations from src.mdx_normalizer import _extract_slide_overrides, normalize_mdx_content _CSS_BLOCK = "" def _mdx_with_frontmatter(fm_body: str, body: str = "# 제목\n\n본문 한 줄.\n") -> str: return f"---\n{fm_body}---\n{body}" # -- case 1: present (nested css string survives verbatim) ------------------ def test_normalize_surfaces_nested_slide_overrides_css(): raw = _mdx_with_frontmatter( "title: 04 sample\n" "slide_overrides:\n" f" css: \"{_CSS_BLOCK}\"\n" ) result = normalize_mdx_content(raw) assert result["slide_overrides"] == {"css": _CSS_BLOCK} # Other axes unaffected by the new key. assert result["title"] == "04 sample" assert "본문" in result["clean_text"] # -- case 2: absent (no slide_overrides key in frontmatter) ----------------- def test_normalize_returns_empty_slide_overrides_when_key_absent(): raw = _mdx_with_frontmatter("title: 03 sample\n") result = normalize_mdx_content(raw) assert result["slide_overrides"] == {} # Confirm key is always present (callers can rely on .get without default). assert "slide_overrides" in result # -- case 3: non-string css (fail-closed drop) ------------------------------ def test_normalize_drops_non_string_css_under_slide_overrides(): # YAML list under .css should be dropped; sibling unknown keys survive # so the future generalization path (e.g., slide_overrides.js) stays # forward-compatible per the Stage 2 plan. raw = _mdx_with_frontmatter( "title: typo case\n" "slide_overrides:\n" " css:\n" " - .f29b__col_right { width: 320px; }\n" " note: experimental sibling\n" ) result = normalize_mdx_content(raw) assert "css" not in result["slide_overrides"] assert result["slide_overrides"].get("note") == "experimental sibling" # -- case 4: title-only frontmatter (no slide_overrides at all) ------------- def test_normalize_title_only_frontmatter_yields_empty_slide_overrides(): raw = _mdx_with_frontmatter("title: title only\n") result = normalize_mdx_content(raw) assert result["title"] == "title only" assert result["slide_overrides"] == {} # -- direct helper coverage (defensive against future return-shape drift) --- def test_extract_slide_overrides_non_mapping_returns_empty_dict(): # Frontmatter parsers can yield odd types if the user writes # ``slide_overrides: 42`` or ``slide_overrides: ".x{}"``. The helper # must coerce to ``{}`` rather than raise. for bad in (None, 42, "literal string", ["css"]): assert _extract_slide_overrides({"slide_overrides": bad}) == {} def test_extract_slide_overrides_passes_through_unknown_siblings(): payload = {"slide_overrides": {"css": ".a{}", "js": "console.log(1)"}} assert _extract_slide_overrides(payload) == { "css": ".a{}", "js": "console.log(1)", }