wonq-backend / tests /test_ocr_processor.py
Aaron
Sync backend with GitHub main (ce306d7): model registry expansion, ensemble OCR, FLD lines, Qwen3.6 AI analysis, opencv-contrib for cloud FLD support
d9106f7
Raw History Blame Contribute Delete
4.63 kB
"""
Unit tests for OCRProcessor.
"""
import cv2
import numpy as np
import pytest
from processors.ocr_processor import OCRProcessor
@pytest.fixture
def processor():
return OCRProcessor()
@pytest.fixture
def text_drawing():
"""Large, clear image with well-spaced text for reliable OCR."""
img = np.ones((900, 1200), dtype=np.uint8) * 255
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, "Living Room", (100, 200), font, 2.0, 0, 4)
cv2.putText(img, "3640", (100, 450), font, 2.0, 0, 4)
cv2.putText(img, "Bedroom", (100, 700), font, 2.0, 0, 4)
return img
class TestExtractText:
def test_returns_dict_with_expected_keys(self, processor, synthetic_drawing):
result = processor.extract_text(synthetic_drawing)
for key in ("full_text", "element_count", "elements", "classified"):
assert key in result, f"Missing key: {key}"
def test_classified_has_correct_categories(self, processor, synthetic_drawing):
result = processor.extract_text(synthetic_drawing)
for cat in ("dimensions", "room_names", "numbers", "labels"):
assert cat in result["classified"]
def test_element_count_matches_elements_list(self, processor, text_drawing):
result = processor.extract_text(text_drawing)
assert result["element_count"] == len(result["elements"])
def test_each_element_has_required_fields(self, processor, text_drawing):
result = processor.extract_text(text_drawing)
for el in result["elements"]:
for field in ("text", "confidence", "x", "y", "width", "height"):
assert field in el, f"Missing field '{field}' in element"
def test_confidence_values_in_range(self, processor, text_drawing):
result = processor.extract_text(text_drawing)
for el in result["elements"]:
assert 0 <= el["confidence"] <= 100
def test_detects_dimension_number(self, processor, text_drawing):
result = processor.extract_text(text_drawing)
all_texts = [el["text"] for el in result["elements"]]
assert any("3640" in t for t in all_texts), \
f"Expected '3640' in OCR output, got: {all_texts}"
def test_classifies_bare_number_as_number(self, processor, text_drawing):
result = processor.extract_text(text_drawing)
num_texts = [el["text"] for el in result["classified"]["numbers"]]
assert "3640" in num_texts, \
f"'3640' (no unit) should be in numbers, got: {num_texts}"
def test_blank_image_returns_empty(self, processor):
blank = np.ones((400, 600), dtype=np.uint8) * 255
result = processor.extract_text(blank)
assert result["element_count"] == 0
assert result["elements"] == []
def test_full_text_is_string(self, processor, synthetic_drawing):
result = processor.extract_text(synthetic_drawing)
assert isinstance(result["full_text"], str)
class TestClassify:
def test_dimension_pattern(self, processor):
elements = [{"text": "3640mm", "confidence": 90, "x": 0, "y": 0, "width": 50, "height": 20}]
classified = processor._classify(elements)
assert any(e["text"] == "3640mm" for e in classified["dimensions"])
def test_room_name_pattern(self, processor):
elements = [{"text": "Kitchen", "confidence": 90, "x": 0, "y": 0, "width": 80, "height": 20}]
classified = processor._classify(elements)
assert any(e["text"] == "Kitchen" for e in classified["room_names"])
def test_number_pattern(self, processor):
elements = [{"text": "42", "confidence": 90, "x": 0, "y": 0, "width": 30, "height": 20}]
classified = processor._classify(elements)
assert any(e["text"] == "42" for e in classified["numbers"])
def test_dimension_with_unit(self, processor):
elements = [{"text": "3640mm", "confidence": 90, "x": 0, "y": 0, "width": 60, "height": 20}]
classified = processor._classify(elements)
assert any(e["text"] == "3640mm" for e in classified["dimensions"])
def test_bare_number_not_in_dimensions(self, processor):
elements = [{"text": "100", "confidence": 90, "x": 0, "y": 0, "width": 40, "height": 20}]
classified = processor._classify(elements)
assert not any(e["text"] == "100" for e in classified["dimensions"])
def test_label_catchall(self, processor):
elements = [{"text": "note", "confidence": 90, "x": 0, "y": 0, "width": 40, "height": 20}]
classified = processor._classify(elements)
assert any(e["text"] == "note" for e in classified["labels"])