"""Tests for exception classes.""" class TestErrorCode: """Tests for ErrorCode enum.""" def test_error_code_values(self): """Test error code values.""" from exceptions import ErrorCode assert ErrorCode.UNKNOWN_ERROR.value == "KB_UNKNOWN_ERROR" assert ( ErrorCode.DATABASE_CONNECTION_ERROR.value == "KB_DATABASE_CONNECTION_ERROR" ) assert ( ErrorCode.EMBEDDING_GENERATION_ERROR.value == "KB_EMBEDDING_GENERATION_ERROR" ) assert ErrorCode.CHUNKING_ERROR.value == "KB_CHUNKING_ERROR" assert ErrorCode.SEARCH_ERROR.value == "KB_SEARCH_ERROR" assert ErrorCode.COLLECTION_NOT_FOUND.value == "KB_COLLECTION_NOT_FOUND" assert ErrorCode.DOCUMENT_NOT_FOUND.value == "KB_DOCUMENT_NOT_FOUND" class TestKnowledgeBaseError: """Tests for base exception class.""" def test_basic_error(self): """Test basic error creation.""" from exceptions import ErrorCode, KnowledgeBaseError error = KnowledgeBaseError( message="Something went wrong", code=ErrorCode.UNKNOWN_ERROR, ) assert error.message == "Something went wrong" assert error.code == ErrorCode.UNKNOWN_ERROR assert error.details == {} assert error.cause is None def test_error_with_details(self): """Test error with details.""" from exceptions import ErrorCode, KnowledgeBaseError error = KnowledgeBaseError( message="Query failed", code=ErrorCode.DATABASE_QUERY_ERROR, details={"query": "SELECT * FROM table", "error_code": 42}, ) assert error.details["query"] == "SELECT * FROM table" assert error.details["error_code"] == 42 def test_error_with_cause(self): """Test error with underlying cause.""" from exceptions import ErrorCode, KnowledgeBaseError original = ValueError("Original error") error = KnowledgeBaseError( message="Wrapped error", code=ErrorCode.INTERNAL_ERROR, cause=original, ) assert error.cause is original assert isinstance(error.cause, ValueError) def test_to_dict(self): """Test to_dict method.""" from exceptions import ErrorCode, KnowledgeBaseError error = KnowledgeBaseError( message="Test error", code=ErrorCode.INVALID_REQUEST, details={"field": "value"}, ) result = error.to_dict() assert result["error"] == "KB_INVALID_REQUEST" assert result["message"] == "Test error" assert result["details"]["field"] == "value" def test_str_representation(self): """Test string representation.""" from exceptions import ErrorCode, KnowledgeBaseError error = KnowledgeBaseError( message="Test error", code=ErrorCode.INVALID_REQUEST, ) assert str(error) == "[KB_INVALID_REQUEST] Test error" def test_repr_representation(self): """Test repr representation.""" from exceptions import ErrorCode, KnowledgeBaseError error = KnowledgeBaseError( message="Test error", code=ErrorCode.INVALID_REQUEST, details={"key": "value"}, ) repr_str = repr(error) assert "KnowledgeBaseError" in repr_str assert "Test error" in repr_str assert "KB_INVALID_REQUEST" in repr_str class TestDatabaseErrors: """Tests for database-related exceptions.""" def test_database_connection_error(self): """Test database connection error.""" from exceptions import DatabaseConnectionError, ErrorCode error = DatabaseConnectionError( message="Cannot connect to database", details={"host": "localhost", "port": 5432}, ) assert error.code == ErrorCode.DATABASE_CONNECTION_ERROR assert error.details["host"] == "localhost" def test_database_connection_error_default_message(self): """Test database connection error with default message.""" from exceptions import DatabaseConnectionError error = DatabaseConnectionError() assert error.message == "Failed to connect to database" def test_database_query_error(self): """Test database query error.""" from exceptions import DatabaseQueryError, ErrorCode error = DatabaseQueryError( message="Query failed", query="SELECT * FROM missing_table", ) assert error.code == ErrorCode.DATABASE_QUERY_ERROR assert error.details["query"] == "SELECT * FROM missing_table" class TestEmbeddingErrors: """Tests for embedding-related exceptions.""" def test_embedding_generation_error(self): """Test embedding generation error.""" from exceptions import EmbeddingGenerationError, ErrorCode error = EmbeddingGenerationError( message="Failed to generate", texts_count=10, ) assert error.code == ErrorCode.EMBEDDING_GENERATION_ERROR assert error.details["texts_count"] == 10 def test_embedding_dimension_mismatch(self): """Test embedding dimension mismatch error.""" from exceptions import EmbeddingDimensionMismatchError, ErrorCode error = EmbeddingDimensionMismatchError( expected=1536, actual=768, ) assert error.code == ErrorCode.EMBEDDING_DIMENSION_MISMATCH assert "expected 1536" in error.message assert "got 768" in error.message assert error.details["expected_dimension"] == 1536 assert error.details["actual_dimension"] == 768 class TestChunkingErrors: """Tests for chunking-related exceptions.""" def test_unsupported_file_type_error(self): """Test unsupported file type error.""" from exceptions import ErrorCode, UnsupportedFileTypeError error = UnsupportedFileTypeError( file_type=".xyz", supported_types=[".py", ".js", ".md"], ) assert error.code == ErrorCode.UNSUPPORTED_FILE_TYPE assert error.details["file_type"] == ".xyz" assert len(error.details["supported_types"]) == 3 def test_file_too_large_error(self): """Test file too large error.""" from exceptions import ErrorCode, FileTooLargeError error = FileTooLargeError( file_size=10_000_000, max_size=1_000_000, ) assert error.code == ErrorCode.FILE_TOO_LARGE assert error.details["file_size"] == 10_000_000 assert error.details["max_size"] == 1_000_000 def test_encoding_error(self): """Test encoding error.""" from exceptions import EncodingError, ErrorCode error = EncodingError( message="Cannot decode file", encoding="utf-8", ) assert error.code == ErrorCode.ENCODING_ERROR assert error.details["encoding"] == "utf-8" class TestSearchErrors: """Tests for search-related exceptions.""" def test_invalid_search_type_error(self): """Test invalid search type error.""" from exceptions import ErrorCode, InvalidSearchTypeError error = InvalidSearchTypeError( search_type="invalid", valid_types=["semantic", "keyword", "hybrid"], ) assert error.code == ErrorCode.INVALID_SEARCH_TYPE assert error.details["search_type"] == "invalid" assert len(error.details["valid_types"]) == 3 def test_search_timeout_error(self): """Test search timeout error.""" from exceptions import ErrorCode, SearchTimeoutError error = SearchTimeoutError(timeout=30.0) assert error.code == ErrorCode.SEARCH_TIMEOUT assert error.details["timeout"] == 30.0 assert "30" in error.message class TestCollectionErrors: """Tests for collection-related exceptions.""" def test_collection_not_found_error(self): """Test collection not found error.""" from exceptions import CollectionNotFoundError, ErrorCode error = CollectionNotFoundError( collection="missing-collection", project_id="proj-123", ) assert error.code == ErrorCode.COLLECTION_NOT_FOUND assert error.details["collection"] == "missing-collection" assert error.details["project_id"] == "proj-123" class TestDocumentErrors: """Tests for document-related exceptions.""" def test_document_not_found_error(self): """Test document not found error.""" from exceptions import DocumentNotFoundError, ErrorCode error = DocumentNotFoundError( source_path="/path/to/file.py", project_id="proj-123", ) assert error.code == ErrorCode.DOCUMENT_NOT_FOUND assert error.details["source_path"] == "/path/to/file.py" def test_invalid_document_error(self): """Test invalid document error.""" from exceptions import ErrorCode, InvalidDocumentError error = InvalidDocumentError( message="Empty content", details={"reason": "no content"}, ) assert error.code == ErrorCode.INVALID_DOCUMENT class TestProjectErrors: """Tests for project-related exceptions.""" def test_project_not_found_error(self): """Test project not found error.""" from exceptions import ErrorCode, ProjectNotFoundError error = ProjectNotFoundError(project_id="missing-proj") assert error.code == ErrorCode.PROJECT_NOT_FOUND assert error.details["project_id"] == "missing-proj" def test_project_access_denied_error(self): """Test project access denied error.""" from exceptions import ErrorCode, ProjectAccessDeniedError error = ProjectAccessDeniedError(project_id="restricted-proj") assert error.code == ErrorCode.PROJECT_ACCESS_DENIED assert "restricted-proj" in error.message