use crate::context::winning_dna::analysis::{
classify_for_row, classify_reply_archetype, classify_tweet_format, compute_days_since,
truncate_at_char_boundary,
};
use crate::context::winning_dna::scoring::{compute_engagement_score, compute_retrieval_weight};
#[test]
fn classify_reply_why_question() {
assert_eq!(
classify_reply_archetype("Why do you think this approach works?"),
"ask_question"
);
}
#[test]
fn classify_reply_have_you_question() {
assert_eq!(
classify_reply_archetype("Have you tried using this pattern?"),
"ask_question"
);
}
#[test]
fn classify_reply_do_you_question() {
assert_eq!(
classify_reply_archetype("Do you think this scales well?"),
"ask_question"
);
}
#[test]
fn classify_reply_ends_with_question_mark() {
assert_eq!(
classify_reply_archetype("Is this the right approach to use here?"),
"ask_question"
);
}
#[test]
fn classify_reply_i_recently_experience() {
assert_eq!(
classify_reply_archetype("I recently deployed this in production and it worked"),
"share_experience"
);
}
#[test]
fn classify_reply_when_i_was_experience() {
assert_eq!(
classify_reply_archetype("When I was building my last project, this helped a lot"),
"share_experience"
);
}
#[test]
fn classify_reply_ive_experienced() {
assert_eq!(
classify_reply_archetype("I've experienced the same issue with my deployments"),
"share_experience"
);
}
#[test]
fn classify_reply_ive_found() {
assert_eq!(
classify_reply_archetype("I've found that testing early prevents most regressions"),
"share_experience"
);
}
#[test]
fn classify_reply_data_shows() {
assert_eq!(
classify_reply_archetype("Data shows that teams shipping daily have fewer bugs"),
"add_data"
);
}
#[test]
fn classify_reply_stats_show() {
assert_eq!(
classify_reply_archetype("Stats show a 40% improvement in deployment frequency"),
"add_data"
);
}
#[test]
fn classify_reply_study_shows() {
assert_eq!(
classify_reply_archetype("A recent study shows that TDD improves code quality"),
"add_data"
);
}
#[test]
fn classify_reply_percent_of() {
assert_eq!(
classify_reply_archetype("About 73% of teams use some form of CI now"),
"add_data"
);
}
#[test]
fn classify_reply_actually_i_think_disagree() {
assert_eq!(
classify_reply_archetype("Actually, I think there are better alternatives"),
"respectful_disagree"
);
}
#[test]
fn classify_reply_but_not_sure_disagree() {
assert_eq!(
classify_reply_archetype("But I'm not sure that holds in all cases"),
"respectful_disagree"
);
}
#[test]
fn classify_reply_however_id_argue() {
assert_eq!(
classify_reply_archetype("However, I'd argue that simplicity wins here"),
"respectful_disagree"
);
}
#[test]
fn classify_reply_empty_string_defaults() {
assert_eq!(classify_reply_archetype(""), "agree_and_expand");
}
#[test]
fn classify_reply_generic_agreement() {
assert_eq!(
classify_reply_archetype("Great point, I think that applies to many teams"),
"agree_and_expand"
);
}
#[test]
fn classify_reply_case_insensitive_question() {
assert_eq!(
classify_reply_archetype("WHAT tools do you use for deployment?"),
"ask_question"
);
}
#[test]
fn classify_reply_case_insensitive_experience() {
assert_eq!(
classify_reply_archetype("IN MY EXPERIENCE, this approach works well"),
"share_experience"
);
}
#[test]
fn classify_tweet_everyone_says_pattern() {
assert_eq!(
classify_tweet_format("Everyone says you need a degree. They're wrong."),
"most_people_think_x"
);
}
#[test]
fn classify_tweet_contrarian_actually_but() {
assert_eq!(
classify_tweet_format("Actually, the common wisdom is wrong but there's a better way"),
"contrarian_take"
);
}
#[test]
fn classify_tweet_before_after() {
assert_eq!(
classify_tweet_format("Before: 200ms response time. After: 20ms."),
"before_after"
);
}
#[test]
fn classify_tweet_before_arrow() {
assert_eq!(
classify_tweet_format("Before → After transformation in our pipeline"),
"before_after"
);
}
#[test]
fn classify_tweet_tip_short() {
assert_eq!(
classify_tweet_format("Tip: always validate input before processing"),
"tip"
);
}
#[test]
fn classify_tweet_pro_tip_with_arrow() {
assert_eq!(
classify_tweet_format("Pro tip: use → for chaining operations"),
"tip"
);
}
#[test]
fn classify_tweet_tip_too_long_defaults() {
let long_tip = format!("Tip: {}", "a".repeat(200));
assert_eq!(classify_tweet_format(&long_tip), "storytelling");
}
#[test]
fn classify_tweet_empty_string() {
assert_eq!(classify_tweet_format(""), "storytelling");
}
#[test]
fn classify_tweet_numbered_list_with_three_items() {
assert_eq!(
classify_tweet_format("1. Write tests 2. Run CI 3. Deploy"),
"list"
);
}
#[test]
fn engagement_score_mid_range() {
let score = compute_engagement_score(25.0, 100.0);
assert!((score - 0.25).abs() < 0.001);
assert!(score >= 0.0);
assert!(score <= 1.0);
}
#[test]
fn engagement_score_very_small_max() {
let score = compute_engagement_score(0.001, 0.001);
assert!((score - 1.0).abs() < 0.001);
}
#[test]
fn engagement_score_zero_performance() {
let score = compute_engagement_score(0.0, 50.0);
assert!((score - 0.0).abs() < 0.001);
}
#[test]
fn engagement_score_negative_performance() {
let score = compute_engagement_score(-10.0, 100.0);
assert!((score - 0.0).abs() < 0.001);
}
#[test]
fn retrieval_weight_two_half_lives() {
let w = compute_retrieval_weight(1.0, 28.0, 14.0);
assert!((w - 0.25).abs() < 0.05, "got {w}");
}
#[test]
fn retrieval_weight_three_half_lives() {
let w = compute_retrieval_weight(1.0, 42.0, 14.0);
assert!((w - 0.125).abs() < 0.05, "got {w}");
}
#[test]
fn retrieval_weight_with_partial_engagement() {
let w = compute_retrieval_weight(0.5, 14.0, 14.0);
assert!((w - 0.25).abs() < 0.05, "got {w}");
}
#[test]
fn retrieval_weight_zero_engagement() {
let w = compute_retrieval_weight(0.0, 14.0, 14.0);
assert!((w - 0.0).abs() < 0.001);
}
#[test]
fn retrieval_weight_negative_days() {
let w = compute_retrieval_weight(1.0, -5.0, 14.0);
assert!(w > 1.0, "negative days should increase weight: got {w}");
}
#[test]
fn retrieval_weight_very_large_days() {
let w = compute_retrieval_weight(1.0, 365.0, 14.0);
assert!(
w < 0.001,
"very old content should have near-zero weight: got {w}"
);
}
#[test]
fn retrieval_weight_very_small_half_life() {
let w = compute_retrieval_weight(1.0, 1.0, 0.001);
assert!(w < 0.001, "tiny half-life should decay quickly: got {w}");
}
#[test]
fn compute_days_since_iso_z_format() {
let now = chrono::Utc::now();
let one_week_ago = now - chrono::Duration::days(7);
let posted = one_week_ago.format("%Y-%m-%dT%H:%M:%SZ").to_string();
let days = compute_days_since(&posted, &now);
assert!((days - 7.0).abs() < 0.2, "should be ~7 days, got {days}");
}
#[test]
fn compute_days_since_rfc3339_with_offset() {
let now = chrono::Utc::now();
let posted = (now - chrono::Duration::hours(48)).to_rfc3339();
let days = compute_days_since(&posted, &now);
assert!((days - 2.0).abs() < 0.1, "should be ~2 days, got {days}");
}
#[test]
fn compute_days_since_future_date() {
let now = chrono::Utc::now();
let future = (now + chrono::Duration::hours(24)).to_rfc3339();
let days = compute_days_since(&future, &now);
assert!(
days < 0.0,
"future date should give negative days: got {days}"
);
}
#[test]
fn compute_days_since_empty_string() {
let now = chrono::Utc::now();
let days = compute_days_since("", &now);
assert!(
(days - 30.0).abs() < 0.1,
"empty string should default to 30 days"
);
}
#[test]
fn compute_days_since_partial_date() {
let now = chrono::Utc::now();
let days = compute_days_since("2026-01-01", &now);
assert!(
(days - 30.0).abs() < 0.1,
"unparseable partial date should default to 30"
);
}
#[test]
fn classify_for_row_reply_experience() {
assert_eq!(
classify_for_row("reply", "I've found this to be true in practice"),
"share_experience"
);
}
#[test]
fn classify_for_row_tweet_list() {
assert_eq!(
classify_for_row("tweet", "1. First item 2. Second item"),
"list"
);
}
#[test]
fn classify_for_row_empty_type() {
let result = classify_for_row("", "Some content here");
assert_eq!(result, "storytelling");
}
#[test]
fn truncate_at_char_boundary_empty_string() {
assert_eq!(truncate_at_char_boundary("", 10), "");
}
#[test]
fn truncate_at_char_boundary_zero_max() {
assert_eq!(truncate_at_char_boundary("hello", 0), "");
}
#[test]
fn truncate_at_char_boundary_multibyte_char() {
let s = "hello \u{1F600} world";
let result = truncate_at_char_boundary(s, 7);
assert!(result.len() <= 7);
assert!(result.is_char_boundary(result.len()));
}
#[test]
fn truncate_at_char_boundary_unicode() {
let s = "\u{00E9}\u{00E9}\u{00E9}\u{00E9}\u{00E9}";
let result = truncate_at_char_boundary(s, 4);
assert!(result.len() <= 4);
assert!(result.is_char_boundary(result.len()));
}