SolarImageDownloader / tests /test_validation_service.py
AK51's picture
Upload 13308 files
b610d23 verified
"""Tests for validation service."""
import pytest
import tempfile
import shutil
from pathlib import Path
from PIL import Image
import io
from src.storage.validation_service import ValidationService
class TestValidationService:
"""Test cases for ValidationService class."""
def setup_method(self):
"""Set up test fixtures."""
self.temp_dir = Path(tempfile.mkdtemp())
self.validator = ValidationService()
def teardown_method(self):
"""Clean up temporary directory."""
shutil.rmtree(self.temp_dir)
def create_test_image(self, filename: str, width: int = 512, height: int = 512, format: str = 'JPEG') -> Path:
"""Create a test image file."""
file_path = self.temp_dir / filename
# Create a simple test image
img = Image.new('RGB', (width, height), color='red')
img.save(file_path, format)
return file_path
def create_corrupted_file(self, filename: str, content: bytes = b"not an image") -> Path:
"""Create a corrupted file."""
file_path = self.temp_dir / filename
file_path.write_bytes(content)
return file_path
def test_validate_image_format_valid_jpeg(self):
"""Test validation of valid JPEG image."""
image_path = self.create_test_image("test.jpg", format='JPEG')
is_valid, error = self.validator.validate_image_format(image_path)
assert is_valid is True
assert error is None
def test_validate_image_format_invalid_format(self):
"""Test validation of non-JPEG image."""
image_path = self.create_test_image("test.png", format='PNG')
is_valid, error = self.validator.validate_image_format(image_path)
assert is_valid is False
assert "Expected JPEG format, got PNG" in error
def test_validate_image_format_corrupted_file(self):
"""Test validation of corrupted file."""
corrupted_path = self.create_corrupted_file("corrupted.jpg")
is_valid, error = self.validator.validate_image_format(corrupted_path)
assert is_valid is False
assert error is not None
def test_calculate_file_hash(self):
"""Test file hash calculation."""
image_path = self.create_test_image("test.jpg")
hash1 = self.validator.calculate_file_hash(image_path, 'md5')
hash2 = self.validator.calculate_file_hash(image_path, 'md5')
assert hash1 is not None
assert hash1 == hash2 # Same file should have same hash
assert len(hash1) == 32 # MD5 hash length
def test_calculate_file_hash_different_algorithms(self):
"""Test different hash algorithms."""
image_path = self.create_test_image("test.jpg")
md5_hash = self.validator.calculate_file_hash(image_path, 'md5')
sha256_hash = self.validator.calculate_file_hash(image_path, 'sha256')
assert md5_hash is not None
assert sha256_hash is not None
assert len(md5_hash) == 32 # MD5
assert len(sha256_hash) == 64 # SHA256
assert md5_hash != sha256_hash
def test_validate_file_size_exact_match(self):
"""Test file size validation with exact match."""
image_path = self.create_test_image("test.jpg")
actual_size = image_path.stat().st_size
is_valid, error = self.validator.validate_file_size(image_path, actual_size)
assert is_valid is True
assert error is None
def test_validate_file_size_within_tolerance(self):
"""Test file size validation within tolerance."""
image_path = self.create_test_image("test.jpg")
actual_size = image_path.stat().st_size
is_valid, error = self.validator.validate_file_size(image_path, actual_size + 5, tolerance=10)
assert is_valid is True
assert error is None
def test_validate_file_size_outside_tolerance(self):
"""Test file size validation outside tolerance."""
image_path = self.create_test_image("test.jpg")
actual_size = image_path.stat().st_size
is_valid, error = self.validator.validate_file_size(image_path, actual_size + 100, tolerance=10)
assert is_valid is False
assert "Size mismatch" in error
def test_validate_image_content_valid(self):
"""Test validation of valid image content."""
image_path = self.create_test_image("test.jpg", width=1024, height=768)
is_valid, error = self.validator.validate_image_content(image_path)
assert is_valid is True
assert error is None
def test_validate_image_content_too_small(self):
"""Test validation of image that's too small."""
image_path = self.create_test_image("small.jpg", width=50, height=50)
is_valid, error = self.validator.validate_image_content(image_path)
assert is_valid is False
assert "Image too small" in error
def test_validate_image_content_too_large(self):
"""Test validation of image that's too large."""
# Note: We won't actually create a 15000x15000 image for performance reasons
# Instead, we'll mock the Image.open to return large dimensions
from unittest.mock import patch, MagicMock
image_path = self.create_test_image("test.jpg")
with patch('PIL.Image.open') as mock_open:
mock_img = MagicMock()
mock_img.size = (15000, 15000)
mock_img.mode = 'RGB'
mock_open.return_value.__enter__.return_value = mock_img
is_valid, error = self.validator.validate_image_content(image_path)
assert is_valid is False
assert "Image too large" in error
def test_comprehensive_validation_success(self):
"""Test comprehensive validation of valid image."""
image_path = self.create_test_image("test.jpg")
expected_size = image_path.stat().st_size
all_valid, errors = self.validator.comprehensive_validation(image_path, expected_size)
assert all_valid is True
assert len(errors) == 0
def test_comprehensive_validation_missing_file(self):
"""Test comprehensive validation of missing file."""
missing_path = self.temp_dir / "missing.jpg"
all_valid, errors = self.validator.comprehensive_validation(missing_path)
assert all_valid is False
assert len(errors) == 1
assert "File does not exist" in errors[0]
def test_comprehensive_validation_empty_file(self):
"""Test comprehensive validation of empty file."""
empty_path = self.temp_dir / "empty.jpg"
empty_path.write_bytes(b"")
all_valid, errors = self.validator.comprehensive_validation(empty_path)
assert all_valid is False
assert any("File is empty" in error for error in errors)
def test_comprehensive_validation_multiple_errors(self):
"""Test comprehensive validation with multiple errors."""
corrupted_path = self.create_corrupted_file("corrupted.jpg")
all_valid, errors = self.validator.comprehensive_validation(corrupted_path, expected_size=1000000)
assert all_valid is False
assert len(errors) >= 2 # Size mismatch + format error
def test_get_image_info_success(self):
"""Test getting image information."""
image_path = self.create_test_image("test.jpg", width=800, height=600)
info = self.validator.get_image_info(image_path)
assert info is not None
assert info['filename'] == 'test.jpg'
assert info['format'] == 'JPEG'
assert info['width'] == 800
assert info['height'] == 600
assert info['size'] == (800, 600)
assert info['file_size'] > 0
assert 'has_transparency' in info
assert 'has_exif' in info
def test_get_image_info_corrupted_file(self):
"""Test getting image information from corrupted file."""
corrupted_path = self.create_corrupted_file("corrupted.jpg")
info = self.validator.get_image_info(corrupted_path)
assert info is None
def test_repair_corrupted_image_success(self):
"""Test successful image repair."""
# Skip this test on Windows due to file locking issues
import platform
if platform.system() == "Windows":
pytest.skip("Skipping repair test on Windows due to file locking")
# Create a valid image first
image_path = self.create_test_image("test.jpg")
# For this test, we'll assume the image can be "repaired"
# In reality, this would work on images with minor corruption
success = self.validator.repair_corrupted_image(image_path)
# The repair should succeed for a valid image
assert success is True
assert image_path.exists()
def test_repair_corrupted_image_failure(self):
"""Test failed image repair."""
corrupted_path = self.create_corrupted_file("corrupted.jpg")
success = self.validator.repair_corrupted_image(corrupted_path)
assert success is False