Update some tests and improve Makefile.

This commit is contained in:
Nicholas Marriott
2026-07-06 10:00:26 +01:00
parent 6a6822b906
commit 501e8da925
6 changed files with 244 additions and 119 deletions

View File

@@ -77,3 +77,11 @@ jobs:
cd regress cd regress
export ASAN_OPTIONS="abort_on_error=1:detect_leaks=0" export ASAN_OPTIONS="abort_on_error=1:detect_leaks=0"
${{ matrix.make }} ${{ matrix.make }}
- name: upload regress logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: regress-logs-${{ matrix.name }}
path: regress/logs/*.log
if-no-files-found: ignore

1
.gitignore vendored
View File

@@ -21,6 +21,7 @@ configure
core core
etc/ etc/
fuzz/*-fuzzer fuzz/*-fuzzer
regress/logs/
tags tags
tmux tmux
tmux.1.* tmux.1.*

View File

@@ -1,22 +1,30 @@
TESTS!= echo *.sh TESTS!= echo *.sh
LOGDIR=logs
.PHONY: all $(TESTS) .PHONY: all
.NOTPARALLEL: all $(TESTS) .NOTPARALLEL: all
all: all:
@failed=0; failures=; \ @mkdir -p "$(LOGDIR)"; \
rm -f "$(LOGDIR)"/*.log; \
failed=0; failures=; \
for test in $(TESTS); do \ for test in $(TESTS); do \
base=$${test##*/}; \
log="$(LOGDIR)/$${base%.sh}.log"; \
rm -f "$$log"; \
printf '%-40s ' "$$test"; \ printf '%-40s ' "$$test"; \
start=$$(date +%s); \ start=$$(date +%s); \
ASAN_OPTIONS="abort_on_error=1:detect_leaks=0:$$ASAN_OPTIONS"; \ ASAN_OPTIONS="abort_on_error=1:detect_leaks=0:$$ASAN_OPTIONS"; \
env -i LC_CTYPE=C.UTF-8 ASAN_OPTIONS="$$ASAN_OPTIONS" \ env -i LC_CTYPE=C.UTF-8 ASAN_OPTIONS="$$ASAN_OPTIONS" \
sh "$$test" >/dev/null 2>&1; \ sh -x "$$test" >"$$log" 2>&1; \
if [ $$? -eq 0 ]; then \ if [ $$? -eq 0 ]; then \
end=$$(date +%s); \ end=$$(date +%s); \
rm -f "$$log"; \
echo "PASS ($$((end - start))s)"; \ echo "PASS ($$((end - start))s)"; \
else \ else \
end=$$(date +%s); \ end=$$(date +%s); \
echo "FAIL ($$((end - start))s)"; \ echo "FAIL ($$((end - start))s)"; \
echo " log: $$log"; \
failed=1; \ failed=1; \
failures="$$failures $$test"; \ failures="$$failures $$test"; \
fi; \ fi; \
@@ -28,9 +36,7 @@ all:
for test in $$failures; do \ for test in $$failures; do \
echo " $$test"; \ echo " $$test"; \
done; \ done; \
else \
rmdir "$(LOGDIR)" 2>/dev/null || true; \
fi; \ fi; \
exit $$failed exit $$failed
$(TESTS):
sh $@
sleep 1

View File

