use super::TmuxDriver;
use crate::core::tmux::TmuxTarget;
use crate::test_support::tmux_session::{
PrivateTmuxServer, ScratchTmuxSession, reserved_session_name,
};
const TMUX: &str = "tmux";
fn sibling_fixture(
tag: &str,
) -> Option<(PrivateTmuxServer, ScratchTmuxSession, String, TmuxDriver)> {
if !ScratchTmuxSession::tmux_available(TMUX) {
eprintln!("tmux not available; skipping");
return None;
}
let server = PrivateTmuxServer::new(TMUX, tag);
let missing = reserved_session_name(&format!("exact-{tag}"));
let sibling = ScratchTmuxSession::spawn_on_socket(
TMUX,
Some(server.name()),
&format!("{missing}-suffix"),
"sh",
);
let driver = TmuxDriver::with_tmux_path_for_test(server.shim_bin());
Some((server, sibling, missing, driver))
}
fn pane_identity(server: &PrivateTmuxServer, session: &str) -> Option<String> {
server.query(&[
"display-message",
"-p",
"-t",
&trusty_common::tmux::exact_window_target(session),
"#{pane_id}:#{pane_pid}",
])
}
fn assert_tmux_miss<T: std::fmt::Debug>(what: &str, result: crate::core::Result<T>) {
let err = result.expect_err(what);
let msg = err.to_string();
assert!(
msg.contains("can't find"),
"{what}: expected tmux's own 'can't find' reply, got: {msg}"
);
}
#[serial_test::serial]
#[test]
fn kill_session_leaves_a_prefix_sibling_alive() {
let Some((server, sibling, missing, driver)) = sibling_fixture("kill") else {
return;
};
let before = pane_identity(&server, sibling.name());
assert!(
before.is_some(),
"fixture precondition: the sibling is live"
);
assert_tmux_miss(
"killing the missing session must fail, not succeed on a sibling",
driver.kill_session(&missing),
);
assert!(
ScratchTmuxSession::exists_on_socket(TMUX, Some(server.name()), sibling.name()),
"kill_session('{missing}') destroyed '{}' — the #8443 prefix match",
sibling.name()
);
assert_eq!(pane_identity(&server, sibling.name()), before);
}
#[serial_test::serial]
#[test]
fn send_and_capture_never_reach_a_prefix_sibling() {
let Some((_server, sibling, missing, driver)) = sibling_fixture("io") else {
return;
};
let marker = "marker-8443-must-not-land";
driver
.capture(&TmuxTarget::session(sibling.name()), Some(5))
.expect("fixture precondition: the driver reaches the private server");
assert_tmux_miss(
"send-keys to the missing session must fail",
driver.send_line(&TmuxTarget::session(&missing), &format!("echo {marker}")),
);
assert_tmux_miss(
"capture-pane of the missing session must fail",
driver.capture(&TmuxTarget::session(&missing), Some(50)),
);
std::thread::sleep(std::time::Duration::from_millis(300));
let sibling_screen = driver
.capture(&TmuxTarget::session(sibling.name()), Some(50))
.expect("the sibling itself is capturable by its exact name");
assert!(
!sibling_screen.contains(marker),
"keys aimed at '{missing}' landed in '{}': {sibling_screen}",
sibling.name()
);
}
#[serial_test::serial]
#[test]
fn an_empty_session_name_never_reaches_a_session() {
let Some((server, sibling, _missing, driver)) = sibling_fixture("empty") else {
return;
};
let before = pane_identity(&server, sibling.name());
assert!(
before.is_some(),
"fixture precondition: the session is live"
);
let marker = "marker-8443-empty";
for name in ["", "="] {
let target = TmuxTarget::session(name);
assert!(
driver
.send_line(&target, &format!("echo {marker}"))
.is_err()
);
assert!(driver.send_interrupt(&target).is_err());
assert!(driver.capture(&target, Some(5)).is_err());
assert!(driver.kill_session(name).is_err());
assert!(driver.pane_id(name).is_none());
assert!(driver.pane_current_path(name).is_none());
}
std::thread::sleep(std::time::Duration::from_millis(300));
assert_eq!(pane_identity(&server, sibling.name()), before);
let screen = driver
.capture(&TmuxTarget::session(sibling.name()), Some(50))
.expect("capture the live session");
assert!(
!screen.contains(marker),
"an empty target typed into '{}'",
sibling.name()
);
}