epub2md/tests/test_chapters.py

124 lines
6 KiB
Python
Raw Normal View History

import yaml
from conftest import Book, Doc
def frontmatter(text: str) -> dict:
assert text.startswith("---\n")
return yaml.safe_load(text.split("---\n")[1])
def test_files_are_numbered_and_slugged(convert):
docs = [Doc("c1.xhtml", "<h1>Übersicht & Größen</h1><p>a</p>"), Doc("c2.xhtml", "<h1>Übersicht & Größen</h1><p>b</p>")]
run = convert(Book(docs=docs))
assert [p.name for p in run.chapters()] == ["001-uebersicht-groessen.md", "002-uebersicht-groessen.md"]
run_en = convert(Book(docs=docs), "--slug-language", "en")
assert run_en.chapters()[0].name == "001-ubersicht-grossen.md"
run_none = convert(Book(docs=docs), "--slug-language", "none")
assert run_none.chapters()[0].name == "001-übersicht-größen.md"
def test_h1_split_inside_one_file(convert):
body = "<h1>Eins</h1><p>a</p><h2>Eins.Eins</h2><p>b</p><h1>Zwei</h1><p>c</p>"
run = convert(Book(docs=[Doc("all.xhtml", body)]))
assert [p.name for p in run.chapters()] == ["001-eins.md", "002-zwei.md"]
assert "## Eins.Eins" in run.chapter("001")
def test_h2_split_with_chapter_level_2(convert):
body = "<h1>Teil I</h1><p>Intro</p><h2>Kapitel 1</h2><p>a</p><h2>Kapitel 2</h2><p>b</p>"
run = convert(Book(docs=[Doc("all.xhtml", body)]), "--chapter-level", "2")
names = [p.name for p in run.chapters()]
assert names == ["001-teil-i.md", "002-kapitel-1.md", "003-kapitel-2.md"]
assert run.chapter("002").count("\n# ") == 1 # exactly one H1 per file
def test_section_files_without_h1_continue_previous_chapter(convert):
docs = [
Doc("01.xhtml", "<h1>Kapitel 1</h1><p>a</p>"),
Doc("01b.xhtml", '<div class="wrap"><h2>1.1 Abschnitt</h2><p>b</p></div>'),
Doc("02.xhtml", "<h1>Kapitel 2</h1><p>c</p>"),
]
run = convert(Book(docs=docs))
assert len(run.chapters()) == 2
first = run.chapter("001")
assert "## 1.1 Abschnitt" in first
assert frontmatter(first)["source_hrefs"] == ["01.xhtml", "01b.xhtml"]
def test_headingless_documents_become_own_chapters_with_nav_title(convert):
docs = [Doc("titel.xhtml", "<p>Widmung für alle</p>"), Doc("c.xhtml", "<h1>Start</h1><p>x</p>")]
book = Book(docs=docs, nav=[("Widmung", "titel.xhtml"), ("Start", "c.xhtml")])
run = convert(book)
assert [p.name for p in run.chapters()] == ["001-widmung.md", "002-start.md"]
fm = frontmatter(run.chapter("001"))
assert fm["chapter_title"] == "Widmung"
assert "dedication" in fm["epub_type"]
def test_semantic_sections_are_split_and_classified(convert):
body = (
'<section epub:type="chapter"><h1>Kapitel</h1><p>Text</p></section>'
'<section epub:type="glossary"><h2>Glossar</h2><dl><dt>API</dt><dd>Schnittstelle.</dd></dl></section>'
'<section epub:type="bibliography"><h2>Literatur</h2><ul><li>Knuth, D.: TAOCP. '
'<a href="https://doi.org/10.1000/xyz">doi:10.1000/xyz</a>, ISBN 978-0-201-89683-1</li></ul></section>'
'<section epub:type="index"><h2>Sachregister</h2><p>A</p></section>'
'<section epub:type="index"><h2>Personenregister</h2><p>Knuth</p></section>'
)
run = convert(Book(docs=[Doc("b.xhtml", body)]))
names = [p.name for p in run.chapters()]
assert names == ["001-kapitel.md", "002-glossar.md", "003-literatur.md", "004-sachregister.md", "005-personenregister.md"]
assert frontmatter(run.chapter("002"))["epub_type"] == ["glossary"]
assert "**API:** Schnittstelle." in run.chapter("002")
lit = run.chapter("003")
assert "[doi:10.1000/xyz](https://doi.org/10.1000/xyz)" in lit and "ISBN 978-0-201-89683-1" in lit
assert "index-persons" in frontmatter(run.chapter("005"))["epub_type"]
readme = (run.out / "README.md").read_text(encoding="utf-8")
assert "Glossar: [Glossar](chapters/002-glossar.md)" in readme
assert "Personenregister: [Personenregister](chapters/005-personenregister.md)" in readme
types = {s["type"] for s in run.report["special_sections"]}
assert {"glossary", "bibliography", "index", "index-persons"} <= types
def test_wrapper_preamble_belongs_to_heading_chapter(convert):
body = '<div epub:type="chapter"><div class="ctx">Kontextinfo</div><h1>Kapitel</h1><p>Text</p></div>'
run = convert(Book(docs=[Doc("c.xhtml", body)]))
assert len(run.chapters()) == 1
text = run.chapter("001")
assert "Kontextinfo" in text and text.count("# Kapitel") == 1
def test_html_toc_document_is_not_duplicated(convert):
toc = '<h1>Inhaltsverzeichnis</h1><p><a href="a.xhtml">Kapitel A</a></p><p><a href="b.xhtml">Kapitel B</a></p><p><a href="b.xhtml#x">B.1</a></p>'
docs = [Doc("toc.xhtml", toc), Doc("a.xhtml", "<h1>A</h1><p>a</p>"), Doc("b.xhtml", '<h1>B</h1><p id="x">b</p>')]
run = convert(Book(docs=docs, nav=[("A", "a.xhtml"), ("B", "b.xhtml")]))
assert [p.name for p in run.chapters()] == ["001-a.md", "002-b.md"]
assert run.report["skipped_documents"] == [{"href": "OEBPS/toc.xhtml", "reason": "html-toc"}]
def test_short_title_page_is_kept(convert):
docs = [Doc("t.xhtml", "<p>Für M.</p>", "Widmung"), Doc("c.xhtml", "<h1>K</h1><p>x</p>")]
run = convert(Book(docs=docs, nav=[]))
assert len(run.chapters()) == 2
assert "Für M." in run.chapter("001")
def test_layout_table_headings_are_recognized(convert):
body = (
'<table class="Document_number"><tr><td>3</td><td class="Title_document">Grundlagen</td></tr></table>'
"<p>Text</p>"
'<table class="Head1"><tr><td>3.1</td><td>Einführung</td></tr></table><p>mehr</p>'
)
run = convert(Book(docs=[Doc("c.xhtml", body)]))
text = run.chapter("001")
assert "# 3 Grundlagen" in text
assert "## 3.1 Einführung" in text
assert "<table" not in text
def test_glossary_anchor_is_placed_before_bold_term(convert):
"""QA-F2: the anchor of a <dt id> must not end up inside the bold markers."""
body = ('<h1>K</h1><p><a href="#g">API</a></p><section epub:type="glossary"><h2>Glossar</h2>'
'<dl><dt id="g">API</dt><dd>Schnittstelle.</dd></dl></section>')
text = convert(Book(docs=[Doc("c.xhtml", body)])).chapter("002")
assert '<a id="g"></a>**API:** Schnittstelle.' in text