"""Unit tests for EPUB structure parsing (no rendering involved).""" import pytest import app from tests.helpers import build_epub_tree def test_missing_container_xml_raises(tmp_path): (tmp_path / "META-INF").mkdir() with pytest.raises(ValueError, match="missing META-INF/container.xml"): app.parse_opf(tmp_path) def test_container_xml_without_rootfile_raises(tmp_path): (tmp_path / "META-INF").mkdir() (tmp_path / "META-INF" / "container.xml").write_text( '', encoding="utf-8", ) with pytest.raises(ValueError, match="no rootfile"): app.parse_opf(tmp_path) def test_parse_opf_returns_meta_spine_and_pdir_ltr(tmp_path): build_epub_tree(tmp_path) meta, opf_dir, spine, pdir = app.parse_opf(tmp_path) assert meta["title"] == "Tree Book" assert meta["creator"] == "Tree Author" assert meta["language"] == "en" assert str(opf_dir).endswith("OEBPS") assert [i["href"] for i in spine] == ["chapter1.xhtml", "chapter2.xhtml"] # img filtered out assert pdir == "ltr" # unset defaults to ltr def test_parse_opf_rtl_page_progression(tmp_path): build_epub_tree(tmp_path, pdir="rtl") _, _, _, pdir = app.parse_opf(tmp_path) assert pdir == "rtl" def test_nonlinear_spine_items_are_skipped(tmp_path): items = [ ("front", "front.xhtml", "application/xhtml+xml", ""), ("ch1", "chapter1.xhtml", "application/xhtml+xml", ""), ] build_epub_tree(tmp_path, items=items, spine_ids=["ch1"]) # Add a non-linear itemref for 'front' via raw OPF edit opf_path = tmp_path / "OEBPS" / "book.opf" text = opf_path.read_text(encoding="utf-8") text = text.replace( '', '' '', ) opf_path.write_text(text, encoding="utf-8") _, _, spine, _ = app.parse_opf(tmp_path) assert [i["href"] for i in spine] == ["chapter1.xhtml"] def test_empty_spine_falls_back_to_non_nav_html(tmp_path): items = [ ("nav", "nav.xhtml", "application/xhtml+xml", "nav"), ("ch1", "chapter1.xhtml", "application/xhtml+xml", ""), ("img1", "img.png", "image/png", ""), ] build_epub_tree(tmp_path, items=items, spine_ids=[]) # spine refs: none _, _, spine, _ = app.parse_opf(tmp_path) assert [i["href"] for i in spine] == ["chapter1.xhtml"] # nav + image excluded def test_no_readable_content_raises(tmp_path): items = [("img1", "img.png", "image/png", "")] build_epub_tree(tmp_path, items=items, spine_ids=["img1"]) with pytest.raises(ValueError, match="No readable content"): app.parse_opf(tmp_path)