import pytest from unittest.mock import patch, MagicMock from app.services.exif_service import extract_exif, _dms_to_decimal def test_dms_to_decimal(): # 48° 51' 23.82" N -> 48.8566167 dms = ((48, 1), (51, 1), (2382, 100)) assert _dms_to_decimal(dms, "N") == 48.8566167 assert _dms_to_decimal(dms, "S") == -48.8566167 @patch("app.services.exif_service.piexif") @patch("app.services.exif_service.PILImage") @patch("app.services.exif_service.Path.exists", return_value=True) def test_extract_exif_success(mock_path_exists, mock_pil, mock_piexif): # Mock piexif data import piexif mock_data = { "0th": { piexif.ImageIFD.Make: b"Canon", piexif.ImageIFD.Model: b"EOS R5", piexif.ImageIFD.Software: b"1.1.0" }, "Exif": { piexif.ExifIFD.DateTimeOriginal: b"2024:06:15 14:30:00", piexif.ExifIFD.ISOSpeedRatings: 400, piexif.ExifIFD.FNumber: (28, 10), piexif.ExifIFD.ExposureTime: (1, 250), piexif.ExifIFD.FocalLength: (500, 10), piexif.ExifIFD.Flash: 0 }, "GPS": { piexif.GPSIFD.GPSLatitude: ((48, 1), (51, 1), (2382, 100)), piexif.GPSIFD.GPSLatitudeRef: b"N", piexif.GPSIFD.GPSLongitude: ((2, 1), (21, 1), (792, 100)), piexif.GPSIFD.GPSLongitudeRef: b"E", piexif.GPSIFD.GPSAltitude: (350, 10) } } mock_piexif.load.return_value = mock_data mock_piexif.ImageIFD = piexif.ImageIFD mock_piexif.ExifIFD = piexif.ExifIFD mock_piexif.GPSIFD = piexif.GPSIFD # Mock PIL mock_img = mock_pil.open.return_value.__enter__.return_value mock_img._getexif.return_value = {271: "Canon"} # 271 is Make result = extract_exif("fake/path.jpg") assert result["make"] == "Canon" assert result["model"] == "EOS R5" assert result["iso"] == 400 assert result["aperture"] == "f/2.8" assert result["shutter"] == "1/250" assert result["focal"] == "50mm" assert result["gps_lat"] == 48.8566167 assert result["altitude"] == 35.0