83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
"""Tests for file validation."""
|
|
|
|
import io
|
|
from unittest.mock import AsyncMock, Mock
|
|
|
|
import pytest
|
|
from fastapi import HTTPException, UploadFile
|
|
|
|
from app.images.validation import sanitize_filename, validate_image_file
|
|
|
|
|
|
class TestSanitizeFilename:
|
|
"""Tests for filename sanitization."""
|
|
|
|
def test_sanitize_normal_filename(self):
|
|
"""Test sanitizing normal filename."""
|
|
assert sanitize_filename("image.jpg") == "image.jpg"
|
|
assert sanitize_filename("my_photo-2025.png") == "my_photo-2025.png"
|
|
|
|
def test_sanitize_path_traversal(self):
|
|
"""Test preventing path traversal."""
|
|
assert "/" not in sanitize_filename("../../../etc/passwd")
|
|
assert "\\" not in sanitize_filename("..\\..\\..\\windows\\system32")
|
|
|
|
def test_sanitize_special_characters(self):
|
|
"""Test removing special characters."""
|
|
result = sanitize_filename("file name with spaces!@#.jpg")
|
|
assert " " not in result or result == "file_name_with_spaces___.jpg"
|
|
|
|
def test_sanitize_long_filename(self):
|
|
"""Test truncating long filenames."""
|
|
long_name = "a" * 300 + ".jpg"
|
|
result = sanitize_filename(long_name)
|
|
assert len(result) <= 255
|
|
assert result.endswith(".jpg")
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
class TestValidateImageFile:
|
|
"""Tests for image file validation."""
|
|
|
|
async def test_validate_empty_file(self):
|
|
"""Test rejection of empty files."""
|
|
mock_file = AsyncMock(spec=UploadFile)
|
|
mock_file.read = AsyncMock(return_value=b"")
|
|
mock_file.seek = AsyncMock()
|
|
mock_file.filename = "empty.jpg"
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
await validate_image_file(mock_file)
|
|
|
|
assert exc.value.status_code == 400
|
|
assert "empty" in exc.value.detail.lower()
|
|
|
|
async def test_validate_file_too_large(self):
|
|
"""Test rejection of oversized files."""
|
|
# Create 60MB file
|
|
large_data = b"x" * (60 * 1024 * 1024)
|
|
mock_file = AsyncMock(spec=UploadFile)
|
|
mock_file.read = AsyncMock(return_value=large_data)
|
|
mock_file.seek = AsyncMock()
|
|
mock_file.filename = "large.jpg"
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
await validate_image_file(mock_file)
|
|
|
|
assert exc.value.status_code == 413
|
|
assert "too large" in exc.value.detail.lower()
|
|
|
|
async def test_validate_invalid_extension(self):
|
|
"""Test rejection of invalid extensions."""
|
|
mock_file = AsyncMock(spec=UploadFile)
|
|
mock_file.read = AsyncMock(return_value=b"fake image data")
|
|
mock_file.seek = AsyncMock()
|
|
mock_file.filename = "document.pdf"
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
await validate_image_file(mock_file)
|
|
|
|
assert exc.value.status_code == 400
|
|
assert "extension" in exc.value.detail.lower()
|
|
|