#[cfg(test)]
mod tests {
use crate::session::Session;
use crate::tui::app::input::{handle_enter, handle_paste};
use crate::tui::app::state::App;
use crate::tui::chat::message::MessageType;
use crate::tui::models::ViewMode;
use tokio::sync::mpsc;
#[tokio::test]
async fn paste_keeps_multiline_text_in_single_chat_input() {
let mut app = App::default();
app.state.view_mode = ViewMode::Chat;
handle_paste(&mut app, "first line\nsecond line").await;
assert_eq!(app.state.input, "first line\nsecond line");
assert_eq!(app.state.status, "Pasted 2 lines into input");
}
#[tokio::test]
async fn multiline_paste_then_enter_submits_as_single_message() {
let mut app = App::default();
app.state.view_mode = ViewMode::Chat;
let pasted = "line one\nline two\nline three";
handle_paste(&mut app, pasted).await;
assert_eq!(app.state.input, pasted);
let cwd = std::path::Path::new(".");
let mut session = Session::new().await.expect("session");
let (event_tx, _) = mpsc::channel(8);
let (result_tx, _) = mpsc::channel(8);
handle_enter(
&mut app,
cwd,
&mut session,
&None,
&None,
&event_tx,
&result_tx,
)
.await;
let user_messages: Vec<&str> = app
.state
.messages
.iter()
.filter(|m| matches!(m.message_type, MessageType::User))
.map(|m| m.content.as_str())
.collect();
assert_eq!(
user_messages.len(),
1,
"expected exactly one User message from a multi-line paste, got {}: {:?}",
user_messages.len(),
user_messages
);
assert_eq!(
user_messages[0], pasted,
"the single User message must contain every pasted line verbatim"
);
assert!(
user_messages[0].contains('\n'),
"newlines must be preserved inside the single message"
);
}
#[tokio::test]
async fn large_paste_is_summarised_into_sidecar() {
let mut app = App::default();
app.state.view_mode = ViewMode::Chat;
let pasted = "alpha\nbeta\ngamma\ndelta\nepsilon\nzeta";
handle_paste(&mut app, pasted).await;
assert!(
app.state.input.starts_with("[Pasted text #1:"),
"input should be a placeholder, got: {:?}",
app.state.input
);
assert!(!app.state.input.contains("epsilon"));
assert_eq!(app.state.pending_text_pastes.len(), 1);
assert_eq!(app.state.pending_text_pastes[0].id, 1);
assert_eq!(app.state.pending_text_pastes[0].content, pasted);
assert!(
app.state.status.contains("6 lines"),
"status missing line count: {:?}",
app.state.status
);
assert!(app.state.status.contains("#1"));
}
#[tokio::test]
async fn submit_expands_placeholder_into_agent_prompt() {
use crate::tui::app::input::pasted_text::expand_paste_placeholders;
let mut app = App::default();
app.state.view_mode = ViewMode::Chat;
let pasted = "one\ntwo\nthree\nfour\nfive\nsix";
handle_paste(&mut app, pasted).await;
app.state.insert_text("\nplease summarise this");
let display_prompt = app.state.input.trim().to_string();
assert!(display_prompt.starts_with("[Pasted text #1:"));
assert!(display_prompt.ends_with("please summarise this"));
assert!(!display_prompt.contains("four"));
let agent_prompt =
expand_paste_placeholders(&display_prompt, &app.state.pending_text_pastes);
assert!(agent_prompt.contains("--- Begin pasted text #1"));
assert!(agent_prompt.contains("four\nfive\nsix"));
assert!(agent_prompt.contains("--- End pasted text #1 ---"));
assert!(agent_prompt.contains("please summarise this"));
}
#[tokio::test]
async fn two_large_pastes_get_independent_ids() {
let mut app = App::default();
app.state.view_mode = ViewMode::Chat;
handle_paste(&mut app, "a\nb\nc\nd\ne\nf").await;
handle_paste(&mut app, "g\nh\ni\nj\nk\nl").await;
assert_eq!(app.state.pending_text_pastes.len(), 2);
assert_eq!(app.state.pending_text_pastes[0].id, 1);
assert_eq!(app.state.pending_text_pastes[1].id, 2);
assert!(app.state.input.contains("[Pasted text #1:"));
assert!(app.state.input.contains("[Pasted text #2:"));
}
#[tokio::test]
async fn short_multiline_paste_still_inlines() {
let mut app = App::default();
app.state.view_mode = ViewMode::Chat;
handle_paste(&mut app, "alpha\nbeta").await;
assert_eq!(app.state.input, "alpha\nbeta");
assert!(app.state.pending_text_pastes.is_empty());
}
#[tokio::test]
async fn typed_newline_then_enter_submits_as_single_message() {
let mut app = App::default();
app.state.view_mode = ViewMode::Chat;
app.state.input = "hello\nworld".to_string();
app.state.input_cursor = app.state.input.chars().count();
let cwd = std::path::Path::new(".");
let mut session = Session::new().await.expect("session");
let (event_tx, _) = mpsc::channel(8);
let (result_tx, _) = mpsc::channel(8);
handle_enter(
&mut app,
cwd,
&mut session,
&None,
&None,
&event_tx,
&result_tx,
)
.await;
let user_messages: Vec<&str> = app
.state
.messages
.iter()
.filter(|m| matches!(m.message_type, MessageType::User))
.map(|m| m.content.as_str())
.collect();
assert_eq!(user_messages.len(), 1, "got: {:?}", user_messages);
assert_eq!(user_messages[0], "hello\nworld");
}
}