Some checks failed
CI / Check / Test (push) Failing after 27m0s
- WatchMedium enum (cinema/streaming/tv/physical_media/download/media_server/other) - PATCH /api/v1/reviews/:id partial update (rating, comment, watched_at, watch_medium) - edit_review use case w/ ownership + remote review guard, best-effort AP Update broadcast - SPA: icon picker, edit sheet (long-press mobile / pencil desktop), watch medium badge - shared ReviewFormFields, EditableContextMenu, parse_watched_at/format_watched_at - deploy.sh parameterized (--features, --tag), CORS allows PATCH - CONTEXT.md glossary, ADR-0001 general review editing
112 lines
3.0 KiB
Rust
112 lines
3.0 KiB
Rust
use std::sync::Arc;
|
|
|
|
use chrono::Utc;
|
|
|
|
use domain::{
|
|
models::{Movie, Review},
|
|
ports::{MovieRepository, ReviewRepository},
|
|
testing::{
|
|
FakeDiaryRepository, InMemoryMovieRepository, InMemoryReviewRepository, NoopEventPublisher,
|
|
},
|
|
value_objects::{MovieId, MovieTitle, Rating, ReleaseYear, UserId},
|
|
};
|
|
|
|
use crate::{
|
|
diary::commands::DeleteReviewCommand, diary::delete_review, diary::deps::DeleteReviewDeps,
|
|
};
|
|
|
|
fn make_movie() -> Movie {
|
|
Movie::new(
|
|
None,
|
|
MovieTitle::new("Terminator".into()).unwrap(),
|
|
ReleaseYear::new(1984).unwrap(),
|
|
None,
|
|
None,
|
|
)
|
|
}
|
|
|
|
fn make_review(movie_id: MovieId, user_id: UserId) -> Review {
|
|
Review::new(
|
|
movie_id,
|
|
user_id,
|
|
Rating::new(4).unwrap(),
|
|
None,
|
|
Utc::now().naive_utc(),
|
|
None,
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_delete_review_removes_it() {
|
|
let movies = InMemoryMovieRepository::new();
|
|
let reviews = InMemoryReviewRepository::new();
|
|
let diary = FakeDiaryRepository::new();
|
|
let events = NoopEventPublisher::new();
|
|
|
|
let movie = make_movie();
|
|
let user_id = UserId::from_uuid(uuid::Uuid::new_v4());
|
|
let review = make_review(movie.id().clone(), user_id.clone());
|
|
|
|
movies.upsert_movie(&movie).await.unwrap();
|
|
reviews.save_review(&review).await.unwrap();
|
|
diary.seed_history(movie.clone(), vec![]);
|
|
|
|
let deps = DeleteReviewDeps {
|
|
review: Arc::clone(&reviews) as _,
|
|
diary: diary.clone() as _,
|
|
movie: Arc::clone(&movies) as _,
|
|
event_publisher: Arc::clone(&events) as _,
|
|
};
|
|
|
|
delete_review::execute(
|
|
&deps,
|
|
DeleteReviewCommand {
|
|
review_id: review.id().value(),
|
|
requesting_user_id: user_id.value(),
|
|
},
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(reviews.count(), 0, "review should be deleted");
|
|
assert!(
|
|
movies.get_movie_by_id(movie.id()).await.unwrap().is_none(),
|
|
"movie should be deleted when no reviews remain"
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_delete_review_wrong_user_is_unauthorized() {
|
|
let reviews = InMemoryReviewRepository::new();
|
|
let diary = FakeDiaryRepository::new();
|
|
let movies = InMemoryMovieRepository::new();
|
|
let events = NoopEventPublisher::new();
|
|
|
|
let movie_id = MovieId::from_uuid(uuid::Uuid::new_v4());
|
|
let owner_id = UserId::from_uuid(uuid::Uuid::new_v4());
|
|
let other_id = uuid::Uuid::new_v4();
|
|
let review = make_review(movie_id, owner_id);
|
|
|
|
reviews.save_review(&review).await.unwrap();
|
|
|
|
let deps = DeleteReviewDeps {
|
|
review: Arc::clone(&reviews) as _,
|
|
diary: diary as _,
|
|
movie: movies as _,
|
|
event_publisher: Arc::clone(&events) as _,
|
|
};
|
|
|
|
let result = delete_review::execute(
|
|
&deps,
|
|
DeleteReviewCommand {
|
|
review_id: review.id().value(),
|
|
requesting_user_id: other_id,
|
|
},
|
|
)
|
|
.await;
|
|
|
|
assert!(result.is_err(), "wrong user should not be able to delete");
|
|
assert_eq!(reviews.count(), 1, "review should still exist");
|
|
}
|