from __future__ import annotations import numpy as np import pytest from core.models import Bounds from perception.ocr import OCRBox, PaddleOCREngine, parse_paddle_result, run_ocr def test_paddle_ocr_engine_disables_doc_preprocessing_by_default() -> None: # Screenshots are flat, upright digital captures, not photographed paper # documents: PaddleOCR's document-unwarping preprocessing has nothing real # to correct and instead warps the image, so detected box coordinates no # longer line up with the original screenshot. engine = PaddleOCREngine(lang="ch") assert engine.kwargs["use_doc_orientation_classify"] is False assert engine.kwargs["use_doc_unwarping"] is False def test_paddle_ocr_engine_lets_callers_override_doc_preprocessing() -> None: engine = PaddleOCREngine(use_doc_unwarping=True) assert engine.kwargs["use_doc_unwarping"] is True def test_parse_paddle_result_accepts_ndarray_fields() -> None: boxes = parse_paddle_result( { "rec_texts": np.array(["Search"]), "rec_scores": np.array([0.95]), "rec_boxes": np.array([[1, 2, 10, 12]]), } ) assert boxes == [ OCRBox( text="Search", bounds=Bounds(x=1.0, y=2.0, width=9.0, height=10.0), confidence=0.95, ) ] class CallableJsonResult: def json(self) -> dict[str, object]: return { "res": { "rec_texts": ["Search"], "rec_scores": [0.95], "rec_boxes": [[1, 2, 10, 12]], } } def test_parse_paddle_result_accepts_callable_json_result() -> None: assert parse_paddle_result(CallableJsonResult()) == [ OCRBox( text="Search", bounds=Bounds(x=1.0, y=2.0, width=9.0, height=10.0), confidence=0.95, ) ] class FailingOCREngine: def extract(self, image: bytes | str) -> list[OCRBox]: raise ValueError( "The truth value of an array with more than one element is ambiguous" ) def test_run_ocr_degrades_when_ocr_engine_raises() -> None: assert run_ocr(b"image", engine=FailingOCREngine()) == [] # type: ignore[arg-type] def test_run_ocr_strict_mode_preserves_engine_error() -> None: with pytest.raises(ValueError, match="truth value"): run_ocr(b"image", engine=FailingOCREngine(), strict=True) # type: ignore[arg-type]