Spaces:
Sleeping
Sleeping
| """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 |