use super::*;
use crate::interactive::tui::application::tests_support::idle_app;
#[test]
fn copy_transcript_excludes_thinking_blocks() {
let mut app = idle_app();
app.transcript.push(BlockKind::User, "what is the answer");
app.transcript.push(
BlockKind::Thinking,
"the secret chain-of-thought about row values",
);
app.transcript
.push(BlockKind::Assistant, "the answer is 42");
app.copy_transcript();
let copied = app.pending_clipboard.expect("transcript was queued");
assert!(
copied.contains("the answer is 42"),
"assistant text must be copied: {copied}"
);
assert!(
copied.contains("what is the answer"),
"user text must be copied: {copied}"
);
assert!(
!copied.contains("the secret chain-of-thought about row values"),
"thinking must not reach the clipboard: {copied}"
);
}
#[test]
fn folding_does_not_change_what_copy_yields() {
let mut app = idle_app();
app.transcript.push(BlockKind::User, "count the red orders");
app.transcript
.push(BlockKind::Assistant, "the red orders total 42");
app.transcript.push(BlockKind::User, "and the blue ones");
app.copy_transcript();
let plain = app.pending_clipboard.take().expect("transcript was queued");
app.transcript.toggle_chapter(1);
app.copy_transcript();
let folded = app.pending_clipboard.expect("folded transcript was queued");
assert_eq!(plain, folded, "a fold is a view, not a redaction");
assert!(
folded.contains("the red orders total 42"),
"hidden rows still copy: {folded}"
);
}
#[test]
fn copy_last_answer_skips_thinking_blocks() {
let mut app = idle_app();
app.transcript
.push(BlockKind::Assistant, "the answer is 42");
app.transcript
.push(BlockKind::Thinking, "the secret chain-of-thought");
app.copy_last_answer();
let copied = app.pending_clipboard.expect("answer was queued");
assert_eq!(copied, "the answer is 42");
}
#[test]
fn selection_mode_says_the_terminal_can_copy_visible_thinking() {
let mut app = idle_app();
app.transcript
.push(BlockKind::Thinking, "chain-of-thought about row values");
app.toggle_selection_mode();
let notice = app
.transcript
.blocks()
.iter()
.rev()
.find(|b| b.kind == BlockKind::System)
.expect("a selection-mode notice");
assert!(
notice.text.contains("Thinking is on screen"),
"the notice must name the exposure while thinking is visible: {}",
notice.text
);
}
#[test]
fn selection_mode_stays_quiet_about_thinking_when_none_is_shown() {
let mut app = idle_app();
app.transcript
.push(BlockKind::Assistant, "the answer is 42");
app.toggle_selection_mode();
let notice = app
.transcript
.blocks()
.iter()
.rev()
.find(|b| b.kind == BlockKind::System)
.expect("a selection-mode notice");
assert!(
!notice.text.contains("Thinking"),
"no thinking is shown, so the notice must not mention it: {}",
notice.text
);
}
use crate::interactive::tui::history::History;
use crate::interactive::tui::types::App;
pub(super) fn app_with_history() -> App {
let mut app = idle_app();
app.history = History::with_entries(&["select 1", "select 2"]);
app
}
pub(super) fn type_draft(app: &mut App, text: &str) {
use crate::interactive::tui::keys::handle_key;
use ratatui::crossterm::event::{KeyCode, KeyModifiers};
for c in text.chars() {
handle_key(app, KeyCode::Char(c), KeyModifiers::NONE);
}
}
#[test]
fn down_at_idle_leaves_the_draft_alone() {
use crate::interactive::tui::keys::handle_key;
use ratatui::crossterm::event::{KeyCode, KeyModifiers};
let mut app = app_with_history();
type_draft(&mut app, "draft note");
handle_key(&mut app, KeyCode::Down, KeyModifiers::NONE);
assert_eq!(
app.input.text(),
"draft note",
"Down with no history position never wipes the draft"
);
}
#[test]
fn stepping_up_then_back_down_restores_the_draft() {
use crate::interactive::tui::keys::handle_key;
use ratatui::crossterm::event::{KeyCode, KeyModifiers};
let mut app = app_with_history();
type_draft(&mut app, "draft note");
handle_key(&mut app, KeyCode::Up, KeyModifiers::NONE);
assert_eq!(app.input.text(), "select 2", "precondition: Up recalled");
handle_key(&mut app, KeyCode::Down, KeyModifiers::NONE);
assert_eq!(
app.input.text(),
"draft note",
"stepping back down restores the stashed draft"
);
}