use std::time::Duration;
use termlens::{Key, Terminal};
fn answered(n: usize) -> termlens::Result<usize> {
let script = format!(
"stty -icanon -echo min 0 time 100; i=0; \
while [ $i -lt {n} ]; do printf '\\033[6n'; i=$((i+1)); done; \
printf ASKED; \
got=$(dd bs=1 count=$(({n} * 6)) 2>/dev/null | tr -cd 'R' | wc -c | tr -d ' '); \
printf ' GOT[%s] DONE' \"$got\"; read guard"
);
let mut t = Terminal::builder()
.size(80, 6)
.timeout(Duration::from_secs(30))
.args(["-c", &script])
.spawn("/bin/sh")?;
t.wait_until(|s| s.contains("DONE"))?;
let text = t.screen().text();
let count = text
.split("GOT[")
.nth(1)
.and_then(|s| s.split(']').next())
.and_then(|s| s.trim().parse().ok())
.unwrap_or(usize::MAX);
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
Ok(count)
}
#[test]
fn a_batch_of_probes_is_answered_in_full() -> termlens::Result<()> {
for n in [50usize, 200, 400] {
assert_eq!(answered(n)?, n, "asked {n} probes back to back");
}
Ok(())
}
#[test]
fn fine_grained_arrival_is_answered_in_full() -> termlens::Result<()> {
for n in [100usize, 400] {
let script = format!(
"stty -icanon -echo min 0 time 100; i=0; \
while [ $i -lt {n} ]; do x=$(true); printf '\\033[6n'; i=$((i+1)); done; \
printf ASKED; \
got=$(dd bs=1 count=$(({n} * 6)) 2>/dev/null | tr -cd 'R' | wc -c | tr -d ' '); \
printf ' GOT[%s] DONE' \"$got\"; read guard"
);
let mut t = Terminal::builder()
.size(80, 6)
.timeout(Duration::from_secs(40))
.args(["-c", &script])
.spawn("/bin/sh")?;
t.wait_until(|s| s.contains("DONE"))?;
let text = t.screen().text();
let got: usize = text
.split("GOT[")
.nth(1)
.and_then(|s| s.split(']').next())
.and_then(|s| s.trim().parse().ok())
.unwrap_or(usize::MAX);
assert_eq!(got, n, "one read per query must not lose answers");
t.send(Key::Enter)?;
assert!(t.wait_exit()?.success());
}
Ok(())
}