use crate::channels::telegram::handler::format_reply_context;
#[test]
fn recovered_bot_rich_message_with_no_quote_produces_context() {
let ctx = format_reply_context("assistant", "Here is your photo!", "");
assert!(
ctx.is_some(),
"format_reply_context must return Some when reply_full_text is populated by recovery path"
);
let text = ctx.unwrap();
assert!(
text.contains("assistant"),
"context must include the sender name"
);
assert!(
text.contains("Here is your photo!"),
"context must include the recovered message text"
);
assert!(
!text.contains("highlighted"),
"context must NOT mention highlighting since quote_text is empty"
);
}
#[test]
fn empty_full_and_empty_quote_returns_none() {
let ctx = format_reply_context("assistant", "", "");
assert!(
ctx.is_none(),
"format_reply_context must return None when both sides are empty (the pre-#225 bug)"
);
}
#[test]
fn quote_without_full_text_produces_context() {
let ctx = format_reply_context("John", "", "check this part");
assert!(
ctx.is_some(),
"format_reply_context must return Some when quote_text is present"
);
let text = ctx.unwrap();
assert!(
text.contains("check this part"),
"context must include the quoted text"
);
}
#[test]
fn both_full_and_quote_distinct_shows_both() {
let ctx = format_reply_context("assistant", "Full bot message here.", "highlighted bit");
assert!(ctx.is_some());
let text = ctx.unwrap();
assert!(text.contains("Full bot message here."));
assert!(text.contains("highlighted bit"));
assert!(text.contains("highlighted"), "must label the quote");
}
#[test]
fn bot_quote_without_recovery_still_works() {
let ctx = format_reply_context("assistant", "", "look at this");
assert!(
ctx.is_some(),
"bot quote without recovery must still produce context"
);
}
use crate::db::models::Message;
use crate::db::{Database, MessageRepository};
use crate::services::{ServiceContext, SessionService};
#[tokio::test]
async fn dm_recovery_returns_last_assistant_message() {
let db = Database::connect_in_memory().await.unwrap();
db.run_migrations().await.unwrap();
let context = ServiceContext::new(db.pool().clone());
let session = SessionService::new(context)
.create_session(Some("DM".to_string()))
.await
.unwrap();
let repo = MessageRepository::new(db.pool().clone());
repo.create(&Message::new(
session.id,
"user".into(),
"earlier question".into(),
1,
))
.await
.unwrap();
repo.create(&Message::new(
session.id,
"assistant".into(),
"Here is your rich photo report.".into(),
2,
))
.await
.unwrap();
let recovered = repo
.get_last_assistant_message(session.id)
.await
.unwrap()
.expect("must find the assistant message for DM reply recovery");
assert_eq!(recovered.content, "Here is your rich photo report.");
let ctx = format_reply_context("assistant", &recovered.content, "");
assert!(ctx.is_some());
assert!(ctx.unwrap().contains("Here is your rich photo report."));
}
#[tokio::test]
async fn dm_recovery_skips_trailing_user_message() {
let db = Database::connect_in_memory().await.unwrap();
db.run_migrations().await.unwrap();
let context = ServiceContext::new(db.pool().clone());
let session = SessionService::new(context)
.create_session(Some("DM".to_string()))
.await
.unwrap();
let repo = MessageRepository::new(db.pool().clone());
repo.create(&Message::new(
session.id,
"assistant".into(),
"bot reply text".into(),
1,
))
.await
.unwrap();
repo.create(&Message::new(
session.id,
"user".into(),
"a later user line".into(),
2,
))
.await
.unwrap();
let recovered = repo
.get_last_assistant_message(session.id)
.await
.unwrap()
.expect("must return the assistant row, not the trailing user row");
assert_eq!(recovered.content, "bot reply text");
}
#[tokio::test]
async fn dm_recovery_returns_none_when_no_assistant_message() {
let db = Database::connect_in_memory().await.unwrap();
db.run_migrations().await.unwrap();
let context = ServiceContext::new(db.pool().clone());
let session = SessionService::new(context)
.create_session(Some("DM".to_string()))
.await
.unwrap();
let repo = MessageRepository::new(db.pool().clone());
repo.create(&Message::new(
session.id,
"user".into(),
"only a user line".into(),
1,
))
.await
.unwrap();
let recovered = repo.get_last_assistant_message(session.id).await.unwrap();
assert!(recovered.is_none());
}