"""Tests for security/file_integrity/base_verifier.py.""" import pytest import tempfile from pathlib import Path class TestFileTypeEnum: """Tests for FileType enum.""" def test_faiss_index_value(self): """Test FAISS_INDEX enum value.""" from local_deep_research.security.file_integrity.base_verifier import ( FileType, ) assert FileType.FAISS_INDEX.value == "faiss_index" def test_pdf_value(self): """Test PDF enum value.""" from local_deep_research.security.file_integrity.base_verifier import ( FileType, ) assert FileType.PDF.value == "pdf" def test_export_value(self): """Test EXPORT enum value.""" from local_deep_research.security.file_integrity.base_verifier import ( FileType, ) assert FileType.EXPORT.value == "export" def test_file_type_is_str_enum(self): """Test that FileType is a string enum.""" from local_deep_research.security.file_integrity.base_verifier import ( FileType, ) assert isinstance(FileType.PDF, str) assert FileType.PDF == "pdf" class TestBaseFileVerifierAbstract: """Tests for BaseFileVerifier abstract class.""" def test_cannot_instantiate_directly(self): """Test that BaseFileVerifier cannot be instantiated directly.""" from local_deep_research.security.file_integrity.base_verifier import ( BaseFileVerifier, ) with pytest.raises(TypeError, match="abstract"): BaseFileVerifier() def test_defines_abstract_methods(self): """Test that abstract methods are defined.""" from local_deep_research.security.file_integrity.base_verifier import ( BaseFileVerifier, ) # Check that the class has the expected abstract methods assert hasattr(BaseFileVerifier, "should_verify") assert hasattr(BaseFileVerifier, "get_file_type") assert hasattr(BaseFileVerifier, "allows_modifications") class TestConcreteVerifier: """Tests using a concrete implementation of BaseFileVerifier.""" @pytest.fixture def concrete_verifier(self): """Create a concrete verifier implementation for testing.""" from local_deep_research.security.file_integrity.base_verifier import ( BaseFileVerifier, FileType, ) class TestVerifier(BaseFileVerifier): def should_verify(self, file_path: Path) -> bool: return file_path.suffix == ".test" def get_file_type(self) -> FileType: return FileType.PDF def allows_modifications(self) -> bool: return False return TestVerifier() def test_calculate_checksum_returns_sha256_hex(self, concrete_verifier): """Test that calculate_checksum returns a SHA256 hex string.""" with tempfile.NamedTemporaryFile(delete=False, suffix=".test") as f: f.write(b"test content") f.flush() file_path = Path(f.name) try: checksum = concrete_verifier.calculate_checksum(file_path) # SHA256 hex string is 64 characters assert len(checksum) == 64 assert all(c in "0123456789abcdef" for c in checksum) finally: file_path.unlink() def test_calculate_checksum_is_deterministic(self, concrete_verifier): """Test that same content produces same checksum.""" with tempfile.NamedTemporaryFile(delete=False, suffix=".test") as f: f.write(b"identical content") f.flush() file_path = Path(f.name) try: checksum1 = concrete_verifier.calculate_checksum(file_path) checksum2 = concrete_verifier.calculate_checksum(file_path) assert checksum1 == checksum2 finally: file_path.unlink() def test_calculate_checksum_different_for_different_content( self, concrete_verifier ): """Test that different content produces different checksum.""" with tempfile.NamedTemporaryFile(delete=False, suffix=".test") as f1: f1.write(b"content one") f1.flush() file_path1 = Path(f1.name) with tempfile.NamedTemporaryFile(delete=False, suffix=".test") as f2: f2.write(b"content two") f2.flush() file_path2 = Path(f2.name) try: checksum1 = concrete_verifier.calculate_checksum(file_path1) checksum2 = concrete_verifier.calculate_checksum(file_path2) assert checksum1 != checksum2 finally: file_path1.unlink() file_path2.unlink() def test_calculate_checksum_raises_for_missing_file( self, concrete_verifier ): """Test that FileNotFoundError is raised for missing file.""" with pytest.raises(FileNotFoundError): concrete_verifier.calculate_checksum(Path("/nonexistent/file.test")) def test_get_algorithm_returns_sha256(self, concrete_verifier): """Test that get_algorithm returns sha256.""" assert concrete_verifier.get_algorithm() == "sha256" def test_should_verify_with_matching_file(self, concrete_verifier): """Test should_verify returns True for matching file type.""" assert ( concrete_verifier.should_verify(Path("/path/to/file.test")) is True ) def test_should_verify_with_non_matching_file(self, concrete_verifier): """Test should_verify returns False for non-matching file type.""" assert ( concrete_verifier.should_verify(Path("/path/to/file.txt")) is False ) def test_get_file_type_returns_expected(self, concrete_verifier): """Test get_file_type returns the expected FileType.""" from local_deep_research.security.file_integrity.base_verifier import ( FileType, ) assert concrete_verifier.get_file_type() == FileType.PDF def test_allows_modifications_returns_false(self, concrete_verifier): """Test allows_modifications returns False.""" assert concrete_verifier.allows_modifications() is False class TestChecksumWithLargeFile: """Tests for checksum calculation with larger files.""" @pytest.fixture def verifier(self): """Create a concrete verifier for testing.""" from local_deep_research.security.file_integrity.base_verifier import ( BaseFileVerifier, FileType, ) class LargeFileVerifier(BaseFileVerifier): def should_verify(self, file_path: Path) -> bool: return True def get_file_type(self) -> FileType: return FileType.EXPORT def allows_modifications(self) -> bool: return True return LargeFileVerifier() def test_handles_file_larger_than_chunk_size(self, verifier): """Test that files larger than 4096 bytes are handled correctly.""" # Create a file larger than the chunk size (4096 bytes) content = b"x" * 10000 # 10KB with tempfile.NamedTemporaryFile(delete=False) as f: f.write(content) f.flush() file_path = Path(f.name) try: checksum = verifier.calculate_checksum(file_path) # Should still return valid SHA256 assert len(checksum) == 64 assert all(c in "0123456789abcdef" for c in checksum) finally: file_path.unlink() def test_empty_file_has_valid_checksum(self, verifier): """Test that empty files have a valid checksum.""" with tempfile.NamedTemporaryFile(delete=False) as f: # Don't write anything - empty file file_path = Path(f.name) try: checksum = verifier.calculate_checksum(file_path) # Empty file should have the SHA256 of empty string # This is the well-known SHA256 hash of "" (not a secret) empty_string_sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" # DevSkim: ignore DS173237 assert checksum == empty_string_sha256 finally: file_path.unlink()