// tests/adresar/post_adresar_test.rs // Import the rstest attribute macros. use rstest::{awt, fixture, rstest}; use server::adresar::handlers::post_adresar; use common::proto::multieko2::adresar::PostAdresarRequest; use crate::common::setup_test_db; use sqlx::PgPool; use tonic; // --- Fixtures --- #[fixture] async fn pool() -> PgPool { setup_test_db().await } #[fixture] async fn closed_pool(pool: PgPool) -> PgPool { // Close the pool so we can simulate a DB error. pool.close().await; pool } #[fixture] fn valid_request() -> PostAdresarRequest { PostAdresarRequest { firma: "Test Company".into(), kz: "KZ123".into(), drc: "DRC456".into(), ulica: "Test Street".into(), psc: "12345".into(), mesto: "Test City".into(), stat: "Test Country".into(), banka: "Test Bank".into(), ucet: "123456789".into(), skladm: "Warehouse M".into(), ico: "12345678".into(), kontakt: "John Doe".into(), telefon: "+421123456789".into(), skladu: "Warehouse U".into(), fax: "+421123456700".into(), } } #[fixture] fn minimal_request() -> PostAdresarRequest { PostAdresarRequest { firma: "Required Only".into(), ..Default::default() } } // A helper that checks that the database record matches the response. async fn assert_response_matches( pool: &PgPool, response: &common::proto::multieko2::adresar::AdresarResponse, ) { let db_record = sqlx::query!("SELECT * FROM adresar WHERE id = $1", response.id) .fetch_one(pool) .await .unwrap(); assert_eq!(db_record.firma, response.firma); assert_eq!( db_record.telefon.as_deref(), Some(response.telefon.as_str()) ); // More field comparisons can be added here… assert!(!db_record.deleted); assert!(db_record.created_at.is_some()); } // --- Tests --- #[rstest] #[awt] // awaits all async fixture inputs #[tokio::test] async fn test_create_adresar_success(pool: PgPool, valid_request: PostAdresarRequest) { let response = post_adresar(&pool, valid_request).await.unwrap(); assert!(response.id > 0, "Should return positive ID"); assert_eq!(response.firma, "Test Company", "Firma should match"); // Comprehensive database check. assert_response_matches(&pool, &response).await; } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_whitespace_trimming( pool: PgPool, mut valid_request: PostAdresarRequest, ) { // Change some fields to include extra whitespace. valid_request.firma = " Test Company ".into(); valid_request.telefon = " +421123456789 ".into(); valid_request.ulica = " Test Street ".into(); let response = post_adresar(&pool, valid_request).await.unwrap(); assert_eq!(response.firma, "Test Company"); assert_eq!(response.telefon, "+421123456789"); assert_eq!(response.ulica, "Test Street"); } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_empty_optional_fields( pool: PgPool, mut valid_request: PostAdresarRequest, ) { valid_request.telefon = " ".into(); let response = post_adresar(&pool, valid_request).await.unwrap(); // Check in the database that telefono was stored as NULL. let db_telefon = sqlx::query_scalar!("SELECT telefon FROM adresar WHERE id = $1", response.id) .fetch_one(&pool) .await .unwrap(); assert!(db_telefon.is_none()); // The response still returns an empty string. assert_eq!(response.telefon, ""); } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_invalid_firma( pool: PgPool, mut valid_request: PostAdresarRequest, ) { valid_request.firma = " ".into(); let result = post_adresar(&pool, valid_request).await; assert!(result.is_err()); assert_eq!(result.unwrap_err().code(), tonic::Code::InvalidArgument); } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_minimal_valid_request( pool: PgPool, minimal_request: PostAdresarRequest, ) { let response = post_adresar(&pool, minimal_request).await.unwrap(); assert!(response.id > 0); assert_eq!(response.firma, "Required Only"); // Verify that all other optional fields appear empty. assert!(response.kz.is_empty()); assert!(response.drc.is_empty()); // ...and so on. } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_empty_firma( pool: PgPool, mut minimal_request: PostAdresarRequest, ) { minimal_request.firma = "".into(); let result = post_adresar(&pool, minimal_request).await; assert!(result.is_err()); assert_eq!(result.unwrap_err().code(), tonic::Code::InvalidArgument); } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_database_error( closed_pool: PgPool, minimal_request: PostAdresarRequest, ) { let result = post_adresar(&closed_pool, minimal_request).await; assert!(result.is_err()); assert_eq!(result.unwrap_err().code(), tonic::Code::Internal); } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_field_length_limits( pool: PgPool, mut valid_request: PostAdresarRequest, ) { valid_request.firma = "a".repeat(255); valid_request.telefon = "1".repeat(20); let response = post_adresar(&pool, valid_request).await.unwrap(); assert_eq!(response.firma.len(), 255); assert_eq!(response.telefon.len(), 20); } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_special_characters( pool: PgPool, mut valid_request: PostAdresarRequest, ) { valid_request.telefon = "+420 123-456.789".into(); valid_request.ulica = "Náměstí 28. října".into(); let response = post_adresar(&pool, valid_request.clone()).await.unwrap(); assert_eq!(response.telefon, valid_request.telefon); assert_eq!(response.ulica, valid_request.ulica); } #[rstest] #[awt] #[tokio::test] async fn test_create_adresar_optional_fields_null_vs_empty( pool: PgPool, mut valid_request: PostAdresarRequest, ) { valid_request.telefon = String::new(); let response = post_adresar(&pool, valid_request).await.unwrap(); let db_telefon = sqlx::query_scalar!("SELECT telefon FROM adresar WHERE id = $1", response.id) .fetch_one(&pool) .await .unwrap(); assert!(db_telefon.is_none()); }