"""Comprehensive renderer audit tests for static/ui.js renderMd(). This file covers the full suite of markdown constructs an LLM might produce, with a focus on edge cases and combinations. Tests are grouped by construct. Python mirrors the renderMd/inlineMd pipeline at the level needed for each test — either source-level assertions (checking the JS source directly) or behavioural assertions (checking rendered HTML via a Python mirror). """ import re import pathlib UI_JS = (pathlib.Path(__file__).parent.parent / "static" / "ui.js").read_text(encoding="utf-8") import html as _html def _esc(s): return _html.escape(str(s), quote=True) def _inline_md(t): """Mirror of inlineMd() in ui.js — processes one line of text.""" _code_stash = [] t = re.sub(r"`([^`\n]+)`", lambda m: (_code_stash.append(f"{_esc(m.group(1))}") or f"\x00C{len(_code_stash)-1}\x00"), t) t = re.sub(r"\*\*\*(.+?)\*\*\*", lambda m: f"{_esc(m.group(1))}", t) t = re.sub(r"\*\*(.+?)\*\*", lambda m: f"{_esc(m.group(1))}", t) t = re.sub(r"\*([^*\n]+)\*", lambda m: f"{_esc(m.group(1))}", t) t = re.sub(r"~~(.+?)~~", lambda m: f"{_esc(m.group(1))}", t) t = re.sub(r"\x00C(\d+)\x00", lambda m: _code_stash[int(m.group(1))], t) return t def _apply_blockquotes(src): """Mirror of _applyBlockquotes() — handles nested + lists + blank lines.""" def replacer(m): block = m.group(0) lines = block.split("\n") while lines and (lines[-1].strip() in (">", "")): if lines[-1].strip() == ">": lines.pop(); break lines.pop() stripped = [re.sub(r"^>[ \t]?", "", l) for l in lines] inner_raw = "\n".join(stripped) if re.search(r"^>", inner_raw, re.MULTILINE): inner = _apply_blockquotes(inner_raw) elif re.search(r"^( )?[-*+] .+", inner_raw, re.MULTILINE): def inner_list(lb): ll = lb.strip().split("\n"); h = "" inner = re.sub(r"((?:^(?: )?[-*+] .+\n?)+)", lambda m2: inner_list(m2.group(0)), inner_raw, flags=re.MULTILINE) else: inner = "\n".join("
" if l.strip() == "" else _inline_md(l) for l in stripped) return f"
{inner}
" return re.sub(r"((?:^>[^\n]*(?:\n|$))+)", replacer, src, flags=re.MULTILINE) # ───────────────────────────────────────────────────────────────────────────── # Source-level structural checks (JS must contain these patterns) # ───────────────────────────────────────────────────────────────────────────── class TestSourceStructure: """Verify key patterns are present in ui.js.""" def test_crlf_normalisation_present(self): assert ".replace(/\\r\\n/g,'\\n').replace(/\\r/g,'\\n')" in UI_JS, ( "renderMd must normalise \\r\\n and bare \\r to \\n at the start" ) def test_strikethrough_in_inline_md(self): assert "~~(.+?)~~" in UI_JS and "" in UI_JS, ( "inlineMd must handle ~~strikethrough~~ → " ) def test_del_in_safe_tags(self): assert "del" in UI_JS and "SAFE_TAGS" in UI_JS, ( " must be in SAFE_TAGS so it is not HTML-escaped" ) def test_del_in_safe_inline(self): # SAFE_INLINE is used inside inlineMd safe_inline_idx = UI_JS.find("SAFE_INLINE") assert safe_inline_idx >= 0 window = UI_JS[safe_inline_idx: safe_inline_idx + 100] assert "del" in window, " must be in SAFE_INLINE" def test_task_list_checked_handled(self): assert "task-done" in UI_JS or "\\u2705" in UI_JS or "✅" in UI_JS, ( "Checked task list items [x] must produce a ✅ or task-done class" ) def test_task_list_unchecked_handled(self): assert "task-todo" in UI_JS or "\\u2610" in UI_JS or "☐" in UI_JS, ( "Unchecked task list items [ ] must produce ☐ or task-todo class" ) def test_nested_blockquote_recurse(self): assert "_applyBlockquotes" in UI_JS, ( "Blockquote handler must use a named function for recursive nesting" ) def test_blockquote_handler_is_function(self): assert "function _applyBlockquotes" in UI_JS, ( "Must define _applyBlockquotes as a named inner function for recursion" ) def test_old_single_line_blockquote_removed(self): assert "replace(/^> (.+)$/gm" not in UI_JS, ( "Old single-line blockquote rule must be removed" ) def test_h1_h2_h3_handled(self): for h in ("h1", "h2", "h3"): assert f"<{h}>" in UI_JS or f"`<{h}>" in UI_JS def test_ordered_list_value_attr(self): assert 'value=' in UI_JS, "Ordered list items must use value= to preserve numbering" def test_table_handler_present(self): assert "" in UI_JS and "" in UI_JS def test_fenced_code_lang_header(self): assert "pre-header" in UI_JS def test_autolink_present(self): # JS stores regex slashes as \/ — search for both forms assert ("https?:\\/\\/" in UI_JS or "https?://" in UI_JS) and "target=\"_blank\"" in UI_JS # ───────────────────────────────────────────────────────────────────────────── # Behavioural: inline formatting # ───────────────────────────────────────────────────────────────────────────── class TestInlineFormatting: def test_bold(self): assert _inline_md("**bold**") == "bold" def test_italic(self): assert _inline_md("*italic*") == "italic" def test_bold_italic(self): out = _inline_md("***bi***") assert "" in out def test_strikethrough(self): out = _inline_md("~~deleted~~") assert "deleted" == out def test_strikethrough_inline(self): out = _inline_md("keep ~~remove~~ keep") assert "remove" in out assert "keep" in out def test_inline_code(self): out = _inline_md("`git status`") assert "git status" in out def test_strikethrough_inside_code_not_processed(self): out = _inline_md("`~~not deleted~~`") assert "" not in out assert "~~not deleted~~" in out def test_bold_with_inline_code(self): # **`code`** → code out = _inline_md("**`code`**") # The code stash protects the backtick span from bold regex assert "" in out def test_xss_in_bold(self): out = _inline_md("****") assert "