Files
wiggleverse-ecomm/backend/tests/test_platform_images.py
T
ben.stull c929282e07
ci / check (push) Has been cancelled
ci / check (pull_request) Has been cancelled
fix(products): bomb-safe image processing + per-image error isolation; honest claim/resumability docs (SLICE-7 review)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 00:58:10 -07:00

66 lines
2.3 KiB
Python

"""platform/images — pure decode + resolution bar + WebP renditions (SD-0002 §6.2)."""
import io
from PIL import Image
from app.platform import images
def _png(width: int, height: int, color=(120, 80, 200)) -> bytes:
buf = io.BytesIO()
Image.new("RGB", (width, height), color).save(buf, format="PNG")
return buf.getvalue()
def _jpeg(width: int, height: int) -> bytes:
buf = io.BytesIO()
Image.new("RGB", (width, height), (10, 200, 90)).save(buf, format="JPEG")
return buf.getvalue()
def test_good_image_produces_three_webp_renditions():
result = images.process(_png(1200, 900))
assert isinstance(result, images.Processed)
assert result.source_format == "PNG"
assert set(result.renditions) == {"thumb", "card", "detail"}
for name, blob in result.renditions.items():
with Image.open(io.BytesIO(blob)) as im:
assert im.format == "WEBP"
with Image.open(io.BytesIO(result.renditions["thumb"])) as im:
assert max(im.size) <= images.RENDITIONS["thumb"]
with Image.open(io.BytesIO(result.renditions["detail"])) as im:
assert max(im.size) <= images.RENDITIONS["detail"]
def test_downscale_only_never_upscales_small_source():
result = images.process(_png(520, 520))
with Image.open(io.BytesIO(result.renditions["detail"])) as im:
assert im.size == (520, 520)
def test_below_resolution_bar_rejected_low_res():
result = images.process(_png(300, 1200)) # shorter side 300 < 500
assert isinstance(result, images.Rejected)
assert result.reason == "rejected_low_res"
def test_not_an_image_rejected_not_image():
result = images.process(b"this is not an image")
assert isinstance(result, images.Rejected)
assert result.reason == "rejected_not_image"
def test_jpeg_source_format_preserved_in_result():
result = images.process(_jpeg(800, 800))
assert result.source_format == "JPEG"
def test_decompression_bomb_rejected_not_image(monkeypatch):
# A small file whose pixel count exceeds Pillow's bomb threshold must be a
# typed rejection, never an escaping exception.
from PIL import Image as PILImage
monkeypatch.setattr(PILImage, "MAX_IMAGE_PIXELS", 100) # 10x10 exceeds it
result = images.process(_png(800, 800))
assert isinstance(result, images.Rejected)
assert result.reason == "rejected_not_image"