diff options
Diffstat (limited to 'app/tests/test_extractors.py')
| -rw-r--r-- | app/tests/test_extractors.py | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/app/tests/test_extractors.py b/app/tests/test_extractors.py index 64666ba..619fe5a 100644 --- a/app/tests/test_extractors.py +++ b/app/tests/test_extractors.py @@ -53,6 +53,86 @@ class TxtExtractionTests(unittest.TestCase): with self.assertRaises(ValueError): extract_text(path) + def test_utf16_without_bom_detected(self): + self.assertEqual(self._extract("chapter one".encode("utf-16-le")), + "chapter one") + + def test_lone_nul_does_not_flip_to_utf16(self): + # A single stray NUL byte in an otherwise-ASCII UTF-8 file must not + # switch the whole book to a UTF-16 decode (mojibake): the text + # comes back readable instead. + self.assertEqual(self._extract(b"hello world\x00rest"), + "hello world\x00rest") + + def test_standalone_page_numbers_removed_but_years_kept(self): + from converter.extractors import clean_text + + cleaned = clean_text("Chapter 1\n\n42\n\nIt was 1984.") + self.assertNotIn("42", cleaned) + self.assertIn("1984", cleaned) + kept = clean_text("It was the year\n\n1984\n\nwhen it began.") + self.assertIn("1984", kept) + + +class EpubZipfileFallbackTests(unittest.TestCase): + """The no-ebooklib EPUB fallback: spine order, no TOC narration.""" + + @staticmethod + def _write_epub(path: Path): + import zipfile + + container = ("<?xml version=\"1.0\"?>" + "<container><rootfiles>" + "<rootfile full-path=\"OEBPS/content.opf\"/>" + "</rootfiles></container>") + opf = ("<?xml version=\"1.0\"?>" + "<package xmlns=\"http://www.idpf.org/2007/opf\">" + "<manifest>" + "<item id=\"nav\" href=\"nav.xhtml\" properties=\"nav\"/>" + "<item id=\"c2\" href=\"text/chapterB.xhtml\"/>" + "<item id=\"c1\" href=\"text/chapterA.xhtml\"/>" + "</manifest>" + "<spine><itemref idref=\"nav\"/>" + "<itemref idref=\"c2\"/><itemref idref=\"c1\"/></spine>" + "</package>") + with zipfile.ZipFile(path, "w") as zf: + zf.writestr("mimetype", "application/epub+zip") + zf.writestr("META-INF/container.xml", container) + zf.writestr("OEBPS/content.opf", opf) + zf.writestr("OEBPS/nav.xhtml", + "<html><body><p>Contents</p></body></html>") + zf.writestr("OEBPS/text/chapterA.xhtml", + "<html><body><p>Alpha text.</p></body></html>") + zf.writestr("OEBPS/text/chapterB.xhtml", + "<html><body><p>Beta text.</p></body></html>") + + def test_spine_order_and_no_nav(self): + from converter.extractors import _read_epub_zipfile + + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "book.epub" + self._write_epub(path) + items = _read_epub_zipfile(path) + + titles = [title for title, _ in items] + self.assertNotIn("nav", titles) + # Spine order (B before A) beats filename sort (A before B). + self.assertEqual(titles, ["chapterB", "chapterA"]) + + def test_unparsable_opf_falls_back_to_filename_order(self): + import zipfile + + from converter.extractors import _read_epub_zipfile + + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "book.epub" + with zipfile.ZipFile(path, "w") as zf: + zf.writestr("a.xhtml", "<html><body><p>A</p></body></html>") + zf.writestr("b.xhtml", "<html><body><p>B</p></body></html>") + items = _read_epub_zipfile(path) + + self.assertEqual([title for title, _ in items], ["a", "b"]) + def _build_test_epub(path: Path, chapters=(("One", "First chapter text."), ("Two", "Second chapter text."))) -> None: |
