import pytest from faker import Faker from ows_text_campaigns.assets.exceptions import ( ImageProcessError, InvalidContentTypeError, InvalidFileSizeError, InvalidImageSizeError, ) from ows_text_campaigns.assets.image import ImageProcessor from ows_text_campaigns.assets.types import BinaryAsset from tests.unit.types import OverrideSettings class TestImageProcessor: def test_validate_jpeg(self, processor: ImageProcessor, faker: Faker) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(400, 400), image_format="JPEG"), filename=faker.file_name(extension="jpg"), ) image_ndarray = processor.validate( asset, min_width=400, min_height=400, allowed_content_types=["image/jpeg"], ) image = image_ndarray.image assert not image.is_processed assert image.extension == ".jpg" assert image.content_type == "image/jpeg" assert image.size == (400, 400) def test_validate_gif(self, processor: ImageProcessor, faker: Faker) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(400, 400), image_format="GIF"), filename=faker.file_name(extension="gif"), ) image_ndarray = processor.validate( asset, min_width=400, min_height=400, allowed_content_types=["image/gif"], ) image = image_ndarray.image assert image.extension == ".gif" assert image.content_type == "image/gif" assert image.size == (400, 400) def test_validate_invalid_content_type( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(400, 400), image_format="JPEG"), filename=faker.file_name(extension="jpg"), ) with pytest.raises(InvalidContentTypeError): processor.validate( asset, min_width=400, min_height=400, allowed_content_types=["image/png"], ) def test_validate_invalid_file_size( self, processor: ImageProcessor, faker: Faker, override_settings: OverrideSettings, ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(400, 400), image_format="JPEG"), filename=faker.file_name(extension="jpg"), ) with ( override_settings( assets_image_min_allowed_file_size=1024, assets_image_max_allowed_file_size=1024 * 2, ), pytest.raises(InvalidFileSizeError), ): processor.validate( asset, min_width=400, min_height=400, allowed_content_types=["image/jpeg"], ) def test_validate_invalid_image_size( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(400, 400), image_format="JPEG"), filename=faker.file_name(extension="jpg"), ) with pytest.raises(InvalidImageSizeError): processor.validate( asset, min_width=500, min_height=500, allowed_content_types=["image/jpeg"], ) def test_validate_and_process_skip_process( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(400, 400), image_format="JPEG"), filename=faker.file_name(extension="jpg"), ) image = processor.validate_and_process( asset, max_file_size=1024 * 1024, # 1MB min_width=400, min_height=400, allowed_content_types=["image/jpeg"], square_crop=False, ) assert not image.is_processed def test_validate_and_process_jpeg( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(1000, 1000), image_format="JPEG"), filename=faker.file_name(extension="jpg"), ) image = processor.validate_and_process( asset, max_file_size=1024 * 10, min_width=100, min_height=100, allowed_content_types=["image/jpeg"], square_crop=False, ) assert image.is_processed def test_validate_and_process_jpeg_quality_change( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(2000, 2000), image_format="JPEG"), filename=faker.file_name(extension="jpg"), ) with pytest.raises(ImageProcessError): _ = processor.validate_and_process( asset, max_file_size=1024 * 5, min_width=400, min_height=400, allowed_content_types=["image/jpeg"], square_crop=False, ) def test_validate_and_process_jpeg_with_crop( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(1000, 600), image_format="JPEG"), filename=faker.file_name(extension="jpg"), ) image = processor.validate_and_process( asset, max_file_size=1024 * 1024 * 1, min_width=500, min_height=500, allowed_content_types=["image/jpeg"], square_crop=True, ) assert image.is_processed assert image.size == (600, 600) def test_validate_and_process_png_with_crop( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(1000, 600), image_format="PNG"), filename=faker.file_name(extension="png"), ) image = processor.validate_and_process( asset, max_file_size=1024 * 1024 * 1, min_width=500, min_height=500, allowed_content_types=["image/png"], square_crop=True, ) assert image.is_processed assert image.size == (600, 600) def test_validate_and_process_gif( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(1000, 1000), image_format="GIF"), filename=faker.file_name(extension="gif"), ) image = processor.validate_and_process( asset, max_file_size=1024 * 2, min_width=100, min_height=100, allowed_content_types=["image/gif"], square_crop=False, ) assert image.is_processed def test_validate_and_process_gif_crop_not_allowed( self, processor: ImageProcessor, faker: Faker ) -> None: asset = BinaryAsset.from_data( data=faker.image(size=(1000, 1000), image_format="GIF"), filename=faker.file_name(extension="gif"), ) with pytest.raises(ImageProcessError): processor.validate_and_process( asset, max_file_size=1024 * 2, min_width=100, min_height=100, allowed_content_types=["image/gif"], square_crop=True, )