""" Regression tests for inline content inside block containers (spec S1). Inline tags are registered to ignore_handler because they are meant to be consumed by extract_text_content. Only

and

-

ever called it, so every other container - div, li, td, th, blockquote - iterated its children as blocks, and inline tags returned None. Their text was silently discarded, and bare text nodes each became a separate paragraph. """ import pytest from pyWebLayout.abstract.block import ( HList, Paragraph, Quote, Table, ) from pyWebLayout.abstract.inline import LinkedWord, Word from pyWebLayout.io.readers.html_extraction import parse_html_string def words_of(block): return [w.text for w in getattr(block, 'words', [])] def all_words(blocks): out = [] for block in blocks: out.extend(words_of(block)) return out def cell_blocks(table): for _, row in table.all_rows(): for cell in row.cells(): yield list(cell.blocks()) EXPECTED = ["hello", "world", "again"] class TestInlineContentIsKept: """The same markup must survive in every container.""" def test_paragraph_control(self): """

already worked - this is the reference behaviour.""" blocks = parse_html_string("

hello world again

") assert all_words(blocks) == EXPECTED def test_div(self): blocks = parse_html_string("
hello world again
") assert all_words(blocks) == EXPECTED def test_list_item(self): blocks = parse_html_string("") hlist = next(b for b in blocks if isinstance(b, HList)) item = list(hlist.items())[0] assert all_words(item.blocks()) == EXPECTED def test_table_cell(self): blocks = parse_html_string( "
hello world again
") table = next(b for b in blocks if isinstance(b, Table)) assert all_words(next(cell_blocks(table))) == EXPECTED def test_table_header_cell(self): blocks = parse_html_string( "
hello world again
") table = next(b for b in blocks if isinstance(b, Table)) assert all_words(next(cell_blocks(table))) == EXPECTED def test_blockquote(self): blocks = parse_html_string("
hello world again
") quote = next(b for b in blocks if isinstance(b, Quote)) assert all_words(quote.blocks()) == EXPECTED class TestInlineRunsCoalesce: """A run of inline content is one paragraph, not one per text node.""" def test_div_yields_a_single_paragraph(self): blocks = parse_html_string("
a b c
") paragraphs = [b for b in blocks if isinstance(b, Paragraph)] assert len(paragraphs) == 1, f"expected one paragraph, got {len(blocks)} blocks" assert words_of(paragraphs[0]) == ["a", "b", "c"] def test_cell_yields_a_single_paragraph(self): blocks = parse_html_string("
a b c
") table = next(b for b in blocks if isinstance(b, Table)) cell = next(cell_blocks(table)) assert len(cell) == 1 assert words_of(cell[0]) == ["a", "b", "c"] def test_block_child_splits_the_run(self): """Inline runs either side of a block child stay separate, in order.""" blocks = parse_html_string( "
before

middle

after
") table = next(b for b in blocks if isinstance(b, Table)) cell = next(cell_blocks(table)) assert [words_of(b) for b in cell] == [["before"], ["middle"], ["after"]] def test_line_break_splits_the_run(self): blocks = parse_html_string("
first
second
") paragraphs = [b for b in blocks if isinstance(b, Paragraph)] assert [words_of(p) for p in paragraphs] == [["first"], ["second"]] def test_whitespace_between_blocks_makes_no_paragraph(self): blocks = parse_html_string("
\n

one

\n

two

\n
") assert [words_of(b) for b in blocks] == [["one"], ["two"]] class TestLinksSurvive: """ must produce LinkedWord wherever it appears.""" def test_link_in_cell(self): blocks = parse_html_string( '
link text
') table = next(b for b in blocks if isinstance(b, Table)) cell = next(cell_blocks(table)) found = [w for b in cell for w in getattr(b, 'words', [])] assert [w.text for w in found] == ["link", "text"] linked = [w for w in found if isinstance(w, LinkedWord)] assert len(linked) == 1 assert linked[0].location == "http://x" def test_link_in_div(self): blocks = parse_html_string('
see Section 2 now
') found = [w for b in blocks for w in getattr(b, 'words', [])] assert [w.text for w in found] == ["see", "Section", "2", "now"] assert all(isinstance(w, LinkedWord) for w in found[1:3]) def test_link_in_list_item(self): blocks = parse_html_string('') hlist = next(b for b in blocks if isinstance(b, HList)) item = hlist._items[0] found = [w for b in item.blocks() for w in getattr(b, 'words', [])] assert [w.text for w in found] == ["click", "here"] assert isinstance(found[0], LinkedWord) class TestNestedContainers: def test_div_in_div(self): blocks = parse_html_string("
outer
inner
tail
") assert [words_of(b) for b in blocks] == [["outer"], ["inner"], ["tail"]] def test_block_children_still_pass_through(self): blocks = parse_html_string("

Title

Body

") assert len(blocks) == 2 assert words_of(blocks[0]) == ["Title"] assert words_of(blocks[1]) == ["Body"] def test_cell_containing_a_list(self): blocks = parse_html_string( "
intro
  • item
") table = next(b for b in blocks if isinstance(b, Table)) cell = next(cell_blocks(table)) assert isinstance(cell[0], Paragraph) assert words_of(cell[0]) == ["intro"] assert isinstance(cell[1], HList) class TestComments: def test_comment_text_is_not_content(self): blocks = parse_html_string("
realtext
") assert all_words(blocks) == ["real", "text"]