Text
")])) plain_readme = (plain.out / "README.md").read_text(encoding="utf-8") assert "## Weiterverarbeitung" in plain_readme and "--mathml" not in plain_readme + + +@pytest.mark.parametrize("tex,expected", [ + (r'\mbox{gr\"un}, \text{F\"{u}r}', r"\mbox{grün}, \text{Für}"), + (r'\text{ f{\"u}r } j', r"\text{ f{ü}r } j"), # braces stay balanced + (r"{\mathscr L}(A,b)={{\O }}", r"{\mathscr L}(A,b)={{\emptyset }}"), + (r"M\cap N=\text{\O }", r"M\cap N=\emptyset"), + (r"\Omega\neq\O", r"\Omega\neq\emptyset"), + (r"\begin{array}{@{}l@{\qquad \quad }l@{}} a & b\end{array}", r"\begin{array}{ll} a & b\end{array}"), + (r"\arraycolsep8pt\begin{array}{c@{\,}r} x\end{array}", r"\begin{array}{cr} x\end{array}"), + (r"a & =&\displaystyle b, \\ & \vdots &\displaystyle \\ c", r"a & =&\displaystyle b, \\ & \vdots &\\ c"), + (r"\frac{a}{b}+\{x\}", r"\frac{a}{b}+\{x\}"), +]) +def test_publisher_tex_is_made_portable(tex, expected): + """Pandoc's texmath rejects \\", \\O, @{…} and \\arraycolsep (Springer alt texts, QA3-06).""" + assert portable_tex(tex) == expected diff --git a/tests/test_merge.py b/tests/test_merge.py index 1a2d122..8277259 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -34,10 +34,10 @@ def test_merge_complete_book(convert, tmp_path): # links between chapters point into the merged file; colliding id "sec" renamed in chapter B assert '' in text and '' in text assert "[B](#c002-sec)" in text and "[A](#sec)" in text and "[hier](#sec)" in text - assert "[Kapitel B](#002-kapitel-b)" in text and '' in text + assert "[Kapitel B](#kap-002-kapitel-b)" in text and '' in text # media paths relative to the merged file, also inside image links assert "" in text - assert "[](#002-kapitel-b)" in text + assert "[](#kap-002-kapitel-b)" in text # code untouched assert '[kein](link.md) id="sec" `code`' in text # footnote defined in both chapters -> only once in the merged file @@ -63,8 +63,8 @@ def test_merge_to_other_location_rewrites_media_paths(convert, tmp_path): text = target.read_text(encoding="utf-8") assert not text.startswith("---") assert f"" in text - assert "1. [Kapitel A](#001-kapitel-a)" in text - assert "001-kapitel-a" in anchors_in(text) + assert "1. [Kapitel A](#kap-001-kapitel-a)" in text + assert "kap-001-kapitel-a" in anchors_in(text) def test_merge_invalid_directory(tmp_path): diff --git a/tests/test_pandoc.py b/tests/test_pandoc.py new file mode 100644 index 0000000..4f4e00c --- /dev/null +++ b/tests/test_pandoc.py @@ -0,0 +1,60 @@ +"""Pandoc path: merged file → EPUB/HTML with the filters from pandoc/ (skipped without pandoc).""" + +import re +import shutil +import subprocess +import zipfile +from pathlib import Path + +import pytest + +from conftest import Book, Doc +from epub2md.merge import main as merge_main + +pytestmark = pytest.mark.skipif(shutil.which("pandoc") is None, reason="pandoc nicht installiert") +FILTERS = Path(__file__).resolve().parent.parent / "pandoc" + + +def merged(convert, book: Book) -> Path: + run = convert(book) + assert merge_main([str(run.out)]) == 0 + return run.out / f"{run.report['input']['name'][:-5]}.md" + + +def pandoc(md: Path, *args: str) -> subprocess.CompletedProcess: + return subprocess.run(["pandoc", md.name, *args], cwd=md.parent, capture_output=True, text=True, check=True) + + +def links_and_ids(epub: Path) -> tuple[list[tuple[str, str]], dict[str, set[str]]]: + with zipfile.ZipFile(epub) as z: + docs = {n: z.read(n).decode("utf-8") for n in z.namelist() if n.endswith(".xhtml")} + ids = {n: set(re.findall(r'\bid="([^"]+)"', t)) for n, t in docs.items()} + links = [(n, h) for n, t in docs.items() for h in re.findall(r'href="([^"]+)"', t) + if not re.match(r"^[a-z]+:", h) and not h.endswith(".css")] + return links, ids + + +def test_epub_links_to_chapter_starts_resolve(convert): + """Chapter start anchors must begin with a letter: Pandoc's EPUB writer breaks '#039-…' (QA3-05).""" + docs = [Doc("a.xhtml", 'Text B.
"), + Doc("c.xhtml", "Nur eine Bildseite ohne Überschrift.
")] + md = merged(convert, Book(docs=docs)) + pandoc(md, "--toc", "-o", "buch.epub") + links, ids = links_and_ids(md.parent / "buch.epub") + broken = [] + for doc, href in links: + file, _, frag = href.partition("#") + target = str(Path(doc).parent / file).replace("\\", "/") if file else doc + target = re.sub(r"[^/]+/\.\./", "", target) + if target not in ids or (frag and frag not in ids[target]): + broken.append(f"{doc}: {href}") + assert not broken + + +def test_book_filter_turns_chapter_anchors_into_chapter_starts(convert): + docs = [Doc("a.xhtml", "a
"), Doc("b.xhtml", "b
")] + md = merged(convert, Book(docs=docs)) + html = pandoc(md, "-s", "--lua-filter", str(FILTERS / "book.lua"), "-t", "html").stdout + assert html.count('class="chapter-start"') == 2 + assert 'id="TOC"' in html and "Kapitel B" in html