use std::sync::Arc; use domain::testing::{ InMemoryGoalRepository, InMemoryWrapUpRepository, InMemoryWrapUpStatsQuery, NoopRemoteWatchlistRepository, NoopSocialQueryPort, }; use domain::{ ports::{ AuthService, DiaryExporter, DiaryRepository, DocumentParser, EventPublisher, GoalRepository, ImportProfileRepository, ImportSessionRepository, MetadataClient, MovieProfileRepository, MovieRepository, ObjectStorage, PasswordHasher, PersonCommand, PersonQuery, PosterFetcherClient, ReviewRepository, SearchCommand, SearchPort, StatsRepository, UserProfileFieldsRepository, UserRepository, UserSettingsRepository, WatchEventRepository, WatchlistRepository, WebhookTokenRepository, WrapUpRepository, WrapUpStatsQuery, }, testing::{ FakeAuthService, FakeDiaryRepository, FakeDocumentParser, FakeMetadataClient, FakePasswordHasher, FakePersonQuery, FakePosterFetcher, FakeSearchCommand, FakeSearchPort, FakeStatsRepository, InMemoryImportProfileRepository, InMemoryImportSessionRepository, InMemoryMovieProfileRepository, InMemoryMovieRepository, InMemoryProfileFieldsRepo, InMemoryReviewRepository, InMemoryUserRepository, InMemoryUserSettingsRepository, InMemoryWatchEventRepository, InMemoryWatchlistRepository, InMemoryWebhookTokenRepository, NoopEventPublisher, NoopObjectStorage, PanicDiaryExporter, PanicPersonCommand, }, }; use async_trait::async_trait; use domain::errors::DomainError; use crate::{ config::AppConfig, context::{AppContext, Repositories, Services}, diary::commands::LogReviewCommand, ports::ReviewLogger, }; pub struct NoopReviewLogger; #[async_trait] impl ReviewLogger for NoopReviewLogger { async fn log_review(&self, _cmd: LogReviewCommand) -> Result<(), DomainError> { Ok(()) } } pub struct TestContextBuilder { pub movie_repo: Arc, pub review_repo: Arc, pub diary_repo: Arc, pub diary_exporter: Arc, pub document_parser: Arc, pub stats_repo: Arc, pub metadata_client: Arc, pub poster_fetcher: Arc, pub object_storage: Arc, pub event_publisher: Arc, pub auth_service: Arc, pub password_hasher: Arc, pub user_repo: Arc, pub import_session_repo: Arc, pub import_profile_repo: Arc, pub movie_profile_repo: Arc, pub watchlist_repo: Arc, pub watch_event_repo: Arc, pub webhook_token_repo: Arc, pub profile_fields_repo: Arc, pub person_command: Arc, pub person_query: Arc, pub search_port: Arc, pub search_command: Arc, pub wrapup_stats: Arc, pub wrapup_repo: Arc, pub goal_repo: Arc, pub user_settings_repo: Arc, pub review_logger: Arc, pub social_query: Arc, pub config: AppConfig, } impl Default for TestContextBuilder { fn default() -> Self { Self::new() } } impl TestContextBuilder { pub fn new() -> Self { Self { movie_repo: InMemoryMovieRepository::new(), review_repo: InMemoryReviewRepository::new(), diary_repo: FakeDiaryRepository::new(), diary_exporter: Arc::new(PanicDiaryExporter), document_parser: Arc::new(FakeDocumentParser), stats_repo: Arc::new(FakeStatsRepository), metadata_client: Arc::new(FakeMetadataClient), poster_fetcher: Arc::new(FakePosterFetcher), object_storage: Arc::new(NoopObjectStorage), event_publisher: NoopEventPublisher::new(), auth_service: Arc::new(FakeAuthService), password_hasher: Arc::new(FakePasswordHasher), user_repo: InMemoryUserRepository::new(), import_session_repo: InMemoryImportSessionRepository::new(), import_profile_repo: InMemoryImportProfileRepository::new(), movie_profile_repo: InMemoryMovieProfileRepository::new(), watchlist_repo: InMemoryWatchlistRepository::new(), watch_event_repo: InMemoryWatchEventRepository::new(), webhook_token_repo: InMemoryWebhookTokenRepository::new(), profile_fields_repo: InMemoryProfileFieldsRepo::new(), person_command: Arc::new(PanicPersonCommand), person_query: Arc::new(FakePersonQuery), search_port: Arc::new(FakeSearchPort), search_command: Arc::new(FakeSearchCommand), wrapup_stats: InMemoryWrapUpStatsQuery::new(), wrapup_repo: InMemoryWrapUpRepository::new(), goal_repo: InMemoryGoalRepository::new(), user_settings_repo: InMemoryUserSettingsRepository::new(), review_logger: Arc::new(NoopReviewLogger), social_query: Arc::new(NoopSocialQueryPort), config: AppConfig { allow_registration: true, base_url: "http://localhost:3000".into(), rate_limit: 20, wrapup: crate::config::WrapUpConfig { font_path: None, logo_path: None, bg_dir: None, }, }, } } pub fn with_movies(mut self, r: Arc) -> Self { self.movie_repo = r; self } pub fn with_reviews(mut self, r: Arc) -> Self { self.review_repo = r; self } pub fn with_users(mut self, r: Arc) -> Self { self.user_repo = r; self } pub fn with_watchlist(mut self, r: Arc) -> Self { self.watchlist_repo = r; self } pub fn with_diary(mut self, r: Arc) -> Self { self.diary_repo = r; self } pub fn with_event_publisher(mut self, p: Arc) -> Self { self.event_publisher = p; self } pub fn wrapup_stats(mut self, r: Arc) -> Self { self.wrapup_stats = r; self } pub fn with_goal(mut self, r: Arc) -> Self { self.goal_repo = r; self } pub fn with_webhook_tokens(mut self, r: Arc) -> Self { self.webhook_token_repo = r; self } pub fn with_watch_events(mut self, r: Arc) -> Self { self.watch_event_repo = r; self } pub fn with_import_sessions(mut self, r: Arc) -> Self { self.import_session_repo = r; self } pub fn with_import_profiles(mut self, r: Arc) -> Self { self.import_profile_repo = r; self } pub fn with_movie_profiles(mut self, r: Arc) -> Self { self.movie_profile_repo = r; self } pub fn with_user_settings(mut self, r: Arc) -> Self { self.user_settings_repo = r; self } pub fn with_profile_fields(mut self, r: Arc) -> Self { self.profile_fields_repo = r; self } pub fn with_review_logger(mut self, r: Arc) -> Self { self.review_logger = r; self } pub fn with_stats(mut self, r: Arc) -> Self { self.stats_repo = r; self } pub fn with_person_query(mut self, r: Arc) -> Self { self.person_query = r; self } pub fn with_search_port(mut self, r: Arc) -> Self { self.search_port = r; self } pub fn with_search_command(mut self, r: Arc) -> Self { self.search_command = r; self } pub fn with_document_parser(mut self, r: Arc) -> Self { self.document_parser = r; self } pub fn with_poster_fetcher(mut self, r: Arc) -> Self { self.poster_fetcher = r; self } pub fn with_metadata_client(mut self, r: Arc) -> Self { self.metadata_client = r; self } pub fn with_social_query(mut self, r: Arc) -> Self { self.social_query = r; self } pub fn with_wrapup_repo(mut self, r: Arc) -> Self { self.wrapup_repo = r; self } pub fn with_config(mut self, config: AppConfig) -> Self { self.config = config; self } pub fn build(self) -> AppContext { AppContext { repos: Repositories { movie: self.movie_repo, review: self.review_repo, diary: self.diary_repo, stats: self.stats_repo, user: self.user_repo, import_session: self.import_session_repo, import_profile: self.import_profile_repo, movie_profile: self.movie_profile_repo, watchlist: self.watchlist_repo, watch_event: self.watch_event_repo, webhook_token: self.webhook_token_repo, profile_fields: self.profile_fields_repo, person_command: self.person_command, person_query: self.person_query, search_port: self.search_port, search_command: self.search_command, remote_watchlist: Arc::new(NoopRemoteWatchlistRepository), social_query: self.social_query, wrapup_stats: self.wrapup_stats, wrapup_repo: self.wrapup_repo, goal: self.goal_repo, user_settings: self.user_settings_repo, remote_goal: Arc::new(domain::testing::NoopRemoteGoalRepository), }, services: Services { auth: self.auth_service, password_hasher: self.password_hasher, metadata: self.metadata_client, poster_fetcher: self.poster_fetcher, object_storage: self.object_storage, event_publisher: self.event_publisher, diary_exporter: self.diary_exporter, document_parser: self.document_parser, review_logger: self.review_logger, person_enrichment: None, }, config: self.config, } } }