| from pathlib import Path |
|
|
| import pytest |
| from ebooklib import epub |
|
|
| from backend.epub import EpubConfig, parse_epub |
|
|
|
|
| def _write_sample_epub(target: Path, chapter_count: int = 2) -> Path: |
| book = epub.EpubBook() |
| book.set_identifier("sample-id") |
| book.set_title("Sample Book") |
| book.set_language("en") |
| book.add_author("Example Author") |
|
|
| chapters = [] |
| for idx in range(chapter_count): |
| chapter = epub.EpubHtml( |
| title=f"Chapter {idx + 1}", |
| file_name=f"chap_{idx + 1}.xhtml", |
| lang="en", |
| ) |
| chapter.content = ( |
| f"<h1>Chapter {idx + 1}</h1>" |
| f"<p>This is chapter {idx + 1}. It has enough words to estimate audio.</p>" |
| ) |
| book.add_item(chapter) |
| chapters.append(chapter) |
|
|
| book.toc = tuple(chapters) |
| book.spine = ["nav", *chapters] |
| book.add_item(epub.EpubNcx()) |
| book.add_item(epub.EpubNav()) |
| epub.write_epub(str(target), book) |
| return target |
|
|
|
|
| def test_parse_epub_extracts_metadata_and_chapters(tmp_path: Path) -> None: |
| epub_path = _write_sample_epub(tmp_path / "sample.epub", chapter_count=3) |
|
|
| payload = parse_epub(epub_path, config=EpubConfig(max_file_bytes=2_000_000)) |
|
|
| assert payload["title"] == "Sample Book" |
| assert payload["author"] == "Example Author" |
| assert len(payload["chapters"]) == 3 |
| assert payload["chapters"][0]["title"] == "Chapter 1" |
| assert payload["chapters"][0]["included"] is True |
| assert payload["chapters"][0]["text"] |
|
|
|
|
| def test_parse_epub_rejects_oversized_upload(tmp_path: Path) -> None: |
| epub_path = _write_sample_epub(tmp_path / "sample.epub", chapter_count=1) |
|
|
| with pytest.raises(ValueError, match="too large"): |
| parse_epub(epub_path, config=EpubConfig(max_file_bytes=32)) |
|
|
|
|
| def test_parse_epub_rejects_malformed_file(tmp_path: Path) -> None: |
| bad_path = tmp_path / "bad.epub" |
| bad_path.write_text("not really an epub", encoding="utf-8") |
|
|
| with pytest.raises(ValueError, match="Invalid EPUB"): |
| parse_epub(bad_path, config=EpubConfig(max_file_bytes=2_000_000)) |
|
|
|
|
| def test_parse_epub_accepts_valid_epub_without_epub_suffix(tmp_path: Path) -> None: |
| epub_path = _write_sample_epub(tmp_path / "sample.epub", chapter_count=1) |
| no_suffix_path = tmp_path / "upload-cache-file" |
| no_suffix_path.write_bytes(epub_path.read_bytes()) |
|
|
| payload = parse_epub(no_suffix_path, config=EpubConfig(max_file_bytes=2_000_000)) |
|
|
| assert payload["title"] == "Sample Book" |
| assert len(payload["chapters"]) == 1 |
|
|