#![allow( clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::absurd_extreme_comparisons, clippy::field_reassign_with_default, clippy::manual_flatten, clippy::tests_outside_test_module, unused_imports, unused_variables, unused_comparisons, dead_code, )] //! Comprehensive test coverage for database module //! Target: 95%+ coverage for database operations and error handling use config::database::{DatabaseConfig, PoolConfig, TransactionConfig}; use database::*; #[cfg(test)] mod database_error_tests { use super::*; #[test] fn test_database_error_types() { let connection_error = DatabaseError::Connection { message: "Failed to connect".to_string(), }; assert!(connection_error.to_string().contains("Connection failed")); let query_error = DatabaseError::Query { query: "SELECT *".to_string(), message: "Invalid SQL".to_string(), }; assert!(query_error.to_string().contains("Query execution failed")); let transaction_error = DatabaseError::Transaction { message: "Commit failed".to_string(), }; assert!(transaction_error.to_string().contains("Transaction error")); let pool_error = DatabaseError::ConnectionPool { message: "Pool exhausted".to_string(), }; assert!(pool_error.to_string().contains("Connection pool error")); } #[test] fn test_database_error_debug() { let error = DatabaseError::Connection { message: "Test".to_string(), }; let debug_str = format!("{:?}", error); assert!(debug_str.contains("Connection")); } #[test] fn test_database_error_retryable() { let timeout_error = DatabaseError::Timeout { operation: "query".to_string(), timeout_secs: 30, }; assert!(timeout_error.is_retryable()); let validation_error = DatabaseError::Validation { field: "email".to_string(), message: "invalid format".to_string(), }; assert!(!validation_error.is_retryable()); } #[test] fn test_database_error_category() { let error = DatabaseError::Configuration { message: "Bad config".to_string(), }; assert_eq!(error.category(), "configuration"); let error = DatabaseError::Migration { message: "Migration failed".to_string(), }; assert_eq!(error.category(), "migration"); } } #[cfg(test)] mod pool_config_tests { use super::*; #[test] fn test_pool_config_defaults() { let config = PoolConfig::default(); assert!(config.max_connections > 0); assert!(config.min_connections > 0); assert!(config.max_connections >= config.min_connections); assert!(config.health_check_enabled); } #[test] fn test_pool_config_validation() { let config = PoolConfig { max_connections: 20, min_connections: 5, acquire_timeout_secs: 30, idle_timeout_secs: 600, max_lifetime_secs: 1800, test_before_acquire: true, database_url: "postgresql://localhost/test".to_string(), health_check_enabled: true, health_check_interval_secs: 60, }; // Validate logical constraints assert!(config.max_connections > config.min_connections); assert!(config.acquire_timeout_secs > 0); assert!(config.idle_timeout_secs > 0); assert!(config.max_lifetime_secs > config.idle_timeout_secs); } #[test] fn test_pool_config_serialization() { let config = PoolConfig { max_connections: 10, min_connections: 2, acquire_timeout_secs: 15, idle_timeout_secs: 300, max_lifetime_secs: 900, test_before_acquire: false, database_url: "postgresql://localhost/test".to_string(), health_check_enabled: false, health_check_interval_secs: 30, }; let serialized = serde_json::to_string(&config).expect("Serialization failed"); let deserialized: PoolConfig = serde_json::from_str(&serialized).expect("Deserialization failed"); assert_eq!(config.max_connections, deserialized.max_connections); assert_eq!(config.test_before_acquire, deserialized.test_before_acquire); } #[test] fn test_pool_config_edge_cases() { // Test minimum possible values let min_config = PoolConfig { max_connections: 1, min_connections: 1, acquire_timeout_secs: 1, idle_timeout_secs: 1, max_lifetime_secs: 1, test_before_acquire: false, database_url: "postgresql://localhost/test".to_string(), health_check_enabled: false, health_check_interval_secs: 1, }; assert_eq!(min_config.max_connections, min_config.min_connections); // Test large values let large_config = PoolConfig { max_connections: 1000, min_connections: 100, acquire_timeout_secs: 3600, idle_timeout_secs: 7200, max_lifetime_secs: 86400, test_before_acquire: true, database_url: "postgresql://localhost/test".to_string(), health_check_enabled: true, health_check_interval_secs: 300, }; assert!(large_config.max_connections > 100); } } #[cfg(test)] mod transaction_config_tests { use super::*; #[test] fn test_transaction_config_defaults() { let config = TransactionConfig::default(); assert!(config.max_retries > 0); assert!(config.retry_delay_ms > 0); assert!(config.enable_retry); } #[test] fn test_transaction_config_validation() { let config = TransactionConfig { isolation_level: "READ_COMMITTED".to_string(), timeout: std::time::Duration::from_secs(30), default_timeout_secs: 30, enable_retry: true, max_retries: 5, retry_delay_ms: 100, max_savepoints: 10, }; assert!(config.max_retries > 0); assert!(config.retry_delay_ms > 0); assert!(!config.isolation_level.is_empty()); assert!(config.enable_retry); } #[test] fn test_transaction_config_serialization() { let config = TransactionConfig { isolation_level: "SERIALIZABLE".to_string(), timeout: std::time::Duration::from_secs(60), default_timeout_secs: 60, enable_retry: false, max_retries: 3, retry_delay_ms: 50, max_savepoints: 5, }; let serialized = serde_json::to_string(&config).expect("Serialization failed"); let deserialized: TransactionConfig = serde_json::from_str(&serialized).expect("Deserialization failed"); assert_eq!(config.isolation_level, deserialized.isolation_level); assert_eq!(config.enable_retry, deserialized.enable_retry); } #[test] fn test_transaction_isolation_levels() { let levels = vec![ "READ_UNCOMMITTED", "READ_COMMITTED", "REPEATABLE_READ", "SERIALIZABLE", ]; for level in levels { let config = TransactionConfig { isolation_level: level.to_string(), timeout: std::time::Duration::from_secs(30), default_timeout_secs: 30, enable_retry: true, max_retries: 3, retry_delay_ms: 100, max_savepoints: 10, }; assert_eq!(config.isolation_level, level); } } } #[cfg(test)] mod query_builder_tests { use super::*; #[test] fn test_query_builder_basic() { let query = Database::select(&["id", "name", "value"]) .from("test_table") .where_raw("active = true") .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("SELECT")); assert!(sql.contains("FROM test_table")); assert!(sql.contains("WHERE")); } #[test] fn test_query_builder_with_joins() { let query = Database::select(&["a.id", "b.name"]) .from("table_a a") .inner_join("table_b b", "a.id = b.a_id") .where_raw("a.status = 'active'") .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("INNER JOIN")); assert!(sql.contains("a.id = b.a_id")); } #[test] fn test_query_builder_with_order_and_limit() { let query = Database::select(&["*"]) .from("orders") .where_raw("amount > 1000") .order_by("created_at", OrderDirection::Desc) .limit(10) .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("ORDER BY")); assert!(sql.contains("LIMIT 10")); } #[test] fn test_insert_builder() { let query = Database::insert("users") .values(&[("name", "Alice"), ("email", "alice@example.com")]) .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("INSERT INTO users")); } #[test] fn test_update_builder() { let query = Database::update("users") .set("name", "Bob") .where_eq("id", 1) .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("UPDATE users")); assert!(sql.contains("SET")); assert!(sql.contains("WHERE")); } #[test] fn test_delete_builder() { let query = Database::delete("users") .where_raw("id = 1") .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("DELETE FROM users")); assert!(sql.contains("WHERE")); } } #[cfg(test)] mod database_config_tests { use super::*; #[test] fn test_database_config_new() { let config = DatabaseConfig::new(); assert!(!config.url.is_empty()); assert!(config.max_connections > 0); assert!(config.min_connections > 0); assert!(config.max_connections >= config.min_connections); } #[test] fn test_database_config_validation() { let mut config = DatabaseConfig::new(); assert!(config.validate().is_ok()); config.url = String::new(); assert!(config.validate().is_err()); } #[test] fn test_database_config_serialization() { let config = DatabaseConfig::new(); let serialized = serde_json::to_string(&config).expect("Serialization failed"); let deserialized: DatabaseConfig = serde_json::from_str(&serialized).expect("Deserialization failed"); assert_eq!(config.url, deserialized.url); } #[test] fn test_database_config_pool_and_transaction() { let config = DatabaseConfig::new(); assert!(config.pool.max_connections > 0); assert!(config.transaction.max_retries > 0); } } #[cfg(test)] mod edge_case_tests { use super::*; #[test] fn test_zero_max_connections() { let config = PoolConfig { max_connections: 0, // Invalid but should handle gracefully min_connections: 0, acquire_timeout_secs: 30, idle_timeout_secs: 600, max_lifetime_secs: 1800, test_before_acquire: false, database_url: "postgresql://localhost/test".to_string(), health_check_enabled: false, health_check_interval_secs: 60, }; assert_eq!(config.max_connections, 0); // Real implementation should validate this } #[test] fn test_negative_timeout() { // Using i64 to test negative values let timeout = -1; assert!(timeout < 0); // System should handle negative timeouts (convert to u64 or error) } #[test] fn test_empty_database_url() { let mut config = DatabaseConfig::new(); config.url = String::new(); assert!(config.url.is_empty()); // Should be caught by validation assert!(config.validate().is_err()); } #[test] fn test_constraint_violation_error() { let error = DatabaseError::ConstraintViolation { constraint: "unique_email".to_string(), message: "Email already exists".to_string(), }; assert!(error.to_string().contains("Constraint violation")); assert_eq!(error.category(), "constraint_violation"); } #[test] fn test_not_found_error() { let error = DatabaseError::NotFound { resource_type: "User".to_string(), identifier: "id=123".to_string(), }; assert!(error.to_string().contains("Resource not found")); assert_eq!(error.category(), "not_found"); } #[test] fn test_serialization_error() { let error = DatabaseError::Serialization { message: "Failed to serialize JSON".to_string(), }; assert!(error.to_string().contains("Serialization error")); assert_eq!(error.category(), "serialization"); } } #[cfg(test)] mod query_builder_advanced_tests { use super::*; #[test] fn test_select_with_multiple_where_clauses() { let query = Database::select(&["id"]) .from("products") .where_raw("price > 100") .where_raw("stock > 0") .where_raw("category = 'electronics'") .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("WHERE")); // Should combine multiple where clauses assert!(sql.contains("price > 100")); } #[test] fn test_insert_returning() { let query = Database::insert("users") .values(&[("name", "Alice"), ("email", "alice@example.com")]) .returning("id") .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("RETURNING")); } #[test] fn test_update_with_multiple_sets() { let query = Database::update("users") .set("name", "Bob") .set("email", "bob@example.com") .where_eq("id", 1) .build() .expect("Query build failed"); let sql = query.sql(); assert!(sql.contains("UPDATE users")); } }