@@ -17,18 +17,23 @@ PATH=/bin:/usr/bin
TERM=screen TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) [ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest -f/dev/null" TMP=$(mktemp -d) || exit 1
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null" TMUX_TMPDIR="$TMP"
export TMUX_TMPDIR
TMUX="$TEST_TMUX -Ltest$$ -f/dev/null"
TMUX2="$TEST_TMUX -Ltest2$$ -f/dev/null"
cleanup() cleanup()
{ {
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
$TMUX2 kill-server 2>/dev/null $TMUX2 kill-server 2>/dev/null
rm -rf "$TMP"
} }
trap cleanup EXIT
fail() fail()
{ {
echo "$1" echo "$1" >&2
cleanup
exit 1 exit 1
} }
@@ -46,16 +51,33 @@ wait_for()
{ {
i=0 i=0
while [ "$i" -lt 50 ]; do while [ "$i" -lt 50 ]; do
if capture | grep -q "$1"; then CAPTURED=$(capture)
sleep 0.5 if echo "$CAPTURED" | grep -q "$1"; then
return 0 return 0
fi fi
sleep 0.5 sleep 0.2
i=$((i + 1)) i=$((i + 1))
done done
fail "timed out waiting for '$1'" fail "timed out waiting for '$1'"
} }
# wait_count $marker $n
#
# Wait (up to ~10s) until exactly $n rendered lines contain $marker. The
# matching capture is left in CAPTURED.
wait_count()
{
i=0
while [ "$i" -lt 50 ]; do
CAPTURED=$(capture)
c=$(echo "$CAPTURED" | grep -c "$1")
[ "$c" -eq "$2" ] && return 0
sleep 0.2
i=$((i + 1))
done
fail "timed out waiting for $2 lines of '$1' (have $c)"
}
# wait_buffers $n # wait_buffers $n
# #
# Wait (up to ~10s) until the test server has exactly $n paste buffers. # Wait (up to ~10s) until the test server has exactly $n paste buffers.
@@ -86,8 +108,30 @@ wait_clients()
return 1 return 1
} }
$TMUX kill-server 2>/dev/null # wait_mode $target $state
$TMUX2 kill-server 2>/dev/null #
# Wait (up to ~10s) until a pane enters or leaves mode.
wait_mode()
{
t=$1
want=$2
i=0
while [ "$i" -lt 50 ]; do
got=$($TMUX display-message -p -t "$t" '#{pane_in_mode}' \
2>/dev/null)
[ "$got" = "$want" ] && return 0
sleep 0.2
i=$((i + 1))
done
fail "pane $t mode state is $got, expected $want"
}
exit_mode()
{
$TMUX send-keys -t aaa:0 "$@" || fail "send-keys $* failed"
wait_mode aaa:0 0
}
$TMUX new-session -d -s aaa -x 80 -y 24 || exit 1 $TMUX new-session -d -s aaa -x 80 -y 24 || exit 1
@@ -100,57 +144,57 @@ $TMUX set-buffer -b bufz "other buffer" || exit 1
# --- filter by buffer name --------------------------------------------------- # --- filter by buffer name ---------------------------------------------------
$TMUX choose-buffer -t aaa:0 -F 'B1' -f '#{==:#{buffer_name},bufa}' || exit 1 $TMUX choose-buffer -t aaa:0 -F 'B1' -f '#{==:#{buffer_name},bufa}' || exit 1
wait_for 'B1' wait_count ': B1' 1
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'bufa: B1' || fail "bufa missing when it matches" echo "$out" | grep -q 'bufa: B1' || fail "bufa missing when it matches"
echo "$out" | grep -q 'bufz: B1' && fail "bufz shown but does not match" echo "$out" | grep -q 'bufz: B1' && fail "bufz shown but does not match"
[ "$(echo "$out" | grep -c ': B1')" -eq 1 ] || fail "expected 1 buffer" [ "$(echo "$out" | grep -c ': B1')" -eq 1 ] || fail "expected 1 buffer"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- filter by buffer content ------------------------------------------------ # --- filter by buffer content ------------------------------------------------
$TMUX choose-buffer -t aaa:0 -F 'B2' -f '#{m:*hello*,#{buffer_sample}}' || \ $TMUX choose-buffer -t aaa:0 -F 'B2' -f '#{m:*hello*,#{buffer_sample}}' || \
exit 1 exit 1
wait_for 'B2' wait_count ': B2' 1
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'bufa: B2' || fail "bufa missing when content matches" echo "$out" | grep -q 'bufa: B2' || fail "bufa missing when content matches"
echo "$out" | grep -q 'bufz: B2' && fail "bufz shown but content not matched" echo "$out" | grep -q 'bufz: B2' && fail "bufz shown but content not matched"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- no filter shows both buffers --------------------------------------------- # --- no filter shows both buffers ---------------------------------------------
$TMUX choose-buffer -t aaa:0 -F 'B3' || exit 1 $TMUX choose-buffer -t aaa:0 -F 'B3' || exit 1
wait_for 'B3' wait_count ': B3' 2
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'bufa: B3' || fail "bufa missing with no filter" echo "$out" | grep -q 'bufa: B3' || fail "bufa missing with no filter"
echo "$out" | grep -q 'bufz: B3' || fail "bufz missing with no filter" echo "$out" | grep -q 'bufz: B3' || fail "bufz missing with no filter"
[ "$(echo "$out" | grep -c ': B3')" -eq 2 ] || fail "expected 2 buffers" [ "$(echo "$out" | grep -c ': B3')" -eq 2 ] || fail "expected 2 buffers"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- filter matching nothing --------------------------------------------------- # --- filter matching nothing ---------------------------------------------------
# #
# Everything is shown and the filter indicator reports no matches. # Everything is shown and the filter indicator reports no matches.
$TMUX choose-buffer -t aaa:0 -F 'B4' -f '#{==:#{buffer_name},nosuch}' || \ $TMUX choose-buffer -t aaa:0 -F 'B4' -f '#{==:#{buffer_name},nosuch}' || \
exit 1 exit 1
wait_for 'B4' wait_count ': B4' 2
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'bufa: B4' || fail "bufa missing with no-match filter" echo "$out" | grep -q 'bufa: B4' || fail "bufa missing with no-match filter"
echo "$out" | grep -q 'bufz: B4' || fail "bufz missing with no-match filter" echo "$out" | grep -q 'bufz: B4' || fail "bufz missing with no-match filter"
echo "$out" | grep -q 'no matches' || fail "no matches indicator missing" echo "$out" | grep -q 'no matches' || fail "no matches indicator missing"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- sort orders --------------------------------------------------------------- # --- sort orders ---------------------------------------------------------------
# #
# By name bufa sorts first and -r reverses. # By name bufa sorts first and -r reverses.
$TMUX choose-buffer -t aaa:0 -F 'B5' -O name || exit 1 $TMUX choose-buffer -t aaa:0 -F 'B5' -O name || exit 1
wait_for 'B5' wait_count ': B5' 2
capture | grep ': B5' | head -1 | grep -q 'bufa: B5' || \ echo "$CAPTURED" | grep ': B5' | head -1 | grep -q 'bufa: B5' || \
fail "bufa not first with -O name" fail "bufa not first with -O name"
$TMUX send-keys -t aaa:0 q exit_mode q
$TMUX choose-buffer -t aaa:0 -F 'B6' -O name -r || exit 1 $TMUX choose-buffer -t aaa:0 -F 'B6' -O name -r || exit 1
wait_for 'B6' wait_count ': B6' 2
capture | grep ': B6' | head -1 | grep -q 'bufz: B6' || \ echo "$CAPTURED" | grep ': B6' | head -1 | grep -q 'bufz: B6' || \
fail "bufz not first with -O name -r" fail "bufz not first with -O name -r"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- d deletes the selected buffer -------------------------------------------- # --- d deletes the selected buffer --------------------------------------------
# #
@@ -161,16 +205,16 @@ $TMUX send-keys -t aaa:0 d
wait_buffers 1 wait_buffers 1
$TMUX list-buffers -F '#{buffer_name}' | grep -q 'bufa' || \ $TMUX list-buffers -F '#{buffer_name}' | grep -q 'bufa' || \
fail "wrong buffer deleted" fail "wrong buffer deleted"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- C-t tags all buffers and D deletes the tagged ------------------------------ # --- C-t tags all buffers and D deletes the tagged ------------------------------
$TMUX set-buffer -b bufz "other buffer" || exit 1 $TMUX set-buffer -b bufz "other buffer" || exit 1
$TMUX set-buffer -b bufb "third buffer" || exit 1 $TMUX set-buffer -b bufb "third buffer" || exit 1
$TMUX choose-buffer -t aaa:0 -F 'G2' || exit 1 $TMUX choose-buffer -t aaa:0 -F 'G2' || exit 1
wait_for ': G2' wait_count ': G2' 3
$TMUX send-keys -t aaa:0 C-t D $TMUX send-keys -t aaa:0 C-t D
wait_buffers 0 wait_buffers 0
$TMUX send-keys -t aaa:0 q exit_mode q
# --- Enter runs the default command (paste-buffer) ------------------------------ # --- Enter runs the default command (paste-buffer) ------------------------------
# #
@@ -178,22 +222,14 @@ $TMUX send-keys -t aaa:0 q
# into the shell in the pane, where it appears on the screen. # into the shell in the pane, where it appears on the screen.
$TMUX set-buffer -b bufa "hello buffer" || exit 1 $TMUX set-buffer -b bufa "hello buffer" || exit 1
$TMUX choose-buffer -t aaa:0 -F 'G3' || exit 1 $TMUX choose-buffer -t aaa:0 -F 'G3' || exit 1
wait_for 'bufa: G3' wait_count ': G3' 1
$TMUX send-keys -t aaa:0 Enter exit_mode Enter
i=0
while [ "$i" -lt 50 ]; do
[ "$($TMUX display -p -t aaa:0 '#{pane_in_mode}')" = "0" ] && break
sleep 0.5
i=$((i + 1))
done
[ "$i" -lt 50 ] || fail "mode did not exit after Enter"
i=0 i=0
while [ "$i" -lt 50 ]; do while [ "$i" -lt 50 ]; do
$TMUX capture-pane -p -t aaa:0 | grep -q 'hello buffer' && break $TMUX capture-pane -p -t aaa:0 | grep -q 'hello buffer' && break
sleep 0.5 sleep 0.2
i=$((i + 1)) i=$((i + 1))
done done
[ "$i" -lt 50 ] || fail "buffer not pasted into pane" [ "$i" -lt 50 ] || fail "buffer not pasted into pane"
cleanup
exit 0 exit 0

