Identifiers are a collection, but the whole dict was replaced per format, so the last file to report won outright — an EPUB declaring an ASIN, a Google id and a Calibre id kept none of them once a PDF contributed one ISBN. Accumulate instead, letting a declared identifier outrank one scraped off a page.
77 lines
2.9 KiB
Python
77 lines
2.9 KiB
Python
import pytest
|
|
from pathlib import Path
|
|
from datetime import date
|
|
from chitai.services.metadata_extractor import EpubExtractor, Extractor, PdfExtractor
|
|
|
|
|
|
@pytest.mark.asyncio()
|
|
class TestEpubExtractor:
|
|
async def test_extraction_by_path(self):
|
|
path = Path("tests/data_files/Moby Dick; Or, The Whale - Herman Melville.epub")
|
|
|
|
metadata = await EpubExtractor.extract_metadata(path)
|
|
|
|
assert metadata["title"] == "Moby Dick; Or, The Whale"
|
|
assert metadata["authors"] == ["Herman Melville"]
|
|
assert metadata["published_date"] == date(year=2001, month=7, day=1)
|
|
|
|
|
|
|
|
EPUB = Path("tests/data_files/Metamorphosis - Franz Kafka.epub")
|
|
PDF = Path("tests/data_files/Calculus Made Easy - Silvanus Thompson.pdf")
|
|
|
|
|
|
@pytest.mark.asyncio()
|
|
class TestIdentifierMerging:
|
|
"""A book's formats each contribute identifiers; none of them replaces the rest."""
|
|
|
|
async def test_every_format_contributes(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""
|
|
Identifiers are a collection, not a single value.
|
|
|
|
Merging the whole dict meant the last format to report won outright: an EPUB
|
|
declaring an ASIN, a Google volume id and a Calibre id kept none of them once
|
|
a PDF contributed one ISBN.
|
|
"""
|
|
|
|
async def epub(_file):
|
|
return {
|
|
"title": "How Linux Works",
|
|
"identifiers": {"isbn-13": "9781718500419", "asin": "1718500408"},
|
|
}
|
|
|
|
async def pdf(_file):
|
|
return {"identifiers": {"isbn-13": "9781718500402", "isbn-10": "1593270356"}}
|
|
|
|
monkeypatch.setattr(EpubExtractor, "extract_metadata", epub)
|
|
monkeypatch.setattr(PdfExtractor, "extract_metadata", pdf)
|
|
|
|
metadata = await Extractor.extract_metadata(
|
|
[Path("How Linux Works.epub"), Path("How Linux Works.pdf")]
|
|
)
|
|
|
|
assert metadata["identifiers"] == {
|
|
# Declared by the publisher's toolchain, so it outranks the PDF's, which
|
|
# was scraped off a copyright page that also prints the print edition's.
|
|
"isbn-13": "9781718500419",
|
|
"asin": "1718500408",
|
|
"isbn-10": "1593270356",
|
|
}
|
|
|
|
async def test_a_second_format_that_finds_nothing_erases_nothing(self) -> None:
|
|
"""The PDF fixture carries no ISBN, so it must leave the EPUB's alone."""
|
|
metadata = await Extractor.extract_metadata([EPUB, PDF])
|
|
|
|
assert metadata["identifiers"] == {"id": "http://www.gutenberg.org/5200"}
|
|
|
|
async def test_one_format_on_its_own_is_unaffected(self) -> None:
|
|
metadata = await Extractor.extract_metadata([EPUB])
|
|
|
|
assert metadata["identifiers"] == {"id": "http://www.gutenberg.org/5200"}
|
|
|
|
async def test_no_identifiers_anywhere_leaves_the_field_absent(self) -> None:
|
|
"""An empty dict would count as extracted metadata and overwrite nothing."""
|
|
metadata = await Extractor.extract_metadata([PDF])
|
|
|
|
assert "identifiers" not in metadata
|