"""Tests for sibilla.markdown — server-side Markdown → HTML conversion.""" from sibilla.markdown import render, strip_markdown class TestBasicMarkdown: def test_empty_returns_empty(self): assert render("") == "" assert render(None) == "" def test_plain_text(self): result = render("Ciao mondo") assert "Ciao mondo" in result assert result.startswith("
")
def test_bold(self):
result = render("Test **bold** text")
assert "bold" in result
def test_italic(self):
result = render("Test *italic* text")
assert "italic" in result
def test_bold_italic(self):
result = render("Test ***bold italic*** text")
assert "" in result
assert "" in result
def test_inline_code(self):
result = render("Use `print()` function")
assert " ") >= 2
def test_single_line_break(self):
result = render("Line 1.\nLine 2.")
assert "Line 1." in result
assert "Line 2." in result
def test_multiple_paragraphs(self):
text = "Primo paragrafo.\n\nSecondo paragrafo.\n\nTerzo."
result = render(text)
assert "Primo paragrafo" in result
assert "Secondo paragrafo" in result
assert "Terzo" in result
# ── strip_markdown (TTS-friendly plain text) ──────────────────────
class TestStripMarkdown:
def test_empty_returns_empty(self):
assert strip_markdown("") == ""
assert strip_markdown(None) == ""
def test_plain_text_passes_through(self):
text = "Ciao mondo, oggi è una bella giornata."
assert strip_markdown(text) == text
def test_bold_double_asterisk(self):
result = strip_markdown("Questo è **importante** da sapere.")
assert result == "Questo è importante da sapere."
def test_bold_double_underscore(self):
result = strip_markdown("Questo è __importante__ da sapere.")
assert result == "Questo è importante da sapere."
def test_italic_single_asterisk(self):
result = strip_markdown("Una parola *italica* nel testo.")
assert result == "Una parola italica nel testo."
def test_italic_single_underscore(self):
result = strip_markdown("Una parola _italica_ nel testo.")
assert result == "Una parola italica nel testo."
def test_links_stripped(self):
result = strip_markdown(
"Visita [il nostro sito](https://example.com) per info."
)
assert result == "Visita il nostro sito per info."
def test_images_stripped(self):
result = strip_markdown(
"Ecco una foto: "
)
assert result == "Ecco una foto: logo"
def test_headings_stripped(self):
result = strip_markdown("# Titolo\n\nTesto del paragrafo.")
assert result == "Titolo\n\nTesto del paragrafo."
def test_code_blocks_stripped(self):
result = strip_markdown("```python\nprint('hello')\n```\n\nFine.")
assert "```" not in result
assert "print('hello')" in result
assert "Fine." in result
def test_inline_code_stripped(self):
result = strip_markdown("Usa il comando `pip install` per procedere.")
assert result == "Usa il comando pip install per procedere."
def test_blockquotes_stripped(self):
result = strip_markdown("> Questa è una citazione.\n> Seconda riga.")
assert "Questa è una citazione." in result
assert ">" not in result
def test_unordered_list_stripped(self):
result = strip_markdown("- Primo elemento\n- Secondo elemento\n- Terzo")
assert "Primo elemento" in result
assert "Secondo elemento" in result
assert "Terzo" in result
assert "-" not in result.split("Primo")[0]
def test_ordered_list_stripped(self):
result = strip_markdown("1. Primo\n2. Secondo\n3. Terzo")
assert "Primo" in result
assert "Secondo" in result
assert "Terzo" in result
def test_html_tags_stripped(self):
result = strip_markdown("Testo con HTML inline.")
assert result == "Testo con HTML inline."
def test_horizontal_rules_stripped(self):
result = strip_markdown("Prima sezione\n---\nSeconda sezione")
assert "---" not in result
assert "Prima sezione" in result
assert "Seconda sezione" in result
def test_multiple_blank_lines_collapsed(self):
result = strip_markdown("Riga 1\n\n\n\nRiga 2")
assert result == "Riga 1\n\nRiga 2"
def test_complex_mixed_markdown(self):
"""Realistic AI output with multiple markdown constructs."""
text = """## Risposta
**L'Odissea** è un poema epico attribuito a [Omero](https://it.wikipedia.org/wiki/Omero).
Ecco alcuni punti chiave:
- Composto intorno all'*VIII secolo a.C.*
- Narra il viaggio di **Ulisse**
- È diviso in `24 libri`
Per approfondire, vedi [Wikipedia](https://it.wikipedia.org)."""
result = strip_markdown(text)
# No markdown artifacts
assert "**" not in result
assert "*" not in result.split("VIII")[0] # no italic markers
assert "[" not in result
assert "](" not in result
assert "`" not in result
assert "##" not in result
assert "-" not in result.split("Composto")[0]
# Content preserved
assert "Odissea" in result
assert "Omero" in result
assert "VIII secolo a.C." in result
assert "Ulisse" in result
assert "24 libri" in result
assert "Wikipedia" in result
print()" in result
def test_headers(self):
result = render("# H1\n## H2\n### H3")
assert "H1
" in result
assert "H2
" in result
assert "H3
" in result
class TestLinks:
def test_basic_link(self):
result = render("[Google](https://google.com)")
assert 'Google' in result
def test_link_with_title(self):
result = render('[Home](https://example.com "Example Home")')
assert 'href="https://example.com"' in result
assert 'title="Example Home"' in result
def test_link_target_blank_is_preserved(self):
"""The markdown library doesn't add target, but if already in HTML..."""
# This tests that our sanitizer doesn't strip legitimate attrs
result = render("[link](https://a.com)")
assert "href" in result
class TestLists:
def test_unordered_list(self):
result = render("- Item 1\n- Item 2\n- Item 3")
assert "" in result
assert "
" in result
assert "
" in result or "" in result
def test_indented_code_block(self):
result = render(" code line 1\n code line 2")
assert "" in result or "" in result
class TestBlockquotes:
def test_blockquote(self):
result = render("> This is a quote\n> Second line")
assert "" in result
assert "This is a quote" in result
class TestTables:
def test_table(self):
result = render("| A | B |\n|---|---|\n| 1 | 2 |")
assert "
" in result
assert "
A " in result
assert "1 " in result
class TestHorizontalRule:
def test_hr(self):
result = render("---")
assert "
tags must be absent from rendered output."""
result = render("")
assert "" not in result
def test_event_handlers_stripped(self):
"""onerror/onclick handlers must be stripped even on allowed tags."""
result = render('')
assert "onerror" not in result
assert 'src="x"' in result # legitimate attrs preserved
def test_javascript_url_stripped(self):
result = render("[click](javascript:alert(1))")
# The link text might appear, but the javascript: href must not
assert "javascript:" not in result.lower()
assert "click" in result
def test_regular_html_preserved_in_markdown(self):
"""Sanitization should NOT strip tags that come from markdown rendering."""
result = render("**bold** and *italic*")
assert "bold" in result
assert "italic" in result
class TestParagraphs:
def test_paragraph_wrapping(self):
result = render("Line 1.\n\nLine 2.")
assert result.count("