Update user and product entities to not allow empty username and name, and update corresponding tests

This commit is contained in:
continuist 2025-06-24 23:02:48 -04:00
parent 0117f9b490
commit 9de4f0b64c
7 changed files with 261 additions and 332 deletions

View file

@ -239,10 +239,7 @@ mod tests {
let repo = MockRepository::<User>::new();
let service = Service::new(repo);
let create_user = CreateUser {
username: "test_user".to_string(),
email: "test@example.com".to_string(),
};
let create_user = CreateUser::new("test_user".to_string(), "test@example.com".to_string()).unwrap();
let user = service.create(create_user).await.unwrap();
assert_eq!(user.username, "test_user");
@ -254,10 +251,7 @@ mod tests {
let repo = MockRepository::<User>::new();
let service = Service::new(repo);
let create_user = CreateUser {
username: "test_user".to_string(),
email: "test@example.com".to_string(),
};
let create_user = CreateUser::new("test_user".to_string(), "test@example.com".to_string()).unwrap();
let created = service.create(create_user).await.unwrap();
let found = service.get(created.id).await.unwrap();
@ -269,14 +263,8 @@ mod tests {
let repo = MockRepository::<User>::new();
let service = Service::new(repo);
let user1 = CreateUser {
username: "user1".to_string(),
email: "user1@example.com".to_string(),
};
let user2 = CreateUser {
username: "user2".to_string(),
email: "user2@example.com".to_string(),
};
let user1 = CreateUser::new("user1".to_string(), "user1@example.com".to_string()).unwrap();
let user2 = CreateUser::new("user2".to_string(), "user2@example.com".to_string()).unwrap();
service.create(user1).await.unwrap();
service.create(user2).await.unwrap();
@ -290,16 +278,10 @@ mod tests {
let repo = MockRepository::<User>::new();
let service = Service::new(repo);
let create_user = CreateUser {
username: "test_user".to_string(),
email: "test@example.com".to_string(),
};
let create_user = CreateUser::new("test_user".to_string(), "test@example.com".to_string()).unwrap();
let created = service.create(create_user).await.unwrap();
let update = UpdateUser {
username: Some("updated_user".to_string()),
email: None,
};
let update = UpdateUser::new(Some("updated_user".to_string()), None).unwrap();
let updated = service.update(created.id, update).await.unwrap();
assert_eq!(updated.username, "updated_user");
@ -311,10 +293,7 @@ mod tests {
let repo = MockRepository::<User>::new();
let service = Service::new(repo);
let create_user = CreateUser {
username: "test_user".to_string(),
email: "test@example.com".to_string(),
};
let create_user = CreateUser::new("test_user".to_string(), "test@example.com".to_string()).unwrap();
let created = service.create(create_user).await.unwrap();
service.delete(created.id).await.unwrap();
@ -326,10 +305,7 @@ mod tests {
let repo = MockRepository::<Product>::new();
let service = Service::new(repo);
let create_product = CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
};
let create_product = CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap();
let product = service.create(create_product).await.unwrap();
assert_eq!(product.name, "Test Product");
@ -341,10 +317,7 @@ mod tests {
let repo = MockRepository::<Product>::new();
let service = Service::new(repo);
let create_product = CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
};
let create_product = CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap();
let created = service.create(create_product).await.unwrap();
let found = service.get(created.id).await.unwrap();
@ -356,14 +329,8 @@ mod tests {
let repo = MockRepository::<Product>::new();
let service = Service::new(repo);
let product1 = CreateProduct {
name: "Product 1".to_string(),
description: "Description 1".to_string(),
};
let product2 = CreateProduct {
name: "Product 2".to_string(),
description: "Description 2".to_string(),
};
let product1 = CreateProduct::new("Product 1".to_string(), "Description 1".to_string()).unwrap();
let product2 = CreateProduct::new("Product 2".to_string(), "Description 2".to_string()).unwrap();
service.create(product1).await.unwrap();
service.create(product2).await.unwrap();
@ -377,16 +344,10 @@ mod tests {
let repo = MockRepository::<Product>::new();
let service = Service::new(repo);
let create_product = CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
};
let create_product = CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap();
let created = service.create(create_product).await.unwrap();
let update = UpdateProduct {
name: Some("Updated Product".to_string()),
description: None,
};
let update = UpdateProduct::new(Some("Updated Product".to_string()), None).unwrap();
let updated = service.update(created.id, update).await.unwrap();
assert_eq!(updated.name, "Updated Product");
@ -398,10 +359,7 @@ mod tests {
let repo = MockRepository::<Product>::new();
let service = Service::new(repo);
let create_product = CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
};
let create_product = CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap();
let created = service.create(create_product).await.unwrap();
service.delete(created.id).await.unwrap();
@ -426,10 +384,7 @@ mod tests {
let repo = MockRepository::<User>::new();
let service = Service::new(repo);
let update = UpdateUser {
username: Some("new_username".to_string()),
email: None,
};
let update = UpdateUser::new(Some("new_username".to_string()), None).unwrap();
let result = service.update(Uuid::new_v4(), update).await;
assert!(matches!(result, Err(ApplicationError::Domain(domain::DomainError::NotFound(_)))));

View file

@ -123,7 +123,7 @@ impl Cli {
match self.command {
Some(Commands::User { command }) => match command {
UserCommands::Create { username, email } => {
let user = user_service.create(CreateUser { username, email }).await?;
let user = user_service.create(CreateUser::new(username, email)?).await?;
println!("Created user: {:?}", user);
}
UserCommands::List => {
@ -135,7 +135,7 @@ impl Cli {
println!("User: {:?}", user);
}
UserCommands::Update { id, username, email } => {
let update = UpdateUser { username, email };
let update = UpdateUser::new(username, email)?;
let user = user_service.update(id, update).await?;
println!("Updated user: {:?}", user);
}
@ -146,7 +146,7 @@ impl Cli {
},
Some(Commands::Product { command }) => match command {
ProductCommands::Create { name, description } => {
let product = product_service.create(CreateProduct { name, description }).await?;
let product = product_service.create(CreateProduct::new(name, description)?).await?;
println!("Created product: {:?}", product);
}
ProductCommands::List => {
@ -158,7 +158,7 @@ impl Cli {
println!("Product: {:?}", product);
}
ProductCommands::Update { id, name, description } => {
let update = UpdateProduct { name, description };
let update = UpdateProduct::new(name, description)?;
let product = product_service.update(id, update).await?;
println!("Updated product: {:?}", product);
}
@ -1074,7 +1074,7 @@ mod tests {
let product_service = MockProductService::new();
let result = cli.run(user_service, product_service).await;
assert!(result.is_ok()); // Should succeed even with empty strings
assert!(result.is_err()); // Should fail due to empty username validation
}
/// Tests CLI with empty strings in product creation.
@ -1093,7 +1093,7 @@ mod tests {
let product_service = MockProductService::new();
let result = cli.run(user_service, product_service).await;
assert!(result.is_ok()); // Should succeed even with empty strings
assert!(result.is_err()); // Should fail due to empty product name validation
}
/// Tests CLI with very long strings.

View file

@ -69,24 +69,64 @@ pub struct CreateUser {
pub email: String,
}
impl CreateUser {
pub fn new(username: String, email: String) -> Result<Self> {
if username.trim().is_empty() {
return Err(DomainError::InvalidInput("Username cannot be empty".to_string()));
}
Ok(Self { username, email })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateUser {
pub username: Option<String>,
pub email: Option<String>,
}
impl UpdateUser {
pub fn new(username: Option<String>, email: Option<String>) -> Result<Self> {
if let Some(ref username) = username {
if username.trim().is_empty() {
return Err(DomainError::InvalidInput("Username cannot be empty".to_string()));
}
}
Ok(Self { username, email })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateProduct {
pub name: String,
pub description: String,
}
impl CreateProduct {
pub fn new(name: String, description: String) -> Result<Self> {
if name.trim().is_empty() {
return Err(DomainError::InvalidInput("Product name cannot be empty".to_string()));
}
Ok(Self { name, description })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateProduct {
pub name: Option<String>,
pub description: Option<String>,
}
impl UpdateProduct {
pub fn new(name: Option<String>, description: Option<String>) -> Result<Self> {
if let Some(ref name) = name {
if name.trim().is_empty() {
return Err(DomainError::InvalidInput("Product name cannot be empty".to_string()));
}
}
Ok(Self { name, description })
}
}
pub trait Repository<T, Create, Update>: Send + Sync
where
T: Send,
@ -124,25 +164,61 @@ mod tests {
#[test]
fn test_create_user_validation() {
let create_user = CreateUser {
username: "test_user".to_string(),
email: "test@example.com".to_string(),
};
let create_user = CreateUser::new("test_user".to_string(), "test@example.com".to_string()).unwrap();
assert_eq!(create_user.username, "test_user");
assert_eq!(create_user.email, "test@example.com");
}
#[test]
fn test_create_user_empty_username() {
let result = CreateUser::new("".to_string(), "test@example.com".to_string());
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DomainError::InvalidInput(_)));
}
#[test]
fn test_create_user_whitespace_username() {
let result = CreateUser::new(" ".to_string(), "test@example.com".to_string());
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DomainError::InvalidInput(_)));
}
#[test]
fn test_create_user_empty_email() {
let create_user = CreateUser::new("test_user".to_string(), "".to_string()).unwrap();
assert_eq!(create_user.username, "test_user");
assert_eq!(create_user.email, "");
}
#[test]
fn test_update_user_partial() {
let update_user = UpdateUser {
username: Some("new_username".to_string()),
email: None,
};
let update_user = UpdateUser::new(Some("new_username".to_string()), None).unwrap();
assert_eq!(update_user.username, Some("new_username".to_string()));
assert_eq!(update_user.email, None);
}
#[test]
fn test_update_user_empty_username() {
let result = UpdateUser::new(Some("".to_string()), None);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DomainError::InvalidInput(_)));
}
#[test]
fn test_update_user_whitespace_username() {
let result = UpdateUser::new(Some(" ".to_string()), None);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DomainError::InvalidInput(_)));
}
#[test]
fn test_update_user_empty_email() {
let update_user = UpdateUser::new(None, Some("".to_string())).unwrap();
assert_eq!(update_user.username, None);
assert_eq!(update_user.email, Some("".to_string()));
}
}
mod product_tests {
@ -164,25 +240,59 @@ mod tests {
#[test]
fn test_create_product_validation() {
let create_product = CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
};
let create_product = CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap();
assert_eq!(create_product.name, "Test Product");
assert_eq!(create_product.description, "Test Description");
}
#[test]
fn test_update_product_partial() {
let update_product = UpdateProduct {
name: Some("New Product Name".to_string()),
description: None,
};
fn test_create_product_empty_name() {
let result = CreateProduct::new("".to_string(), "desc".to_string());
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DomainError::InvalidInput(_)));
}
#[test]
fn test_create_product_whitespace_name() {
let result = CreateProduct::new(" ".to_string(), "desc".to_string());
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DomainError::InvalidInput(_)));
}
#[test]
fn test_create_product_empty_description() {
let create_product = CreateProduct::new("Test Product".to_string(), "".to_string()).unwrap();
assert_eq!(create_product.name, "Test Product");
assert_eq!(create_product.description, "");
}
#[test]
fn test_update_product_partial() {
let update_product = UpdateProduct::new(Some("New Product Name".to_string()), None).unwrap();
assert_eq!(update_product.name, Some("New Product Name".to_string()));
assert_eq!(update_product.description, None);
}
#[test]
fn test_update_product_empty_name() {
let result = UpdateProduct::new(Some("".to_string()), None);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DomainError::InvalidInput(_)));
}
#[test]
fn test_update_product_whitespace_name() {
let result = UpdateProduct::new(Some(" ".to_string()), None);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DomainError::InvalidInput(_)));
}
#[test]
fn test_update_product_empty_description() {
let update_product = UpdateProduct::new(None, Some("".to_string())).unwrap();
assert_eq!(update_product.name, None);
assert_eq!(update_product.description, Some("".to_string()));
}
}
mod domain_error_tests {
@ -229,10 +339,7 @@ mod tests {
#[tokio::test]
async fn test_repository_create() {
let repo = MockRepository::<User>::new();
let create_user = CreateUser {
username: "test_user".to_string(),
email: "test@example.com".to_string(),
};
let create_user = CreateUser::new("test_user".to_string(), "test@example.com".to_string()).unwrap();
let user = User {
id: Uuid::new_v4(),

View file

@ -346,20 +346,47 @@ async fn test_cli_edge_cases() -> Result<()> {
let user_service = Service::new(user_repo);
let product_service = Service::new(product_repo);
// Test empty strings (currently allowed by domain layer)
// Test empty username (should fail validation)
let cli = Cli::parse_from(&[
"cli", "user", "create", "--username", "", "--email", ""
"cli", "user", "create", "--username", "", "--email", "test@example.com"
]);
let _result = cli.run(user_service.clone(), product_service.clone()).await;
// Note: Empty strings are currently allowed by the domain layer
// This test documents the current behavior
let result = cli.run(user_service.clone(), product_service.clone()).await;
assert!(result.is_err());
// Test whitespace username (should fail validation)
let cli = Cli::parse_from(&[
"cli", "user", "create", "--username", " ", "--email", "test@example.com"
]);
let result = cli.run(user_service.clone(), product_service.clone()).await;
assert!(result.is_err());
// Test empty email (should be allowed)
let cli = Cli::parse_from(&[
"cli", "user", "create", "--username", "testuser", "--email", ""
]);
let result = cli.run(user_service.clone(), product_service.clone()).await;
assert!(result.is_ok());
// Test empty product name (should fail validation)
let cli = Cli::parse_from(&[
"cli", "product", "create", "--name", "", "--description", ""
]);
let _result = cli.run(user_service.clone(), product_service.clone()).await;
// Note: Empty strings are currently allowed by the domain layer
// This test documents the current behavior
let result = cli.run(user_service.clone(), product_service.clone()).await;
assert!(result.is_err());
// Test whitespace product name (should fail validation)
let cli = Cli::parse_from(&[
"cli", "product", "create", "--name", " ", "--description", "desc"
]);
let result = cli.run(user_service.clone(), product_service.clone()).await;
assert!(result.is_err());
// Test empty product description (should be allowed)
let cli = Cli::parse_from(&[
"cli", "product", "create", "--name", "Test Product", "--description", ""
]);
let result = cli.run(user_service.clone(), product_service.clone()).await;
assert!(result.is_ok());
// Test very long strings
let long_string = "a".repeat(1000);

View file

@ -196,10 +196,7 @@ mod tests {
#[tokio::test]
async fn test_create_user() {
let repo = InMemoryUserRepository::new();
let create_data = CreateUser {
username: "testuser".to_string(),
email: "test@example.com".to_string(),
};
let create_data = CreateUser::new("testuser".to_string(), "test@example.com".to_string()).unwrap();
let user = repo.create(create_data).await.unwrap();
@ -213,10 +210,7 @@ mod tests {
#[tokio::test]
async fn test_find_by_id_existing() {
let repo = InMemoryUserRepository::new();
let create_data = CreateUser {
username: "testuser".to_string(),
email: "test@example.com".to_string(),
};
let create_data = CreateUser::new("testuser".to_string(), "test@example.com".to_string()).unwrap();
let created_user = repo.create(create_data).await.unwrap();
let found_user = repo.find_by_id(created_user.id).await.unwrap();
@ -255,15 +249,9 @@ mod tests {
async fn test_find_all_with_users() {
let repo = InMemoryUserRepository::new();
let user1 = repo.create(CreateUser {
username: "user1".to_string(),
email: "user1@example.com".to_string(),
}).await.unwrap();
let user1 = repo.create(CreateUser::new("user1".to_string(), "user1@example.com".to_string()).unwrap()).await.unwrap();
let user2 = repo.create(CreateUser {
username: "user2".to_string(),
email: "user2@example.com".to_string(),
}).await.unwrap();
let user2 = repo.create(CreateUser::new("user2".to_string(), "user2@example.com".to_string()).unwrap()).await.unwrap();
let users = repo.find_all().await.unwrap();
@ -275,18 +263,12 @@ mod tests {
#[tokio::test]
async fn test_update_user_existing() {
let repo = InMemoryUserRepository::new();
let user = repo.create(CreateUser {
username: "olduser".to_string(),
email: "old@example.com".to_string(),
}).await.unwrap();
let user = repo.create(CreateUser::new("olduser".to_string(), "old@example.com".to_string()).unwrap()).await.unwrap();
let original_updated_at = user.updated_at;
sleep(Duration::from_millis(1)).await; // Ensure timestamp difference
let update_data = UpdateUser {
username: Some("newuser".to_string()),
email: Some("new@example.com".to_string()),
};
let update_data = UpdateUser::new(Some("newuser".to_string()), Some("new@example.com".to_string())).unwrap();
let updated_user = repo.update(user.id, update_data).await.unwrap();
@ -298,15 +280,9 @@ mod tests {
#[tokio::test]
async fn test_update_user_partial() {
let repo = InMemoryUserRepository::new();
let user = repo.create(CreateUser {
username: "testuser".to_string(),
email: "test@example.com".to_string(),
}).await.unwrap();
let user = repo.create(CreateUser::new("testuser".to_string(), "test@example.com".to_string()).unwrap()).await.unwrap();
let update_data = UpdateUser {
username: Some("newuser".to_string()),
email: None,
};
let update_data = UpdateUser::new(Some("newuser".to_string()), None).unwrap();
let updated_user = repo.update(user.id, update_data).await.unwrap();
@ -318,10 +294,7 @@ mod tests {
async fn test_update_user_not_found() {
let repo = InMemoryUserRepository::new();
let non_existent_id = Uuid::new_v4();
let update_data = UpdateUser {
username: Some("newuser".to_string()),
email: None,
};
let update_data = UpdateUser::new(Some("newuser".to_string()), None).unwrap();
let result = repo.update(non_existent_id, update_data).await;
assert!(result.is_err());
@ -338,10 +311,7 @@ mod tests {
#[tokio::test]
async fn test_delete_user_existing() {
let repo = InMemoryUserRepository::new();
let user = repo.create(CreateUser {
username: "testuser".to_string(),
email: "test@example.com".to_string(),
}).await.unwrap();
let user = repo.create(CreateUser::new("testuser".to_string(), "test@example.com".to_string()).unwrap()).await.unwrap();
let result = repo.delete(user.id).await;
assert!(result.is_ok());
@ -377,10 +347,7 @@ mod tests {
let handles: Vec<_> = (0..10).map(|i| {
let repo = repo_clone.clone();
tokio::spawn(async move {
repo.create(CreateUser {
username: format!("user{}", i),
email: format!("user{}@example.com", i),
}).await
repo.create(CreateUser::new(format!("user{}", i), format!("user{}@example.com", i)).unwrap()).await
})
}).collect();
@ -402,10 +369,7 @@ mod tests {
#[tokio::test]
async fn test_create_product() {
let repo = InMemoryProductRepository::new();
let create_data = CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
};
let create_data = CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap();
let product = repo.create(create_data).await.unwrap();
@ -419,10 +383,7 @@ mod tests {
#[tokio::test]
async fn test_find_by_id_existing() {
let repo = InMemoryProductRepository::new();
let create_data = CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
};
let create_data = CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap();
let created_product = repo.create(create_data).await.unwrap();
let found_product = repo.find_by_id(created_product.id).await.unwrap();
@ -461,15 +422,9 @@ mod tests {
async fn test_find_all_with_products() {
let repo = InMemoryProductRepository::new();
let product1 = repo.create(CreateProduct {
name: "Product 1".to_string(),
description: "Description 1".to_string(),
}).await.unwrap();
let product1 = repo.create(CreateProduct::new("Product 1".to_string(), "Description 1".to_string()).unwrap()).await.unwrap();
let product2 = repo.create(CreateProduct {
name: "Product 2".to_string(),
description: "Description 2".to_string(),
}).await.unwrap();
let product2 = repo.create(CreateProduct::new("Product 2".to_string(), "Description 2".to_string()).unwrap()).await.unwrap();
let products = repo.find_all().await.unwrap();
@ -481,18 +436,12 @@ mod tests {
#[tokio::test]
async fn test_update_product_existing() {
let repo = InMemoryProductRepository::new();
let product = repo.create(CreateProduct {
name: "Old Product".to_string(),
description: "Old Description".to_string(),
}).await.unwrap();
let product = repo.create(CreateProduct::new("Old Product".to_string(), "Old Description".to_string()).unwrap()).await.unwrap();
let original_updated_at = product.updated_at;
sleep(Duration::from_millis(1)).await; // Ensure timestamp difference
let update_data = UpdateProduct {
name: Some("New Product".to_string()),
description: Some("New Description".to_string()),
};
let update_data = UpdateProduct::new(Some("New Product".to_string()), Some("New Description".to_string())).unwrap();
let updated_product = repo.update(product.id, update_data).await.unwrap();
@ -504,15 +453,9 @@ mod tests {
#[tokio::test]
async fn test_update_product_partial() {
let repo = InMemoryProductRepository::new();
let product = repo.create(CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
}).await.unwrap();
let product = repo.create(CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap()).await.unwrap();
let update_data = UpdateProduct {
name: Some("New Product".to_string()),
description: None,
};
let update_data = UpdateProduct::new(Some("New Product".to_string()), None).unwrap();
let updated_product = repo.update(product.id, update_data).await.unwrap();
@ -524,10 +467,7 @@ mod tests {
async fn test_update_product_not_found() {
let repo = InMemoryProductRepository::new();
let non_existent_id = Uuid::new_v4();
let update_data = UpdateProduct {
name: Some("New Product".to_string()),
description: None,
};
let update_data = UpdateProduct::new(Some("New Product".to_string()), None).unwrap();
let result = repo.update(non_existent_id, update_data).await;
assert!(result.is_err());
@ -544,10 +484,7 @@ mod tests {
#[tokio::test]
async fn test_delete_product_existing() {
let repo = InMemoryProductRepository::new();
let product = repo.create(CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
}).await.unwrap();
let product = repo.create(CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap()).await.unwrap();
let result = repo.delete(product.id).await;
assert!(result.is_ok());
@ -583,10 +520,7 @@ mod tests {
let handles: Vec<_> = (0..10).map(|i| {
let repo = repo_clone.clone();
tokio::spawn(async move {
repo.create(CreateProduct {
name: format!("Product {}", i),
description: format!("Description {}", i),
}).await
repo.create(CreateProduct::new(format!("Product {}", i), format!("Description {}", i)).unwrap()).await
})
}).collect();
@ -612,10 +546,7 @@ mod tests {
let service = MemoryUserService::new(repo);
// Test create
let user = service.create(CreateUser {
username: "testuser".to_string(),
email: "test@example.com".to_string(),
}).await.unwrap();
let user = service.create(CreateUser::new("testuser".to_string(), "test@example.com".to_string()).unwrap()).await.unwrap();
assert_eq!(user.username, "testuser");
assert_eq!(user.email, "test@example.com");
@ -625,10 +556,7 @@ mod tests {
assert_eq!(found_user.id, user.id);
// Test update
let updated_user = service.update(user.id, UpdateUser {
username: Some("newuser".to_string()),
email: None,
}).await.unwrap();
let updated_user = service.update(user.id, UpdateUser::new(Some("newuser".to_string()), None).unwrap()).await.unwrap();
assert_eq!(updated_user.username, "newuser");
assert_eq!(updated_user.email, "test@example.com");
@ -652,10 +580,7 @@ mod tests {
let service = MemoryProductService::new(repo);
// Test create
let product = service.create(CreateProduct {
name: "Test Product".to_string(),
description: "Test Description".to_string(),
}).await.unwrap();
let product = service.create(CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap()).await.unwrap();
assert_eq!(product.name, "Test Product");
assert_eq!(product.description, "Test Description");
@ -665,10 +590,7 @@ mod tests {
assert_eq!(found_product.id, product.id);
// Test update
let updated_product = service.update(product.id, UpdateProduct {
name: Some("New Product".to_string()),
description: None,
}).await.unwrap();
let updated_product = service.update(product.id, UpdateProduct::new(Some("New Product".to_string()), None).unwrap()).await.unwrap();
assert_eq!(updated_product.name, "New Product");
assert_eq!(updated_product.description, "Test Description");
@ -695,25 +617,16 @@ mod tests {
let repo = InMemoryUserRepository::new();
// Create multiple users
let user1 = repo.create(CreateUser {
username: "user1".to_string(),
email: "user1@example.com".to_string(),
}).await.unwrap();
let user1 = repo.create(CreateUser::new("user1".to_string(), "user1@example.com".to_string()).unwrap()).await.unwrap();
let user2 = repo.create(CreateUser {
username: "user2".to_string(),
email: "user2@example.com".to_string(),
}).await.unwrap();
let user2 = repo.create(CreateUser::new("user2".to_string(), "user2@example.com".to_string()).unwrap()).await.unwrap();
// Verify both users exist
let users = repo.find_all().await.unwrap();
assert_eq!(users.len(), 2);
// Update one user
let updated_user1 = repo.update(user1.id, UpdateUser {
username: Some("updated_user1".to_string()),
email: None,
}).await.unwrap();
let updated_user1 = repo.update(user1.id, UpdateUser::new(Some("updated_user1".to_string()), None).unwrap()).await.unwrap();
assert_eq!(updated_user1.username, "updated_user1");
assert_eq!(updated_user1.email, "user1@example.com");
@ -732,25 +645,16 @@ mod tests {
let repo = InMemoryProductRepository::new();
// Create multiple products
let product1 = repo.create(CreateProduct {
name: "Product 1".to_string(),
description: "Description 1".to_string(),
}).await.unwrap();
let product1 = repo.create(CreateProduct::new("Product 1".to_string(), "Description 1".to_string()).unwrap()).await.unwrap();
let product2 = repo.create(CreateProduct {
name: "Product 2".to_string(),
description: "Description 2".to_string(),
}).await.unwrap();
let product2 = repo.create(CreateProduct::new("Product 2".to_string(), "Description 2".to_string()).unwrap()).await.unwrap();
// Verify both products exist
let products = repo.find_all().await.unwrap();
assert_eq!(products.len(), 2);
// Update one product
let updated_product1 = repo.update(product1.id, UpdateProduct {
name: Some("Updated Product 1".to_string()),
description: None,
}).await.unwrap();
let updated_product1 = repo.update(product1.id, UpdateProduct::new(Some("Updated Product 1".to_string()), None).unwrap()).await.unwrap();
assert_eq!(updated_product1.name, "Updated Product 1");
assert_eq!(updated_product1.description, "Description 1");

View file

@ -295,10 +295,7 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let create_data = CreateUser {
username: "testuser".to_string(),
email: "test@example.com".to_string(),
};
let create_data = CreateUser::new("testuser".to_string(), "test@example.com".to_string()).unwrap();
let result = repo.create(create_data).await;
assert!(result.is_ok());
@ -322,20 +319,14 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let create_data = CreateUser {
username: "duplicate_user".to_string(),
email: "test1@example.com".to_string(),
};
let create_data = CreateUser::new("duplicate_user".to_string(), "test1@example.com".to_string()).unwrap();
// Create first user
let result1 = repo.create(create_data.clone()).await;
assert!(result1.is_ok());
// Try to create second user with same username
let create_data2 = CreateUser {
username: "duplicate_user".to_string(),
email: "test2@example.com".to_string(),
};
let create_data2 = CreateUser::new("duplicate_user".to_string(), "test2@example.com".to_string()).unwrap();
let result2 = repo.create(create_data2).await;
assert!(result2.is_err());
@ -351,10 +342,7 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let create_data = CreateUser {
username: "finduser".to_string(),
email: "find@example.com".to_string(),
};
let create_data = CreateUser::new("finduser".to_string(), "find@example.com".to_string()).unwrap();
let created_user = repo.create(create_data).await.unwrap();
let found_user = repo.find_by_id(created_user.id).await;
@ -404,15 +392,9 @@ mod tests {
let (username1, email1) = unique_test_data("user1");
let (username2, email2) = unique_test_data("user2");
let _user1 = repo.create(CreateUser {
username: username1.clone(),
email: email1,
}).await.unwrap();
let _user1 = repo.create(CreateUser::new(username1.clone(), email1).unwrap()).await.unwrap();
let _user2 = repo.create(CreateUser {
username: username2.clone(),
email: email2,
}).await.unwrap();
let _user2 = repo.create(CreateUser::new(username2.clone(), email2).unwrap()).await.unwrap();
let users = repo.find_all().await.unwrap();
assert_eq!(users.len(), 2);
@ -448,19 +430,13 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let create_data = CreateUser {
username: "updateuser".to_string(),
email: "update@example.com".to_string(),
};
let create_data = CreateUser::new("updateuser".to_string(), "update@example.com".to_string()).unwrap();
let user = repo.create(create_data).await.unwrap();
let original_updated_at = user.updated_at;
// Update username only
let update_data = UpdateUser {
username: Some("updateduser".to_string()),
email: None,
};
let update_data = UpdateUser::new(Some("updateduser".to_string()), None).unwrap();
let updated_user = repo.update(user.id, update_data).await.unwrap();
assert_eq!(updated_user.username, "updateduser");
@ -479,17 +455,11 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let create_data = CreateUser {
username: "emailuser".to_string(),
email: "old@example.com".to_string(),
};
let create_data = CreateUser::new("emailuser".to_string(), "old@example.com".to_string()).unwrap();
let user = repo.create(create_data).await.unwrap();
let update_data = UpdateUser {
username: None,
email: Some("new@example.com".to_string()),
};
let update_data = UpdateUser::new(None, Some("new@example.com".to_string())).unwrap();
let updated_user = repo.update(user.id, update_data).await.unwrap();
assert_eq!(updated_user.username, "emailuser"); // Should remain unchanged
@ -507,17 +477,11 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let create_data = CreateUser {
username: "bothuser".to_string(),
email: "both@example.com".to_string(),
};
let create_data = CreateUser::new("bothuser".to_string(), "both@example.com".to_string()).unwrap();
let user = repo.create(create_data).await.unwrap();
let update_data = UpdateUser {
username: Some("newbothuser".to_string()),
email: Some("newboth@example.com".to_string()),
};
let update_data = UpdateUser::new(Some("newbothuser".to_string()), Some("newboth@example.com".to_string())).unwrap();
let updated_user = repo.update(user.id, update_data).await.unwrap();
assert_eq!(updated_user.username, "newbothuser");
@ -536,10 +500,7 @@ mod tests {
cleanup_test_data(&pool).await;
let nonexistent_id = Uuid::new_v4();
let update_data = UpdateUser {
username: Some("nonexistent".to_string()),
email: None,
};
let update_data = UpdateUser::new(Some("nonexistent".to_string()), None).unwrap();
let result = repo.update(nonexistent_id, update_data).await;
assert!(result.is_err());
@ -563,10 +524,7 @@ mod tests {
cleanup_test_data(&pool).await;
let (username, email) = unique_test_data("delete_user");
let create_data = CreateUser {
username: username.clone(),
email: email.clone(),
};
let create_data = CreateUser::new(username.clone(), email.clone()).unwrap();
let user = repo.create(create_data).await.unwrap();
let user_id = user.id;
@ -619,10 +577,7 @@ mod tests {
cleanup_test_data(&pool).await;
let (username, email) = unique_test_data("concurrent_user");
let create_data = CreateUser {
username: username.clone(),
email: email.clone(),
};
let create_data = CreateUser::new(username.clone(), email.clone()).unwrap();
// Create a user
let user = repo.create(create_data).await.unwrap();
@ -666,17 +621,13 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let (name, _) = unique_test_data("test_product");
let create_data = CreateProduct {
name: name.clone(),
description: "Test Description".to_string(),
};
let create_data = CreateProduct::new("Test Product".to_string(), "Test Description".to_string()).unwrap();
let result = repo.create(create_data).await;
assert!(result.is_ok());
let product = result.unwrap();
assert_eq!(product.name, name);
assert_eq!(product.name, "Test Product");
assert_eq!(product.description, "Test Description");
assert!(product.id != Uuid::nil());
assert!(product.created_at <= Utc::now());
@ -694,10 +645,7 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let create_data = CreateProduct {
name: "Find Product".to_string(),
description: "Find Description".to_string(),
};
let create_data = CreateProduct::new("findproduct".to_string(), "finddesc".to_string()).unwrap();
let created_product = repo.create(create_data).await.unwrap();
let found_product = repo.find_by_id(created_product.id).await;
@ -705,8 +653,8 @@ mod tests {
assert!(found_product.is_ok());
let product = found_product.unwrap();
assert_eq!(product.id, created_product.id);
assert_eq!(product.name, "Find Product");
assert_eq!(product.description, "Find Description");
assert_eq!(product.name, "findproduct");
assert_eq!(product.description, "finddesc");
cleanup_test_data(&pool).await;
}
@ -744,18 +692,11 @@ mod tests {
cleanup_test_data(&pool).await;
// Create multiple products with unique names
let (name1, _) = unique_test_data("product1");
let (name2, _) = unique_test_data("product2");
let (name1, desc1) = unique_test_data("product1");
let (name2, desc2) = unique_test_data("product2");
let _product1 = repo.create(CreateProduct {
name: name1.clone(),
description: "Description 1".to_string(),
}).await.unwrap();
let _product2 = repo.create(CreateProduct {
name: name2.clone(),
description: "Description 2".to_string(),
}).await.unwrap();
let _product1 = repo.create(CreateProduct::new(name1.clone(), desc1).unwrap()).await.unwrap();
let _product2 = repo.create(CreateProduct::new(name2.clone(), desc2).unwrap()).await.unwrap();
let products = repo.find_all().await.unwrap();
assert_eq!(products.len(), 2);
@ -791,24 +732,17 @@ mod tests {
// Clean up at the beginning to ensure isolation
cleanup_test_data(&pool).await;
let (name, _) = unique_test_data("update_product");
let create_data = CreateProduct {
name: name.clone(),
description: "Update Description".to_string(),
};
let create_data = CreateProduct::new("updateproduct".to_string(), "updatedesc".to_string()).unwrap();
let product = repo.create(create_data).await.unwrap();
let original_updated_at = product.updated_at;
// Update name only
let update_data = UpdateProduct {
name: Some("Updated Product".to_string()),
description: None,
};
let update_data = UpdateProduct::new(Some("updatedproduct".to_string()), None).unwrap();
let updated_product = repo.update(product.id, update_data).await.unwrap();
assert_eq!(updated_product.name, "Updated Product");
assert_eq!(updated_product.description, "Update Description"); // Should remain unchanged
assert_eq!(updated_product.name, "updatedproduct");
assert_eq!(updated_product.description, "updatedesc"); // Should remain unchanged
assert!(updated_product.updated_at > original_updated_at);
cleanup_test_data(&pool).await;
@ -971,10 +905,7 @@ mod tests {
cleanup_test_data(&pool).await;
let (username, email) = unique_test_data("service_user");
let create_data = CreateUser {
username: username.clone(),
email: email.clone(),
};
let create_data = CreateUser::new(username.clone(), email.clone()).unwrap();
// Test create
let user = service.create(create_data).await.unwrap();
@ -991,10 +922,7 @@ mod tests {
// Test update
let (new_username, _) = unique_test_data("updated_service_user");
let update_data = UpdateUser {
username: Some(new_username.clone()),
email: None,
};
let update_data = UpdateUser::new(Some(new_username.clone()), None).unwrap();
let updated_user = service.update(user.id, update_data).await.unwrap();
assert_eq!(updated_user.username, new_username);

View file

@ -212,10 +212,9 @@ where
cmd if cmd.starts_with("user create") => {
match parse_user_create(cmd) {
Ok((username, email)) => {
match user_service_clone
.create(CreateUser { username, email })
.await
{
match CreateUser::new(username, email) {
Ok(create_user) => {
match user_service_clone.create(create_user).await {
Ok(user) => app.add_message(format!("Created user: {:?}", user)),
Err(e) => app.add_message(format!("Error: {}", e)),
}
@ -223,6 +222,9 @@ where
Err(e) => app.add_message(format!("Error: {}", e)),
}
}
Err(e) => app.add_message(format!("Error: {}", e)),
}
}
"user list" => {
match user_service_clone.list().await {
Ok(users) => app.add_message(format!("Users: {:?}", users)),
@ -233,7 +235,13 @@ where
match parse_product_create(cmd) {
Ok((name, description)) => {
match product_service_clone
.create(CreateProduct { name, description })
.create(match CreateProduct::new(name, description) {
Ok(create_product) => create_product,
Err(e) => {
app.add_message(format!("Error: {}", e));
continue;
}
})
.await
{
Ok(product) => app.add_message(format!("Created product: {:?}", product)),