File size: 2,769 Bytes
23d337e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""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"