music on atproto
plyr.fm
1"""tests for image format validation."""
2
3import pytest
4
5from backend._internal.image import ImageFormat
6
7
8class TestImageFormat:
9 """test ImageFormat enum functionality."""
10
11 @pytest.mark.parametrize(
12 ("filename", "expected_format"),
13 [
14 # jpeg (jpg)
15 ("image.jpg", ImageFormat.JPEG),
16 ("image.JPG", ImageFormat.JPEG),
17 ("photo.jpeg", ImageFormat.JPEG),
18 ("photo.JPEG", ImageFormat.JPEG),
19 # png
20 ("image.png", ImageFormat.PNG),
21 ("image.PNG", ImageFormat.PNG),
22 # webp
23 ("image.webp", ImageFormat.WEBP),
24 ("image.WEBP", ImageFormat.WEBP),
25 # gif
26 ("image.gif", ImageFormat.GIF),
27 ("image.GIF", ImageFormat.GIF),
28 ],
29 )
30 def test_from_filename_supported(self, filename: str, expected_format: ImageFormat):
31 """test supported filename recognition (case-insensitive)."""
32 assert ImageFormat.from_filename(filename) == expected_format
33
34 @pytest.mark.parametrize(
35 "filename",
36 [
37 "image.bmp",
38 "image.tiff",
39 "image.svg",
40 "image.ico",
41 "image.txt",
42 "image",
43 "noextension",
44 ],
45 )
46 def test_from_filename_unsupported(self, filename: str):
47 """test unsupported filenames return None."""
48 assert ImageFormat.from_filename(filename) is None
49
50 def test_media_types(self):
51 """test media type mappings."""
52 assert ImageFormat.JPEG.media_type == "image/jpeg"
53 assert ImageFormat.PNG.media_type == "image/png"
54 assert ImageFormat.WEBP.media_type == "image/webp"
55 assert ImageFormat.GIF.media_type == "image/gif"
56
57 def test_jpeg_alias(self):
58 """test that both jpg and jpeg extensions map to JPEG format."""
59 assert ImageFormat.from_filename("image.jpg") == ImageFormat.JPEG
60 assert ImageFormat.from_filename("image.jpeg") == ImageFormat.JPEG
61
62 def test_case_insensitive(self):
63 """test that extension matching is case-insensitive."""
64 assert ImageFormat.from_filename("IMAGE.JPG") == ImageFormat.JPEG
65 assert ImageFormat.from_filename("Image.Png") == ImageFormat.PNG
66 assert ImageFormat.from_filename("photo.WebP") == ImageFormat.WEBP
67
68 def test_with_path(self):
69 """test that filenames with paths work correctly."""
70 assert ImageFormat.from_filename("/path/to/image.jpg") == ImageFormat.JPEG
71 assert ImageFormat.from_filename("../images/photo.png") == ImageFormat.PNG
72 assert (
73 ImageFormat.from_filename("C:\\Users\\test\\pic.webp") == ImageFormat.WEBP
74 )
75
76 @pytest.mark.parametrize(
77 ("content_type", "expected_format"),
78 [
79 ("image/jpeg", ImageFormat.JPEG),
80 ("image/jpg", ImageFormat.JPEG),
81 ("image/png", ImageFormat.PNG),
82 ("image/webp", ImageFormat.WEBP),
83 ("image/gif", ImageFormat.GIF),
84 # with charset
85 ("image/jpeg; charset=utf-8", ImageFormat.JPEG),
86 # case insensitive
87 ("IMAGE/JPEG", ImageFormat.JPEG),
88 ("Image/Png", ImageFormat.PNG),
89 ],
90 )
91 def test_from_content_type_supported(
92 self, content_type: str, expected_format: ImageFormat
93 ):
94 """test supported content type recognition."""
95 assert ImageFormat.from_content_type(content_type) == expected_format
96
97 @pytest.mark.parametrize(
98 "content_type",
99 [
100 "image/heic",
101 "image/bmp",
102 "image/tiff",
103 "application/octet-stream",
104 "",
105 None,
106 ],
107 )
108 def test_from_content_type_unsupported(self, content_type: str | None):
109 """test unsupported content types return None."""
110 assert ImageFormat.from_content_type(content_type) is None
111
112 def test_validate_and_extract_prefers_content_type(self):
113 """test that content_type is preferred over filename extension.
114
115 this is the iOS HEIC case: filename is .heic but content is jpeg.
116 """
117 # HEIC filename but JPEG content type -> should return JPEG
118 image_format, is_valid = ImageFormat.validate_and_extract(
119 "IMG_1234.HEIC", "image/jpeg"
120 )
121 assert is_valid is True
122 assert image_format == ImageFormat.JPEG
123
124 def test_validate_and_extract_falls_back_to_filename(self):
125 """test fallback to filename when no content_type provided."""
126 image_format, is_valid = ImageFormat.validate_and_extract("photo.png", None)
127 assert is_valid is True
128 assert image_format == ImageFormat.PNG
129
130 def test_validate_and_extract_unsupported_both(self):
131 """test unsupported format when both filename and content_type are invalid."""
132 image_format, is_valid = ImageFormat.validate_and_extract(
133 "image.heic", "image/heic"
134 )
135 assert is_valid is False
136 assert image_format is None
137
138 def test_enum_iteration_includes_jpeg_extension(self):
139 """test that iterating over ImageFormat includes both jpg and jpeg.
140
141 regression test: files uploaded as .jpeg were not found by get_url()
142 because the enum only had JPEG="jpg", so iteration only checked .jpg files.
143 """
144 extensions = [fmt.value for fmt in ImageFormat]
145 assert "jpg" in extensions
146 assert "jpeg" in extensions
147
148 def test_jpeg_alt_media_type(self):
149 """test that JPEG_ALT has the same media type as JPEG."""
150 assert ImageFormat.JPEG_ALT.media_type == "image/jpeg"
151 assert ImageFormat.JPEG_ALT.media_type == ImageFormat.JPEG.media_type