"""Unit tests for html_to_sx converter.""" from __future__ import annotations import pytest from shared.sx.html_to_sx import html_to_sx class TestBasicElements: def test_simple_paragraph(self): assert html_to_sx("

Hello

") == '(p "Hello")' def test_with_class(self): assert html_to_sx('

Hi

') == '(p :class "intro" "Hi")' def test_multiple_attrs(self): result = html_to_sx('click') assert result == '(a :href "u" :class "link" "click")' def test_nested_inline(self): result = html_to_sx("

Hello world

") assert result == '(p "Hello " (em "world"))' def test_deeply_nested(self): result = html_to_sx("

bold

") assert result == '(div (p (strong "bold")))' class TestVoidElements: def test_br(self): assert html_to_sx("
") == "(br)" def test_img(self): result = html_to_sx('pic') assert result == '(img :src "a.jpg" :alt "pic")' def test_hr(self): assert html_to_sx("
") == "(hr)" def test_input(self): result = html_to_sx('') assert result == '(input :type "text" :value "hi")' class TestBooleanAttrs: def test_checked(self): result = html_to_sx('') assert result == '(input :type "checkbox" :checked true)' def test_disabled(self): result = html_to_sx('') assert result == '(button :disabled true "No")' def test_controls(self): result = html_to_sx('') assert result == '(video :controls true)' class TestTopLevel: def test_multiple_top_level(self): result = html_to_sx("

A

B

") assert result == '(<> (p "A") (p "B"))' def test_single_top_level(self): result = html_to_sx("

Only

") assert result == '(p "Only")' def test_text_only(self): result = html_to_sx("just text") assert result == '"just text"' def test_empty(self): assert html_to_sx("") == '""' def test_whitespace_only(self): assert html_to_sx(" \n ") == '""' class TestWhitespace: def test_root_whitespace_stripped(self): result = html_to_sx("\n

A

\n

B

\n") assert result == '(<> (p "A") (p "B"))' class TestEntities: def test_amp(self): result = html_to_sx("

A & B

") assert result == '(p "A & B")' def test_lt_gt(self): result = html_to_sx("

<tag>

") assert result == '(p "")' def test_nbsp(self): result = html_to_sx("

hello world

") assert result == '(p "hello\u00a0world")' class TestEscaping: def test_quotes_in_text(self): result = html_to_sx('

He said "hello"

') assert result == '(p "He said \\"hello\\"")' def test_backslash_in_text(self): result = html_to_sx("

a\\b

") assert result == '(p "a\\\\b")' def test_quotes_in_attr(self): # Attribute values with quotes get escaped result = html_to_sx('
x
') assert result == '(div :title "a\\"b" "x")' class TestComments: def test_comment_stripped(self): result = html_to_sx("

hi

") assert result == '(p "hi")' class TestMixedContent: def test_caption_with_link(self): result = html_to_sx('Photo by Author') assert result == '(<> "Photo by " (a :href "https://x.com" "Author"))' def test_caption_plain_text(self): result = html_to_sx("Figure 1") assert result == '"Figure 1"' class TestRoundtrip: """html_to_sx → parse → render should produce equivalent HTML.""" def _roundtrip(self, html_in: str) -> str: from shared.sx.parser import parse from shared.sx.html import render sx_src = html_to_sx(html_in) expr = parse(sx_src) return render(expr) def test_simple(self): assert self._roundtrip("

Hello

") == "

Hello

" def test_nested(self): assert self._roundtrip("

A B C

") == "

A B C

" def test_void(self): assert self._roundtrip('') == '' def test_link(self): html = 'click' assert self._roundtrip(html) == html def test_entities_roundtrip(self): # Entities get decoded by parser, then re-escaped by render assert self._roundtrip("

A & B

") == "

A & B

" def test_multi_block(self): html = "

A

B

" assert self._roundtrip(html) == html