/* * This file is part of Sharenet. * * Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. * * You may obtain a copy of the license at: * https://creativecommons.org/licenses/by-nc-sa/4.0/ * * Copyright (c) 2024 Continuist */ use application::{Service, UseCase}; use domain::{CreateProduct, CreateUser, Product, UpdateProduct, UpdateUser, User}; use memory::{InMemoryUserRepository, InMemoryProductRepository}; use postgres::{PostgresUserRepository, PostgresProductRepository}; use sqlx::PgPool; use uuid::Uuid; use serial_test::serial; // Import the centralized test setup use crate::test_setup::{setup_test_db, cleanup_test_data, unique_test_data}; // Helper functions are now imported from test_setup module above // Test data structures for comparison #[derive(Debug, PartialEq, Clone)] struct UserData { username: String, email: String, } impl From<&User> for UserData { fn from(user: &User) -> Self { Self { username: user.username().to_string(), email: user.email().to_string(), } } } #[derive(Debug, PartialEq, Clone)] struct ProductData { name: String, description: String, } impl From<&Product> for ProductData { fn from(product: &Product) -> Self { Self { name: product.name().to_string(), description: product.description().to_string(), } } } // Helper function to compare user lists (ignoring IDs and timestamps) fn compare_user_lists(users1: &[User], users2: &[User]) { let data1: Vec = users1.iter().map(UserData::from).collect(); let data2: Vec = users2.iter().map(UserData::from).collect(); assert_eq!(data1.len(), data2.len(), "User count mismatch"); // Sort by username for consistent comparison let mut sorted1 = data1.clone(); let mut sorted2 = data2.clone(); sorted1.sort_by(|a, b| a.username.cmp(&b.username)); sorted2.sort_by(|a, b| a.username.cmp(&b.username)); assert_eq!(sorted1, sorted2, "User data mismatch"); } // Helper function to compare product lists (ignoring IDs and timestamps) fn compare_product_lists(products1: &[Product], products2: &[Product]) { let data1: Vec = products1.iter().map(ProductData::from).collect(); let data2: Vec = products2.iter().map(ProductData::from).collect(); assert_eq!(data1.len(), data2.len(), "Product count mismatch"); // Sort by name for consistent comparison let mut sorted1 = data1.clone(); let mut sorted2 = data2.clone(); sorted1.sort_by(|a, b| a.name.cmp(&b.name)); sorted2.sort_by(|a, b| a.name.cmp(&b.name)); assert_eq!(sorted1, sorted2, "Product data mismatch"); } // Helper function to create services for different interfaces fn create_memory_services() -> (Service, Service) { let user_repo = InMemoryUserRepository::new(); let product_repo = InMemoryProductRepository::new(); let user_service = Service::new(user_repo); let product_service = Service::new(product_repo); (user_service, product_service) } fn create_postgres_services(pool: PgPool) -> (Service, Service) { let user_repo = PostgresUserRepository::new(pool.clone()); let product_repo = PostgresProductRepository::new(pool); let user_service = Service::new(user_repo); let product_service = Service::new(product_repo); (user_service, product_service) } #[tokio::test] #[serial] async fn test_api_cli_consistency_with_memory() { // Create services for both interfaces using memory backend let (api_user_service, api_product_service) = create_memory_services(); let (cli_user_service, cli_product_service) = create_memory_services(); // Test data let (username1, email1) = unique_test_data("api_cli_user1"); let (username2, email2) = unique_test_data("api_cli_user2"); let (name1, _) = unique_test_data("api_cli_product1"); let (name2, _) = unique_test_data("api_cli_product2"); // Test 1: Create users via API interface and capture state let create_user1 = CreateUser::new(username1.clone(), email1.clone()).unwrap(); let create_user2 = CreateUser::new(username2.clone(), email2.clone()).unwrap(); let api_user1 = api_user_service.create(create_user1.clone()).await.unwrap(); let _api_user2 = api_user_service.create(create_user2.clone()).await.unwrap(); let api_users_after_create = api_user_service.list().await.unwrap(); assert_eq!(api_users_after_create.len(), 2); // Test 2: Create same users via CLI interface and compare let cli_user1 = cli_user_service.create(create_user1).await.unwrap(); let _cli_user2 = cli_user_service.create(create_user2).await.unwrap(); let cli_users_after_create = cli_user_service.list().await.unwrap(); assert_eq!(cli_users_after_create.len(), 2); // Compare user data (ignoring IDs and timestamps) compare_user_lists(&api_users_after_create, &cli_users_after_create); // Test 3: Create products via API interface and capture state let create_product1 = CreateProduct::new(name1.clone(), "Description 1".to_string()).unwrap(); let create_product2 = CreateProduct::new(name2.clone(), "Description 2".to_string()).unwrap(); let api_product1 = api_product_service.create(create_product1.clone()).await.unwrap(); let _api_product2 = api_product_service.create(create_product2.clone()).await.unwrap(); let api_products_after_create = api_product_service.list().await.unwrap(); assert_eq!(api_products_after_create.len(), 2); // Test 4: Create same products via CLI interface and compare let cli_product1 = cli_product_service.create(create_product1).await.unwrap(); let _cli_product2 = cli_product_service.create(create_product2).await.unwrap(); let cli_products_after_create = cli_product_service.list().await.unwrap(); assert_eq!(cli_products_after_create.len(), 2); // Compare product data (ignoring IDs and timestamps) compare_product_lists(&api_products_after_create, &cli_products_after_create); // Test 5: Test that both interfaces can access the same data let api_retrieved_user = api_user_service.get(api_user1.id()).await.unwrap(); let cli_retrieved_user = cli_user_service.get(cli_user1.id()).await.unwrap(); assert_eq!(api_retrieved_user.username(), cli_retrieved_user.username()); assert_eq!(api_retrieved_user.email(), cli_retrieved_user.email()); let api_retrieved_product = api_product_service.get(api_product1.id()).await.unwrap(); let cli_retrieved_product = cli_product_service.get(cli_product1.id()).await.unwrap(); assert_eq!(api_retrieved_product.name(), cli_retrieved_product.name()); assert_eq!(api_retrieved_product.description(), cli_retrieved_product.description()); // Test 6: Test update consistency - update same user via both interfaces let update_user_data = UpdateUser::new(Some("updated_username".to_string()), Some("updated@example.com".to_string())).unwrap(); let api_updated_user = api_user_service.update(api_user1.id(), update_user_data.clone()).await.unwrap(); let cli_updated_user = cli_user_service.update(cli_user1.id(), update_user_data).await.unwrap(); assert_eq!(api_updated_user.username(), cli_updated_user.username()); assert_eq!(api_updated_user.email(), cli_updated_user.email()); // Test 7: Test delete consistency api_user_service.delete(api_user1.id()).await.unwrap(); cli_user_service.delete(cli_user1.id()).await.unwrap(); let api_users_after_delete = api_user_service.list().await.unwrap(); let cli_users_after_delete = cli_user_service.list().await.unwrap(); assert_eq!(api_users_after_delete.len(), 1); assert_eq!(cli_users_after_delete.len(), 1); compare_user_lists(&api_users_after_delete, &cli_users_after_delete); } #[tokio::test] #[serial] async fn test_api_tui_consistency_with_memory() { // Create services for both interfaces using memory backend let (api_user_service, api_product_service) = create_memory_services(); let (tui_user_service, tui_product_service) = create_memory_services(); // Test data let (username1, email1) = unique_test_data("api_tui_user1"); let (username2, email2) = unique_test_data("api_tui_user2"); let (name1, _) = unique_test_data("api_tui_product1"); let (name2, _) = unique_test_data("api_tui_product2"); // Test 1: Create users via API interface and capture state let create_user1 = CreateUser::new(username1.clone(), email1.clone()).unwrap(); let create_user2 = CreateUser::new(username2.clone(), email2.clone()).unwrap(); let api_user1 = api_user_service.create(create_user1.clone()).await.unwrap(); let _api_user2 = api_user_service.create(create_user2.clone()).await.unwrap(); let api_users_after_create = api_user_service.list().await.unwrap(); assert_eq!(api_users_after_create.len(), 2); // Test 2: Create same users via TUI interface and compare let tui_user1 = tui_user_service.create(create_user1).await.unwrap(); let _tui_user2 = tui_user_service.create(create_user2).await.unwrap(); let tui_users_after_create = tui_user_service.list().await.unwrap(); assert_eq!(tui_users_after_create.len(), 2); // Compare user data (ignoring IDs and timestamps) compare_user_lists(&api_users_after_create, &tui_users_after_create); // Test 3: Create products via API interface and capture state let create_product1 = CreateProduct::new(name1.clone(), "Description 1".to_string()).unwrap(); let create_product2 = CreateProduct::new(name2.clone(), "Description 2".to_string()).unwrap(); let api_product1 = api_product_service.create(create_product1.clone()).await.unwrap(); let _api_product2 = api_product_service.create(create_product2.clone()).await.unwrap(); let api_products_after_create = api_product_service.list().await.unwrap(); assert_eq!(api_products_after_create.len(), 2); // Test 4: Create same products via TUI interface and compare let tui_product1 = tui_product_service.create(create_product1).await.unwrap(); let _tui_product2 = tui_product_service.create(create_product2).await.unwrap(); let tui_products_after_create = tui_product_service.list().await.unwrap(); assert_eq!(tui_products_after_create.len(), 2); // Compare product data (ignoring IDs and timestamps) compare_product_lists(&api_products_after_create, &tui_products_after_create); // Test 5: Test that both interfaces can access the same data let api_retrieved_user = api_user_service.get(api_user1.id()).await.unwrap(); let tui_retrieved_user = tui_user_service.get(tui_user1.id()).await.unwrap(); assert_eq!(api_retrieved_user.username(), tui_retrieved_user.username()); assert_eq!(api_retrieved_user.email(), tui_retrieved_user.email()); let api_retrieved_product = api_product_service.get(api_product1.id()).await.unwrap(); let tui_retrieved_product = tui_product_service.get(tui_product1.id()).await.unwrap(); assert_eq!(api_retrieved_product.name(), tui_retrieved_product.name()); assert_eq!(api_retrieved_product.description(), tui_retrieved_product.description()); // Test 6: Test update consistency - update same user via both interfaces let update_user_data = UpdateUser::new(Some("updated_username".to_string()), Some("updated@example.com".to_string())).unwrap(); let api_updated_user = api_user_service.update(api_user1.id(), update_user_data.clone()).await.unwrap(); let tui_updated_user = tui_user_service.update(tui_user1.id(), update_user_data).await.unwrap(); assert_eq!(api_updated_user.username(), tui_updated_user.username()); assert_eq!(api_updated_user.email(), tui_updated_user.email()); // Test 7: Test delete consistency api_user_service.delete(api_user1.id()).await.unwrap(); tui_user_service.delete(tui_user1.id()).await.unwrap(); let api_users_after_delete = api_user_service.list().await.unwrap(); let tui_users_after_delete = tui_user_service.list().await.unwrap(); assert_eq!(api_users_after_delete.len(), 1); assert_eq!(tui_users_after_delete.len(), 1); compare_user_lists(&api_users_after_delete, &tui_users_after_delete); } #[tokio::test] #[serial] async fn test_cli_tui_consistency_with_memory() { // Create services for both interfaces using memory backend let (cli_user_service, cli_product_service) = create_memory_services(); let (tui_user_service, tui_product_service) = create_memory_services(); // Test data let (username1, email1) = unique_test_data("cli_tui_user1"); let (username2, email2) = unique_test_data("cli_tui_user2"); let (name1, _) = unique_test_data("cli_tui_product1"); let (name2, _) = unique_test_data("cli_tui_product2"); // Test 1: Create users via CLI interface and capture state let create_user1 = CreateUser::new(username1.clone(), email1.clone()).unwrap(); let create_user2 = CreateUser::new(username2.clone(), email2.clone()).unwrap(); let cli_user1 = cli_user_service.create(create_user1.clone()).await.unwrap(); let _cli_user2 = cli_user_service.create(create_user2.clone()).await.unwrap(); let cli_users_after_create = cli_user_service.list().await.unwrap(); assert_eq!(cli_users_after_create.len(), 2); // Test 2: Create same users via TUI interface and compare let tui_user1 = tui_user_service.create(create_user1).await.unwrap(); let _tui_user2 = tui_user_service.create(create_user2).await.unwrap(); let tui_users_after_create = tui_user_service.list().await.unwrap(); assert_eq!(tui_users_after_create.len(), 2); // Compare user data (ignoring IDs and timestamps) compare_user_lists(&cli_users_after_create, &tui_users_after_create); // Test 3: Create products via CLI interface and capture state let create_product1 = CreateProduct::new(name1.clone(), "Description 1".to_string()).unwrap(); let create_product2 = CreateProduct::new(name2.clone(), "Description 2".to_string()).unwrap(); let cli_product1 = cli_product_service.create(create_product1.clone()).await.unwrap(); let _cli_product2 = cli_product_service.create(create_product2.clone()).await.unwrap(); let cli_products_after_create = cli_product_service.list().await.unwrap(); assert_eq!(cli_products_after_create.len(), 2); // Test 4: Create same products via TUI interface and compare let tui_product1 = tui_product_service.create(create_product1).await.unwrap(); let _tui_product2 = tui_product_service.create(create_product2).await.unwrap(); let tui_products_after_create = tui_product_service.list().await.unwrap(); assert_eq!(tui_products_after_create.len(), 2); // Compare product data (ignoring IDs and timestamps) compare_product_lists(&cli_products_after_create, &tui_products_after_create); // Test 5: Test that both interfaces can access the same data let cli_retrieved_user = cli_user_service.get(cli_user1.id()).await.unwrap(); let tui_retrieved_user = tui_user_service.get(tui_user1.id()).await.unwrap(); assert_eq!(cli_retrieved_user.username(), tui_retrieved_user.username()); assert_eq!(cli_retrieved_user.email(), tui_retrieved_user.email()); let cli_retrieved_product = cli_product_service.get(cli_product1.id()).await.unwrap(); let tui_retrieved_product = tui_product_service.get(tui_product1.id()).await.unwrap(); assert_eq!(cli_retrieved_product.name(), tui_retrieved_product.name()); assert_eq!(cli_retrieved_product.description(), tui_retrieved_product.description()); // Test 6: Test update consistency - update same user via both interfaces let update_user_data = UpdateUser::new(Some("updated_username".to_string()), Some("updated@example.com".to_string())).unwrap(); let cli_updated_user = cli_user_service.update(cli_user1.id(), update_user_data.clone()).await.unwrap(); let tui_updated_user = tui_user_service.update(tui_user1.id(), update_user_data).await.unwrap(); assert_eq!(cli_updated_user.username(), tui_updated_user.username()); assert_eq!(cli_updated_user.email(), tui_updated_user.email()); // Test 7: Test delete consistency cli_user_service.delete(cli_user1.id()).await.unwrap(); tui_user_service.delete(tui_user1.id()).await.unwrap(); let cli_users_after_delete = cli_user_service.list().await.unwrap(); let tui_users_after_delete = tui_user_service.list().await.unwrap(); assert_eq!(cli_users_after_delete.len(), 1); assert_eq!(tui_users_after_delete.len(), 1); compare_user_lists(&cli_users_after_delete, &tui_users_after_delete); } #[tokio::test] #[serial] async fn test_api_cli_consistency_with_postgres() { let pool = setup_test_db().await; cleanup_test_data(&pool).await; // Double-check that the database is empty let users_count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM users").fetch_one(&pool).await.expect("Failed to count users"); let products_count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM products").fetch_one(&pool).await.expect("Failed to count products"); println!("Database state before test: {} users, {} products", users_count.0, products_count.0); assert_eq!(users_count.0, 0, "Users table not empty before test"); assert_eq!(products_count.0, 0, "Products table not empty before test"); // Test data let (username1, email1) = unique_test_data("api_cli_user1"); let (username2, email2) = unique_test_data("api_cli_user2"); let (name1, _) = unique_test_data("api_cli_product1"); let (name2, _) = unique_test_data("api_cli_product2"); println!("Generated usernames: {}, {}", username1, username2); // Test 1: Create users via API interface and capture state let (api_user_service, _api_product_service) = create_postgres_services(pool.clone()); let create_user1 = CreateUser::new(username1.clone(), email1.clone()).unwrap(); let create_user2 = CreateUser::new(username2.clone(), email2.clone()).unwrap(); println!("Creating API user 1: {}", username1); let _api_user1 = api_user_service.create(create_user1.clone()).await.unwrap(); println!("Creating API user 2: {}", username2); let _api_user2 = api_user_service.create(create_user2.clone()).await.unwrap(); let api_users_after_create = api_user_service.list().await.unwrap(); assert_eq!(api_users_after_create.len(), 2); // Test 2: Create same users via CLI interface and compare cleanup_test_data(&pool).await; let (cli_user_service, _cli_product_service) = create_postgres_services(pool.clone()); println!("Creating CLI user 1: {}", username1); let _cli_user1 = cli_user_service.create(create_user1).await.unwrap(); println!("Creating CLI user 2: {}", username2); let _cli_user2 = cli_user_service.create(create_user2).await.unwrap(); let cli_users_after_create = cli_user_service.list().await.unwrap(); assert_eq!(cli_users_after_create.len(), 2); // Compare user data (ignoring IDs and timestamps) compare_user_lists(&api_users_after_create, &cli_users_after_create); // Test 3: Create products via API interface and capture state cleanup_test_data(&pool).await; let (_api_user_service, api_product_service) = create_postgres_services(pool.clone()); let create_product1 = CreateProduct::new(name1.clone(), "Description 1".to_string()).unwrap(); let create_product2 = CreateProduct::new(name2.clone(), "Description 2".to_string()).unwrap(); let _api_product1 = api_product_service.create(create_product1.clone()).await.unwrap(); let _api_product2 = api_product_service.create(create_product2.clone()).await.unwrap(); let api_products_after_create = api_product_service.list().await.unwrap(); assert_eq!(api_products_after_create.len(), 2); // Test 4: Create same products via CLI interface and compare cleanup_test_data(&pool).await; let (_cli_user_service, cli_product_service) = create_postgres_services(pool.clone()); let _cli_product1 = cli_product_service.create(create_product1).await.unwrap(); let _cli_product2 = cli_product_service.create(create_product2).await.unwrap(); let cli_products_after_create = cli_product_service.list().await.unwrap(); assert_eq!(cli_products_after_create.len(), 2); // Compare product data (ignoring IDs and timestamps) compare_product_lists(&api_products_after_create, &cli_products_after_create); // Test 5: Test that both interfaces can access the same data (using shared database) cleanup_test_data(&pool).await; let (api_user_service, _api_product_service) = create_postgres_services(pool.clone()); let (cli_user_service, _cli_product_service) = create_postgres_services(pool); // Create a user via API let create_user = CreateUser::new(username1.clone(), email1.clone()).unwrap(); let api_user = api_user_service.create(create_user).await.unwrap(); // Both services should be able to access the same user let api_retrieved_user = api_user_service.get(api_user.id()).await.unwrap(); let cli_retrieved_user = cli_user_service.get(api_user.id()).await.unwrap(); assert_eq!(api_retrieved_user.username(), cli_retrieved_user.username()); assert_eq!(api_retrieved_user.email(), cli_retrieved_user.email()); // Test 6: Test update consistency - update same user via both interfaces let update_user_data = UpdateUser::new(Some("updated_username".to_string()), Some("updated@example.com".to_string())).unwrap(); let api_updated_user = api_user_service.update(api_user.id(), update_user_data.clone()).await.unwrap(); let cli_updated_user = cli_user_service.update(api_user.id(), update_user_data).await.unwrap(); assert_eq!(api_updated_user.username(), cli_updated_user.username()); assert_eq!(api_updated_user.email(), cli_updated_user.email()); // Test 7: Test delete consistency api_user_service.delete(api_user.id()).await.unwrap(); // Both services should see the user as deleted let api_users_after_delete = api_user_service.list().await.unwrap(); let cli_users_after_delete = cli_user_service.list().await.unwrap(); assert_eq!(api_users_after_delete.len(), 0); assert_eq!(cli_users_after_delete.len(), 0); } #[tokio::test] #[serial] async fn test_error_handling_consistency_across_interfaces() { let pool = setup_test_db().await; // Create services for all interfaces using PostgreSQL backend let (api_user_service, api_product_service) = create_postgres_services(pool.clone()); let (cli_user_service, cli_product_service) = create_postgres_services(pool.clone()); let (tui_user_service, tui_product_service) = create_postgres_services(pool); // Test 1: Get non-existent user via all interfaces let non_existent_id = Uuid::new_v4(); let api_user_result = api_user_service.get(non_existent_id).await; let cli_user_result = cli_user_service.get(non_existent_id).await; let tui_user_result = tui_user_service.get(non_existent_id).await; assert!(api_user_result.is_err()); assert!(cli_user_result.is_err()); assert!(tui_user_result.is_err()); // All should return the same error type assert!(matches!(api_user_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); assert!(matches!(cli_user_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); assert!(matches!(tui_user_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); // Test 2: Get non-existent product via all interfaces let api_product_result = api_product_service.get(non_existent_id).await; let cli_product_result = cli_product_service.get(non_existent_id).await; let tui_product_result = tui_product_service.get(non_existent_id).await; assert!(api_product_result.is_err()); assert!(cli_product_result.is_err()); assert!(tui_product_result.is_err()); assert!(matches!(api_product_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); assert!(matches!(cli_product_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); assert!(matches!(tui_product_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); // Test 3: Update non-existent user via all interfaces let update_user_data = UpdateUser::new(Some("new_username".to_string()), None).unwrap(); let api_update_result = api_user_service.update(non_existent_id, update_user_data.clone()).await; let cli_update_result = cli_user_service.update(non_existent_id, update_user_data.clone()).await; let tui_update_result = tui_user_service.update(non_existent_id, update_user_data).await; assert!(api_update_result.is_err()); assert!(cli_update_result.is_err()); assert!(tui_update_result.is_err()); assert!(matches!(api_update_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); assert!(matches!(cli_update_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); assert!(matches!(tui_update_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); // Test 4: Delete non-existent user via all interfaces let api_delete_result = api_user_service.delete(non_existent_id).await; let cli_delete_result = cli_user_service.delete(non_existent_id).await; let tui_delete_result = tui_user_service.delete(non_existent_id).await; assert!(api_delete_result.is_err()); assert!(cli_delete_result.is_err()); assert!(tui_delete_result.is_err()); assert!(matches!(api_delete_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); assert!(matches!(cli_delete_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); assert!(matches!(tui_delete_result.unwrap_err(), application::ApplicationError::Domain(domain::DomainError::NotFound(_)))); } #[tokio::test] #[serial] async fn test_validation_consistency_across_interfaces() { // Test that all interfaces validate input consistently // This test doesn't need actual services since validation happens at the domain level // Test 1: Create user with empty username let create_user_empty_username = CreateUser::new("".to_string(), "test@example.com".to_string()); assert!(create_user_empty_username.is_err()); assert!(matches!(create_user_empty_username.unwrap_err(), domain::DomainError::InvalidInput(_))); // Test 2: Create product with empty name let create_product_empty_name = CreateProduct::new("".to_string(), "description".to_string()); assert!(create_product_empty_name.is_err()); assert!(matches!(create_product_empty_name.unwrap_err(), domain::DomainError::InvalidInput(_))); // Test 3: Update user with empty username let update_user_empty_username = UpdateUser::new(Some("".to_string()), None); assert!(update_user_empty_username.is_err()); assert!(matches!(update_user_empty_username.unwrap_err(), domain::DomainError::InvalidInput(_))); // Test 4: Update product with empty name let update_product_empty_name = UpdateProduct::new(Some("".to_string()), None); assert!(update_product_empty_name.is_err()); assert!(matches!(update_product_empty_name.unwrap_err(), domain::DomainError::InvalidInput(_))); }