idol-commons / tests /test_image_upload_errors.py
fffiloni's picture
Accept JPEG photos with auxiliary MPO images
1b453ef verified
Raw History Blame Contribute Delete
2.36 kB
import io
import json
from pathlib import Path
import pytest
from PIL import Image
from backend.rendering import normalize_image_isolated
from backend.validation import InvalidAsset, IMAGE_ERRORS
def encoded(size=(64, 64), color=(60, 100, 180, 255), **kwargs):
buffer=io.BytesIO()
Image.new('RGBA',size,color).save(buffer,'PNG',**kwargs)
return buffer.getvalue()
@pytest.mark.parametrize('raw,code',[
(b'<svg><script>alert(1)</script></svg>','decode'),
(encoded((16, 200)),'aspect'),
(encoded((8, 8)),'dimensions'),
(encoded(color=(0, 0, 0, 0)),'transparent'),
])
def test_worker_returns_actionable_allowlisted_errors(tmp_path,raw,code):
output=tmp_path/'safe.png'
with pytest.raises(InvalidAsset,match='^'+__import__('re').escape(IMAGE_ERRORS[code])+'$'):
normalize_image_isolated(raw,output)
assert not output.exists()
def test_worker_keeps_server_pixel_limit(tmp_path):
# Browser preparation does not relax direct API upload limits.
with pytest.raises(InvalidAsset,match='safe image limits'):
normalize_image_isolated(encoded((4001,4000)),tmp_path/'too-large.png')
def test_worker_rejects_animation(tmp_path):
b=io.BytesIO();a=Image.new('RGBA',(64,64),'red');z=Image.new('RGBA',(64,64),'blue')
a.save(b,'PNG',save_all=True,append_images=[z],duration=100,loop=0)
with pytest.raises(InvalidAsset,match='Animated images'):
normalize_image_isolated(b.getvalue(),tmp_path/'animated.png')
def test_worker_preserves_orientation_and_removes_metadata(tmp_path):
b=io.BytesIO();im=Image.new('RGB',(32,64),'red');exif=Image.Exif();exif[274]=6;exif[270]='private fixture metadata'
im.save(b,'JPEG',exif=exif)
output=tmp_path/'safe.png';result=normalize_image_isolated(b.getvalue(),output)
assert (result['width'],result['height'])==(64,32)
with Image.open(output) as image:assert image.format=='PNG' and not image.info
def test_unrecognized_worker_diagnostic_is_never_returned(tmp_path,monkeypatch):
def fake(args,cwd,env,**kwargs):
(Path(cwd)/'process.log').write_text(json.dumps({'ok':False,'code':'/private/user-secret'}))
monkeypatch.setattr('backend.rendering.bounded_run',fake)
with pytest.raises(InvalidAsset,match='^'+__import__('re').escape(IMAGE_ERRORS['decode'])+'$'):
normalize_image_isolated(b'bad',tmp_path/'safe.png')