|
| 1 | +"""A page that describes nothing must never be emitted. |
| 2 | +
|
| 3 | +A block that fits in no column of a given page shape used to produce a blank image on |
| 4 | +every remaining page, each carrying an annotation that claimed content the image did not |
| 5 | +have. The block is dropped instead, because a page with a confident label and no ink is |
| 6 | +worse than a page that is missing. |
| 7 | +""" |
| 8 | + |
| 9 | +import random |
| 10 | +from pathlib import Path |
| 11 | + |
| 12 | +import pytest |
| 13 | + |
| 14 | +from ocrsmith.core.documents import ( |
| 15 | + DocumentBuilder, |
| 16 | + DocumentRenderer, |
| 17 | + PageSpec, |
| 18 | + TypographySampler, |
| 19 | +) |
| 20 | + |
| 21 | +FONT_DIR = Path(__file__).resolve().parents[1] / "assets" / "fonts" |
| 22 | + |
| 23 | +pytestmark = pytest.mark.skipif(not FONT_DIR.exists(), reason="bundled fonts unavailable") |
| 24 | + |
| 25 | + |
| 26 | +@pytest.fixture |
| 27 | +def typography(): |
| 28 | + fonts = sorted(FONT_DIR.glob("NotoSansArabic-*.ttf")) |
| 29 | + return TypographySampler(fonts, body_size_range=(16, 18)).sample(random.Random(3)) |
| 30 | + |
| 31 | + |
| 32 | +@pytest.fixture |
| 33 | +def renderer(): |
| 34 | + return DocumentRenderer() |
| 35 | + |
| 36 | + |
| 37 | +def test_every_emitted_page_carries_at_least_one_region(renderer, typography): |
| 38 | + content = DocumentBuilder().title("Title").paragraph("Body text goes here.").build() |
| 39 | + |
| 40 | + pages = renderer.render(content, PageSpec.from_paper("a6", dpi=90), typography, max_pages=10) |
| 41 | + |
| 42 | + assert pages |
| 43 | + for page in pages: |
| 44 | + assert page.page.regions |
| 45 | + |
| 46 | + |
| 47 | +def test_an_unplaceable_block_is_dropped_rather_than_blanking_pages(renderer, typography): |
| 48 | + # A table far too wide for the column fits nowhere, and tables never split. |
| 49 | + rows = [[f"column-{index}" * 4 for index in range(12)] for _ in range(3)] |
| 50 | + content = DocumentBuilder().paragraph("Readable prose.").table(rows).build() |
| 51 | + |
| 52 | + pages = renderer.render(content, PageSpec.from_paper("a6", dpi=80), typography, max_pages=10) |
| 53 | + |
| 54 | + assert pages |
| 55 | + assert all(page.page.regions for page in pages) |
| 56 | + |
| 57 | + |
| 58 | +def test_page_numbers_stay_dense_when_a_block_is_dropped(renderer, typography): |
| 59 | + rows = [[f"wide-{index}" * 5 for index in range(10)] for _ in range(2)] |
| 60 | + content = DocumentBuilder().paragraph("First.").table(rows).paragraph("Second.").build() |
| 61 | + |
| 62 | + pages = renderer.render(content, PageSpec.from_paper("a6", dpi=80), typography, max_pages=10) |
| 63 | + |
| 64 | + assert [page.number for page in pages] == list(range(1, len(pages) + 1)) |
| 65 | + |
| 66 | + |
| 67 | +def test_a_document_of_nothing_but_unplaceable_content_yields_no_pages(renderer, typography): |
| 68 | + rows = [[f"enormous-{index}" * 8 for index in range(14)]] |
| 69 | + content = DocumentBuilder().table(rows).build() |
| 70 | + |
| 71 | + pages = renderer.render(content, PageSpec.from_paper("a6", dpi=80), typography, max_pages=10) |
| 72 | + |
| 73 | + assert pages == [] |
0 commit comments