from __future__ import annotations import unittest from app.application.services.setup.request_options import DefaultProcessingOptionsResolver from app.domain.schemas import ( ImageSizeModel, MetadataModel, PipelineDefaultsModel, ProcessRequestModel, UploadOptionsModel, WatermarkModel, ) class DefaultProcessingOptionsResolverTests(unittest.TestCase): def test_resolve_merges_defaults_with_request_overrides(self) -> None: defaults = PipelineDefaultsModel( sizes=[ImageSizeModel(name="desktop", width=1024)], metadata=MetadataModel(title="Mặc định", tags=["mac-dinh"], rating=5), watermark=WatermarkModel(assetPath="watermark.png", widthRatio=0.2, opacity=1.0), ) resolver = DefaultProcessingOptionsResolver(defaults, ("avif", "jpg")) request = ProcessRequestModel( metadata=MetadataModel(title="Tiêu đề mới", comments="Ghi chú"), watermark=WatermarkModel(assetPath="override.png", opacity=0.7), upload=UploadOptionsModel(uploadToR2=True), ) resolved = resolver.resolve(request) self.assertEqual(("avif", "jpg"), resolved.formats) self.assertEqual(("desktop",), tuple(size.name for size in resolved.sizes)) self.assertIsNotNone(resolved.metadata) self.assertEqual("Tiêu đề mới", resolved.metadata.title) self.assertEqual(["mac-dinh"], resolved.metadata.tags) self.assertEqual("Ghi chú", resolved.metadata.comments) self.assertEqual(5, resolved.metadata.rating) self.assertIsNotNone(resolved.watermark) self.assertEqual("override.png", resolved.watermark.asset_path) self.assertEqual(0.2, resolved.watermark.width_ratio) self.assertEqual(0.7, resolved.watermark.opacity) self.assertTrue(resolved.upload_to_r2) self.assertIsNone(resolved.r2_prefix) def test_resolve_keeps_explicit_request_sizes_and_formats(self) -> None: defaults = PipelineDefaultsModel(sizes=[ImageSizeModel(name="desktop", width=1024)]) resolver = DefaultProcessingOptionsResolver(defaults, ("avif", "jpg")) request = ProcessRequestModel( sizes=[ImageSizeModel(name="mobile", width=480)], formats=["jpg"], ) resolved = resolver.resolve(request) self.assertEqual(("mobile",), tuple(size.name for size in resolved.sizes)) self.assertEqual(("jpg",), resolved.formats) self.assertIsNone(resolved.metadata) self.assertIsNone(resolved.watermark) self.assertIsNone(resolved.r2_prefix) def test_rejects_invalid_default_formats(self) -> None: defaults = PipelineDefaultsModel(sizes=[ImageSizeModel(name="desktop", width=1024)]) with self.assertRaisesRegex(ValueError, "Unsupported default output format"): DefaultProcessingOptionsResolver(defaults, ("avif", "webp")) def test_resolve_normalizes_request_r2_prefix(self) -> None: defaults = PipelineDefaultsModel(sizes=[ImageSizeModel(name="desktop", width=1024)]) resolver = DefaultProcessingOptionsResolver(defaults, ("avif", "jpg")) resolved = resolver.resolve( ProcessRequestModel(upload=UploadOptionsModel(uploadToR2=True, r2Prefix="/custom/listing-123/")) ) self.assertEqual("custom/listing-123", resolved.r2_prefix) def test_rejects_blank_request_r2_prefix(self) -> None: defaults = PipelineDefaultsModel(sizes=[ImageSizeModel(name="desktop", width=1024)]) resolver = DefaultProcessingOptionsResolver(defaults, ("avif", "jpg")) with self.assertRaisesRegex(ValueError, "r2Prefix must not be empty"): resolver.resolve(ProcessRequestModel(upload=UploadOptionsModel(r2Prefix="///"))) if __name__ == "__main__": unittest.main()