XmLLM / tests /unit /test_canonical_builder.py
Claude
Code quality: fix all ruff warnings, add CI/CD, improve test coverage
bbbfba8 unverified
Raw
History Blame Contribute Delete
3.95 kB
"""Tests for the CanonicalBuilder."""
from __future__ import annotations
import pytest
from src.app.domain.models import (
EvidenceType,
Geometry,
GeometryStatus,
Provenance,
)
from src.app.domain.models.status import BlockRole, InputType
from src.app.normalization.canonical_builder import CanonicalBuilder
def _geo() -> Geometry:
return Geometry(bbox=(100, 200, 300, 50), status=GeometryStatus.EXACT)
def _prov(ref: str = "$.test") -> Provenance:
return Provenance(
provider="test",
adapter="test.v1",
source_ref=ref,
evidence_type=EvidenceType.PROVIDER_NATIVE,
)
class TestCanonicalBuilder:
def test_minimal_document(self) -> None:
builder = CanonicalBuilder("doc1", InputType.IMAGE, "test.png")
page = builder.add_page("p1", 0, 2480, 3508)
region = page.add_text_region("tb1", _geo(), _prov(), role=BlockRole.BODY)
line = region.add_line("tl1", _geo(), _prov())
line.add_word("w1", "Hello", _geo(), _prov(), confidence=0.95)
doc = builder.build()
assert doc.document_id == "doc1"
assert len(doc.pages) == 1
assert len(doc.pages[0].text_regions) == 1
assert doc.pages[0].text_regions[0].lines[0].words[0].text == "Hello"
def test_reading_order_auto_built(self) -> None:
builder = CanonicalBuilder("doc1", InputType.IMAGE)
page = builder.add_page("p1", 0, 100, 100)
page.add_text_region("tb1", _geo(), _prov()).\
add_line("tl1", _geo(), _prov()).\
add_word("w1", "A", _geo(), _prov())
page.add_text_region("tb2", _geo(), _prov()).\
add_line("tl2", _geo(), _prov()).\
add_word("w2", "B", _geo(), _prov())
doc = builder.build()
assert doc.pages[0].reading_order == ["tb1", "tb2"]
def test_no_pages_raises(self) -> None:
builder = CanonicalBuilder("doc1", InputType.IMAGE)
with pytest.raises(ValueError, match="at least one page"):
builder.build()
def test_empty_region_raises(self) -> None:
builder = CanonicalBuilder("doc1", InputType.IMAGE)
page = builder.add_page("p1", 0, 100, 100)
page.add_text_region("tb1", _geo(), _prov())
with pytest.raises(ValueError, match="no lines"):
builder.build()
def test_empty_line_raises(self) -> None:
builder = CanonicalBuilder("doc1", InputType.IMAGE)
page = builder.add_page("p1", 0, 100, 100)
region = page.add_text_region("tb1", _geo(), _prov())
region.add_line("tl1", _geo(), _prov())
with pytest.raises(ValueError, match="no words"):
builder.build()
def test_multiple_words_per_line(self) -> None:
builder = CanonicalBuilder("doc1", InputType.IMAGE)
page = builder.add_page("p1", 0, 1000, 1000)
region = page.add_text_region("tb1", _geo(), _prov())
line = region.add_line("tl1", _geo(), _prov())
line.add_word("w1", "Hello", _geo(), _prov())
line.add_word("w2", "world", _geo(), _prov())
doc = builder.build()
assert len(doc.pages[0].text_regions[0].lines[0].words) == 2
assert doc.pages[0].text_regions[0].lines[0].text == "Hello world"
def test_with_metadata(self) -> None:
builder = CanonicalBuilder(
"doc1", InputType.IMAGE, metadata={"project": "test"}
)
page = builder.add_page("p1", 0, 100, 100)
page.set_metadata({"page_quality": "good"})
region = page.add_text_region("tb1", _geo(), _prov())
line = region.add_line("tl1", _geo(), _prov())
line.add_word("w1", "ok", _geo(), _prov(), metadata={"custom": True})
doc = builder.build()
assert doc.metadata == {"project": "test"}
assert doc.pages[0].metadata == {"page_quality": "good"}
assert doc.pages[0].text_regions[0].lines[0].words[0].metadata == {"custom": True}