"""Upload validation: size cap and PDF magic-byte check (SEC-06).""" import asyncio from io import BytesIO import pytest from fastapi import UploadFile from app.uploads import read_pdf_upload def make_upload(data: bytes, filename: str = "test.pdf") -> UploadFile: return UploadFile(file=BytesIO(data), filename=filename) def test_valid_pdf_accepted(): data = b"%PDF-1.7 fake content" out = asyncio.run(read_pdf_upload(make_upload(data))) assert out == data def test_non_pdf_rejected_with_filename(): with pytest.raises(ValueError, match=r"evil\.pdf: not a PDF"): asyncio.run(read_pdf_upload(make_upload(b"MZ\x90\x00binary", "evil.pdf"))) def test_oversized_rejected(): big = b"%PDF" + b"x" * 100 with pytest.raises(ValueError, match="exceeds the 0 MB limit"): asyncio.run(read_pdf_upload(make_upload(big), max_bytes=50)) def test_exact_limit_accepted(): data = b"%PDF" + b"x" * 46 # exactly 50 bytes out = asyncio.run(read_pdf_upload(make_upload(data), max_bytes=50)) assert len(out) == 50 def test_empty_file_rejected(): with pytest.raises(ValueError, match="not a PDF"): asyncio.run(read_pdf_upload(make_upload(b"")))