use std::time::Duration;
use termlens::{Key, Terminal};
mod common;
fn emit(steps: &[&str]) -> termlens::Result<Terminal> {
common::spawn_emit(
Terminal::builder()
.size(24, 4)
.timeout(Duration::from_secs(10)),
steps,
)
}
fn col_of(screen: &termlens::Screen, needle: &str) -> Option<u16> {
screen.find(needle).map(|(_, col)| col)
}
#[test]
fn a_tab_lands_on_a_stop_set_by_hts() -> termlens::Result<()> {
let mut t = emit(&[
"--csi", "4G", "--esc", "H", "--csi", "1G", "a\tb", " DONE", "--wait",
])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "a"), Some(0), "{s}");
assert_eq!(col_of(&s, "b"), Some(3), "the stop set at column 4:\n{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn the_default_stops_survive_a_custom_one() -> termlens::Result<()> {
let mut t = emit(&[
"--csi", "4G", "--esc", "H", "--csi", "1G", "a\tb\tc", " DONE", "--wait",
])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "b"), Some(3), "{s}");
assert_eq!(col_of(&s, "c"), Some(8), "the default eighth column:\n{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn tbc_clears_the_stop_under_the_cursor() -> termlens::Result<()> {
let mut t = emit(&[
"--csi", "9G", "--csi", "g", "--csi", "1G", "a\tb", " DONE", "--wait",
])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "b"), Some(16), "{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn csi_3_g_clears_every_stop() -> termlens::Result<()> {
let mut t = emit(&["--csi", "3g", "a\t\tb\r\nDONE", "--wait"])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "a"), Some(0), "{s}");
assert_eq!(
col_of(&s, "b"),
Some(23),
"the last column, and the second tab does not move on from it:\n{s}"
);
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn cht_moves_forward_by_whole_stops() -> termlens::Result<()> {
let mut t = emit(&["--csi", "2I", "a", " DONE", "--wait"])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "a"), Some(16), "two stops forward:\n{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn cbt_moves_back_by_whole_stops() -> termlens::Result<()> {
let mut t = emit(&["\t\t", "--csi", "1Z", "y", " DONE", "--wait"])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "y"), Some(8), "{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn a_back_tab_returns_to_the_stop_the_cursor_is_just_past() -> termlens::Result<()> {
let mut t = emit(&["\t\tX", "--csi", "1Z", "y", " DONE", "--wait"])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "y"), Some(16), "{s}");
assert!(!s.contains("X"), "y is written over X:\n{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn a_hard_reset_restores_the_default_stops() -> termlens::Result<()> {
let mut t = emit(&[
"--csi", "3g", "--csi", "4G", "--esc", "H", "--esc", "c", "\tx", " DONE", "--wait",
])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "x"), Some(8), "every eighth column again:\n{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
#[cfg_attr(windows, ignore = "ConPTY does not forward DECSTR (#149)")]
fn a_soft_reset_restores_the_default_stops() -> termlens::Result<()> {
let mut t = emit(&[
"--csi", "3g", "--csi", "4G", "--esc", "H", "--csi", "!p", "--csi", "1G", "\tx", " DONE",
"--wait",
])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "x"), Some(8), "every eighth column again:\n{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn a_resize_extends_the_stops_and_keeps_the_ones_it_had() -> termlens::Result<()> {
let mut t = emit(&[
"--csi",
"4G",
"--esc",
"H",
"--csi",
"1G",
"READY\r\n",
"--wait",
"\ta",
"--csi",
"25G",
"\tb\r\nDONE",
])?;
t.wait_until(|s| s.contains("READY"))?;
t.resize(40, 4)?;
t.send(Key::Enter)?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(col_of(&s, "a"), Some(3), "the custom stop survives:\n{s}");
assert_eq!(
col_of(&s, "b"),
Some(32),
"and column 25 tabs on to the every-eighth stop at 33:\n{s}"
);
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn a_table_laid_out_with_its_own_stops_lines_up() -> termlens::Result<()> {
let mut t = emit(&[
"--csi",
"3g",
"--csi",
"5G",
"--esc",
"H",
"--csi",
"13G",
"--esc",
"H",
"--csi",
"1G",
"id\tname\trole\r\n",
"7\tada\tdev\r\n",
"DONE",
"--wait",
])?;
t.wait_until(|s| s.contains("DONE"))?;
let s = t.screen();
assert_eq!(s.row_text(0).trim_end(), "id name role", "{s}");
assert_eq!(s.row_text(1).trim_end(), "7 ada dev", "{s}");
assert_eq!(col_of(&s, "name"), Some(4), "{s}");
assert_eq!(col_of(&s, "ada"), Some(4), "{s}");
assert_eq!(col_of(&s, "role"), Some(12), "{s}");
assert_eq!(col_of(&s, "dev"), Some(12), "{s}");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(())
}