mirror of
https://github.com/tmux/tmux.git
synced 2026-07-03 10:12:31 +00:00
389 lines
9.2 KiB
Bash
389 lines
9.2 KiB
Bash
#!/bin/sh
|
|
|
|
# Tests that every format variable listed in tmux(1) (the format_table in
|
|
# format.c) can be expanded without crashing the server, and checks the value
|
|
# of a stable subset.
|
|
#
|
|
# The main point is coverage and crash-safety: each variable is expanded in a
|
|
# rich context - a real attached client (from a nested tmux), a control-mode
|
|
# client, a grouped session, two windows with a bell alert, a window with two
|
|
# panes running cat, a paste buffer and options - so the per-variable callbacks
|
|
# actually run. format-modifiers.sh covers the modifier machinery; this covers
|
|
# the variable callbacks.
|
|
|
|
PATH=/bin:/usr/bin
|
|
TERM=screen
|
|
|
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
|
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
|
# A second server on its own socket provides a real terminal (an inner client
|
|
# attached inside one of its panes) so client terminal variables are populated.
|
|
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
|
|
|
# Every variable name in format_table[]. Kept as a plain word list so it can be
|
|
# iterated with normal shell word splitting.
|
|
NAMES="
|
|
active_window_index
|
|
alternate_on
|
|
alternate_saved_x
|
|
alternate_saved_y
|
|
bracket_paste_flag
|
|
buffer_created
|
|
buffer_full
|
|
buffer_mode_format
|
|
buffer_name
|
|
buffer_sample
|
|
buffer_size
|
|
client_activity
|
|
client_cell_height
|
|
client_cell_width
|
|
client_colours
|
|
client_control_mode
|
|
client_created
|
|
client_discarded
|
|
client_flags
|
|
client_height
|
|
client_key_table
|
|
client_last_session
|
|
client_mode_format
|
|
client_name
|
|
client_pid
|
|
client_prefix
|
|
client_readonly
|
|
client_session
|
|
client_termfeatures
|
|
client_termname
|
|
client_termtype
|
|
client_theme
|
|
client_tty
|
|
client_uid
|
|
client_user
|
|
client_utf8
|
|
client_width
|
|
client_written
|
|
config_files
|
|
cursor_blinking
|
|
cursor_character
|
|
cursor_colour
|
|
cursor_flag
|
|
cursor_shape
|
|
cursor_very_visible
|
|
cursor_x
|
|
cursor_y
|
|
history_all_bytes
|
|
history_bytes
|
|
history_limit
|
|
history_size
|
|
host
|
|
host_short
|
|
insert_flag
|
|
keypad_cursor_flag
|
|
keypad_flag
|
|
last_window_index
|
|
mouse_all_flag
|
|
mouse_any_flag
|
|
mouse_button_flag
|
|
mouse_hyperlink
|
|
mouse_line
|
|
mouse_pane
|
|
mouse_sgr_flag
|
|
mouse_standard_flag
|
|
mouse_status_line
|
|
mouse_status_range
|
|
mouse_utf8_flag
|
|
mouse_word
|
|
mouse_x
|
|
mouse_y
|
|
next_session_id
|
|
origin_flag
|
|
pane_active
|
|
pane_at_bottom
|
|
pane_at_left
|
|
pane_at_right
|
|
pane_at_top
|
|
pane_bg
|
|
pane_bottom
|
|
pane_current_command
|
|
pane_current_path
|
|
pane_dead
|
|
pane_dead_signal
|
|
pane_dead_status
|
|
pane_dead_time
|
|
pane_fg
|
|
pane_flags
|
|
pane_floating_flag
|
|
pane_format
|
|
pane_height
|
|
pane_id
|
|
pane_in_mode
|
|
pane_index
|
|
pane_input_off
|
|
pane_key_mode
|
|
pane_last
|
|
pane_left
|
|
pane_marked
|
|
pane_marked_set
|
|
pane_mode
|
|
pane_path
|
|
pane_pb_progress
|
|
pane_pb_state
|
|
pane_pid
|
|
pane_pipe
|
|
pane_pipe_pid
|
|
pane_right
|
|
pane_search_string
|
|
pane_start_command
|
|
pane_start_path
|
|
pane_synchronized
|
|
pane_tabs
|
|
pane_title
|
|
pane_top
|
|
pane_tty
|
|
pane_unseen_changes
|
|
pane_width
|
|
pane_x
|
|
pane_y
|
|
pane_z
|
|
pane_zoomed_flag
|
|
pid
|
|
scroll_region_lower
|
|
scroll_region_upper
|
|
server_sessions
|
|
session_active
|
|
session_activity
|
|
session_activity_flag
|
|
session_alert
|
|
session_alerts
|
|
session_attached
|
|
session_attached_list
|
|
session_bell_flag
|
|
session_created
|
|
session_format
|
|
session_group
|
|
session_group_attached
|
|
session_group_attached_list
|
|
session_group_list
|
|
session_group_many_attached
|
|
session_group_size
|
|
session_grouped
|
|
session_id
|
|
session_last_attached
|
|
session_many_attached
|
|
session_marked
|
|
session_name
|
|
session_path
|
|
session_silence_flag
|
|
session_stack
|
|
session_windows
|
|
sixel_support
|
|
socket_path
|
|
start_time
|
|
synchronized_output_flag
|
|
tree_mode_format
|
|
uid
|
|
user
|
|
version
|
|
window_active
|
|
window_active_clients
|
|
window_active_clients_list
|
|
window_active_sessions
|
|
window_active_sessions_list
|
|
window_activity
|
|
window_activity_flag
|
|
window_bell_flag
|
|
window_bigger
|
|
window_cell_height
|
|
window_cell_width
|
|
window_end_flag
|
|
window_flags
|
|
window_format
|
|
window_height
|
|
window_id
|
|
window_index
|
|
window_last_flag
|
|
window_layout
|
|
window_linked
|
|
window_linked_sessions
|
|
window_linked_sessions_list
|
|
window_marked_flag
|
|
window_name
|
|
window_offset_x
|
|
window_offset_y
|
|
window_panes
|
|
window_raw_flags
|
|
window_silence_flag
|
|
window_stack_index
|
|
window_start_flag
|
|
window_visible_layout
|
|
window_width
|
|
window_zoomed_flag
|
|
wrap_flag
|
|
"
|
|
|
|
# test_var $name $expected [$extra_args...]
|
|
#
|
|
# Expand a single #{name} and compare against $expected. Any extra arguments
|
|
# are passed straight to display-message (e.g. -c or -t).
|
|
test_var()
|
|
{
|
|
name="$1"
|
|
exp="$2"
|
|
shift 2
|
|
|
|
out=$($TMUX display-message "$@" -p "#{$name}")
|
|
if [ "$out" != "$exp" ]; then
|
|
echo "Variable test failed for '#{$name}'."
|
|
echo "Expected: '$exp'"
|
|
echo "But got '$out'"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
assert_alive()
|
|
{
|
|
if [ "$($TMUX display-message -p alive)" != "alive" ]; then
|
|
echo "Server did not survive: $1"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
FIFO="${TMPDIR:-/tmp}/fmt-vars-$$"
|
|
HOLD=""
|
|
CC=""
|
|
|
|
cleanup()
|
|
{
|
|
[ -n "$HOLD" ] && kill $HOLD 2>/dev/null
|
|
[ -n "$CC" ] && kill $CC 2>/dev/null
|
|
rm -f "$FIFO"
|
|
$TMUX kill-server 2>/dev/null
|
|
$TMUX2 kill-server 2>/dev/null
|
|
}
|
|
fail()
|
|
{
|
|
echo "$1"
|
|
cleanup
|
|
exit 1
|
|
}
|
|
|
|
$TMUX kill-server 2>/dev/null
|
|
$TMUX2 kill-server 2>/dev/null
|
|
|
|
# A session "cov" with a window "win0" holding two panes running cat, plus a
|
|
# second window, an option and a paste buffer.
|
|
$TMUX new-session -d -s cov -x 80 -y 24 -n win0 'cat' || exit 1
|
|
$TMUX set -g automatic-rename off
|
|
$TMUX set -g monitor-bell on
|
|
$TMUX set -g monitor-activity on
|
|
$TMUX split-window -t cov:win0 -d 'cat' || exit 1
|
|
$TMUX new-window -d -t cov:1 -n win1 'cat' || exit 1
|
|
$TMUX set -g @opt 'optionvalue' || exit 1
|
|
$TMUX set-buffer -b buf0 'somebuffer' || exit 1
|
|
|
|
# A second session grouped with cov, so the session_group_* variables have real
|
|
# data to report.
|
|
$TMUX new-session -d -s cov2 -t cov || exit 1
|
|
|
|
sleep 1
|
|
$TMUX send-keys -t cov:win0.0 'some pane content' Enter
|
|
# Ring the bell in the non-current window so a bell alert is raised on the
|
|
# session (this populates session_alert/session_alerts and window_bell_flag).
|
|
$TMUX send-keys -t cov:win1.0 C-g
|
|
sleep 1
|
|
|
|
# Attach a control-mode client, held open by a background process keeping the
|
|
# write end of a FIFO open, so client_* variables have a client to read.
|
|
rm -f "$FIFO"
|
|
mkfifo "$FIFO" || exit 1
|
|
sleep 30 >"$FIFO" &
|
|
HOLD=$!
|
|
$TMUX -C attach -t cov <"$FIFO" >/dev/null 2>&1 &
|
|
CC=$!
|
|
|
|
# Attach a real client too: an inner tmux running inside a pane of the second
|
|
# server gets a genuine terminal, which populates the terminal-dependent client
|
|
# variables (client_termname, cursor_shape, the I modifier, ...).
|
|
$TMUX2 new-session -d -x 90 -y 30 "$TMUX attach -t cov" || exit 1
|
|
sleep 1
|
|
|
|
# The real (terminal) client, identified by not being in control mode.
|
|
RC=$($TMUX list-clients -F '#{client_control_mode} #{client_name}' |
|
|
awk '$1==0 { print $2; exit }')
|
|
# The control client.
|
|
CLIENT=$($TMUX list-clients -F '#{client_control_mode} #{client_name}' |
|
|
awk '$1==1 { print $2; exit }')
|
|
[ -n "$RC" ] || fail "No real client attached."
|
|
[ -n "$CLIENT" ] || fail "No control client attached."
|
|
|
|
# Expand every variable at once, with the real terminal client and a target
|
|
# pane in context, and confirm the server survives. This runs every callback.
|
|
FMT=""
|
|
for n in $NAMES; do
|
|
FMT="$FMT#{$n}"
|
|
done
|
|
$TMUX display-message -c "$RC" -t cov:win0.0 -p "$FMT" >/dev/null 2>&1
|
|
assert_alive "expanding all variables together"
|
|
|
|
# Expand each variable on its own too, so a crash can be pinned to one name.
|
|
for n in $NAMES; do
|
|
$TMUX display-message -c "$RC" -t cov:win0.0 -p "#{$n}" >/dev/null 2>&1
|
|
assert_alive "expanding #{$n}"
|
|
done
|
|
|
|
# Deterministic checks on stable variables (targeting pane 0 of window 0).
|
|
TGT="cov:win0.0"
|
|
test_var session_name "cov" -t "$TGT"
|
|
test_var window_name "win0" -t "$TGT"
|
|
test_var window_index "0" -t "$TGT"
|
|
test_var window_panes "2" -t "$TGT"
|
|
test_var session_windows "2" -t "$TGT"
|
|
test_var pane_index "0" -t "$TGT"
|
|
test_var pane_in_mode "0" -t "$TGT"
|
|
test_var pane_at_top "1" -t "$TGT"
|
|
test_var pane_at_left "1" -t "$TGT"
|
|
test_var last_window_index "1" -t "$TGT"
|
|
test_var pid "$($TMUX display-message -p '#{pid}')" -t "$TGT"
|
|
|
|
# The grouped session is reported as such.
|
|
test_var session_grouped "1" -t "cov:"
|
|
test_var session_group_size "2" -t "cov:"
|
|
|
|
# list-buffers -F formats each paste buffer (this fills in the paste-buffer
|
|
# format defaults).
|
|
if [ "$($TMUX list-buffers -F '#{buffer_name}=#{buffer_sample}')" != \
|
|
"buf0=somebuffer" ]; then
|
|
fail "Unexpected list-buffers format output."
|
|
fi
|
|
|
|
# Version reported by the variable matches tmux -V.
|
|
VER=$($TMUX -V | sed 's/^tmux //')
|
|
test_var version "$VER" -t "$TGT"
|
|
|
|
# Client variables from each kind of client.
|
|
test_var client_name "$CLIENT" -c "$CLIENT"
|
|
test_var client_control_mode "1" -c "$CLIENT"
|
|
test_var client_control_mode "0" -c "$RC"
|
|
test_var socket_path "$($TMUX display-message -p '#{socket_path}')" -c "$CLIENT"
|
|
# The real client has a terminal, so termcap/feature/environ queries work.
|
|
test_var "I/e:TERM" "$($TMUX display-message -c "$RC" -p '#{client_termname}')" \
|
|
-c "$RC"
|
|
# Termcap and feature queries against a real terminal return a boolean.
|
|
case "$($TMUX display-message -c "$RC" -p '#{I/c:colors}')" in
|
|
0|1) ;;
|
|
*) fail "Unexpected #{I/c:colors} for real client." ;;
|
|
esac
|
|
case "$($TMUX display-message -c "$RC" -p '#{I/f:256}')" in
|
|
0|1) ;;
|
|
*) fail "Unexpected #{I/f:256} for real client." ;;
|
|
esac
|
|
|
|
# Time variables through the pretty and relative modifiers: start_time is the
|
|
# recent server start, exercising the "last 24 hours" and "just now" paths.
|
|
[ -n "$($TMUX display-message -p '#{t/p:start_time}')" ] ||
|
|
fail "Empty #{t/p:start_time}."
|
|
[ -n "$($TMUX display-message -p '#{t/r:start_time}')" ] ||
|
|
fail "Empty #{t/r:start_time}."
|
|
|
|
cleanup
|
|
exit 0
|