use std::sync::Arc; use domain::activity::{ActivityName, CategoryName}; use domain::ports::ActivityCommandPort; use domain::testing::{InMemoryStore, test_activity, test_user}; use domain::user::UserId; use application::activity::commands::{ CreateActivityCommand, RenameActivityCommand, SetCategoryCommand, }; use application::activity::use_cases::{ archive_activity, create_activity, delete_activity, get_activity, list_activities, rename_activity, set_category, }; fn store_and_events() -> Arc { Arc::new(InMemoryStore::new()) } #[tokio::test] async fn creates_activity() { let store = store_and_events(); let user = test_user("alice"); let deps = create_activity::Deps { activities: store.clone(), events: store.clone(), }; let cmd = CreateActivityCommand { user_id: user.id().clone(), name: ActivityName::new("gaming").unwrap(), category: Some(CategoryName::new("hobbies").unwrap()), }; let activity = create_activity::execute(cmd, &deps).await.unwrap(); assert_eq!(activity.name().value(), "gaming"); assert_eq!(activity.category().map(|c| c.value()), Some("hobbies")); } #[tokio::test] async fn renames_activity() { let store = store_and_events(); let user = test_user("alice"); let activity = test_activity(user.id().clone(), "gaming"); store.save(&activity).await.unwrap(); let deps = rename_activity::Deps { command: store.clone(), query: store.clone(), events: store.clone(), }; let cmd = RenameActivityCommand { activity_id: activity.id().clone(), new_name: ActivityName::new("video games").unwrap(), }; rename_activity::execute(cmd, user.id().clone(), &deps) .await .unwrap(); let fetched = get_activity::execute( activity.id().clone(), user.id().clone(), &get_activity::Deps { query: store.clone(), }, ) .await .unwrap(); assert_eq!(fetched.name().value(), "video games"); } #[tokio::test] async fn sets_category() { let store = store_and_events(); let user = test_user("alice"); let activity = test_activity(user.id().clone(), "gaming"); store.save(&activity).await.unwrap(); let deps = set_category::Deps { command: store.clone(), query: store.clone(), }; let cmd = SetCategoryCommand { activity_id: activity.id().clone(), category: Some(CategoryName::new("hobbies").unwrap()), }; set_category::execute(cmd, user.id().clone(), &deps) .await .unwrap(); let fetched = get_activity::execute( activity.id().clone(), user.id().clone(), &get_activity::Deps { query: store.clone(), }, ) .await .unwrap(); assert_eq!(fetched.category().map(|c| c.value()), Some("hobbies")); } #[tokio::test] async fn archives_and_unarchives() { let store = store_and_events(); let user = test_user("alice"); let activity = test_activity(user.id().clone(), "gaming"); store.save(&activity).await.unwrap(); let deps = archive_activity::Deps { command: store.clone(), query: store.clone(), events: store.clone(), }; archive_activity::archive(activity.id().clone(), user.id().clone(), &deps) .await .unwrap(); let list_deps = list_activities::Deps { query: store.clone(), }; let active = list_activities::active_only(user.id().clone(), &list_deps) .await .unwrap(); assert!(active.is_empty()); archive_activity::unarchive(activity.id().clone(), user.id().clone(), &deps) .await .unwrap(); let active = list_activities::active_only(user.id().clone(), &list_deps) .await .unwrap(); assert_eq!(active.len(), 1); } #[tokio::test] async fn deletes_activity() { let store = store_and_events(); let user = test_user("alice"); let activity = test_activity(user.id().clone(), "gaming"); store.save(&activity).await.unwrap(); let deps = delete_activity::Deps { command: store.clone(), query: store.clone(), }; delete_activity::execute(activity.id().clone(), user.id().clone(), &deps) .await .unwrap(); assert_eq!(store.activity_count(), 0); } #[tokio::test] async fn rename_rejects_different_user() { let store = store_and_events(); let user = test_user("alice"); let activity = test_activity(user.id().clone(), "gaming"); store.save(&activity).await.unwrap(); let deps = rename_activity::Deps { command: store.clone(), query: store.clone(), events: store.clone(), }; let cmd = RenameActivityCommand { activity_id: activity.id().clone(), new_name: ActivityName::new("hacking").unwrap(), }; let result = rename_activity::execute(cmd, UserId::generate(), &deps).await; assert!(result.is_err()); } #[tokio::test] async fn delete_rejects_different_user() { let store = store_and_events(); let user = test_user("alice"); let activity = test_activity(user.id().clone(), "gaming"); store.save(&activity).await.unwrap(); let deps = delete_activity::Deps { command: store.clone(), query: store.clone(), }; let result = delete_activity::execute(activity.id().clone(), UserId::generate(), &deps).await; assert!(result.is_err()); assert_eq!(store.activity_count(), 1); } #[tokio::test] async fn archive_rejects_different_user() { let store = store_and_events(); let user = test_user("alice"); let activity = test_activity(user.id().clone(), "gaming"); store.save(&activity).await.unwrap(); let deps = archive_activity::Deps { command: store.clone(), query: store.clone(), events: store.clone(), }; let result = archive_activity::archive(activity.id().clone(), UserId::generate(), &deps).await; assert!(result.is_err()); }