View File

@@ -16,18 +16,23 @@ PATH=/bin:/usr/bin
TERM=screen TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) [ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest -f/dev/null" TMP=$(mktemp -d) || exit 1
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null" TMUX_TMPDIR="$TMP"
export TMUX_TMPDIR
TMUX="$TEST_TMUX -Ltest$$ -f/dev/null"
TMUX2="$TEST_TMUX -Ltest2$$ -f/dev/null"
cleanup() cleanup()
{ {
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
$TMUX2 kill-server 2>/dev/null $TMUX2 kill-server 2>/dev/null
rm -rf "$TMP"
} }
trap cleanup EXIT
fail() fail()
{ {
echo "$1" echo "$1" >&2
cleanup
exit 1 exit 1
} }
@@ -45,16 +50,33 @@ wait_for()
{ {
i=0 i=0
while [ "$i" -lt 50 ]; do while [ "$i" -lt 50 ]; do
if capture | grep -q "$1"; then CAPTURED=$(capture)
sleep 0.5 if echo "$CAPTURED" | grep -q "$1"; then
return 0 return 0
fi fi
sleep 0.5 sleep 0.2
i=$((i + 1)) i=$((i + 1))
done done
fail "timed out waiting for '$1'" fail "timed out waiting for '$1'"
} }
# wait_count $marker $n
#
# Wait (up to ~10s) until exactly $n rendered lines contain $marker. The
# matching capture is left in CAPTURED.
wait_count()
{
i=0
while [ "$i" -lt 50 ]; do
CAPTURED=$(capture)
c=$(echo "$CAPTURED" | grep -c "$1")
[ "$c" -eq "$2" ] && return 0
sleep 0.2
i=$((i + 1))
done
fail "timed out waiting for $2 lines of '$1' (have $c)"
}
# wait_clients $n # wait_clients $n
# #
# Wait (up to ~10s) until the test server has exactly $n clients attached. # Wait (up to ~10s) until the test server has exactly $n clients attached.
@@ -70,8 +92,30 @@ wait_clients()
return 1 return 1
} }
$TMUX kill-server 2>/dev/null # wait_mode $target $state
$TMUX2 kill-server 2>/dev/null #
# Wait (up to ~10s) until a pane enters or leaves mode.
wait_mode()
{
t=$1
want=$2
i=0
while [ "$i" -lt 50 ]; do
got=$($TMUX display-message -p -t "$t" '#{pane_in_mode}' \
2>/dev/null)
[ "$got" = "$want" ] && return 0
sleep 0.2
i=$((i + 1))
done
fail "pane $t mode state is $got, expected $want"
}
exit_mode()
{
$TMUX send-keys -t aaa:0 "$@" || fail "send-keys $* failed"
wait_mode aaa:0 0
}
# One client attached to each of two sessions; the mode is displayed on the # One client attached to each of two sessions; the mode is displayed on the
# client attached to aaa (in window 0 of the outer server) and the filters # client attached to aaa (in window 0 of the outer server) and the filters
@@ -86,43 +130,43 @@ wait_clients 2 || fail "expected two clients attached to test server"
# --- filter keeping only the aaa client ------------------------------------- # --- filter keeping only the aaa client -------------------------------------
$TMUX choose-client -t aaa:0 -F 'C1=#{client_session}' \ $TMUX choose-client -t aaa:0 -F 'C1=#{client_session}' \
-f '#{==:#{client_session},aaa}' || exit 1 -f '#{==:#{client_session},aaa}' || exit 1
wait_for 'C1=' wait_count 'C1=' 1
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'C1=aaa' || fail "aaa client missing when it matches" echo "$out" | grep -q 'C1=aaa' || fail "aaa client missing when it matches"
echo "$out" | grep -q 'C1=bbb' && fail "bbb client shown but does not match" echo "$out" | grep -q 'C1=bbb' && fail "bbb client shown but does not match"
[ "$(echo "$out" | grep -c 'C1=')" -eq 1 ] || fail "expected 1 client" [ "$(echo "$out" | grep -c 'C1=')" -eq 1 ] || fail "expected 1 client"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- filter keeping only the bbb client ------------------------------------- # --- filter keeping only the bbb client -------------------------------------
$TMUX choose-client -t aaa:0 -F 'C2=#{client_session}' \ $TMUX choose-client -t aaa:0 -F 'C2=#{client_session}' \
-f '#{==:#{client_session},bbb}' || exit 1 -f '#{==:#{client_session},bbb}' || exit 1
wait_for 'C2=' wait_count 'C2=' 1
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'C2=bbb' || fail "bbb client missing when it matches" echo "$out" | grep -q 'C2=bbb' || fail "bbb client missing when it matches"
echo "$out" | grep -q 'C2=aaa' && fail "aaa client shown but does not match" echo "$out" | grep -q 'C2=aaa' && fail "aaa client shown but does not match"
[ "$(echo "$out" | grep -c 'C2=')" -eq 1 ] || fail "expected 1 client" [ "$(echo "$out" | grep -c 'C2=')" -eq 1 ] || fail "expected 1 client"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- no filter shows both clients ------------------------------------------- # --- no filter shows both clients -------------------------------------------
$TMUX choose-client -t aaa:0 -F 'C3=#{client_session}' || exit 1 $TMUX choose-client -t aaa:0 -F 'C3=#{client_session}' || exit 1
wait_for 'C3=' wait_count 'C3=' 2
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'C3=aaa' || fail "aaa client missing with no filter" echo "$out" | grep -q 'C3=aaa' || fail "aaa client missing with no filter"
echo "$out" | grep -q 'C3=bbb' || fail "bbb client missing with no filter" echo "$out" | grep -q 'C3=bbb' || fail "bbb client missing with no filter"
[ "$(echo "$out" | grep -c 'C3=')" -eq 2 ] || fail "expected 2 clients" [ "$(echo "$out" | grep -c 'C3=')" -eq 2 ] || fail "expected 2 clients"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- filter matching nothing ------------------------------------------------ # --- filter matching nothing ------------------------------------------------
# #
# Everything is shown and the filter indicator reports no matches. # Everything is shown and the filter indicator reports no matches.
$TMUX choose-client -t aaa:0 -F 'C4=#{client_session}' \ $TMUX choose-client -t aaa:0 -F 'C4=#{client_session}' \
-f '#{==:#{client_session},nosuch}' || exit 1 -f '#{==:#{client_session},nosuch}' || exit 1
wait_for 'C4=' wait_count 'C4=' 2
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'C4=aaa' || fail "aaa client missing with no-match filter" echo "$out" | grep -q 'C4=aaa' || fail "aaa client missing with no-match filter"
echo "$out" | grep -q 'C4=bbb' || fail "bbb client missing with no-match filter" echo "$out" | grep -q 'C4=bbb' || fail "bbb client missing with no-match filter"
echo "$out" | grep -q 'no matches' || fail "no matches indicator missing" echo "$out" | grep -q 'no matches' || fail "no matches indicator missing"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- Enter runs the default command (detach-client) -------------------------- # --- Enter runs the default command (detach-client) --------------------------
# #
@@ -131,10 +175,10 @@ $TMUX send-keys -t aaa:0 q
$TMUX choose-client -t aaa:0 -F 'G1=#{client_session}' \ $TMUX choose-client -t aaa:0 -F 'G1=#{client_session}' \
-f '#{==:#{client_session},bbb}' || exit 1 -f '#{==:#{client_session},bbb}' || exit 1
wait_for 'G1=bbb' wait_for 'G1=bbb'
$TMUX send-keys -t aaa:0 Enter $TMUX send-keys -t aaa:0 Enter || fail "send-keys Enter failed"
wait_clients 1 || fail "bbb client did not detach" wait_clients 1 || fail "bbb client did not detach"
wait_mode aaa:0 0
[ "$($TMUX list-clients -F '#{client_session}')" = "aaa" ] || \ [ "$($TMUX list-clients -F '#{client_session}')" = "aaa" ] || \
fail "wrong client detached" fail "wrong client detached"
cleanup
exit 0 exit 0

