"""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