use justerm_core::Engine;
#[test]
fn extracts_command_text_excluding_prompt_and_output() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b]133;A\x07user$ \x1b]133;B\x07ls\x1b]133;C\x07out\r\n\x1b]133;D;0\x07");
let cmds = t.command_lines();
assert_eq!(cmds.len(), 1);
assert_eq!(cmds[0].command, "ls");
assert_eq!(cmds[0].exit, Some(0));
assert_eq!(cmds[0].line, 0, "jump anchor = CommandStart (B) line");
}
#[test]
fn carries_nonzero_exit() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07false\x1b]133;C\x07\r\n\x1b]133;D;1\x07");
let cmds = t.command_lines();
assert_eq!(cmds.len(), 1);
assert_eq!(cmds[0].command, "false");
assert_eq!(cmds[0].exit, Some(1));
}
#[test]
fn command_without_finish_has_no_exit() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07sleep 10\x1b]133;C\x07");
let cmds = t.command_lines();
assert_eq!(cmds.len(), 1);
assert_eq!(cmds[0].command, "sleep 10");
assert_eq!(cmds[0].exit, None);
}
#[test]
fn command_still_typing_is_excluded() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07ls -l");
assert!(t.command_lines().is_empty());
}
#[test]
fn multiple_commands_in_order() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07echo hi\x1b]133;C\x07hi\r\n\x1b]133;D;0\x07");
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07nope\x1b]133;C\x07\r\n\x1b]133;D;127\x07");
let cmds = t.command_lines();
assert_eq!(cmds.len(), 2);
assert_eq!(cmds[0].command, "echo hi");
assert_eq!(cmds[0].exit, Some(0));
assert_eq!(cmds[1].command, "nope");
assert_eq!(cmds[1].exit, Some(127));
assert!(cmds[1].line > cmds[0].line, "second command sits lower");
}
#[test]
fn soft_wrapped_command_joins() {
let mut t = Engine::new(10, 24);
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07echo abcdefgh\x1b]133;C\x07\r\n\x1b]133;D;0\x07");
let cmds = t.command_lines();
assert_eq!(cmds.len(), 1);
assert_eq!(cmds[0].command, "echo abcdefgh");
}
#[test]
fn jump_line_is_document_line_not_absolute() {
let mut t = Engine::new(10, 24);
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07one\x1b]133;C\x07\r\n");
t.feed(b"0123456789XYZ\r\n");
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07two\x1b]133;C\x07\r\n\x1b]133;D;0\x07");
let cmds = t.command_lines();
assert_eq!(cmds.len(), 2);
assert_eq!(cmds[0].command, "one");
assert_eq!(cmds[0].line, 0);
assert_eq!(cmds[1].command, "two");
assert_eq!(
cmds[1].line, 2,
"abs row 3 -> document row 2 (one soft wrap)"
);
}
#[test]
fn command_text_survives_a_resize_reflow() {
let mut t = Engine::new(20, 6);
t.feed(
b"\x1b]133;A\x07prompt> \x1b]133;B\x07mycommand\x1b]133;C\x07\r\nout\r\n\x1b]133;D;0\x07",
);
assert_eq!(t.command_lines()[0].command, "mycommand");
t.resize(8, 6);
assert_eq!(
t.command_lines()[0].command,
"mycommand",
"the marker column reflows with the line"
);
}
#[test]
fn re_emitted_command_start_takes_the_latest() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07old\x1b]133;B\x07new\x1b]133;C\x07\r\n\x1b]133;D;0\x07");
let cmds = t.command_lines();
assert_eq!(cmds.len(), 1);
assert_eq!(cmds[0].command, "new");
}
#[test]
fn output_start_without_command_start_is_ignored() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b]133;C\x07out\r\n\x1b]133;D;0\x07");
assert!(t.command_lines().is_empty());
}
#[test]
fn command_text_is_primary_scoped_on_the_alt_screen() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07ls -la\x1b]133;C\x07\r\nout\r\n\x1b]133;D;0\x07");
t.feed(b"\x1b[?1049h");
let cmds = t.command_lines();
assert_eq!(cmds.len(), 1);
assert_eq!(cmds[0].command, "ls -la"); assert_eq!(cmds[0].exit, Some(0));
}
#[test]
fn command_line_number_is_primary_scoped_on_alt() {
let mut t = Engine::new(6, 24);
t.feed(b"0123456789\r\n"); t.feed(b"\x1b]133;A\x07$ \x1b]133;B\x07cmd\x1b]133;C\x07\r\n\x1b]133;D;0\x07"); let on_primary = t.command_lines()[0].line;
assert_eq!(
on_primary, 1,
"abs row2 -> document row1 (one soft wrap above)"
);
t.feed(b"\x1b[?1049h"); assert_eq!(
t.command_lines()[0].line,
on_primary,
"document line tracks the primary buffer, not the blank alt grid"
);
}
#[test]
fn alt_screen_yields_no_commands() {
let mut t = Engine::new(40, 24);
t.feed(b"\x1b[?1049h");
t.feed(b"\x1b]133;A\x07\x1b]133;B\x07x\x1b]133;C\x07\x1b]133;D;0\x07");
assert!(t.command_lines().is_empty());
}