//! Common tests for Veza Common Library //! //! This module provides integration tests and test utilities for the Veza common library. use veza_common::utils::{ generate_uuid, format_duration, format_file_size, validate_email, validate_username, validate_password, validate_email_result, validate_username_result, to_json, from_json, format_timestamp, parse_date, format_relative_time, format_log_message, StructuredLogEntry, }; use veza_common::types::{ Track, }; use veza_common::config::{ DatabaseConfig, RedisConfig, }; use veza_common::error::{ CommonError, ErrorResponse, }; /// Test fixtures for common library tests pub mod fixtures { use veza_common::types::{User, Track, Playlist}; use veza_common::config::{DatabaseConfig, RedisConfig}; use uuid::Uuid; use std::collections::HashMap; /// Create a test user pub fn create_test_user(id: i64) -> User { User::new(id, format!("testuser{}", id), format!("test{}@example.com", id)) } /// Create a test track pub fn create_test_track(id: Uuid) -> Track { Track::new(id, "Test Track".to_string(), "Test Artist".to_string(), 180) } /// Create a test playlist pub fn create_test_playlist(id: Uuid, owner_id: Uuid) -> Playlist { Playlist::new(id, "Test Playlist".to_string(), owner_id) } /// Create a test database configuration pub fn create_test_database_config() -> DatabaseConfig { DatabaseConfig::new( "postgresql://test:test@localhost:5432/test_db".to_string(), 10 ) } /// Create a test Redis configuration pub fn create_test_redis_config() -> RedisConfig { RedisConfig::new("redis://localhost:6379".to_string()) } /// Create test context for logging pub fn create_test_context() -> HashMap { let mut context = HashMap::new(); context.insert("user_id".to_string(), "123".to_string()); context.insert("ip".to_string(), "192.168.1.1".to_string()); context.insert("request_id".to_string(), Uuid::new_v4().to_string()); context } } /// Test helpers for common library tests pub mod helpers { use veza_common::types::{ApiResponse, PaginationParams, PaginatedResponse}; /// Assert that a result is ok pub fn assert_ok(result: Result) -> T { result.expect("Expected Ok result") } /// Assert that a result is an error pub fn assert_err(result: Result) -> E { result.expect_err("Expected Err result") } /// Assert that two values are equal pub fn assert_eq_expected( actual: T, expected: T, message: &str, ) { assert_eq!( actual, expected, "{}: expected {:?}, got {:?}", message, expected, actual ); } /// Create a test API response pub fn create_test_api_response(data: T) -> ApiResponse { ApiResponse::success(data) } /// Create a test error API response pub fn create_test_error_response(message: &str) -> ApiResponse { ApiResponse::error(message.to_string()) } /// Create test pagination parameters pub fn create_test_pagination(page: u32, limit: u32) -> PaginationParams { PaginationParams { page, limit } } /// Create test paginated response pub fn create_test_paginated_response(items: Vec, total: u64) -> PaginatedResponse { PaginatedResponse::new(items, total, 1, 20) } } #[cfg(test)] mod tests { use super::*; use fixtures::*; use helpers::*; use uuid::Uuid; #[test] fn test_common_utilities() { // Test UUID generation let uuid1 = generate_uuid(); let uuid2 = generate_uuid(); assert_ne!(uuid1, uuid2); // Test duration formatting let formatted = format_duration(125); assert_eq!(formatted, "2:05"); // Test file size formatting let size = format_file_size(1024); assert_eq!(size, "1.00 KB"); } #[test] fn test_validation_utilities() { // Test email validation assert!(validate_email("test@example.com")); assert!(!validate_email("invalid-email")); // Test username validation assert!(validate_username("user123")); assert!(!validate_username("ab")); // Too short // Test password validation assert!(validate_password("Password123")); assert!(!validate_password("short")); // Too short } #[test] fn test_serialization_utilities() { use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, PartialEq)] struct TestData { name: String, value: i32, } let data = TestData { name: "test".to_string(), value: 42, }; // Test serialization let json = to_json(&data).unwrap(); assert!(json.contains("test")); assert!(json.contains("42")); // Test deserialization let deserialized: TestData = from_json(&json).unwrap(); assert_eq!(data, deserialized); } #[test] fn test_date_utilities() { use chrono::{Utc, Duration, Datelike}; // Test timestamp formatting let timestamp = 1609459200; // 2021-01-01 00:00:00 UTC let formatted = format_timestamp(timestamp); assert!(formatted.contains("2021")); // Test date parsing let date_str = "2021-01-01T00:00:00Z"; let dt = parse_date(date_str).unwrap(); assert_eq!(dt.year(), 2021); // Test relative time let now = Utc::now(); let past = now - Duration::hours(2); let relative = format_relative_time(&past, &now); assert!(relative.contains("2")); assert!(relative.contains("hour")); } #[test] fn test_logging_utilities() { // Test log message formatting let message = format_log_message("api", "INFO", "Test message"); assert!(message.contains("api")); assert!(message.contains("INFO")); assert!(message.contains("Test message")); // Test structured log entry let entry = StructuredLogEntry::new("api", "INFO", "Test message") .with_context("user_id".to_string(), "123".to_string()); let json = entry.to_json(); assert!(json.contains("api")); assert!(json.contains("user_id")); assert!(json.contains("123")); } #[test] fn test_type_utilities() { // Test User let user = create_test_user(1); assert_eq!(user.id, 1); assert_eq!(user.username, "testuser1"); assert!(user.validate().is_ok()); // Test Track let track_id = Uuid::new_v4(); let track = create_test_track(track_id); assert_eq!(track.id, track_id); assert_eq!(track.title, "Test Track"); assert!(track.validate().is_ok()); // Test Playlist let playlist_id = Uuid::new_v4(); let owner_id = Uuid::new_v4(); let playlist = create_test_playlist(playlist_id, owner_id); assert_eq!(playlist.id, playlist_id); assert_eq!(playlist.owner_id, owner_id); assert!(playlist.validate().is_ok()); } #[test] fn test_config_utilities() { // Test DatabaseConfig let db_config = create_test_database_config(); assert!(db_config.validate().is_ok()); assert_eq!(db_config.host(), Some("localhost".to_string())); assert_eq!(db_config.port(), Some(5432)); // Test RedisConfig let redis_config = create_test_redis_config(); assert!(redis_config.validate().is_ok()); assert_eq!(redis_config.host(), Some("localhost".to_string())); assert_eq!(redis_config.port(), Some(6379)); } #[test] fn test_api_response_utilities() { // Test success response let response = create_test_api_response("test data"); assert!(response.success); assert!(response.data.is_some()); assert_eq!(response.data.unwrap(), "test data"); // Test error response let error_response = create_test_error_response("Test error"); assert!(!error_response.success); assert!(error_response.data.is_none()); assert_eq!(error_response.error, Some("Test error".to_string())); } #[test] fn test_pagination_utilities() { // Test pagination parameters let params = create_test_pagination(2, 50); assert_eq!(params.page, 2); assert_eq!(params.limit, 50); // Test paginated response let items = vec![1, 2, 3, 4, 5]; let response = create_test_paginated_response(items.clone(), 100); assert_eq!(response.items.len(), 5); assert_eq!(response.total, 100); assert_eq!(response.total_pages, 5); // 100 / 20 } #[test] fn test_error_handling() { // Test CommonError let error = CommonError::NotFound("Resource not found".to_string()); assert_eq!(error.code(), "NOT_FOUND"); assert_eq!(error.http_status_code(), 404); assert_eq!(error.message(), "Resource not found"); // Test ErrorResponse let error_response: ErrorResponse = (&error).into(); assert_eq!(error_response.code, "NOT_FOUND"); assert_eq!(error_response.status, 404); } #[test] fn test_validation_result() { // Test validation with Result assert!(validate_email_result("test@example.com").is_ok()); assert!(validate_email_result("invalid-email").is_err()); assert!(validate_username_result("user123").is_ok()); assert!(validate_username_result("ab").is_err()); } #[test] fn test_config_validation() { // Test DatabaseConfig validation let mut db_config = create_test_database_config(); assert!(db_config.validate().is_ok()); // Test invalid URL db_config.url = "invalid-url".to_string(); assert!(db_config.validate().is_err()); // Test RedisConfig validation let mut redis_config = create_test_redis_config(); assert!(redis_config.validate().is_ok()); // Test invalid URL redis_config.url = "invalid-url".to_string(); assert!(redis_config.validate().is_err()); } #[test] fn test_playlist_operations() { let playlist_id = Uuid::new_v4(); let owner_id = Uuid::new_v4(); let track_id = Uuid::new_v4(); let mut playlist = create_test_playlist(playlist_id, owner_id); // Test adding tracks playlist.add_track(track_id); assert_eq!(playlist.track_count(), 1); assert!(!playlist.is_empty()); // Test removing tracks playlist.remove_track(track_id); assert_eq!(playlist.track_count(), 0); assert!(playlist.is_empty()); } #[test] fn test_track_utilities() { let track_id = Uuid::new_v4(); let track = Track::new(track_id, "Test Song".to_string(), "Test Artist".to_string(), 125); // Test formatted duration assert_eq!(track.formatted_duration(), "2:05"); // Test validation assert!(track.validate().is_ok()); } #[test] fn test_helper_functions() { // Test assert_ok let ok_result: Result = Ok(42); let value = assert_ok(ok_result); assert_eq!(value, 42); // Test assert_err let err_result: Result = Err("Error".to_string()); let error = assert_err(err_result); assert_eq!(error, "Error"); // Test assert_eq_expected assert_eq_expected(5, 5, "Values should be equal"); } #[test] fn test_context_creation() { let context = create_test_context(); assert!(context.contains_key("user_id")); assert!(context.contains_key("ip")); assert!(context.contains_key("request_id")); } #[test] fn test_round_trip_serialization() { use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, PartialEq)] struct TestStruct { id: i32, name: String, active: bool, } let original = TestStruct { id: 1, name: "Test".to_string(), active: true, }; // Serialize let json = to_json(&original).unwrap(); // Deserialize let deserialized: TestStruct = from_json(&json).unwrap(); assert_eq!(original, deserialized); } #[test] fn test_config_url_parsing() { // Test database URL parsing let db_config = DatabaseConfig::new( "postgresql://user:pass@localhost:5433/mydb?sslmode=require".to_string(), 10 ); assert_eq!(db_config.host(), Some("localhost".to_string())); assert_eq!(db_config.port(), Some(5433)); assert_eq!(db_config.database_name(), Some("mydb".to_string())); // Test Redis URL parsing let redis_config = RedisConfig::new("redis://user:pass@localhost:6380/1".to_string()); assert_eq!(redis_config.host(), Some("localhost".to_string())); assert_eq!(redis_config.port(), Some(6380)); } }