#![cfg(feature = "test-support")]
#![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
use libtmux::test::TestServer;
use libtmux::{NewWindowOptions, TmuxText};
fn bytes(value: Option<TmuxText>) -> Vec<u8> {
value.expect("tmux reports a value").as_bytes().to_vec()
}
#[tokio::test]
async fn option_values_survive_bytes_that_tmux_would_quote_for_display() {
let guard = TestServer::builder().start().await.expect("tmux starts");
let server = guard.server();
for value in [
"plain",
"a b c",
"has\"quote",
"has\\back",
"has;semi",
"has'single",
"tab\tsep",
] {
server
.set_option("@probe", value)
.await
.expect("option is set");
assert_eq!(
bytes(server.get_option("@probe").await.expect("option is read")),
value.as_bytes(),
"{value:?} round-trips exactly",
);
}
guard.shutdown().await.expect("tmux fixture shuts down");
}
#[tokio::test]
async fn an_unknown_option_is_an_error_while_an_unset_one_is_absent() {
let guard = TestServer::builder().start().await.expect("tmux starts");
let server = guard.server();
assert!(
server
.get_option("@absent")
.await
.expect("an unset user option is absent")
.is_none(),
);
let error = server
.get_option("no-such-built-in")
.await
.expect_err("an unknown built-in name is refused");
assert!(matches!(error, libtmux::Error::CommandFailed { .. }));
assert!(
server
.get_global_option("after-kill-pane[0]")
.await
.expect("a known hook name is accepted")
.is_none(),
);
guard.shutdown().await.expect("tmux fixture shuts down");
}
#[tokio::test]
async fn options_are_scoped_to_the_object_that_set_them() {
let guard = TestServer::builder().start().await.expect("tmux starts");
let server = guard.server();
let session = server.new_session("scoped").await.expect("session created");
let window = session
.new_window(NewWindowOptions::new("scoped").command("sleep 300"))
.await
.expect("window created");
let pane = window
.try_panes()
.await
.expect("panes list")
.into_iter()
.next()
.expect("one pane");
server.set_option("@where", "server").await.expect("set");
session.set_option("@where", "session").await.expect("set");
window.set_option("@where", "window").await.expect("set");
pane.set_option("@where", "pane").await.expect("set");
assert_eq!(
bytes(server.get_option("@where").await.expect("read")),
b"server"
);
assert_eq!(
bytes(session.get_option("@where").await.expect("read")),
b"session"
);
assert_eq!(
bytes(window.get_option("@where").await.expect("read")),
b"window"
);
assert_eq!(
bytes(pane.get_option("@where").await.expect("read")),
b"pane"
);
window.unset_option("@where").await.expect("unset");
assert!(window.get_option("@where").await.expect("read").is_none());
assert_eq!(
bytes(session.get_option("@where").await.expect("read")),
b"session"
);
assert_eq!(
bytes(pane.get_option("@where").await.expect("read")),
b"pane"
);
guard.shutdown().await.expect("tmux fixture shuts down");
}
#[tokio::test]
async fn appending_extends_a_value_rather_than_replacing_it() {
let guard = TestServer::builder().start().await.expect("tmux starts");
let server = guard.server();
let session = server
.new_session("appending")
.await
.expect("session created");
session.set_option("@parts", "one").await.expect("set");
session
.append_option("@parts", "-two")
.await
.expect("append");
assert_eq!(
bytes(session.get_option("@parts").await.expect("read")),
b"one-two",
);
guard.shutdown().await.expect("tmux fixture shuts down");
}
#[tokio::test]
async fn option_names_lists_what_is_set_without_guessing_at_values() {
let guard = TestServer::builder().start().await.expect("tmux starts");
let server = guard.server();
server
.set_option("@listed", "a value with spaces")
.await
.expect("option is set");
let names = server.option_names().await.expect("names are listed");
assert!(names.iter().any(|name| name == "@listed"));
assert!(
names.iter().any(|name| name.starts_with("command-alias[")),
"array options keep their index",
);
guard.shutdown().await.expect("tmux fixture shuts down");
}
#[tokio::test]
async fn a_hook_is_stored_as_an_indexed_option() {
let guard = TestServer::builder().start().await.expect("tmux starts");
let server = guard.server();
server
.set_hook("after-new-window", "display-message hooked")
.await
.expect("hook is set");
assert_eq!(
bytes(
server
.get_global_option("after-new-window[0]")
.await
.expect("hook is read"),
),
b"display-message hooked",
);
server
.unset_hook("after-new-window")
.await
.expect("hook is removed");
assert!(
server
.get_global_option("after-new-window[0]")
.await
.expect("hook is read")
.is_none(),
);
guard.shutdown().await.expect("tmux fixture shuts down");
}
#[tokio::test]
async fn option_values_decode_into_flags_and_numbers() {
let guard = TestServer::builder().start().await.expect("tmux starts");
let server = guard.server();
server.new_session("typed").await.expect("session");
let status = server
.get_global_option("status")
.await
.expect("read")
.expect("status is set");
assert_eq!(status.as_flag(), Some(true));
let limit = server
.get_global_option("history-limit")
.await
.expect("read")
.expect("history-limit is set");
assert!(limit.parse::<u32>().is_some_and(|value| value > 0));
server.set_option("@prose", "sometimes").await.expect("set");
let prose = server
.get_option("@prose")
.await
.expect("read")
.expect("the option is set");
assert_eq!(prose.as_flag(), None);
assert_eq!(prose.parse::<u32>(), None);
guard.shutdown().await.expect("tmux fixture shuts down");
}
#[tokio::test]
async fn options_decode_by_declared_kind_rather_than_by_shape() {
use libtmux::{OptionKind, OptionValue, option_schema};
let guard = TestServer::builder().start().await.expect("tmux starts");
let server = guard.server();
server.new_session("typed").await.expect("session");
assert_eq!(
option_schema("mouse").map(OptionSchemaKind::kind),
Some(OptionKind::Flag),
);
assert_eq!(
server.typed_global_option("mouse").await.expect("read"),
Some(OptionValue::Flag(false)),
);
assert!(matches!(
server
.typed_global_option("history-limit")
.await
.expect("read"),
Some(OptionValue::Number(limit)) if limit > 0,
));
assert_eq!(
option_schema("status").map(OptionSchemaKind::kind),
Some(OptionKind::Choice),
);
assert!(matches!(
server.typed_global_option("status").await.expect("read"),
Some(OptionValue::Text(_)),
));
assert_eq!(option_schema("@mine"), None);
server.set_option("@mine", "on").await.expect("set");
assert!(matches!(
server.typed_option("@mine").await.expect("read"),
Some(OptionValue::Text(_)),
));
guard.shutdown().await.expect("tmux fixture shuts down");
}
use libtmux::OptionSchema as OptionSchemaKind;