From b5a8ea23952a2aacc3a26c94616b879ea3cbcb03 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Mon, 4 May 2026 20:52:07 +0200 Subject: [PATCH] feat: add title param to render_feed, use dynamic title in RSS adapter --- crates/adapters/rss/src/lib.rs | 29 ++++++++++++++++++++++----- crates/application/src/ports.rs | 2 +- crates/presentation/src/extractors.rs | 6 +++--- crates/presentation/src/handlers.rs | 2 +- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/crates/adapters/rss/src/lib.rs b/crates/adapters/rss/src/lib.rs index 7ebca2b..a25ac3d 100644 --- a/crates/adapters/rss/src/lib.rs +++ b/crates/adapters/rss/src/lib.rs @@ -14,11 +14,11 @@ impl RssAdapter { } impl RssFeedRenderer for RssAdapter { - fn render_feed(&self, entries: &[DiaryEntry]) -> Result { + fn render_feed(&self, entries: &[DiaryEntry], title: &str) -> Result { let items = entries .iter() .map(|e| { - let title = format!( + let item_title = format!( "{} ({})", e.movie().title().value(), e.movie().release_year().value() @@ -38,7 +38,7 @@ impl RssFeedRenderer for RssAdapter { .permalink(false) .build(); ItemBuilder::default() - .title(Some(title)) + .title(Some(item_title)) .description(Some(description)) .pub_date(Some(pub_date)) .guid(Some(guid)) @@ -47,12 +47,31 @@ impl RssFeedRenderer for RssAdapter { .collect::>(); let channel = ChannelBuilder::default() - .title(self.feed_title.clone()) + .title(title.to_string()) .link(self.feed_link.clone()) - .description(self.feed_title.clone()) + .description(title.to_string()) .items(items) .build(); Ok(channel.to_string()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn render_feed_uses_provided_title() { + let adapter = RssAdapter::new("ignored".into(), "http://example.com".into()); + let xml = adapter.render_feed(&[], "Custom Title").unwrap(); + assert!(xml.contains("Custom Title")); + } + + #[test] + fn render_feed_empty_entries_produces_valid_xml() { + let adapter = RssAdapter::new("ignored".into(), "http://example.com".into()); + let xml = adapter.render_feed(&[], "My Feed").unwrap(); + assert!(xml.starts_with(" Result; + fn render_feed(&self, entries: &[DiaryEntry], title: &str) -> Result; } diff --git a/crates/presentation/src/extractors.rs b/crates/presentation/src/extractors.rs index ba391e4..e1e35ed 100644 --- a/crates/presentation/src/extractors.rs +++ b/crates/presentation/src/extractors.rs @@ -153,7 +153,7 @@ mod tests { struct PanicRssRenderer; impl crate::ports::RssFeedRenderer for PanicRssRenderer { - fn render_feed(&self, _: &[domain::models::DiaryEntry]) -> Result { panic!() } + fn render_feed(&self, _: &[domain::models::DiaryEntry], _: &str) -> Result { panic!() } } struct PanicMeta; struct PanicFetcher; struct PanicStorage; struct PanicEvent; struct PanicHasher; struct PanicAuth; struct PanicUserRepo; @@ -269,7 +269,7 @@ mod tests { } struct PanicRssRenderer2; impl crate::ports::RssFeedRenderer for PanicRssRenderer2 { - fn render_feed(&self, _: &[domain::models::DiaryEntry]) -> Result { panic!() } + fn render_feed(&self, _: &[domain::models::DiaryEntry], _: &str) -> Result { panic!() } } struct PanicAuth2; crate::state::AppState { @@ -329,7 +329,7 @@ mod tests { } struct PanicRssRenderer3; impl crate::ports::RssFeedRenderer for PanicRssRenderer3 { - fn render_feed(&self, _: &[domain::models::DiaryEntry]) -> Result { panic!() } + fn render_feed(&self, _: &[domain::models::DiaryEntry], _: &str) -> Result { panic!() } } crate::state::AppState { app_ctx: AppContext { diff --git a/crates/presentation/src/handlers.rs b/crates/presentation/src/handlers.rs index b776f98..0e711db 100644 --- a/crates/presentation/src/handlers.rs +++ b/crates/presentation/src/handlers.rs @@ -380,7 +380,7 @@ pub mod rss { let page = get_diary::execute(&state.app_ctx, query).await?; let xml = state .rss_renderer - .render_feed(&page.items) + .render_feed(&page.items, "Movie Diary") .map_err(|e| ApiError(DomainError::InfrastructureError(e)))?; Ok(([(header::CONTENT_TYPE, "application/rss+xml; charset=utf-8")], xml)) }