import io from pathlib import Path import pytest from PIL import Image from src.image_sanitizer import MAX_IMAGE_PIXELS, sanitize_image def test_runtime_dependencies_install_the_image_decoder(): requirements = (Path(__file__).parents[1] / "requirements.txt").read_text().splitlines() assert any(line.startswith("Pillow==") for line in requirements) def encoded_image(format_name, size=(3, 2), *, exif=None): image = Image.new("RGB", size) image.putdata( [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255), (255, 0, 255)] ) output = io.BytesIO() image.save(output, format=format_name, exif=exif or b"") return output.getvalue() def test_sanitize_image_applies_orientation_and_removes_jpeg_metadata(): exif = Image.Exif() exif[274] = 6 exif[ GPS_TAG := 34853 ] = {1: "N", 2: (1, 1, 1)} source = encoded_image("JPEG", exif=exif) sanitized = sanitize_image("image/jpeg", source) with Image.open(io.BytesIO(sanitized)) as result: assert result.size == (2, 3) assert not result.getexif() assert GPS_TAG not in result.info assert result.format == "JPEG" def test_sanitize_image_rejects_bytes_that_do_not_match_claimed_type(): source = encoded_image("PNG") with pytest.raises(ValueError, match="does not match"): sanitize_image("image/jpeg", source) def test_sanitize_image_rejects_over_twelve_megapixels_before_decoding(): image = Image.new("RGB", (4096, 3073)) output = io.BytesIO() image.save(output, format="PNG") with pytest.raises(ValueError, match="12 megapixels"): sanitize_image("image/png", output.getvalue()) def test_sanitize_image_rejects_animated_webp(): first = Image.new("RGB", (2, 2), "red") second = Image.new("RGB", (2, 2), "blue") output = io.BytesIO() first.save(output, format="WEBP", save_all=True, append_images=[second], duration=100) with pytest.raises(ValueError, match="animated"): sanitize_image("image/webp", output.getvalue())