use super::*;
use crate::app::CmdLineKind;
#[test]
fn ex_history_records_dispatched_commands() {
let mut app = App::new(None, false, None, None).unwrap();
app.dispatch_ex("set nu");
app.dispatch_ex("set nonu");
assert_eq!(app.ex_history.len(), 2);
assert_eq!(app.ex_history[0], "set nu");
assert_eq!(app.ex_history[1], "set nonu");
}
#[test]
fn ex_history_skips_immediate_duplicate() {
let mut app = App::new(None, false, None, None).unwrap();
app.dispatch_ex("set nu");
app.dispatch_ex("set nu");
assert_eq!(
app.ex_history.len(),
1,
"consecutive duplicate must not be pushed"
);
}
#[test]
fn ex_history_caps_at_100() {
let mut app = App::new(None, false, None, None).unwrap();
for i in 0..105usize {
app.dispatch_ex(&format!("set ts={i}"));
}
assert_eq!(
app.ex_history.len(),
100,
"history must be capped at 100 entries"
);
assert_eq!(
app.ex_history[0], "set ts=5",
"oldest entries must be dropped first"
);
}
#[test]
fn prompt_ctrl_p_recalls_previous() {
let mut app = App::new(None, false, None, None).unwrap();
app.dispatch_ex("set nu");
app.dispatch_ex("set nonu");
app.open_command_prompt();
assert!(app.command_field.is_some());
app.handle_command_field_key(crossterm::event::KeyEvent::new(
crossterm::event::KeyCode::Char('p'),
crossterm::event::KeyModifiers::CONTROL,
));
let text = app.command_field.as_ref().unwrap().text();
assert_eq!(text, "set nonu", "Ctrl-P must recall the most recent entry");
}
#[test]
fn prompt_ctrl_n_after_p_advances() {
let mut app = App::new(None, false, None, None).unwrap();
app.dispatch_ex("set nu");
app.dispatch_ex("set nonu");
app.dispatch_ex("set ts=4");
app.open_command_prompt();
let ctrl_p = crossterm::event::KeyEvent::new(
crossterm::event::KeyCode::Char('p'),
crossterm::event::KeyModifiers::CONTROL,
);
let ctrl_n = crossterm::event::KeyEvent::new(
crossterm::event::KeyCode::Char('n'),
crossterm::event::KeyModifiers::CONTROL,
);
app.handle_command_field_key(ctrl_p);
app.handle_command_field_key(ctrl_p);
let text = app.command_field.as_ref().unwrap().text();
assert_eq!(text, "set nonu", "two Ctrl-P should be 2nd from end");
app.handle_command_field_key(ctrl_n);
let text = app.command_field.as_ref().unwrap().text();
assert_eq!(text, "set ts=4", "Ctrl-N after two Ctrl-P must go forward");
}
#[test]
fn q_colon_opens_cmdline_window() {
let mut app = App::new(None, false, None, None).unwrap();
app.dispatch_ex("set nu");
app.dispatch_ex("set nonu");
app.dispatch_ex("set ts=4");
let wins_before = app.windows.iter().filter(|w| w.is_some()).count();
let slots_before = app.slots().len();
app.open_cmdline_window(CmdLineKind::Ex);
let wins_after = app.windows.iter().filter(|w| w.is_some()).count();
let slots_after = app.slots().len();
assert_eq!(wins_after, wins_before + 1, "one new window expected");
assert_eq!(slots_after, slots_before + 1, "one new slot expected");
assert!(app.cmdline_win.is_some(), "cmdline_win must be Some");
assert_eq!(
app.cmdline_win.as_ref().unwrap().kind,
CmdLineKind::Ex,
"kind must be Ex"
);
assert!(
app.is_cmdline_win_focused(),
"cmdline window must be focused"
);
let slot_idx = app.cmdline_win.as_ref().unwrap().slot_idx;
let line_count = app.slots()[slot_idx].editor.buffer().row_count();
assert_eq!(line_count, 3, "buffer must have 3 history lines");
}
#[test]
fn q_colon_window_cr_on_history_line_re_executes() {
let mut app = App::new(None, false, None, None).unwrap();
app.dispatch_ex("set nu");
app.open_cmdline_window(CmdLineKind::Ex);
assert!(app.cmdline_win.is_some());
let slot_idx = app.cmdline_win.as_ref().unwrap().slot_idx;
app.slots_mut()[slot_idx].editor.jump_cursor(0, 0);
let wins_before = app.windows.iter().filter(|w| w.is_some()).count();
app.commit_cmdline_window();
assert!(app.cmdline_win.is_none(), "cmdline_win must be cleared");
let wins_after = app.windows.iter().filter(|w| w.is_some()).count();
assert_eq!(wins_after, wins_before - 1, "window must have been removed");
assert_eq!(
app.last_ex_command.as_deref(),
Some("set nu"),
"command must have been re-dispatched"
);
}
#[test]
fn q_colon_window_quit_without_execute() {
let mut app = App::new(None, false, None, None).unwrap();
app.dispatch_ex("set nu");
app.last_ex_command = None;
app.open_cmdline_window(CmdLineKind::Ex);
assert!(app.cmdline_win.is_some());
let wins_before = app.windows.iter().filter(|w| w.is_some()).count();
app.dispatch_ex("q");
assert!(app.cmdline_win.is_none(), "cmdline_win must be cleared");
let wins_after = app.windows.iter().filter(|w| w.is_some()).count();
assert_eq!(wins_after, wins_before - 1, "window must have been closed");
assert!(
app.last_ex_command.is_none() || app.last_ex_command.as_deref() == Some("q"),
"no ex command other than q itself must have been dispatched"
);
assert!(
!app.exit_requested,
"app must not exit when cmdline window is closed via :q"
);
}