"""Provider tests for ImagePropertiesProvider.""" from __future__ import annotations import cv2 import numpy as np import pytest from config.settings import Settings from pipeline.feature_extraction import PipelineOutput from providers.image_analysis.image_properties import ImagePropertiesProvider @pytest.fixture def properties_provider(): return ImagePropertiesProvider(settings=Settings(environment="test", db_path=":memory:")) @pytest.fixture def pipeline_output(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", ) class TestImagePropertiesProvider: def test_name(self, properties_provider): assert properties_provider.name == "image_properties" def test_capability(self, properties_provider): from models.providers import ProviderCapability assert properties_provider.capability == ProviderCapability.IMAGE_ANALYSIS def test_execute_returns_properties(self, properties_provider, pipeline_output): result = properties_provider.execute(pipeline_output) assert result.success is True n = result.normalized assert n["width"] == 200 assert n["height"] == 200 assert n["channels"] == 3 assert n["color_profile"] == "BGR" assert isinstance(n["dominant_colors"], list) assert len(n["dominant_colors"]) > 0 # Each color should be a hex string for c in n["dominant_colors"]: assert c.startswith("#") def test_aspect_ratio(self, properties_provider): img = np.zeros((100, 200, 3), dtype=np.uint8) po = PipelineOutput(image=img, image_hash="h", width=200, height=100, source="bytes") result = properties_provider.execute(po) assert result.normalized["aspects"]["aspect_ratio"] == 2.0 def test_grayscale_image(self, properties_provider): img = np.zeros((200, 200), dtype=np.uint8) po = PipelineOutput(image=img, image_hash="h", width=200, height=200, source="bytes") result = properties_provider.execute(po) # The preprocessor converts to BGR before reaching here, but if we # bypass it (which we do here), the provider should still handle it # via the color_profile guess assert result.success is True