from io import BytesIO import pytest from PIL import Image from pigway_frame_flow.errors import FlowError from pigway_frame_flow.renderers.images import convert def image_bytes(format="PNG", size=(800, 400)): out = BytesIO() Image.new("RGB", size, "red").save(out, format) return out.getvalue() @pytest.mark.parametrize("format", ["JPEG", "PNG", "WEBP"]) @pytest.mark.parametrize("fit", ["contain", "cover", "smart"]) @pytest.mark.parametrize("profile", ["color", "grayscale"]) def test_conversion(format, fit, profile): img = Image.open(BytesIO(convert(image_bytes(format), fit, profile))) assert img.size == (1200, 1600) assert img.format == "JPEG" if profile == "grayscale": assert len(set(img.getpixel((600, 800)))) == 1 def test_contain_preserves_shape(): img = Image.open(BytesIO(convert(image_bytes(), "contain"))) assert img.getpixel((600, 100)) == (255, 255, 255) assert img.getpixel((600, 800))[0] > 240 def test_invalid_image(): with pytest.raises(FlowError): convert(b"bad") def test_transparency_white(): out = BytesIO() Image.new("RGBA", (100, 100), (255, 0, 0, 0)).save(out, "PNG") img = Image.open(BytesIO(convert(out.getvalue(), "cover"))) assert img.getpixel((600, 800)) == (255, 255, 255) @pytest.mark.parametrize( "template", ["daily-dashboard", "weather", "calendar", "quote", "photo-text", "system-alert"], ) def test_templates(service, template): result = service.renderer.render(template, {}, "color") assert Image.open(BytesIO(result)).size == (1200, 1600) def test_url_default_disabled(service): with pytest.raises(FlowError): service.assets.fetch_url("https://example.com/x.jpg") @pytest.mark.parametrize( "url", [ "http://localhost/x", "file:///etc/passwd", "https://127.0.0.1/x", "https://user:pass@example.com/x", ], ) def test_url_ssrf(service, url): with pytest.raises(FlowError): service.assets.fetch_url(url)