diff --git a/home-mixer/filters/previously_seen_posts_backup_filter.rs b/home-mixer/filters/previously_seen_posts_backup_filter.rs index 17a3e58f..52910add 100644 --- a/home-mixer/filters/previously_seen_posts_backup_filter.rs +++ b/home-mixer/filters/previously_seen_posts_backup_filter.rs @@ -78,6 +78,23 @@ mod tests { } #[test] + fn test_keeps_reply_when_only_parent_was_impressed() { + let query = ScoredPostsQuery { + impressed_post_ids: vec![10], + ..Default::default() + }; + let reply = PostCandidate { + tweet_id: 20, + in_reply_to_tweet_id: Some(10), + ..Default::default() + }; + let result = PreviouslySeenPostsBackupFilter.filter(&query, vec![reply, make_candidate(10)]); + let kept: Vec = result.kept.iter().map(|c| c.tweet_id).collect(); + let removed: Vec = result.removed.iter().map(|c| c.tweet_id).collect(); + assert_eq!(kept, vec![20]); + assert_eq!(removed, vec![10]); + } + fn test_empty_candidates() { let query = ScoredPostsQuery { impressed_post_ids: vec![1, 2], diff --git a/home-mixer/filters/previously_seen_posts_filter.rs b/home-mixer/filters/previously_seen_posts_filter.rs index ec5597a7..cd9ba708 100644 --- a/home-mixer/filters/previously_seen_posts_filter.rs +++ b/home-mixer/filters/previously_seen_posts_filter.rs @@ -33,3 +33,48 @@ impl Filter for PreviouslySeenPostsFilter { FilterResult { kept, removed } } } + +#[cfg(test)] +mod tests { + use super::*; + + fn candidate(tweet_id: u64, retweeted: Option, in_reply_to: Option) -> PostCandidate { + PostCandidate { + tweet_id, + retweeted_tweet_id: retweeted, + in_reply_to_tweet_id: in_reply_to, + ..Default::default() + } + } + + #[test] + fn keeps_reply_when_only_the_parent_was_seen() { + let query = ScoredPostsQuery { + seen_ids: vec![10], + ..Default::default() + }; + let result = PreviouslySeenPostsFilter.filter( + &query, + vec![ + candidate(20, None, Some(10)), + candidate(10, None, None), + candidate(30, Some(10), None), + ], + ); + let kept: Vec = result.kept.iter().map(|c| c.tweet_id).collect(); + let removed: Vec = result.removed.iter().map(|c| c.tweet_id).collect(); + assert_eq!(kept, vec![20]); + assert_eq!(removed, vec![10, 30]); + } + + #[test] + fn drops_reply_when_the_reply_itself_was_seen() { + let query = ScoredPostsQuery { + seen_ids: vec![20], + ..Default::default() + }; + let result = PreviouslySeenPostsFilter.filter(&query, vec![candidate(20, None, Some(10))]); + assert!(result.kept.is_empty()); + assert_eq!(result.removed.len(), 1); + } +} diff --git a/home-mixer/filters/previously_served_posts_filter.rs b/home-mixer/filters/previously_served_posts_filter.rs index e3d421ec..d46097ac 100644 --- a/home-mixer/filters/previously_served_posts_filter.rs +++ b/home-mixer/filters/previously_served_posts_filter.rs @@ -32,3 +32,34 @@ impl Filter for PreviouslyServedPostsFilter { FilterResult { kept, removed } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn keeps_reply_when_only_the_parent_was_served() { + let query = ScoredPostsQuery { + served_ids: vec![10], + ..Default::default() + }; + let result = PreviouslyServedPostsFilter.filter( + &query, + vec![ + PostCandidate { + tweet_id: 20, + in_reply_to_tweet_id: Some(10), + ..Default::default() + }, + PostCandidate { + tweet_id: 10, + ..Default::default() + }, + ], + ); + let kept: Vec = result.kept.iter().map(|c| c.tweet_id).collect(); + let removed: Vec = result.removed.iter().map(|c| c.tweet_id).collect(); + assert_eq!(kept, vec![20]); + assert_eq!(removed, vec![10]); + } +} diff --git a/home-mixer/util/candidates_util.rs b/home-mixer/util/candidates_util.rs index c9d8711d..ea8102e6 100644 --- a/home-mixer/util/candidates_util.rs +++ b/home-mixer/util/candidates_util.rs @@ -4,16 +4,11 @@ use crate::models::query::ScoredPostsQuery; const MAX_FOLLOWERS_THRESHOLD: i64 = 10_000; pub fn get_related_post_ids(candidate: &PostCandidate) -> Vec { - let mut ids = vec![candidate.tweet_id]; - ids.extend(candidate.retweeted_tweet_id); - ids.extend(candidate.in_reply_to_tweet_id); - ids + related_post_ids_iter(candidate).collect() } pub fn related_post_ids_iter(candidate: &PostCandidate) -> impl Iterator { - std::iter::once(candidate.tweet_id) - .chain(candidate.retweeted_tweet_id) - .chain(candidate.in_reply_to_tweet_id) + std::iter::once(candidate.tweet_id).chain(candidate.retweeted_tweet_id) } pub fn vqv_weight( @@ -63,6 +58,27 @@ pub fn quoted_vqv_weight( mod tests { use super::*; + fn candidate(tweet_id: u64, retweeted: Option, in_reply_to: Option) -> PostCandidate { + PostCandidate { + tweet_id, + retweeted_tweet_id: retweeted, + in_reply_to_tweet_id: in_reply_to, + ..Default::default() + } + } + + #[test] + fn related_ids_are_the_card_and_retweet_original_only() { + let reply = candidate(20, None, Some(10)); + assert_eq!(get_related_post_ids(&reply), vec![20]); + + let retweet = candidate(30, Some(10), None); + assert_eq!(get_related_post_ids(&retweet), vec![30, 10]); + + let original = candidate(10, None, None); + assert_eq!(get_related_post_ids(&original), vec![10]); + } + #[test] fn quoted_vqv_returns_weight_when_check_disabled() { let candidate = PostCandidate {