from backend.app.services.file_validator import ( is_validatable, validate_file, ) def test_is_validatable_only_known_extensions(tmp_path): assert is_validatable(tmp_path / "x.jpg") assert is_validatable(tmp_path / "x.JPEG") assert is_validatable(tmp_path / "x.png") assert is_validatable(tmp_path / "x.gif") assert is_validatable(tmp_path / "x.webp") assert not is_validatable(tmp_path / "x.json") assert not is_validatable(tmp_path / "x.mp4") def test_valid_jpeg_passes(tmp_path): from PIL import Image p = tmp_path / "good.jpg" Image.new("RGB", (32, 32), (200, 50, 50)).save(p, "JPEG") r = validate_file(p) assert r.ok is True assert r.format == "jpeg" assert r.size > 0 def test_truncated_jpeg_fails(tmp_path): from PIL import Image p = tmp_path / "bad.jpg" Image.new("RGB", (32, 32), (200, 50, 50)).save(p, "JPEG") raw = p.read_bytes() p.write_bytes(raw[:-16]) r = validate_file(p) assert r.ok is False assert r.format == "jpeg" assert "EOI" in r.reason def test_missing_jpeg_soi_fails(tmp_path): p = tmp_path / "junk.jpg" p.write_bytes(b"\x00" * 64) r = validate_file(p) assert r.ok is False assert "SOI" in r.reason def test_truncated_png_fails(tmp_path): from PIL import Image p = tmp_path / "bad.png" Image.new("RGB", (32, 32), (10, 10, 10)).save(p, "PNG") raw = p.read_bytes() p.write_bytes(raw[:-12]) r = validate_file(p) assert r.ok is False assert r.format == "png" def test_gif_signature_and_trailer(tmp_path): p = tmp_path / "bad.gif" p.write_bytes(b"GIF89a" + b"\x00" * 64) r = validate_file(p) assert r.ok is False assert r.format == "gif" def test_unknown_extension_passes(tmp_path): p = tmp_path / "x.bin" p.write_bytes(b"\x00" * 64) r = validate_file(p) assert r.ok is True assert r.format is None def test_missing_file_fails_cleanly(tmp_path): r = validate_file(tmp_path / "nope.jpg") assert r.ok is False assert "not found" in r.reason def test_too_small_fails(tmp_path): p = tmp_path / "tiny.jpg" p.write_bytes(b"\xff\xd8\xff") r = validate_file(p) assert r.ok is False assert r.reason == "too small"