View File

@@ -24,18 +24,23 @@ PATH=/bin:/usr/bin
TERM=screen TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) [ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest -f/dev/null" TMP=$(mktemp -d) || exit 1
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null" TMUX_TMPDIR="$TMP"
export TMUX_TMPDIR
TMUX="$TEST_TMUX -Ltest$$ -f/dev/null"
TMUX2="$TEST_TMUX -Ltest2$$ -f/dev/null"
cleanup() cleanup()
{ {
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
$TMUX2 kill-server 2>/dev/null $TMUX2 kill-server 2>/dev/null
rm -rf "$TMP"
} }
trap cleanup EXIT
fail() fail()
{ {
echo "$1" echo "$1" >&2
cleanup
exit 1 exit 1
} }
@@ -53,11 +58,11 @@ wait_for()
{ {
i=0 i=0
while [ "$i" -lt 50 ]; do while [ "$i" -lt 50 ]; do
if capture | grep -q "$1"; then CAPTURED=$(capture)
sleep 0.5 if echo "$CAPTURED" | grep -q "$1"; then
return 0 return 0
fi fi
sleep 0.5 sleep 0.2
i=$((i + 1)) i=$((i + 1))
done done
fail "timed out waiting for '$1'" fail "timed out waiting for '$1'"
@@ -70,11 +75,13 @@ wait_count()
{ {
i=0 i=0
while [ "$i" -lt 50 ]; do while [ "$i" -lt 50 ]; do
[ "$(capture | grep -c "$1")" -eq "$2" ] && return 0 CAPTURED=$(capture)
sleep 0.5 c=$(echo "$CAPTURED" | grep -c "$1")
[ "$c" -eq "$2" ] && return 0
sleep 0.2
i=$((i + 1)) i=$((i + 1))
done done
fail "timed out waiting for $2 lines of '$1' (have $(capture | grep -c "$1"))" fail "timed out waiting for $2 lines of '$1' (have $c)"
} }
# wait_clients $n # wait_clients $n
@@ -92,8 +99,30 @@ wait_clients()
return 1 return 1
} }
$TMUX kill-server 2>/dev/null # wait_mode $target $state
$TMUX2 kill-server 2>/dev/null #
# Wait (up to ~10s) until a pane enters or leaves mode.
wait_mode()
{
t=$1
want=$2
i=0
while [ "$i" -lt 50 ]; do
got=$($TMUX display-message -p -t "$t" '#{pane_in_mode}' \
2>/dev/null)
[ "$got" = "$want" ] && return 0
sleep 0.2
i=$((i + 1))
done
fail "pane $t mode state is $got, expected $want"
}
exit_mode()
{
$TMUX send-keys -t aaa:0 "$@" || fail "send-keys $* failed"
wait_mode aaa:0 0
}
# Session zzz is created first, so it sorts first by index, and has a # Session zzz is created first, so it sorts first by index, and has a
# two-pane window 0 and a single-pane window 1. Session aaa has one window # two-pane window 0 and a single-pane window 1. Session aaa has one window
@@ -117,10 +146,10 @@ wait_clients 1 || fail "no client attached to test server"
# (session, window, pane). # (session, window, pane).
$TMUX choose-tree -t aaa:0 -F 'F1' -f '#{==:#{session_name},aaa}' || exit 1 $TMUX choose-tree -t aaa:0 -F 'F1' -f '#{==:#{session_name},aaa}' || exit 1
wait_count 'F1' 3 wait_count 'F1' 3
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'aaa: F1' || fail "aaa missing when filter matches it" echo "$out" | grep -q 'aaa: F1' || fail "aaa missing when filter matches it"
echo "$out" | grep -q 'zzz: F1' && fail "zzz shown but no pane matches" echo "$out" | grep -q 'zzz: F1' && fail "zzz shown but no pane matches"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- filter keeping only zzz ------------------------------------------------ # --- filter keeping only zzz ------------------------------------------------
# #
@@ -128,10 +157,10 @@ $TMUX send-keys -t aaa:0 q
# disappear. # disappear.
$TMUX choose-tree -t aaa:0 -F 'F2' -f '#{==:#{session_name},zzz}' || exit 1 $TMUX choose-tree -t aaa:0 -F 'F2' -f '#{==:#{session_name},zzz}' || exit 1
wait_count 'F2' 6 wait_count 'F2' 6
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'zzz: F2' || fail "zzz missing when filter matches it" echo "$out" | grep -q 'zzz: F2' || fail "zzz missing when filter matches it"
echo "$out" | grep -q 'aaa: F2' && fail "aaa shown but no pane matches" echo "$out" | grep -q 'aaa: F2' && fail "aaa shown but no pane matches"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- filter matching a single pane ------------------------------------------ # --- filter matching a single pane ------------------------------------------
# #
@@ -139,22 +168,22 @@ $TMUX send-keys -t aaa:0 q
# and that pane; zzz:1 and all of aaa must disappear. # and that pane; zzz:1 and all of aaa must disappear.
$TMUX choose-tree -t aaa:0 -F 'F3' -f '#{==:#{pane_index},1}' || exit 1 $TMUX choose-tree -t aaa:0 -F 'F3' -f '#{==:#{pane_index},1}' || exit 1
wait_count 'F3' 3 wait_count 'F3' 3
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'zzz: F3' || fail "zzz missing when its pane matches" echo "$out" | grep -q 'zzz: F3' || fail "zzz missing when its pane matches"
echo "$out" | grep -q 'aaa: F3' && fail "aaa shown but no pane matches" echo "$out" | grep -q 'aaa: F3' && fail "aaa shown but no pane matches"
echo "$out" | grep -q '1: F3' || fail "matching pane missing" echo "$out" | grep -q '1: F3' || fail "matching pane missing"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- filter matching nothing ------------------------------------------------ # --- filter matching nothing ------------------------------------------------
# #
# Everything is shown and the filter indicator reports no matches. # Everything is shown and the filter indicator reports no matches.
$TMUX choose-tree -t aaa:0 -F 'F4' -f '#{==:#{session_name},nosuch}' || exit 1 $TMUX choose-tree -t aaa:0 -F 'F4' -f '#{==:#{session_name},nosuch}' || exit 1
wait_for 'F4' wait_count 'F4' 9
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'aaa: F4' || fail "aaa missing with no-match filter" echo "$out" | grep -q 'aaa: F4' || fail "aaa missing with no-match filter"
echo "$out" | grep -q 'zzz: F4' || fail "zzz missing with no-match filter" echo "$out" | grep -q 'zzz: F4' || fail "zzz missing with no-match filter"
echo "$out" | grep -q 'no matches' || fail "no matches indicator missing" echo "$out" | grep -q 'no matches' || fail "no matches indicator missing"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- -h with the tree pane as the only match -------------------------------- # --- -h with the tree pane as the only match --------------------------------
# #
@@ -163,29 +192,29 @@ $TMUX send-keys -t aaa:0 q
$TMUX choose-tree -h -t aaa:0 -F 'F5' -f '#{==:#{session_name},aaa}' || \ $TMUX choose-tree -h -t aaa:0 -F 'F5' -f '#{==:#{session_name},aaa}' || \
exit 1 exit 1
wait_count 'F5' 2 wait_count 'F5' 2
capture | grep -q 'aaa: F5' || fail "aaa missing with -h" echo "$CAPTURED" | grep -q 'aaa: F5' || fail "aaa missing with -h"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- sort orders ------------------------------------------------------------ # --- sort orders ------------------------------------------------------------
# #
# By index zzz (created first) sorts first, by name aaa does, and -r reverses. # By index zzz (created first) sorts first, by name aaa does, and -r reverses.
$TMUX choose-tree -t aaa:0 -F 'F6' -O index || exit 1 $TMUX choose-tree -t aaa:0 -F 'F6' -O index || exit 1
wait_for 'F6' wait_count 'F6' 9
capture | grep 'F6' | head -1 | grep -q 'zzz: F6' || \ echo "$CAPTURED" | grep 'F6' | head -1 | grep -q 'zzz: F6' || \
fail "zzz not first with -O index" fail "zzz not first with -O index"
$TMUX send-keys -t aaa:0 q exit_mode q
$TMUX choose-tree -t aaa:0 -F 'F7' -O name || exit 1 $TMUX choose-tree -t aaa:0 -F 'F7' -O name || exit 1
wait_for 'F7' wait_count 'F7' 9
capture | grep 'F7' | head -1 | grep -q 'aaa: F7' || \ echo "$CAPTURED" | grep 'F7' | head -1 | grep -q 'aaa: F7' || \
fail "aaa not first with -O name" fail "aaa not first with -O name"
$TMUX send-keys -t aaa:0 q exit_mode q
$TMUX choose-tree -t aaa:0 -F 'F8' -O name -r || exit 1 $TMUX choose-tree -t aaa:0 -F 'F8' -O name -r || exit 1
wait_for 'F8' wait_count 'F8' 9
capture | grep 'F8' | head -1 | grep -q 'zzz: F8' || \ echo "$CAPTURED" | grep 'F8' | head -1 | grep -q 'zzz: F8' || \
fail "zzz not first with -O name -r" fail "zzz not first with -O name -r"
$TMUX send-keys -t aaa:0 q exit_mode q
# --- collapse and expand with h and l ----------------------------------------- # --- collapse and expand with h and l -----------------------------------------
# #
@@ -193,41 +222,43 @@ $TMUX send-keys -t aaa:0 q
# l expands it again. # l expands it again.
$TMUX choose-tree -t aaa:0 -F 'G1' -O index || exit 1 $TMUX choose-tree -t aaa:0 -F 'G1' -O index || exit 1
wait_count 'G1' 9 wait_count 'G1' 9
$TMUX send-keys -t aaa:0 g h $TMUX send-keys -t aaa:0 g h || fail "send-keys collapse failed"
wait_count 'G1' 4 wait_count 'G1' 4
$TMUX send-keys -t aaa:0 l $TMUX send-keys -t aaa:0 l || fail "send-keys expand failed"
wait_count 'G1' 9 wait_count 'G1' 9
$TMUX send-keys -t aaa:0 q exit_mode q
# --- filter entered at the prompt with f, cleared with c ---------------------- # --- filter entered at the prompt with f, cleared with c ----------------------
$TMUX choose-tree -t aaa:0 -F 'G2' -O index || exit 1 $TMUX choose-tree -t aaa:0 -F 'G2' -O index || exit 1
wait_count 'G2' 9 wait_count 'G2' 9
$TMUX send-keys -t aaa:0 f $TMUX send-keys -t aaa:0 f || fail "send-keys f failed"
$TMUX send-keys -t aaa:0 -l '#{==:#{session_name},aaa}' $TMUX send-keys -t aaa:0 -l '#{==:#{session_name},aaa}' || \
$TMUX send-keys -t aaa:0 Enter fail "send-keys filter failed"
$TMUX send-keys -t aaa:0 Enter || fail "send-keys Enter failed"
wait_count 'G2' 3 wait_count 'G2' 3
out=$(capture) out=$CAPTURED
echo "$out" | grep -q 'aaa: G2' || fail "aaa missing with prompt filter" echo "$out" | grep -q 'aaa: G2' || fail "aaa missing with prompt filter"
echo "$out" | grep -q 'zzz: G2' && fail "zzz shown with prompt filter" echo "$out" | grep -q 'zzz: G2' && fail "zzz shown with prompt filter"
$TMUX send-keys -t aaa:0 c $TMUX send-keys -t aaa:0 c || fail "send-keys c failed"
wait_count 'G2' 9 wait_count 'G2' 9
$TMUX send-keys -t aaa:0 q exit_mode q
# --- Enter runs the default command (switch-client) ---------------------------- # --- Enter runs the default command (switch-client) ----------------------------
# #
# g selects session zzz and Enter switches the client to it. # g selects session zzz and Enter switches the client to it.
$TMUX choose-tree -t aaa:0 -F 'G3' -O index || exit 1 $TMUX choose-tree -t aaa:0 -F 'G3' -O index || exit 1
wait_count 'G3' 9 wait_count 'G3' 9
$TMUX send-keys -t aaa:0 g Enter $TMUX send-keys -t aaa:0 g Enter || fail "send-keys Enter failed"
i=0 i=0
while [ "$i" -lt 50 ]; do while [ "$i" -lt 50 ]; do
[ "$($TMUX list-clients -F '#{client_session}')" = "zzz" ] && break [ "$($TMUX list-clients -F '#{client_session}')" = "zzz" ] && break
sleep 0.5 sleep 0.2
i=$((i + 1)) i=$((i + 1))
done done
[ "$i" -lt 50 ] || fail "client did not switch to zzz" [ "$i" -lt 50 ] || fail "client did not switch to zzz"
$TMUX switch-client -c "$($TMUX list-clients -F '#{client_name}')" -t aaa || \ $TMUX switch-client -c "$($TMUX list-clients -F '#{client_name}')" -t aaa || \
exit 1 exit 1
wait_mode aaa:0 0
# --- x kills the current item after confirmation ------------------------------- # --- x kills the current item after confirmation -------------------------------
# #
@@ -235,13 +266,12 @@ $TMUX switch-client -c "$($TMUX list-clients -F '#{client_name}')" -t aaa || \
# kills it, leaving zzz with one window and the tree with seven lines. # kills it, leaving zzz with one window and the tree with seven lines.
$TMUX choose-tree -t aaa:0 -F 'G4' -O index || exit 1 $TMUX choose-tree -t aaa:0 -F 'G4' -O index || exit 1
wait_count 'G4' 9 wait_count 'G4' 9
$TMUX send-keys -t aaa:0 g j j j j x $TMUX send-keys -t aaa:0 g j j j j x || fail "send-keys x failed"
wait_for 'Kill window 1' wait_for 'Kill window 1'
$TMUX send-keys -t aaa:0 y $TMUX send-keys -t aaa:0 y || fail "send-keys y failed"
wait_count 'G4' 7 wait_count 'G4' 7
[ "$($TMUX list-windows -t zzz -F x | grep -c x)" -eq 1 ] || \ [ "$($TMUX list-windows -t zzz -F x | grep -c x)" -eq 1 ] || \
fail "window 1 of zzz not killed" fail "window 1 of zzz not killed"
$TMUX send-keys -t aaa:0 q exit_mode q
cleanup
exit 0 exit 0