test: move application tests to tests/
test_support/test_helpers -> tests/support; watched_at unified w/ domain test_watched_at (2024-03-15). Kept inline: users::diary_filter tests (feed_sort_to_direction_all_variants, paged_user_filter_builds_correctly) - pub(super) helpers in private module. Dropped stale never-compiled users/tests/get_users.rs (old execute signature).
This commit is contained in:
@@ -39,7 +39,3 @@ pub async fn execute(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/add.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -18,7 +18,3 @@ pub async fn execute(
|
||||
let page = PageParams::new(query.limit, query.offset)?;
|
||||
deps.watchlist.get_for_user(&user_id, &page).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/get.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -52,7 +52,3 @@ pub async fn execute(
|
||||
Ok(WatchlistView::Remote(entries))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/get_watchlist_for_owner.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -14,7 +14,3 @@ pub async fn execute(
|
||||
let movie_id = MovieId::from_uuid(query.movie_id);
|
||||
deps.watchlist.contains(&user_id, &movie_id).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/is_on.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -22,7 +22,3 @@ pub async fn execute(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/remove.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
use crate::test_support::{add_to_watchlist_command, movie_input_manual};
|
||||
use domain::testing::test_movie_with_year;
|
||||
use std::sync::Arc;
|
||||
|
||||
use domain::{
|
||||
ports::MovieCommand,
|
||||
testing::{InMemoryStore, NoopEventPublisher},
|
||||
};
|
||||
|
||||
use crate::watchlist::{add, commands::AddToWatchlistCommand, deps::WatchlistAddDeps};
|
||||
|
||||
fn make_deps(movies: Arc<InMemoryStore>, watchlist: Arc<InMemoryStore>) -> WatchlistAddDeps {
|
||||
WatchlistAddDeps {
|
||||
movie_command: Arc::clone(&movies) as _,
|
||||
movie_query: movies,
|
||||
metadata: Arc::new(domain::testing::FakeMetadataClient),
|
||||
watchlist,
|
||||
event_publisher: NoopEventPublisher::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_add_to_watchlist_resolves_and_saves() {
|
||||
let movies = InMemoryStore::new();
|
||||
let watchlist = Arc::clone(&movies);
|
||||
|
||||
let movie = test_movie_with_year("The Thing", 1982);
|
||||
let movie_uuid = movie.id().value();
|
||||
movies.upsert_movie(&movie).await.unwrap();
|
||||
|
||||
let deps = make_deps(Arc::clone(&movies), Arc::clone(&watchlist));
|
||||
|
||||
let cmd = add_to_watchlist_command(uuid::Uuid::new_v4(), movie_uuid);
|
||||
|
||||
add::execute(&deps, cmd).await.unwrap();
|
||||
|
||||
assert_eq!(watchlist.watchlist_count(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_add_to_watchlist_already_present_is_idempotent() {
|
||||
let movies = InMemoryStore::new();
|
||||
let watchlist = Arc::clone(&movies);
|
||||
|
||||
let movie = test_movie_with_year("RoboCop", 1987);
|
||||
let movie_uuid = movie.id().value();
|
||||
let user_id = uuid::Uuid::new_v4();
|
||||
movies.upsert_movie(&movie).await.unwrap();
|
||||
|
||||
let deps = make_deps(Arc::clone(&movies), Arc::clone(&watchlist));
|
||||
|
||||
let make_cmd = || add_to_watchlist_command(user_id, movie_uuid);
|
||||
|
||||
add::execute(&deps, make_cmd()).await.unwrap();
|
||||
add::execute(&deps, make_cmd()).await.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
watchlist.watchlist_count(),
|
||||
1,
|
||||
"idempotent add should not duplicate"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_add_to_watchlist_with_manual_movie() {
|
||||
let movies = InMemoryStore::new();
|
||||
let watchlist = Arc::clone(&movies);
|
||||
|
||||
let deps = make_deps(Arc::clone(&movies), Arc::clone(&watchlist));
|
||||
|
||||
let cmd = AddToWatchlistCommand {
|
||||
user_id: uuid::Uuid::new_v4(),
|
||||
input: movie_input_manual("New Manual Movie", 2024),
|
||||
};
|
||||
|
||||
add::execute(&deps, cmd).await.unwrap();
|
||||
|
||||
assert_eq!(watchlist.watchlist_count(), 1);
|
||||
assert_eq!(movies.movie_count(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_add_to_watchlist_movie_not_found_by_id() {
|
||||
let movies = InMemoryStore::new();
|
||||
let watchlist = Arc::clone(&movies);
|
||||
|
||||
let deps = make_deps(Arc::clone(&movies), Arc::clone(&watchlist));
|
||||
|
||||
let cmd = add_to_watchlist_command(uuid::Uuid::new_v4(), uuid::Uuid::new_v4());
|
||||
|
||||
assert!(add::execute(&deps, cmd).await.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn adding_the_same_movie_to_a_watchlist_twice_keeps_a_single_entry_and_succeeds() {
|
||||
let movies = InMemoryStore::new();
|
||||
let movie = test_movie_with_year("Heat", 1995);
|
||||
let movie_uuid = movie.id().value();
|
||||
let user_id = uuid::Uuid::new_v4();
|
||||
movies.upsert_movie(&movie).await.unwrap();
|
||||
let deps = make_deps(Arc::clone(&movies), Arc::clone(&movies));
|
||||
|
||||
for _ in 0..2 {
|
||||
add::execute(&deps, add_to_watchlist_command(user_id, movie_uuid))
|
||||
.await
|
||||
.expect("second add must not error");
|
||||
}
|
||||
|
||||
assert_eq!(movies.watchlist_count(), 1);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::test_helpers::TestContextBuilder;
|
||||
use crate::watchlist::{deps::GetWatchlistDeps, get, queries::GetWatchlistQuery};
|
||||
|
||||
#[tokio::test]
|
||||
async fn returns_empty_page_for_new_user() {
|
||||
let b = TestContextBuilder::new();
|
||||
let deps = GetWatchlistDeps {
|
||||
watchlist: b.watchlist_repo.clone(),
|
||||
};
|
||||
let result = get::execute(
|
||||
&deps,
|
||||
GetWatchlistQuery {
|
||||
user_id: Uuid::new_v4(),
|
||||
limit: None,
|
||||
offset: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(result.items.is_empty());
|
||||
assert_eq!(result.total_count, 0);
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
use crate::test_support::register_command;
|
||||
use std::sync::Arc;
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use domain::testing::{InMemoryStore, PanicRemoteWatchlistRepository, PanicWatchlistRepository};
|
||||
use domain::value_objects::Email;
|
||||
|
||||
use crate::auth::deps::RegisterDeps;
|
||||
use crate::auth::register;
|
||||
use crate::test_helpers::TestContextBuilder;
|
||||
use crate::watchlist::deps::GetWatchlistForOwnerDeps;
|
||||
use crate::watchlist::get_watchlist_for_owner::{self, WatchlistView};
|
||||
|
||||
async fn setup_user(b: &TestContextBuilder, email: &str, username: &str) {
|
||||
let deps = RegisterDeps {
|
||||
user: b.user_repo.clone(),
|
||||
password_hasher: b.password_hasher.clone(),
|
||||
config: b.config.clone(),
|
||||
};
|
||||
register::execute(&deps, register_command(email, username))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn watchlist_for_owner_returns_local_when_user_row_exists() {
|
||||
let b = TestContextBuilder::new();
|
||||
setup_user(&b, "owner@test.com", "owneruser").await;
|
||||
|
||||
let email = Email::new("owner@test.com".into()).unwrap();
|
||||
let user = b.user_repo.find_by_email(&email).await.unwrap().unwrap();
|
||||
let uid = user.id().value();
|
||||
|
||||
let deps = GetWatchlistForOwnerDeps {
|
||||
user: b.user_repo.clone(),
|
||||
watchlist: InMemoryStore::new(),
|
||||
remote_watchlist: Arc::new(PanicRemoteWatchlistRepository),
|
||||
};
|
||||
|
||||
let view = get_watchlist_for_owner::execute(&deps, uid, Some(20), Some(0))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(view, WatchlistView::Local(_)), "expected Local");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn watchlist_for_owner_returns_remote_when_no_local_row() {
|
||||
let owner_id = Uuid::new_v4();
|
||||
|
||||
let remote = InMemoryStore::with_remote_watchlist(vec![domain::models::RemoteWatchlistEntry {
|
||||
ap_id: "https://remote.example/ap/1".into(),
|
||||
actor_url: "https://remote.example/users/owner".into(),
|
||||
movie_title: "Remote Movie".into(),
|
||||
release_year: 2021,
|
||||
external_metadata_id: None,
|
||||
poster_url: None,
|
||||
added_at: chrono::Utc::now(),
|
||||
}]);
|
||||
|
||||
let deps = GetWatchlistForOwnerDeps {
|
||||
user: InMemoryStore::new(),
|
||||
watchlist: Arc::new(PanicWatchlistRepository),
|
||||
remote_watchlist: remote,
|
||||
};
|
||||
|
||||
let view = get_watchlist_for_owner::execute(&deps, owner_id, Some(20), Some(0))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
match view {
|
||||
WatchlistView::Remote(entries) => {
|
||||
assert_eq!(entries.len(), 1);
|
||||
assert_eq!(entries[0].movie_title, "Remote Movie");
|
||||
}
|
||||
WatchlistView::Local(_) => panic!("expected Remote"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn watchlist_for_owner_local_arm_validates_limit() {
|
||||
let b = TestContextBuilder::new();
|
||||
setup_user(&b, "badlimit@test.com", "badlimituser").await;
|
||||
|
||||
let email = Email::new("badlimit@test.com".into()).unwrap();
|
||||
let user = b.user_repo.find_by_email(&email).await.unwrap().unwrap();
|
||||
let uid = user.id().value();
|
||||
|
||||
let deps = GetWatchlistForOwnerDeps {
|
||||
user: b.user_repo.clone(),
|
||||
watchlist: InMemoryStore::new(),
|
||||
remote_watchlist: Arc::new(PanicRemoteWatchlistRepository),
|
||||
};
|
||||
|
||||
let err = match get_watchlist_for_owner::execute(&deps, uid, Some(0), Some(0)).await {
|
||||
Err(e) => e,
|
||||
Ok(_) => panic!("expected Err(ValidationError) for limit=0 on the local arm, got Ok"),
|
||||
};
|
||||
assert!(matches!(
|
||||
err,
|
||||
domain::errors::DomainError::ValidationError(_)
|
||||
));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn watchlist_for_owner_remote_arm_ignores_invalid_limit() {
|
||||
let owner_id = Uuid::new_v4();
|
||||
let remote = InMemoryStore::new();
|
||||
|
||||
let deps = GetWatchlistForOwnerDeps {
|
||||
user: InMemoryStore::new(),
|
||||
watchlist: Arc::new(PanicWatchlistRepository),
|
||||
remote_watchlist: remote,
|
||||
};
|
||||
|
||||
let view = get_watchlist_for_owner::execute(&deps, owner_id, Some(0), Some(0))
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(matches!(view, WatchlistView::Remote(_)), "expected Remote");
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use domain::models::WatchlistEntry;
|
||||
use domain::ports::WatchlistRepository;
|
||||
use domain::testing::InMemoryStore;
|
||||
use domain::value_objects::{MovieId, UserId};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::test_helpers::TestContextBuilder;
|
||||
use crate::watchlist::{deps::IsOnWatchlistDeps, is_on, queries::IsOnWatchlistQuery};
|
||||
|
||||
#[tokio::test]
|
||||
async fn returns_true_when_present() {
|
||||
let watchlist = InMemoryStore::new();
|
||||
let uid = Uuid::new_v4();
|
||||
let mid = Uuid::new_v4();
|
||||
watchlist
|
||||
.add(&WatchlistEntry::new(
|
||||
UserId::from_uuid(uid),
|
||||
MovieId::from_uuid(mid),
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let deps = IsOnWatchlistDeps {
|
||||
watchlist: Arc::clone(&watchlist) as _,
|
||||
};
|
||||
let result = is_on::execute(
|
||||
&deps,
|
||||
IsOnWatchlistQuery {
|
||||
user_id: uid,
|
||||
movie_id: mid,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn returns_false_when_absent() {
|
||||
let b = TestContextBuilder::new();
|
||||
let deps = IsOnWatchlistDeps {
|
||||
watchlist: b.watchlist_repo.clone(),
|
||||
};
|
||||
let result = is_on::execute(
|
||||
&deps,
|
||||
IsOnWatchlistQuery {
|
||||
user_id: Uuid::new_v4(),
|
||||
movie_id: Uuid::new_v4(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(!result);
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use domain::events::DomainEvent;
|
||||
use domain::models::WatchlistEntry;
|
||||
use domain::ports::WatchlistRepository;
|
||||
use domain::testing::{InMemoryStore, NoopEventPublisher};
|
||||
use domain::value_objects::{MovieId, UserId};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::test_helpers::TestContextBuilder;
|
||||
use crate::watchlist::{
|
||||
commands::RemoveFromWatchlistCommand, deps::RemoveFromWatchlistDeps, remove,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn removes_entry_and_emits_event() {
|
||||
let watchlist = InMemoryStore::new();
|
||||
let events = NoopEventPublisher::new();
|
||||
let uid = Uuid::new_v4();
|
||||
let mid = Uuid::new_v4();
|
||||
watchlist
|
||||
.add(&WatchlistEntry::new(
|
||||
UserId::from_uuid(uid),
|
||||
MovieId::from_uuid(mid),
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let deps = RemoveFromWatchlistDeps {
|
||||
watchlist: Arc::clone(&watchlist) as _,
|
||||
event_publisher: Arc::clone(&events) as _,
|
||||
};
|
||||
remove::execute(
|
||||
&deps,
|
||||
RemoveFromWatchlistCommand {
|
||||
user_id: uid,
|
||||
movie_id: mid,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(watchlist.watchlist_count(), 0);
|
||||
let published = events.published();
|
||||
assert!(
|
||||
published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::WatchlistEntryRemoved { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fails_when_not_on_watchlist() {
|
||||
let b = TestContextBuilder::new();
|
||||
let deps = RemoveFromWatchlistDeps {
|
||||
watchlist: b.watchlist_repo.clone(),
|
||||
event_publisher: b.event_publisher.clone(),
|
||||
};
|
||||
let result = remove::execute(
|
||||
&deps,
|
||||
RemoveFromWatchlistCommand {
|
||||
user_id: Uuid::new_v4(),
|
||||
movie_id: Uuid::new_v4(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
Reference in New Issue
Block a user