use crate::brain::tools::telegram_send::{
resolve_chat_target, resolve_existing_target, resolve_new_target,
};
use crate::channels::telegram::TelegramState;
use serde_json::json;
use teloxide::types::{MessageId, ThreadId};
use uuid::Uuid;
fn empty_state() -> TelegramState {
TelegramState::new()
}
fn error_text(r: crate::brain::tools::r#trait::ToolResult) -> String {
assert!(!r.success, "expected an error ToolResult");
r.error.unwrap_or_default()
}
#[tokio::test]
async fn new_target_honours_explicit_chat_and_thread() {
let input = json!({ "chat_id": 5, "thread_id": 17 });
let target = resolve_new_target(&input, Uuid::nil(), &empty_state())
.await
.expect("explicit chat must resolve");
assert_eq!(target.chat_id, 5);
assert_eq!(target.thread_id, Some(ThreadId(MessageId(17))));
}
#[tokio::test]
async fn new_target_inherits_session_origin_topic() {
let state = empty_state();
let session_id = Uuid::from_u128(0xABCD);
state
.register_session_chat(session_id, 12345, Some(42))
.await;
let input = json!({ "chat_id": 12345 });
let target = resolve_new_target(&input, session_id, &state)
.await
.expect("session chat must resolve");
assert_eq!(target.chat_id, 12345);
assert_eq!(target.thread_id, Some(ThreadId(MessageId(42))));
}
#[tokio::test]
async fn new_target_without_any_thread_source_is_none() {
let input = json!({ "chat_id": 9 });
let target = resolve_new_target(&input, Uuid::nil(), &empty_state())
.await
.expect("explicit chat must resolve");
assert_eq!(target.chat_id, 9);
assert_eq!(target.thread_id, None);
}
#[tokio::test]
async fn new_target_without_a_chat_errors() {
let input = json!({ "thread_id": 17 });
let err = resolve_new_target(&input, Uuid::nil(), &empty_state())
.await
.expect_err("no chat source must error");
let text = error_text(err);
assert!(
text.contains("chat_id"),
"error should point at the missing chat: {text}"
);
}
#[tokio::test]
async fn existing_target_resolves_chat_and_message_id() {
let input = json!({ "chat_id": 5, "message_id": 77 });
let target = resolve_existing_target(&input, Uuid::nil(), &empty_state())
.await
.expect("both fields present must resolve");
assert_eq!(target.chat_id, 5);
assert_eq!(target.message_id, 77);
}
#[tokio::test]
async fn existing_target_requires_message_id() {
let input = json!({ "chat_id": 5 });
let err = resolve_existing_target(&input, Uuid::nil(), &empty_state())
.await
.expect_err("missing message_id must error");
let text = error_text(err);
assert!(
text.contains("'message_id'"),
"error should name the missing param: {text}"
);
}
#[tokio::test]
async fn existing_target_chat_error_precedes_message_id_error() {
let input = json!({});
let err = resolve_existing_target(&input, Uuid::nil(), &empty_state())
.await
.expect_err("no chat source must error");
let text = error_text(err);
assert!(
text.contains("chat_id") && !text.contains("'message_id'"),
"chat error must come first, got: {text}"
);
}
#[tokio::test]
async fn chat_target_uses_explicit_chat() {
let input = json!({ "chat_id": 3 });
let target = resolve_chat_target(&input, Uuid::nil(), &empty_state())
.await
.expect("explicit chat must resolve");
assert_eq!(target.chat_id, 3);
}
#[tokio::test]
async fn chat_target_without_a_chat_errors() {
let input = json!({});
let err = resolve_chat_target(&input, Uuid::nil(), &empty_state())
.await
.expect_err("no chat source must error");
assert!(
error_text(err).contains("chat_id"),
"error should point at the missing chat"
);
}