"""Provider tests for EXIFProvider.""" from __future__ import annotations import cv2 import io import numpy as np import pytest from PIL import Image from config.settings import Settings from pipeline.feature_extraction import PipelineOutput from providers.metadata.exif import EXIFProvider @pytest.fixture def exif_provider(): return EXIFProvider(settings=Settings(environment="test", db_path=":memory:")) @pytest.fixture def pipeline_with_bytes(sample_image_bytes): img = cv2.imdecode(np.frombuffer(sample_image_bytes, np.uint8), cv2.IMREAD_COLOR) return PipelineOutput( image=img, image_hash="h", width=img.shape[1], height=img.shape[0], source="bytes", original_bytes=sample_image_bytes, original_format=".jpg", ) @pytest.fixture def pipeline_without_bytes(sample_image_bytes): """A pipeline output WITHOUT original_bytes — EXIF should gracefully return empty.""" img = cv2.imdecode(np.frombuffer(sample_image_bytes, np.uint8), cv2.IMREAD_COLOR) return PipelineOutput( image=img, image_hash="h", width=img.shape[1], height=img.shape[0], source="bytes", original_bytes=None, original_format=None, ) class TestEXIFProvider: def test_name(self, exif_provider): assert exif_provider.name == "exif" def test_capability(self, exif_provider): from models.providers import ProviderCapability assert exif_provider.capability == ProviderCapability.METADATA def test_is_available(self, exif_provider): # Should be available if Pillow is installed (it is, in requirements) assert exif_provider.is_available() is True def test_execute_with_bytes(self, exif_provider, pipeline_with_bytes): result = exif_provider.execute(pipeline_with_bytes) assert result.success is True assert "format" in result.normalized assert "exif" in result.normalized assert isinstance(result.normalized["exif"], dict) def test_execute_without_bytes_returns_empty(self, exif_provider, pipeline_without_bytes): result = exif_provider.execute(pipeline_without_bytes) assert result.success is True assert result.normalized["exif"] == {} def test_synthetic_jpeg_has_no_exif(self, exif_provider, pipeline_with_bytes): """A synthetic JPEG (no camera) should have no EXIF tags.""" result = exif_provider.execute(pipeline_with_bytes) assert len(result.normalized["exif"]) == 0 assert result.normalized["camera_make"] is None assert result.normalized["capture_time"] is None def test_format_extracted(self, exif_provider, pipeline_with_bytes): result = exif_provider.execute(pipeline_with_bytes) assert result.normalized["format"] == "JPEG"