|
""" |
|
Tests for Local Mock Processor |
|
Simple tests to verify mock processing functionality |
|
""" |
|
|
|
import pytest |
|
import asyncio |
|
import os |
|
from unittest.mock import patch, Mock |
|
from src.file_processor import LocalProcessor |
|
|
|
class TestLocalProcessor: |
|
"""Test suite for the local processor""" |
|
|
|
@pytest.fixture |
|
def local_processor(self): |
|
"""Create a local processor instance""" |
|
return LocalProcessor() |
|
|
|
@pytest.fixture |
|
def sample_document_bytes(self): |
|
"""Sample document bytes for testing""" |
|
return b"Mock PDF document content" |
|
|
|
@pytest.mark.asyncio |
|
async def test_basic_document_processing(self, local_processor, sample_document_bytes): |
|
"""Test basic document processing without fallbacks""" |
|
result = await local_processor.process_document( |
|
document_bytes=sample_document_bytes, |
|
user_id="test-user-123", |
|
filename="test_document.pdf" |
|
) |
|
|
|
|
|
assert result["status"] == "success" |
|
assert result["filename"] == "test_document.pdf" |
|
assert result["processed_by"] == "test-user-123" |
|
assert "entities_found" in result |
|
assert "fhir_bundle" in result |
|
assert "extracted_text" in result |
|
|
|
|
|
fhir_bundle = result["fhir_bundle"] |
|
assert fhir_bundle["resourceType"] == "Bundle" |
|
assert fhir_bundle["type"] == "document" |
|
assert len(fhir_bundle["entry"]) >= 2 |
|
|
|
|
|
resource_types = [entry["resource"]["resourceType"] for entry in fhir_bundle["entry"]] |
|
assert "Patient" in resource_types |
|
assert "Observation" in resource_types |
|
|
|
def test_mock_text_extraction_by_file_type(self, local_processor): |
|
"""Test text extraction based on file types""" |
|
|
|
pdf_text = local_processor._get_mock_text_by_type("medical_record.pdf") |
|
assert "MEDICAL RECORD" in pdf_text |
|
assert "John Doe" in pdf_text |
|
|
|
|
|
image_text = local_processor._get_mock_text_by_type("lab_results.jpg") |
|
assert "LAB REPORT" in image_text |
|
assert "Jane Smith" in image_text |
|
|
|
|
|
other_text = local_processor._get_mock_text_by_type("notes.txt") |
|
assert "CLINICAL NOTE" in other_text |
|
|
|
def test_medical_entity_extraction(self, local_processor): |
|
"""Test medical entity extraction""" |
|
test_text = """ |
|
Patient: John Doe |
|
Diagnosis: Hypertension |
|
Medication: Lisinopril |
|
Blood Pressure: 140/90 |
|
""" |
|
|
|
entities = local_processor._extract_medical_entities(test_text) |
|
|
|
|
|
assert len(entities) > 0 |
|
|
|
|
|
entity_types = [entity["type"] for entity in entities] |
|
assert "PERSON" in entity_types |
|
assert "CONDITION" in entity_types |
|
assert "MEDICATION" in entity_types |
|
assert "VITAL" in entity_types |
|
|
|
|
|
for entity in entities: |
|
assert "text" in entity |
|
assert "type" in entity |
|
assert "confidence" in entity |
|
assert "start" in entity |
|
assert "end" in entity |
|
|
|
def test_processing_mode_detection(self, local_processor): |
|
"""Test processing mode detection""" |
|
|
|
mode = local_processor._get_processing_mode() |
|
assert mode == "local_mock_only" |
|
|
|
|
|
with patch.dict(os.environ, {"USE_MISTRAL_FALLBACK": "true", "MISTRAL_API_KEY": "test-key"}): |
|
processor = LocalProcessor() |
|
mode = processor._get_processing_mode() |
|
assert mode == "local_mock_with_mistral_fallback" |
|
|
|
with patch.dict(os.environ, {"USE_MULTIMODAL_FALLBACK": "true"}): |
|
processor = LocalProcessor() |
|
mode = processor._get_processing_mode() |
|
assert mode == "local_mock_with_multimodal_fallback" |
|
|
|
@pytest.mark.asyncio |
|
async def test_fallback_handling(self, local_processor, sample_document_bytes): |
|
"""Test fallback mechanisms""" |
|
|
|
text = await local_processor._extract_text_with_fallback(sample_document_bytes, "test.pdf") |
|
assert isinstance(text, str) |
|
assert len(text) > 0 |
|
|
|
@pytest.mark.asyncio |
|
@pytest.mark.skipif(not os.getenv("MISTRAL_API_KEY"), reason="Mistral API key not available") |
|
async def test_mistral_fallback(self, local_processor, sample_document_bytes): |
|
"""Test Mistral API fallback (requires API key)""" |
|
with patch.dict(os.environ, {"USE_MISTRAL_FALLBACK": "true"}): |
|
processor = LocalProcessor() |
|
|
|
|
|
with patch('httpx.AsyncClient.post') as mock_post: |
|
mock_response = Mock() |
|
mock_response.status_code = 200 |
|
mock_response.json.return_value = { |
|
"choices": [{"message": {"content": "Extracted medical text from Mistral"}}] |
|
} |
|
mock_post.return_value = mock_response |
|
|
|
text = await processor._extract_with_mistral(sample_document_bytes) |
|
assert text == "Extracted medical text from Mistral" |
|
|
|
def test_fhir_bundle_creation(self, local_processor): |
|
"""Test FHIR bundle creation""" |
|
test_entities = [ |
|
{"text": "John Doe", "type": "PERSON", "confidence": 0.95}, |
|
{"text": "Hypertension", "type": "CONDITION", "confidence": 0.89} |
|
] |
|
|
|
bundle = local_processor._create_simple_fhir_bundle(test_entities, "test-user") |
|
|
|
|
|
assert bundle["resourceType"] == "Bundle" |
|
assert bundle["type"] == "document" |
|
assert "timestamp" in bundle |
|
assert "entry" in bundle |
|
|
|
|
|
assert bundle["_metadata"]["entities_found"] == 2 |
|
assert bundle["_metadata"]["processed_by"] == "test-user" |
|
|
|
|
|
observation_entry = next( |
|
entry for entry in bundle["entry"] |
|
if entry["resource"]["resourceType"] == "Observation" |
|
) |
|
coding = observation_entry["resource"]["code"]["coding"][0] |
|
assert coding["system"] == "http://loinc.org" |
|
assert coding["code"] == "85354-9" |
|
|
|
if __name__ == "__main__": |
|
pytest.main([__file__, "-v"]) |