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