use std::time::Duration;
use termlens::{Error, Key, Terminal};
fn sh(script: &str) -> termlens::Result<Terminal> {
Terminal::builder()
.timeout(Duration::from_secs(10))
.args(["-c", script])
.spawn("/bin/sh")
}
#[test]
fn cursor_position_reports_the_position_at_the_query() -> termlens::Result<()> {
let mut t = sh(concat!(
r"stty -icanon -echo; printf 'abc\033[6n'; ",
r#"reply=$(head -c 6 | tr '\033' 'E'); "#,
r#"printf '\nunblocked:%s' "$reply"; read guard"#
))?;
t.wait_until(|s| s.contains("unblocked:E[1;4R"))?;
t.send(Key::Enter);
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn device_attribute_probes_are_unblocked() -> termlens::Result<()> {
let mut t = sh(concat!(
r"stty -icanon -echo; printf '\033[c'; ",
r#"reply=$(head -c 9 | tr '\033' 'E'); "#,
r#"printf 'unblocked:%s' "$reply"; read guard"#
))?;
t.wait_until(|s| s.contains("unblocked:E[?62;22c"))?;
t.send(Key::Enter);
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn background_color_query_gets_the_configured_answer() -> termlens::Result<()> {
let mut t = Terminal::builder()
.timeout(Duration::from_secs(10))
.background_rgb(0x1e, 0x1e, 0x2e)
.args([
"-c",
concat!(
r"stty -icanon -echo; printf '\033]11;?\007'; ",
r#"reply=$(head -c 24 | tr '\033\007' 'EG'); "#,
r#"printf 'unblocked:%s' "$reply"; read guard"#
),
])
.spawn("/bin/sh")?;
t.wait_until(|s| s.contains("unblocked:E]11;rgb:1e1e/1e1e/2e2eG"))?;
t.send(Key::Enter);
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn text_area_size_reports_the_real_grid() -> termlens::Result<()> {
let mut t = sh(concat!(
r"stty -icanon -echo; printf '\033[18t'; ",
r#"reply=$(head -c 10 | tr '\033' 'E'); "#,
r#"printf 'unblocked:%s' "$reply"; read guard"#
))?;
t.wait_until(|s| s.contains("unblocked:E[8;24;80t"))?;
t.send(Key::Enter);
assert!(t.wait_exit()?.success());
Ok(())
}
#[test]
fn unanswerable_queries_turn_timeouts_into_diagnoses() {
let mut t = Terminal::builder()
.timeout(Duration::from_millis(500))
.args(["-c", r"printf '\033[14t'; head -c 4 >/dev/null; echo never"])
.spawn("/bin/sh")
.unwrap();
let err = t.wait_until(|s| s.contains("never")).unwrap_err();
let msg = err.to_string();
assert!(msg.contains("^[[14t"), "query not named in: {msg}");
assert!(msg.contains("received no answer"), "no diagnosis in: {msg}");
}
#[test]
fn the_responder_can_be_disabled_and_says_what_went_unanswered() {
let mut t = Terminal::builder()
.timeout(Duration::from_millis(500))
.answer_queries(false)
.args(["-c", r"printf '\033[6n'; head -c 6 >/dev/null; echo never"])
.spawn("/bin/sh")
.unwrap();
let err = t.wait_until(|s| s.contains("never")).unwrap_err();
assert!(matches!(err, Error::Timeout { .. }));
let msg = err.to_string();
assert!(msg.contains("^[[6n"), "query not named in: {msg}");
}
#[test]
fn replies_are_not_echoed_into_the_screen() -> termlens::Result<()> {
let mut t = sh(concat!(
r"stty -icanon -echo; printf 'before\033[5n'; ",
r"head -c 4 >/dev/null; ",
r"printf ' after'; read guard"
))?;
t.wait_until(|s| s.contains("before after"))?;
assert!(
!t.screen().text().contains("[0n"),
"reply leaked into the grid:\n{}",
t.screen()
);
t.send(Key::Enter);
assert!(t.wait_exit()?.success());
Ok(())
}