"""Regression tests for defects found in the independent QA run (.qa/QA_REPORT.md, IDs QA2-…).""" import re from conftest import Book, Doc def _pipe_rows(text: str) -> list[str]: return [ln for ln in text.splitlines() if ln.startswith("| ")] def test_pipe_in_inline_code_does_not_split_gfm_table(convert): """QA2-01: GFM splits table cells at every unescaped '|', also inside code spans and link targets.""" body = ("

Operatoren

" "" "" "
OperatorBedeutung
||logisches ODER
a | bLink
") run = convert(Book(docs=[Doc("c.xhtml", body)])) text = run.chapter("001") for row in _pipe_rows(text): cells = re.split(r"(?K

Text1.

' '' '

Zweite2.

' '' "

Danach kommt normaler Text.

") def _fences_closed(text: str) -> bool: """Every opening ``` fence has a closing line that consists only of backticks.""" open_fence = None for line in text.splitlines(): s = line.strip() if open_fence is None: m = re.match(r"(`{3,})", s) if m: open_fence = m.group(1) elif re.fullmatch(r"`{3,}", s) and len(s) >= len(open_fence): open_fence = None return open_fence is None def test_backlink_after_code_block_does_not_break_fence_commonmark(convert): """QA2-02: the ↩ backlink was appended to the closing ``` line, leaving the fence open.""" run = convert(Book(docs=[Doc("c.xhtml", NOTE_WITH_CODE)]), "--format", "commonmark") text = run.chapter("001") assert _fences_closed(text), text assert not re.search(r"\*\*\d+[:.]\*\* ```", text), "Fence hinter Notennummer ist kein Codeblock" assert "[↩](#fnref-001)" in text def test_backlink_after_code_block_does_not_break_fence_end_of_book(convert): run = convert(Book(docs=[Doc("c.xhtml", NOTE_WITH_CODE)]), "--footnotes", "end-of-book") notes = run.chapter("999") assert _fences_closed(notes), notes assert not re.search(r"\*\*\d+[:.]\*\* ```", notes), "Fence hinter Notennummer ist kein Codeblock" assert "[↩](001-k.md#fnref-001)" in notes NOTE_IN_HTML_TABLE = ('

K

' "
Zelle1
ab
" '

Text1.

' '') def test_note_referenced_from_html_table_and_text_has_target(convert): """QA2-03: GFM: the HTML-table reference pointed to #fn-001, but only a [^fn-001] definition existed.""" run = convert(Book(docs=[Doc("c.xhtml", NOTE_IN_HTML_TABLE)])) text = run.chapter("001") assert 'href="#fn-001"' in text and "Text[^fn-001]." in text assert re.search(r'id="fn-001"', text), text assert run.report["output_link_check"]["broken_count"] == 0 def _html_table(text: str) -> str: return text[text.index("")] def test_end_of_book_reference_inside_html_table_is_html(convert): """QA2-04: a Markdown link inside an HTML block is not rendered (shows up as literal text).""" run = convert(Book(docs=[Doc("c.xhtml", NOTE_IN_HTML_TABLE)]), "--footnotes", "end-of-book") table = _html_table(run.chapter("001")) assert "](" not in table, table assert '1' in table def test_inline_svg_inside_html_table_is_html_img(convert): """QA2-05: inline SVG in a complex table was written as Markdown image inside the HTML block.""" body = ('

T

Kopf
A' '' "
") run = convert(Book(docs=[Doc("c.xhtml", body)])) table = _html_table(run.chapter("001")) assert "![" not in table, table assert re.search(r'Kreis', table), table assert run.report["output_link_check"]["broken_count"] == 0 def test_multiple_blank_lines_inside_code_are_kept(convert): """QA2-06: runs of blank lines inside code blocks were collapsed to one (PEP 8: two between functions).""" code = "def f():\n pass\n\n\nclass K:\n pass\n\n\n\nx = 1" body = f"

K

Vorher

{code}

Nachher

" text = convert(Book(docs=[Doc("c.xhtml", body)])).chapter("001") assert f"```python\n{code}\n```" in text, text assert "\n\n\n" not in text.replace(code, "") # outside code blank lines are still normalized def _simple() -> Book: return Book(docs=[Doc("c.xhtml", "

K

Text.

")]) def test_report_must_not_overwrite_generated_output_file(convert, tmp_path): """QA2-07: --report OUTPUT/manifest.json silently replaced the manifest with the report.""" out = tmp_path / "ziel" run = convert(_simple(), "--report", str(out / "manifest.json"), out=out) assert run.rc == 1 assert "--report" in run.stderr assert not out.exists() def test_report_write_error_is_input_error_not_internal(convert, tmp_path): """QA2-07: an unwritable --report target ended with exit 4 ("Interner Fehler").""" import os import stat ro = tmp_path / "ro" ro.mkdir() os.chmod(ro, stat.S_IRUSR | stat.S_IXUSR) try: run = convert(_simple(), "--report", str(ro / "bericht.json"), out=tmp_path / "ziel") finally: os.chmod(ro, stat.S_IRWXU) assert run.rc == 1, run.stderr assert "Interner Fehler" not in run.stderr assert "Bericht" in run.stderr