"""app.image_upload.decode_upload -- pure decoding logic, no HTTP, no DB. See routers/api_widgets.py's api_widget_static_upload for the endpoint that calls this, and tests/test_widget_config_and_queue_endpoints.py for HTTP-level coverage of that endpoint.""" from __future__ import annotations import io import pytest from fastapi import HTTPException from PIL import Image from app import image_upload def _png_bytes(size=(20, 10), color=(255, 0, 0)) -> bytes: buf = io.BytesIO() Image.new("RGB", size, color).save(buf, format="PNG") return buf.getvalue() def _pdf_bytes(size=(40, 30), color=(0, 255, 0)) -> bytes: buf = io.BytesIO() Image.new("RGB", size, color).save(buf, format="PDF") return buf.getvalue() def _gif_bytes(size=(15, 15)) -> bytes: buf = io.BytesIO() Image.new("RGB", size, (0, 0, 255)).save(buf, format="GIF") return buf.getvalue() def test_decodes_a_png(): img = image_upload.decode_upload(_png_bytes(size=(20, 10))) assert img.size == (20, 10) assert img.mode == "RGB" def test_decodes_a_jpeg(): buf = io.BytesIO() Image.new("RGB", (12, 8), (1, 2, 3)).save(buf, format="JPEG") img = image_upload.decode_upload(buf.getvalue()) assert img.size == (12, 8) assert img.mode == "RGB" def test_decodes_a_gif(): img = image_upload.decode_upload(_gif_bytes(size=(15, 15))) assert img.size == (15, 15) assert img.mode == "RGB" def test_decodes_a_pdfs_first_page(): img = image_upload.decode_upload(_pdf_bytes(size=(40, 30))) # Rendered at PDF_RENDER_SCALE (2.0), not the page's native point size. assert img.size == (80, 60) assert img.mode == "RGB" def test_rejects_garbage_bytes(): with pytest.raises(HTTPException) as exc_info: image_upload.decode_upload(b"this is not an image or a pdf") assert exc_info.value.status_code == 400 def test_rejects_a_pdf_with_no_pages(): # A syntactically-valid empty PDF (no /Page objects) -- pypdfium2 # opens it fine but reports zero pages. empty_pdf = ( b"%PDF-1.4\n" b"1 0 obj<>endobj\n" b"2 0 obj<>endobj\n" b"xref\n0 1\n0000000000 65535 f \n" b"trailer<>\n" b"startxref\n0\n%%EOF" ) with pytest.raises(HTTPException) as exc_info: image_upload.decode_upload(empty_pdf) assert exc_info.value.status_code == 400 def test_rejects_a_file_over_the_size_limit(monkeypatch): monkeypatch.setattr(image_upload, "MAX_UPLOAD_BYTES", 10) with pytest.raises(HTTPException) as exc_info: image_upload.decode_upload(_png_bytes()) assert exc_info.value.status_code == 400