mirror of
https://github.com/tmux/tmux.git
synced 2026-10-06 17:49:52 +00:00
Add regress tests for events code.
This commit is contained in:
10
Makefile.am
10
Makefile.am
@@ -160,12 +160,12 @@ dist_tmux_SOURCES = \
|
||||
compat.h \
|
||||
control-notify.c \
|
||||
control.c \
|
||||
events.c \
|
||||
events-payload.c \
|
||||
environ.c \
|
||||
events-payload.c \
|
||||
events.c \
|
||||
file.c \
|
||||
format.c \
|
||||
format-draw.c \
|
||||
format.c \
|
||||
fuzzy.c \
|
||||
grid-reader.c \
|
||||
grid-view.c \
|
||||
@@ -190,8 +190,8 @@ dist_tmux_SOURCES = \
|
||||
paste.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
prompt.c \
|
||||
prompt-history.c \
|
||||
prompt.c \
|
||||
regsub.c \
|
||||
resize.c \
|
||||
screen-redraw.c \
|
||||
@@ -206,9 +206,9 @@ dist_tmux_SOURCES = \
|
||||
spawn.c \
|
||||
status.c \
|
||||
style.c \
|
||||
tmux-protocol.h \
|
||||
tmux.c \
|
||||
tmux.h \
|
||||
tmux-protocol.h \
|
||||
tty-acs.c \
|
||||
tty-draw.c \
|
||||
tty-features.c \
|
||||
|
||||
102
regress/control-notify-events.sh
Normal file
102
regress/control-notify-events.sh
Normal file
@@ -0,0 +1,102 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
IN="$TMPDIR/in"
|
||||
OUT="$TMPDIR/out"
|
||||
PID=
|
||||
|
||||
cleanup()
|
||||
{
|
||||
[ -n "$PID" ] && kill "$PID" 2>/dev/null
|
||||
$TMUX kill-server 2>/dev/null
|
||||
rm -rf "$TMPDIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_for()
|
||||
{
|
||||
pattern=$1
|
||||
timeout=${2:-6}
|
||||
i=0
|
||||
|
||||
while [ "$i" -lt "$timeout" ]; do
|
||||
if grep -F -- "$pattern" "$OUT" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
echo "missing: $pattern"
|
||||
cat "$OUT"
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_count()
|
||||
{
|
||||
pattern=$1
|
||||
expected=$2
|
||||
timeout=${3:-6}
|
||||
i=0
|
||||
|
||||
while [ "$i" -lt "$timeout" ]; do
|
||||
count=$(grep -F -- "$pattern" "$OUT" 2>/dev/null | wc -l)
|
||||
if [ "$count" -ge "$expected" ]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
echo "missing count $expected for: $pattern"
|
||||
cat "$OUT"
|
||||
return 1
|
||||
}
|
||||
|
||||
send()
|
||||
{
|
||||
printf '%s\n' "$*" >&3
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX new-session -d -s notify -x 80 -y 24 || exit 1
|
||||
wid=$($TMUX display-message -p -t notify:0 '#{window_id}') || exit 1
|
||||
pane=$($TMUX display-message -p -t notify:0.0 '#{pane_id}') || exit 1
|
||||
|
||||
mkfifo "$IN"
|
||||
: >"$OUT"
|
||||
$TMUX -C attach-session -t notify <"$IN" >"$OUT" 2>&1 &
|
||||
PID=$!
|
||||
exec 3>"$IN"
|
||||
|
||||
send 'display-message -p ready'
|
||||
wait_for 'ready' 3 || exit 1
|
||||
|
||||
send 'rename-window notify-renamed'
|
||||
wait_for "%window-renamed $wid notify-renamed" || exit 1
|
||||
|
||||
send 'split-window -h'
|
||||
wait_for "%layout-change $wid " || exit 1
|
||||
|
||||
send 'select-pane -t:.0'
|
||||
wait_for "%window-pane-changed $wid $pane" || exit 1
|
||||
|
||||
send 'copy-mode -t:.0'
|
||||
wait_for "%pane-mode-changed $pane" || exit 1
|
||||
|
||||
sessions_changed=$(grep -F -- '%sessions-changed' "$OUT" 2>/dev/null | \
|
||||
wc -l)
|
||||
send 'new-session -d -s notify-extra'
|
||||
wait_for_count '%sessions-changed' $((sessions_changed + 1)) || exit 1
|
||||
|
||||
send 'kill-session -t notify-extra'
|
||||
wait_for_count '%sessions-changed' $((sessions_changed + 2)) || exit 1
|
||||
|
||||
exit 0
|
||||
@@ -63,10 +63,10 @@ $TMUX new -d -s two || fail "new-session two failed"
|
||||
# An after hook fires with the command arguments as formats.
|
||||
$TMUX set -g @after 0 || fail "set @after failed"
|
||||
$TMUX set-hook -g after-rename-window \
|
||||
'set -gF @after "#{hook}|#{hook_argument_0}|#{hook_flag_t}"' ||
|
||||
'set -gF @after "#{hook}|#{hook_arguments}|#{hook_argument_0}|#{hook_flag_t}"' ||
|
||||
fail "set-hook -g after-rename-window failed"
|
||||
$TMUX rename-window -t one:0 first || fail "rename-window first failed"
|
||||
wait_for @after 'after-rename-window|first|one:0'
|
||||
wait_for @after 'after-rename-window|-t one:0 first|first|one:0'
|
||||
|
||||
# An appended hook command runs after the first.
|
||||
$TMUX set -g @after2 0 || fail "set @after2 failed"
|
||||
@@ -74,10 +74,32 @@ $TMUX set-hook -ga after-rename-window \
|
||||
'set -gF @after2 "#{@after}+2"' ||
|
||||
fail "set-hook -ga after-rename-window failed"
|
||||
$TMUX rename-window -t one:0 second || fail "rename-window second failed"
|
||||
wait_for @after 'after-rename-window|second|one:0'
|
||||
wait_for @after2 'after-rename-window|second|one:0+2'
|
||||
wait_for @after 'after-rename-window|-t one:0 second|second|one:0'
|
||||
wait_for @after2 'after-rename-window|-t one:0 second|second|one:0+2'
|
||||
$TMUX set-hook -gu after-rename-window || fail "set-hook -gu failed"
|
||||
|
||||
# A hook command is inserted after the command that fired it, before the next
|
||||
# command in the same command list.
|
||||
$TMUX set -g @order '' || fail "set @order failed"
|
||||
$TMUX set-hook -g after-rename-window \
|
||||
'set -gF @order "#{@order}H"' ||
|
||||
fail "set-hook -g after-rename-window order failed"
|
||||
$TMUX rename-window -t one:0 ordered \; set -gF @order '#{@order}N' ||
|
||||
fail "rename-window order failed"
|
||||
wait_for @order 'HN'
|
||||
$TMUX set-hook -gu after-rename-window || fail "set-hook -gu order failed"
|
||||
|
||||
# Repeated flag values are available as numbered hook flag formats.
|
||||
$TMUX set -g @flags 0 || fail "set @flags failed"
|
||||
$TMUX set-hook -g after-split-window \
|
||||
'set -gF @flags "#{hook_arguments}|#{hook_argument_0}|#{hook_flag_t}|#{hook_flag_e}|#{hook_flag_e_0}|#{hook_flag_e_1}"' ||
|
||||
fail "set-hook -g after-split-window failed"
|
||||
$TMUX split-window -d -t one:0 -e A=1 -e B=2 'sleep 60' ||
|
||||
fail "split-window flags failed"
|
||||
wait_for @flags '-d -e A=1 -e B=2 -t one:0 "sleep 60"|sleep 60|one:0|B=2|A=1|B=2'
|
||||
$TMUX set-hook -gu after-split-window ||
|
||||
fail "set-hook -gu after-split-window failed"
|
||||
|
||||
# A session after hook only fires for commands targeting that session and
|
||||
# the hook commands run with the command target as current state.
|
||||
$TMUX set -g @safter 0 || fail "set @safter failed"
|
||||
|
||||
@@ -96,6 +96,20 @@ fi
|
||||
$TMUX list-panes -sat main >/dev/null || fail "list-panes failed"
|
||||
$TMUX has -t main || fail "server died after pane exit chain"
|
||||
|
||||
# A pane-exited hook command can run after the pane has been removed. It
|
||||
# should not retain only the event payload's temporary target references.
|
||||
$TMUX set -g @queued-pane-exited 0 || fail "set @queued-pane-exited failed"
|
||||
$TMUX set-hook -g pane-exited \
|
||||
'display-message -p "queued #{hook_pane}" ; set -g @queued-pane-exited 1' ||
|
||||
fail "set-hook queued pane-exited failed"
|
||||
pane=$($TMUX new -d -s queued -n qwin -P -F '#{pane_id}' 'true') ||
|
||||
fail "new-session queued failed"
|
||||
wait_for @queued-pane-exited 1
|
||||
$TMUX has -t main || fail "server died after queued pane-exited hook"
|
||||
$TMUX set-hook -g pane-exited \
|
||||
'set -gF @log "#{@log}|pane-exited:#{hook_pane}"' ||
|
||||
fail "restore pane-exited hook failed"
|
||||
|
||||
# kill-window on the last window: window-unlinked then session-closed but
|
||||
# no pane-exited for the panes in the killed window.
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
|
||||
@@ -181,6 +181,99 @@ $TMUX set-hook -gu pane-title-changed ||
|
||||
fail "unset pane-title-changed failed"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane title failed"
|
||||
|
||||
# pane-created payload from a command pane, an empty pane, and a respawn.
|
||||
$TMUX set -g @pc 0 || fail "set @pc failed"
|
||||
$TMUX set-hook -g pane-created \
|
||||
'set -gF @pc "#{hook}:#{hook_pane}:#{hook_pane_command}:#{hook_created_empty}:#{hook_created_respawn}"' ||
|
||||
fail "set-hook pane-created failed"
|
||||
pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') ||
|
||||
fail "split-window pane-created command failed"
|
||||
wait_for @pc "pane-created:$pane:\"sleep 30\":0:0"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane pane-created command failed"
|
||||
|
||||
$TMUX set -g @pc 0 || fail "reset @pc failed"
|
||||
empty_command=$($TMUX show -gqv default-shell) ||
|
||||
fail "show default-shell failed"
|
||||
pane=$($TMUX splitw -d -E -t main:0 -P -F '#{pane_id}') ||
|
||||
fail "split-window pane-created empty failed"
|
||||
wait_for @pc "pane-created:$pane:$empty_command:1:0"
|
||||
|
||||
$TMUX set -g @pc 0 || fail "reset @pc respawn failed"
|
||||
$TMUX respawnp -k -t "$pane" 'sleep 30' || fail "respawn-pane failed"
|
||||
wait_for @pc "pane-created:$pane:\"sleep 30\":0:1"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane pane-created respawn failed"
|
||||
$TMUX set-hook -gu pane-created || fail "unset pane-created failed"
|
||||
|
||||
# pane-resized carries old and new dimensions.
|
||||
pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') ||
|
||||
fail "split-window pane-resized failed"
|
||||
old_size=$($TMUX display -pt "$pane" '#{pane_width},#{pane_height}') ||
|
||||
fail "display old pane size failed"
|
||||
$TMUX set -g @pr 0 || fail "set @pr failed"
|
||||
$TMUX set-hook -g pane-resized \
|
||||
'set -gF @pr "#{hook}:#{hook_pane}:#{hook_old_width},#{hook_old_height}->#{hook_width},#{hook_height}"' ||
|
||||
fail "set-hook pane-resized failed"
|
||||
$TMUX resizep -t "$pane" -x 20 -y 10 || fail "resize-pane failed"
|
||||
new_size=$($TMUX display -pt "$pane" '#{pane_width},#{pane_height}') ||
|
||||
fail "display new pane size failed"
|
||||
wait_for @pr "pane-resized:$pane:$old_size->$new_size"
|
||||
$TMUX set-hook -gu pane-resized || fail "unset pane-resized failed"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane pane-resized failed"
|
||||
|
||||
# pane-mode-entered and pane-mode-exited expose split transition payloads.
|
||||
$TMUX set -g @me 0 || fail "set @me failed"
|
||||
$TMUX set -g @mx 0 || fail "set @mx failed"
|
||||
pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') ||
|
||||
fail "split-window pane-mode failed"
|
||||
$TMUX set-hook -g pane-mode-entered \
|
||||
'set -gF @me "#{hook}:#{hook_pane}:#{hook_mode_entered}:#{hook_current_mode}:#{hook_previous_mode}"' ||
|
||||
fail "set-hook pane-mode-entered failed"
|
||||
$TMUX set-hook -g pane-mode-exited \
|
||||
'set -gF @mx "#{hook}:#{hook_pane}:#{hook_mode_entered}:#{hook_current_mode}:#{hook_previous_mode}"' ||
|
||||
fail "set-hook pane-mode-exited failed"
|
||||
$TMUX copy-mode -t "$pane" || fail "copy-mode split event failed"
|
||||
wait_for @me "pane-mode-entered:$pane:1:copy-mode:"
|
||||
$TMUX send-keys -t "$pane" -X cancel || fail "cancel split mode failed"
|
||||
wait_for @mx "pane-mode-exited:$pane:0::copy-mode"
|
||||
$TMUX set-hook -gu pane-mode-entered || fail "unset pane-mode-entered failed"
|
||||
$TMUX set-hook -gu pane-mode-exited || fail "unset pane-mode-exited failed"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane pane-mode failed"
|
||||
|
||||
# marked-pane-changed carries the new/old marked pane and marked flag.
|
||||
$TMUX set -g @mk 0 || fail "set @mk failed"
|
||||
pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') ||
|
||||
fail "split-window marked-pane failed"
|
||||
$TMUX set-hook -g marked-pane-changed \
|
||||
'set -gF @mk "#{hook}:#{hook_marked}:#{hook_pane}:#{hook_new_pane}:#{hook_old_pane}"' ||
|
||||
fail "set-hook marked-pane-changed failed"
|
||||
$TMUX selectp -t "$pane" -m || fail "mark pane failed"
|
||||
wait_for @mk "marked-pane-changed:1:$pane:$pane:"
|
||||
$TMUX selectp -t "$pane" -m || fail "unmark pane failed"
|
||||
wait_for @mk "marked-pane-changed:0:$pane::$pane"
|
||||
$TMUX set-hook -gu marked-pane-changed ||
|
||||
fail "unset marked-pane-changed failed"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane marked-pane failed"
|
||||
|
||||
# window-zoomed and window-unzoomed fire on resize-pane -Z.
|
||||
$TMUX set -g @zoom 0 || fail "set @zoom failed"
|
||||
pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'sleep 30') ||
|
||||
fail "split-window zoom failed"
|
||||
window=$($TMUX display -pt "$pane" '#{window_id}') ||
|
||||
fail "display zoom window failed"
|
||||
$TMUX set-hook -g window-zoomed \
|
||||
'set -gF @zoom "#{hook}:#{hook_window}"' ||
|
||||
fail "set-hook window-zoomed failed"
|
||||
$TMUX set-hook -g window-unzoomed \
|
||||
'set -gF @zoom "#{hook}:#{hook_window}"' ||
|
||||
fail "set-hook window-unzoomed failed"
|
||||
$TMUX resizep -Z -t "$pane" || fail "zoom pane failed"
|
||||
wait_for @zoom "window-zoomed:$window"
|
||||
$TMUX resizep -Z -t "$pane" || fail "unzoom pane failed"
|
||||
wait_for @zoom "window-unzoomed:$window"
|
||||
$TMUX set-hook -gu window-zoomed || fail "unset window-zoomed failed"
|
||||
$TMUX set-hook -gu window-unzoomed || fail "unset window-unzoomed failed"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane zoom failed"
|
||||
|
||||
# client-attached and client-detached using a control client.
|
||||
$TMUX set -g @a 0 || fail "set @a failed"
|
||||
$TMUX set-hook -g client-attached 'set -gF @a "#{hook}"' ||
|
||||
|
||||
@@ -36,6 +36,21 @@ check_value()
|
||||
fi
|
||||
}
|
||||
|
||||
check_wait_value()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 30 ]; do
|
||||
out=$($TMUX show $1 2>&1)
|
||||
[ "$out" = "$2" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
echo "show $1 failed."
|
||||
echo "Expected: '$2'"
|
||||
echo "But got: '$out'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# check_array $args $expected
|
||||
#
|
||||
# Compare the full (multi-line) show output for an array option with a
|
||||
@@ -162,6 +177,39 @@ check_ok set-hook -g window-renamed[notify] "display-message renamed"
|
||||
check_value "-gv window-renamed[notify]" "display-message renamed"
|
||||
check_ok set-hook -gu window-renamed[notify]
|
||||
check_value "-gv window-renamed[notify]" ""
|
||||
check_ok set -g @hook_first 0
|
||||
check_ok set -g @hook_second 0
|
||||
check_ok set-hook -g window-renamed[first] "set -g @hook_first 1"
|
||||
check_ok set-hook -g window-renamed[second] "set -g @hook_second 1"
|
||||
shown=$($TMUX show-hooks -g window-renamed) || {
|
||||
echo "show-hooks -g window-renamed failed"
|
||||
exit 1
|
||||
}
|
||||
echo "$shown" | grep -q '^window-renamed\[first\]' || {
|
||||
echo "missing first hook key: $shown"
|
||||
exit 1
|
||||
}
|
||||
echo "$shown" | grep -q '^window-renamed\[second\]' || {
|
||||
echo "missing second hook key: $shown"
|
||||
exit 1
|
||||
}
|
||||
check_ok rename-window -t main:0 array-hooks
|
||||
check_wait_value "-gqv @hook_first" "1"
|
||||
check_wait_value "-gqv @hook_second" "1"
|
||||
check_ok set-hook -gu window-renamed[first]
|
||||
shown=$($TMUX show-hooks -g window-renamed) || {
|
||||
echo "show-hooks -g window-renamed after unset failed"
|
||||
exit 1
|
||||
}
|
||||
echo "$shown" | grep -q '^window-renamed\[first\]' && {
|
||||
echo "first hook key was not unset: $shown"
|
||||
exit 1
|
||||
}
|
||||
echo "$shown" | grep -q '^window-renamed\[second\]' || {
|
||||
echo "second hook key did not remain: $shown"
|
||||
exit 1
|
||||
}
|
||||
check_ok set-hook -gu window-renamed[second]
|
||||
|
||||
# --- colour-type array ----------------------------------------------------
|
||||
#
|
||||
|
||||
@@ -49,6 +49,19 @@ status_line() {
|
||||
got() {
|
||||
$IN show -gv @r
|
||||
}
|
||||
wait_opt() {
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($IN show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
reset() {
|
||||
$IN set -g @r "SENTINEL" || exit 1
|
||||
}
|
||||
@@ -85,6 +98,12 @@ $IN bind -n M-j command-prompt -P -I hello -p '(pre)' "set -g @r '%%'" || e
|
||||
$IN bind -n M-m command-prompt -p 'first,second' "set -g @r '%1/%2'" || exit 1
|
||||
$IN bind -n M-c command-prompt -p '(cmd)' "set -g @r '%%'" || exit 1
|
||||
$IN bind -n M-h command-prompt -T search -p '(srch)' "set -g @r '%%'" || exit 1
|
||||
$IN set-hook -g pane-prompt-opened \
|
||||
'set -gF @prompt_open "#{hook}:#{hook_pane}:#{hook_prompt_type}"' ||
|
||||
exit 1
|
||||
$IN set-hook -g pane-prompt-closed \
|
||||
'set -gF @prompt_close "#{hook}:#{hook_pane}:#{hook_prompt_type}"' ||
|
||||
exit 1
|
||||
|
||||
# --- Outer session: attach the inner one inside its pane. -------------------
|
||||
$OUT new -d -x80 -y24 || exit 1
|
||||
@@ -111,14 +130,17 @@ settle
|
||||
|
||||
# --- 1b. window.c: drawn over the pane, not on the status line. ---
|
||||
reset
|
||||
pane=$($IN display-message -p '#{pane_id}') || exit 1
|
||||
$OUT send-keys M-p || exit 1
|
||||
settle
|
||||
wait_opt @prompt_open "pane-prompt-opened:$pane:command"
|
||||
capture | grep -qF '(pane)' || fail "pane prompt not drawn in the pane"
|
||||
status_line | grep -qF '(pane)' && \
|
||||
fail "pane prompt drawn on the status line, not over the pane"
|
||||
$OUT send-keys -l "deep" || exit 1
|
||||
$OUT send-keys Enter || exit 1
|
||||
settle
|
||||
wait_opt @prompt_close "pane-prompt-closed:$pane:command"
|
||||
[ "$(got)" = "deep" ] || fail "pane prompt accept recovered '$(got)', wanted 'deep'"
|
||||
|
||||
# --- 1c. mode-tree.c: search prompt drawn in the pane. ---
|
||||
|
||||
10
regress/set-hook-B.sh
Executable file → Normal file
10
regress/set-hook-B.sh
Executable file → Normal file
@@ -147,4 +147,14 @@ $TMUX set -pt "$target_pane" @target-value changed ||
|
||||
fail "set pane @target-value failed"
|
||||
wait_for @target-pane "$target_pane"
|
||||
|
||||
$TMUX new -d -s zzz-survivor || fail "new survivor session failed"
|
||||
$TMUX set -g @global-after-destroy 0 ||
|
||||
fail "set @global-after-destroy failed"
|
||||
$TMUX set-hook -g -t three -B '@global-after-destroy-session::#{session_name}' \
|
||||
'set -g @global-after-destroy "#{hook_last}->#{hook_value}"' ||
|
||||
fail "set-hook -B global after destroy failed"
|
||||
assert_unchanged @global-after-destroy 0
|
||||
$TMUX kill-session -t three || fail "kill destroyed monitor session failed"
|
||||
wait_for @global-after-destroy 'three->zzz-survivor'
|
||||
|
||||
exit 0
|
||||
|
||||
150
regress/set-hook-E.sh
Executable file
150
regress/set-hook-E.sh
Executable file
@@ -0,0 +1,150 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_channel()
|
||||
{
|
||||
channel=$1
|
||||
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 10 $TMUX wait-for "$channel" ||
|
||||
fail "wait-for $channel timed out"
|
||||
return
|
||||
fi
|
||||
|
||||
$TMUX wait-for "$channel" &
|
||||
pid=$!
|
||||
i=0
|
||||
while kill -0 "$pid" 2>/dev/null; do
|
||||
[ $i -lt 50 ] || {
|
||||
kill "$pid" 2>/dev/null || true
|
||||
fail "wait-for $channel timed out"
|
||||
}
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
wait "$pid" || fail "wait-for $channel failed"
|
||||
}
|
||||
|
||||
wait_for()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
assert_unchanged()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
count=${3:-15}
|
||||
i=0
|
||||
|
||||
while [ $i -lt "$count" ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] ||
|
||||
fail "expected $option to remain '$expected' but got '$value'"
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
wait_list()
|
||||
{
|
||||
name=$1
|
||||
i=0
|
||||
|
||||
while [ $i -lt 50 ]; do
|
||||
value=$($TMUX wait-for -E -l "$name" 2>/dev/null || true)
|
||||
if [ -n "$value" ]; then
|
||||
printf '%s\n' "$value" | sed -n '1p'
|
||||
return
|
||||
fi
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "wait-for -E -l $name found no waiters"
|
||||
}
|
||||
|
||||
$TMUX new -d -s one || fail "new-session one failed"
|
||||
$TMUX new -d -s two || fail "new-session two failed"
|
||||
|
||||
$TMUX set -g @event_seen 0 || fail "set @event_seen failed"
|
||||
$TMUX wait-for -E @manual-event \; set -g @event_seen 1 \; \
|
||||
wait-for -S she-event &
|
||||
event_pid=$!
|
||||
wait_list @manual-event >/dev/null
|
||||
|
||||
$TMUX set-hook -E @manual-event || fail "set-hook -E @manual-event failed"
|
||||
wait_channel she-event
|
||||
wait "$event_pid" || fail "wait-for -E @manual-event failed"
|
||||
wait_for @event_seen 1
|
||||
|
||||
$TMUX set-hook -E @no-sink || fail "set-hook -E @no-sink failed"
|
||||
|
||||
pane=$($TMUX display -pt two:0.0 '#{pane_id}') ||
|
||||
fail "display-message pane failed"
|
||||
$TMUX set -g @hook_seen 0 || fail "set @hook_seen failed"
|
||||
$TMUX set-hook -g @manual-hook \
|
||||
'set -gF @hook_seen "#{hook}:#{session_name}:#{window_index}:#{pane_id}"' ||
|
||||
fail "set-hook @manual-hook failed"
|
||||
|
||||
$TMUX set-hook -E -t two:0.0 @manual-hook ||
|
||||
fail "set-hook -E @manual-hook failed"
|
||||
wait_for @hook_seen "@manual-hook:two:0:$pane"
|
||||
|
||||
$TMUX set -g @r_hook 0 || fail "set @r_hook failed"
|
||||
$TMUX set -g @r_event 0 || fail "set @r_event failed"
|
||||
$TMUX set-hook -g @manual-r 'set -g @r_hook 1' ||
|
||||
fail "set-hook @manual-r failed"
|
||||
$TMUX wait-for -E @manual-r \; set -g @r_event 1 \; wait-for -S she-r &
|
||||
r_pid=$!
|
||||
r_client=$(wait_list @manual-r)
|
||||
|
||||
$TMUX set-hook -R @manual-r || fail "set-hook -R @manual-r failed"
|
||||
wait_for @r_hook 1
|
||||
assert_unchanged @r_event 0 5
|
||||
|
||||
$TMUX wait-for -E -w "$r_client" @manual-r ||
|
||||
fail "wait-for -E -w @manual-r failed"
|
||||
wait_channel she-r
|
||||
wait "$r_pid" || fail "wait-for -E @manual-r failed"
|
||||
|
||||
if $TMUX set-hook -E window-renamed 2>/dev/null; then
|
||||
fail "set-hook -E window-renamed succeeded"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
206
regress/wait-for-E.sh
Normal file
206
regress/wait-for-E.sh
Normal file
@@ -0,0 +1,206 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_channel()
|
||||
{
|
||||
channel=$1
|
||||
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 10 $TMUX wait-for "$channel" ||
|
||||
fail "wait-for $channel timed out"
|
||||
return
|
||||
fi
|
||||
|
||||
$TMUX wait-for "$channel" &
|
||||
pid=$!
|
||||
i=0
|
||||
while kill -0 "$pid" 2>/dev/null; do
|
||||
[ $i -lt 50 ] || {
|
||||
kill "$pid" 2>/dev/null || true
|
||||
fail "wait-for $channel timed out"
|
||||
}
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
wait "$pid" || fail "wait-for $channel failed"
|
||||
}
|
||||
|
||||
assert_unchanged()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
count=${3:-15}
|
||||
i=0
|
||||
|
||||
while [ $i -lt "$count" ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] ||
|
||||
fail "expected $option to remain '$expected' but got '$value'"
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
wait_list()
|
||||
{
|
||||
event=$1
|
||||
name=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 50 ]; do
|
||||
if [ "$event" = 1 ]; then
|
||||
value=$($TMUX wait-for -E -l "$name" 2>/dev/null || true)
|
||||
else
|
||||
value=$($TMUX wait-for -l "$name" 2>/dev/null || true)
|
||||
fi
|
||||
if [ -n "$value" ]; then
|
||||
printf '%s\n' "$value" | sed -n '1p'
|
||||
return
|
||||
fi
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "wait-for -l $name found no waiters"
|
||||
}
|
||||
|
||||
$TMUX new -d -s wf || fail "new-session failed"
|
||||
|
||||
$TMUX wait-for wf-list &
|
||||
list_pid=$!
|
||||
client=$(wait_list 0 wf-list)
|
||||
$TMUX wait-for -w "$client" wf-list || fail "wait-for -w wf-list failed"
|
||||
wait "$list_pid" || fail "wait-for -w did not wake channel waiter"
|
||||
|
||||
$TMUX set -g @forced 0 || fail "set @forced failed"
|
||||
$TMUX wait-for -E @forced-event \; set -g @forced 1 &
|
||||
forced_pid=$!
|
||||
client=$(wait_list 1 @forced-event)
|
||||
$TMUX wait-for -E -w "$client" @forced-event ||
|
||||
fail "wait-for -E -w @forced-event failed"
|
||||
wait "$forced_pid" || fail "wait-for -E -w did not wake event waiter"
|
||||
[ "$($TMUX show -gqv @forced)" = 1 ] ||
|
||||
fail "wait-for -E -w did not continue event waiter"
|
||||
|
||||
if $TMUX wait-for -E foobar 2>/dev/null; then
|
||||
fail "wait-for -E accepted invalid event"
|
||||
fi
|
||||
|
||||
$TMUX wait-for -E @not-yet-fired &
|
||||
not_yet_pid=$!
|
||||
client=$(wait_list 1 @not-yet-fired)
|
||||
$TMUX wait-for -E -w "$client" @not-yet-fired ||
|
||||
fail "wait-for -E -w @not-yet-fired failed"
|
||||
wait "$not_yet_pid" || fail "wait-for -E @not-yet-fired failed"
|
||||
|
||||
$TMUX set -g @wf_value 0 || fail "set @wf_value failed"
|
||||
$TMUX set-hook -g -B '@wf::#{@wf_value}' 'wait-for -S wf-hook' ||
|
||||
fail "set-hook -B failed"
|
||||
|
||||
$TMUX wait-for -E @wf \; wait-for -S wf-event &
|
||||
event_pid=$!
|
||||
|
||||
# Let the monitor take its first sample so the next change is reported.
|
||||
sleep 1.5
|
||||
|
||||
$TMUX set -g @wf_value 1 || fail "set @wf_value 1 failed"
|
||||
|
||||
wait_channel wf-event
|
||||
wait_channel wf-hook
|
||||
wait "$event_pid" || fail "wait-for -E command failed"
|
||||
|
||||
$TMUX set -g @late 0 || fail "set @late failed"
|
||||
$TMUX wait-for -E @wf \; set -g @late 1 \; wait-for -S wf-late &
|
||||
late_pid=$!
|
||||
assert_unchanged @late 0 5
|
||||
|
||||
$TMUX set -g @wf_value 2 || fail "set @wf_value 2 failed"
|
||||
wait_channel wf-late
|
||||
wait "$late_pid" || fail "late wait-for -E command failed"
|
||||
|
||||
$TMUX set -g @filtered 0 || fail "set @filtered failed"
|
||||
$TMUX wait-for -E -F '#{==:#{value},3}' @wf \; set -g @filtered 1 \; \
|
||||
wait-for -S wf-filtered &
|
||||
filtered_pid=$!
|
||||
assert_unchanged @filtered 0 5
|
||||
|
||||
$TMUX set -g @wf_value unmatched || fail "set @wf_value unmatched failed"
|
||||
assert_unchanged @filtered 0 5
|
||||
|
||||
$TMUX set -g @wf_value 3 || fail "set @wf_value 3 failed"
|
||||
wait_channel wf-filtered
|
||||
wait "$filtered_pid" || fail "filtered wait-for -E command failed"
|
||||
|
||||
verbose_file="$OUT/verbose"
|
||||
$TMUX wait-for -E -v @wf \; wait-for -S wf-verbose >"$verbose_file" &
|
||||
verbose_pid=$!
|
||||
|
||||
sleep 0.5
|
||||
$TMUX set -g @wf_value 4 || fail "set @wf_value 4 failed"
|
||||
wait_channel wf-verbose
|
||||
wait "$verbose_pid" || fail "verbose wait-for -E command failed"
|
||||
grep '^event=@wf$' "$verbose_file" >/dev/null ||
|
||||
fail "verbose wait-for -E did not print event payload"
|
||||
grep '^value=4$' "$verbose_file" >/dev/null ||
|
||||
fail "verbose wait-for -E did not print value payload"
|
||||
grep '^_hook_monitor=' "$verbose_file" >/dev/null &&
|
||||
fail "verbose wait-for -E printed private payload"
|
||||
|
||||
$TMUX new -d -s wf2 || fail "new-session wf2 failed"
|
||||
|
||||
$TMUX wait-for -E window-renamed \; wait-for -S wf-renamed &
|
||||
renamed_pid=$!
|
||||
|
||||
sleep 0.5
|
||||
$TMUX rename-window -t wf2:0 renamed || fail "rename-window failed"
|
||||
wait_channel wf-renamed
|
||||
wait "$renamed_pid" || fail "wait-for -E window-renamed failed"
|
||||
|
||||
$TMUX set-hook -g window-renamed 'wait-for -S wf-hook-renamed' ||
|
||||
fail "set-hook window-renamed failed"
|
||||
$TMUX rename-window -t wf2:0 renamed-again ||
|
||||
fail "rename-window renamed-again failed"
|
||||
wait_channel wf-hook-renamed
|
||||
|
||||
$TMUX set -g @builtin_filtered 0 || fail "set @builtin_filtered failed"
|
||||
target=$($TMUX splitw -d -t wf2:0 -P -F '#{pane_id}' 'sleep 30') ||
|
||||
fail "split-window target failed"
|
||||
$TMUX wait-for -E -F "#{==:#{pane},$target}" pane-exited \; \
|
||||
set -g @builtin_filtered 1 \; wait-for -S wf-builtin-filtered &
|
||||
builtin_filtered_pid=$!
|
||||
assert_unchanged @builtin_filtered 0 5
|
||||
|
||||
$TMUX splitw -d -t wf2:0 'true' || fail "split-window nonmatching failed"
|
||||
assert_unchanged @builtin_filtered 0 5
|
||||
|
||||
$TMUX send-keys -t "$target" C-c || fail "send C-c to target failed"
|
||||
wait_channel wf-builtin-filtered
|
||||
wait "$builtin_filtered_pid" ||
|
||||
fail "filtered wait-for -E pane-exited command failed"
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user