Spaces:
Sleeping
Sleeping
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 Download tests/test_ocr_processor.py from lylron/wonq-backend: direct link, hf CLI and curl.
- Browser
- Download file 4.63 kB
-
https://huggingface.co/spaces/lylron/wonq-backend/resolve/main/tests/test_ocr_processor.py
- Command line
-
hf download hf://spaces/lylron/wonq-backend/tests/test_ocr_processor.py
-
curl -L -o test_ocr_processor.py https://huggingface.co/spaces/lylron/wonq-backend/resolve/main/tests/test_ocr_processor.py
4.63 kB
| """ | |
| Unit tests for OCRProcessor. | |
| """ | |
| import cv2 | |
| import numpy as np | |
| import pytest | |
| from processors.ocr_processor import OCRProcessor | |
| def processor(): | |
| return OCRProcessor() | |
| 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"]) | |