| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- from __future__ import annotations
- import pytest
- class FakeProvider:
- def __init__(self, responses):
- self.responses = list(responses)
- self.calls = []
- def extract(self, image_bytes):
- self.calls.append(image_bytes)
- return self.responses.pop(0)
- def block(text, bbox, confidence=0.9):
- from app.core.data_research.ocr.base import OcrBlock
- return OcrBlock(text=text, bbox=bbox, page=99, confidence=confidence)
- def test_ocr_service_preserves_scanned_pdf_page_order_and_review_flags():
- from app.core.data_research.ocr.service import OcrService
- provider = FakeProvider(
- [
- [block("第一页", (0.1, 0.2, 0.8, 0.3), 0.95)],
- [block("第二页低置信", (0.0, 0.0, 1.0, 1.0), 0.4)],
- ]
- )
- results = OcrService(provider, review_threshold=0.75).extract_pages(
- [b"page-one", b"page-two"]
- )
- assert [result.page for result in results] == [1, 2]
- assert results[0].bbox == (0.1, 0.2, 0.8, 0.3)
- assert results[0].review_required is False
- assert results[1].review_required is True
- def test_ocr_service_rejects_malformed_provider_response():
- from app.core.data_research.ocr.service import OcrResponseInvalid, OcrService
- provider = FakeProvider([[block("bad", (-1.0, 0.0, 2.0, 1.0))]])
- with pytest.raises(OcrResponseInvalid, match="bounding box"):
- OcrService(provider).extract_pages([b"image"])
- def test_ocr_is_fail_closed_when_provider_is_disabled():
- from app.core.data_research.ocr.service import OcrDisabled, OcrService
- with pytest.raises(OcrDisabled, match="not configured"):
- OcrService(None).extract_pages([b"image"])
- class FakeResponse:
- def __init__(self, payload, *, content=b"{}", headers=None):
- self._payload = payload
- self.content = content
- self.headers = headers or {}
- def raise_for_status(self):
- return None
- def json(self):
- return self._payload
- def test_http_provider_enforces_timeout_tls_and_response_limit():
- from app.core.data_research.ocr.http_provider import HttpOcrProvider
- from app.core.data_research.ocr.service import OcrResponseInvalid
- calls = []
- def post(*args, **kwargs):
- calls.append((args, kwargs))
- return FakeResponse(
- {"blocks": [{"text": "编号", "bbox": [0, 0, 1, 1], "confidence": 0.9}]},
- content=b"x" * 20,
- )
- provider = HttpOcrProvider(
- "https://ocr.internal/v1/extract",
- token="secret-token",
- timeout_seconds=3,
- verify_tls=True,
- max_response_bytes=100,
- post=post,
- )
- blocks = provider.extract(b"png")
- assert blocks[0].text == "编号"
- assert calls[0][1]["timeout"] == 3
- assert calls[0][1]["verify"] is True
- provider.max_response_bytes = 10
- with pytest.raises(OcrResponseInvalid, match="response size") as error:
- provider.extract(b"png-secret-source")
- assert "secret-token" not in str(error.value)
- assert "png-secret-source" not in str(error.value)
|