OmniFile-Processor / tests /test_ocr_engine.py
Dr. Abdulmalek
deploy: OmniFile AI Processor v4.3.0
900df0b
"""Tests for the hybrid OCR engine module."""
import numpy as np
import pytest
from unittest.mock import MagicMock, patch
from modules.vision.ocr_engine import OCREngine
@pytest.fixture
def sample_image() -> np.ndarray:
"""Create a simple test image.
Returns:
100x200 BGR white image with some dark regions.
"""
image = np.ones((100, 200, 3), dtype=np.uint8) * 255
image[20:40, 10:80] = 0 # Dark rectangle
image[50:70, 10:120] = 0 # Another dark rectangle
return image
class TestOCREngineInit:
"""Tests for OCR engine initialization."""
def test_default_initialization(self) -> None:
"""Test engine initialization with defaults."""
engine = OCREngine()
assert engine.confidence_threshold == 0.5
assert engine.use_gpu is True
def test_custom_initialization(self) -> None:
"""Test engine initialization with custom parameters."""
engine = OCREngine(
use_gpu=False,
confidence_threshold=0.7,
enable_easyocr=True,
enable_trocr=False,
enable_tesseract=False,
)
assert engine.confidence_threshold == 0.7
assert engine.use_gpu is False
def test_available_engines(self) -> None:
"""Test getting available engines list."""
engine = OCREngine()
engines = engine.get_available_engines()
assert isinstance(engines, list)
assert len(engines) == 4
for e in engines:
assert "name" in e
assert "available" in e
assert "enabled" in e
class TestOCREngineRecognition:
"""Tests for the OCR recognition flow."""
@patch("modules.vision.ocr_engine.OCREngine._load_easyocr")
@patch("modules.vision.ocr_engine.OCREngine._ensure_pil")
def test_recognize_no_engines_available(
self,
mock_ensure_pil: MagicMock,
mock_load_easyocr: MagicMock,
sample_image: np.ndarray,
) -> None:
"""Test recognition when no engines are available."""
from PIL import Image
mock_ensure_pil.return_value = Image.new("RGB", (200, 100))
mock_load_easyocr.return_value = False
engine = OCREngine(
enable_easyocr=True,
enable_trocr=False,
enable_tesseract=False,
)
result = engine.recognize(sample_image)
assert result["text"] == ""
assert result["source"] == "none"
class TestOCREngineBatch:
"""Tests for batch processing."""
@patch("modules.vision.ocr_engine.OCREngine.recognize")
def test_recognize_batch(
self,
mock_recognize: MagicMock,
sample_image: np.ndarray,
) -> None:
"""Test batch recognition."""
mock_recognize.return_value = {
"text": "مرحبا",
"confidence": 0.9,
"source": "mock",
"processing_time": 0.1,
}
engine = OCREngine()
results = engine.recognize_batch([sample_image, sample_image])
assert len(results) == 2
assert results[0]["text"] == "مرحبا"
assert results[0]["batch_index"] == 0
assert results[1]["batch_index"] == 1
class TestOCREngineCaching:
"""Tests for OCR result caching."""
def test_cache_key_generation(self, sample_image: np.ndarray) -> None:
"""Test cache key generation from image."""
from PIL import Image
engine = OCREngine()
pil_image = Image.fromarray(sample_image)
key = engine._get_cache_key(pil_image)
assert isinstance(key, str)
assert len(key) > 0
@patch("modules.vision.ocr_engine.OCREngine.recognize")
@patch("modules.vision.ocr_engine.OCREngine._ensure_pil")
def test_recognize_with_cache(
self,
mock_ensure_pil: MagicMock,
mock_recognize: MagicMock,
sample_image: np.ndarray,
) -> None:
"""Test cached recognition returns same result."""
from PIL import Image
mock_ensure_pil.return_value = Image.fromarray(sample_image)
mock_recognize.return_value = {
"text": "test",
"confidence": 0.9,
"source": "mock",
"processing_time": 0.1,
}
engine = OCREngine()
cache = {}
result1 = engine.recognize_with_cache(sample_image, cache=cache)
result2 = engine.recognize_with_cache(sample_image, cache=cache)
assert result1["from_cache"] is False
assert result2["from_cache"] is True
assert mock_recognize.call_count == 1
class TestImageConversion:
"""Tests for image format conversion."""
def test_ensure_pil_from_numpy(self, sample_image: np.ndarray) -> None:
"""Test converting numpy array to PIL Image."""
result = OCREngine._ensure_pil(sample_image)
assert hasattr(result, "mode")
def test_ensure_pil_grayscale(self) -> None:
"""Test converting grayscale numpy array to PIL Image."""
gray = np.ones((100, 100), dtype=np.uint8) * 128
result = OCREngine._ensure_pil(gray)
assert hasattr(result, "mode")