Files
tmux/regress/buffers.sh
2026-07-06 11:50:58 +01:00

288 lines
8.2 KiB
Bash

#!/bin/sh
# Tests of paste buffer command semantics, as implemented in cmd-set-buffer.c
# (set-buffer and delete-buffer), cmd-paste-buffer.c, cmd-load-buffer.c,
# cmd-save-buffer.c (save-buffer and show-buffer), cmd-list-buffers.c and
# paste.c.
#
# This exercises:
# - set-buffer creating automatic buffers (buffer0, buffer1, ... with the
# most recent first), -b creating/replacing a named buffer, -a appending,
# -n renaming and the error paths (no data, unknown buffer);
# - show-buffer for the top and for named buffers;
# - delete-buffer for the top and named buffers, and when nothing exists;
# - list-buffers -F custom formats and -f filters;
# - paste-buffer into a pane: newline-to-CR translation by default, -r raw,
# -s custom separator, -d delete-after-paste, unknown buffer error;
# - the buffer-limit option evicting the oldest automatic buffers but not
# named buffers;
# - load-buffer/save-buffer round trips including control characters and
# UTF-8, save-buffer -a appending and errors for missing files/buffers.
PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)
TMP2=$(mktemp)
trap 'rm -f "$TMP" "$TMP2"; $TMUX kill-server 2>/dev/null' 0 1 15
# check_ok $cmd...
#
# Run a command and require that it succeeds.
check_ok()
{
if ! $TMUX "$@"; then
echo "Command failed (expected success): $*"
exit 1
fi
}
# check_fail $expected_error $cmd...
#
# Run a command and require that it fails with the given error message.
check_fail()
{
exp="$1"
shift
out=$($TMUX "$@" 2>&1)
if [ $? -eq 0 ]; then
echo "Command succeeded (expected failure): $*"
exit 1
fi
if [ "$out" != "$exp" ]; then
echo "Wrong error for: $*"
echo "Expected: '$exp'"
echo "But got: '$out'"
exit 1
fi
}
# check_buffers $expected
#
# Compare the buffer list (as "name=content ...", most recent first) with
# $expected.
check_buffers()
{
out=$(echo $($TMUX list-buffers -F \
'#{buffer_name}=#{buffer_sample}'))
if [ "$out" != "$1" ]; then
echo "Buffer list wrong."
echo "Expected: '$1'"
echo "But got: '$out'"
exit 1
fi
}
# check_show $args $expected
#
# Compare show-buffer output with $expected.
check_show()
{
out=$($TMUX show-buffer $1 2>&1)
if [ "$out" != "$2" ]; then
echo "show-buffer $1 wrong."
echo "Expected: '$2'"
echo "But got: '$out'"
exit 1
fi
}
assert_alive()
{
if [ "$($TMUX display-message -p alive 2>&1)" != "alive" ]; then
echo "Server died: $1"
exit 1
fi
}
check_ok new-session -d -s B -x 80 -y 24
# ---------------------------------------------------------------------------
# set-buffer, show-buffer, delete-buffer, list-buffers.
# Automatic buffers stack with the most recent first.
check_ok set-buffer one
check_ok set-buffer two
check_buffers 'buffer1=two buffer0=one'
check_show '' 'two'
check_show '-b buffer0' 'one'
# -a only appends to a buffer named with -b: without -b it creates a new
# automatic buffer. Empty data is silently ignored.
check_ok set-buffer -a '!'
check_buffers 'buffer2=! buffer1=two buffer0=one'
check_ok delete-buffer
check_ok set-buffer ''
check_buffers 'buffer1=two buffer0=one'
# -b names a buffer explicitly; setting it again replaces the content;
# -a appends to it.
check_ok set-buffer -b named abc
check_buffers 'named=abc buffer1=two buffer0=one'
check_ok set-buffer -b named xyz
check_ok set-buffer -a -b named 123
check_buffers 'named=xyz123 buffer1=two buffer0=one'
check_show '-b named' 'xyz123'
# -n renames; renaming to a bad source is an error, as is no data at all.
check_ok set-buffer -b named -n other
check_buffers 'other=xyz123 buffer1=two buffer0=one'
check_fail 'unknown buffer: nosuch' set-buffer -b nosuch -n foo
check_fail 'no data specified' set-buffer -b other
check_fail 'no buffer nosuch' show-buffer -b nosuch
# list-buffers -f filters.
out=$($TMUX list-buffers -f '#{==:#{buffer_name},other}' -F '#{buffer_name}')
if [ "$out" != "other" ]; then
echo "list-buffers -f wrong: '$out'"
exit 1
fi
# delete-buffer -b removes one buffer; without -b the most recent automatic
# buffer goes - named buffers are not candidates for the top, for
# show-buffer and delete-buffer alike.
check_ok delete-buffer -b buffer1
check_buffers 'other=xyz123 buffer0=one'
check_fail 'unknown buffer: buffer1' delete-buffer -b buffer1
check_ok delete-buffer
check_buffers 'other=xyz123'
check_fail 'no buffers' show-buffer
check_fail 'no buffer' delete-buffer
check_ok delete-buffer -b other
check_fail 'no buffers' show-buffer
# ---------------------------------------------------------------------------
# buffer-limit.
# Only automatic buffers count against buffer-limit and the oldest are
# evicted; named buffers survive. (Automatic buffer numbers keep counting
# up over the life of the server, so compare content only.)
check_ok set-option -g buffer-limit 3
check_ok set-buffer -b keepme precious
check_ok set-buffer a1
check_ok set-buffer a2
check_ok set-buffer a3
check_ok set-buffer a4
out=$(echo $($TMUX list-buffers -F '#{buffer_sample}'))
if [ "$out" != 'a4 a3 a2 precious' ]; then
echo "buffer-limit eviction wrong: '$out'"
exit 1
fi
check_ok set-option -g buffer-limit 50
check_ok delete-buffer -b keepme
check_ok delete-buffer; check_ok delete-buffer; check_ok delete-buffer
# ---------------------------------------------------------------------------
# paste-buffer.
# Paste into a raw, echo-free pane running cat -v so control characters are
# visible; a fresh window per paste keeps assertions simple.
# paste_line $bufdata $pasteargs $expected
#
# Set a buffer, paste it into a fresh cat -v pane and compare the first
# screen line with $expected.
paste_line()
{
$TMUX kill-window -t B:9 2>/dev/null
check_ok new-window -d -t B:9 'stty raw -echo && exec cat -v'
i=0
while [ "$($TMUX display-message -p -t B:9.0 \
'#{pane_current_command}')" != "cat" ]; do
i=$((i + 1))
[ $i -gt 50 ] && { echo "cat did not start."; exit 1; }
sleep 0.1
done
check_ok set-buffer -b paste "$1"
check_ok paste-buffer $2 -b paste -t B:9.0
i=0
while out=$($TMUX capture-pane -p -t B:9.0 | sed -n 1p) && \
[ "$out" != "$3" ]; do
i=$((i + 1))
if [ $i -gt 50 ]; then
echo "Paste of '$1' ($2) wrong."
echo "Expected: '$3'"
echo "But got: '$out'"
exit 1
fi
sleep 0.1
done
}
# By default linefeeds are replaced with carriage returns (shown as ^M by
# cat -v); -r pastes raw and -s sets an explicit separator.
paste_line 'one
two' '' 'one^Mtwo'
paste_line 'one
two' '-r' 'one'
paste_line 'one
two' '-s |' 'one|two'
paste_line 'one
two' '-s XX' 'oneXXtwo'
# -d deletes the buffer after pasting.
paste_line 'gone' '-d' 'gone'
check_fail 'no buffer paste' show-buffer -b paste
# Unknown buffer is an error.
check_fail 'no buffer nosuch' paste-buffer -b nosuch -t B:9.0
check_ok kill-window -t B:9
# ---------------------------------------------------------------------------
# load-buffer and save-buffer.
# Round trip a file with control characters and UTF-8 through load-buffer
# and save-buffer.
printf 'line1\tx\033[31m\001\002\303\251\n' >"$TMP"
check_ok load-buffer -b file "$TMP"
check_ok save-buffer -b file "$TMP2"
if ! cmp -s "$TMP" "$TMP2"; then
echo "load-buffer/save-buffer round trip differs."
exit 1
fi
# save-buffer -a appends.
check_ok save-buffer -a -b file "$TMP2"
cat "$TMP" "$TMP" >"$TMP".x
if ! cmp -s "$TMP".x "$TMP2"; then
rm -f "$TMP".x
echo "save-buffer -a did not append."
exit 1
fi
rm -f "$TMP".x
# show-buffer prints the loaded content (text form).
check_ok delete-buffer -b file
# load-buffer of a missing file and save-buffer of a missing buffer or to a
# bad path are errors.
check_fail "No such file or directory: $TMP.nosuch" \
load-buffer -b x "$TMP.nosuch"
check_fail 'no buffer nosuch' save-buffer -b nosuch "$TMP2"
check_ok set-buffer -b sb data
out=$($TMUX save-buffer -b sb /nonexistent/dir/file 2>&1)
if [ $? -eq 0 ]; then
echo "save-buffer to bad path succeeded."
exit 1
fi
# save-buffer - writes to stdout and load-buffer - reads from stdin.
out=$($TMUX save-buffer -b sb -)
if [ "$out" != "data" ]; then
echo "save-buffer - wrong: '$out'"
exit 1
fi
check_ok delete-buffer -b sb
printf 'from stdin' | $TMUX load-buffer -b stdinbuf -
check_show '-b stdinbuf' 'from stdin'
check_ok delete-buffer -b stdinbuf
assert_alive
$TMUX kill-server 2>/dev/null
exit 0