mirror of
https://github.com/tmux/tmux.git
synced 2026-10-11 13:04:22 +00:00
Add a few more tests.
This commit is contained in:
281
regress/format-render-contexts.sh
Normal file
281
regress/format-render-contexts.sh
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Exercise format/style rendering in live contexts. These paths use
|
||||||
|
# format_draw rather than plain format expansion, so they have historically
|
||||||
|
# found different crashes and runaway output.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
LANG=C.UTF-8
|
||||||
|
LC_ALL=C.UTF-8
|
||||||
|
export TERM LANG LC_ALL
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
|
||||||
|
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||||
|
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||||
|
LIMIT=20000
|
||||||
|
|
||||||
|
cleanup()
|
||||||
|
{
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
fail()
|
||||||
|
{
|
||||||
|
echo "$1" >&2
|
||||||
|
cleanup
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
run_cmd()
|
||||||
|
{
|
||||||
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
|
timeout 10 "$@"
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
bounded()
|
||||||
|
{
|
||||||
|
name="$1"
|
||||||
|
text="$2"
|
||||||
|
n=$(printf '%s' "$text" | wc -c | tr -d ' ')
|
||||||
|
|
||||||
|
[ "$n" -le "$LIMIT" ] || fail "$name produced $n bytes"
|
||||||
|
}
|
||||||
|
|
||||||
|
tmux_run()
|
||||||
|
{
|
||||||
|
name="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
out=$(run_cmd $TMUX "$@" 2>&1)
|
||||||
|
rc=$?
|
||||||
|
bounded "$name" "$out"
|
||||||
|
[ "$rc" -eq 0 ] || fail "$name failed ($rc): $out"
|
||||||
|
|
||||||
|
printf '%s' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
capture()
|
||||||
|
{
|
||||||
|
out=$(run_cmd $TMUX2 capture-pane -p -t out:0 2>/dev/null)
|
||||||
|
rc=$?
|
||||||
|
bounded "capture-pane" "$out"
|
||||||
|
[ "$rc" -eq 0 ] || fail "capture-pane failed"
|
||||||
|
printf '%s\n' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
capture_esc()
|
||||||
|
{
|
||||||
|
out=$(run_cmd $TMUX2 capture-pane -Cep -t out:0 2>/dev/null)
|
||||||
|
rc=$?
|
||||||
|
bounded "capture-pane -e" "$out"
|
||||||
|
[ "$rc" -eq 0 ] || fail "capture-pane -e failed"
|
||||||
|
printf '%s\n' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_alive()
|
||||||
|
{
|
||||||
|
out=$(tmux_run "server alive ($1)" display-message -p alive)
|
||||||
|
[ "$out" = "alive" ] || fail "server not alive after $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for()
|
||||||
|
{
|
||||||
|
marker="$1"
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 50 ]; do
|
||||||
|
if capture | grep -q "$marker"; then
|
||||||
|
sleep 0.1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 0.2
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
fail "timed out waiting for $marker"
|
||||||
|
}
|
||||||
|
|
||||||
|
render_status_options()
|
||||||
|
{
|
||||||
|
label="$1"
|
||||||
|
fmt="$2"
|
||||||
|
|
||||||
|
tmux_run "$label status-left" \
|
||||||
|
set-option -g status-left "SL$label: $fmt" >/dev/null
|
||||||
|
tmux_run "$label status-right" \
|
||||||
|
set-option -g status-right "SR$label: $fmt" >/dev/null
|
||||||
|
tmux_run "$label status-format left/right" \
|
||||||
|
set-option -g status-format[0] \
|
||||||
|
'#{E:status-left}#[align=right]#{E:status-right}' >/dev/null
|
||||||
|
wait_for "SL$label"
|
||||||
|
assert_alive "$label status-left/right"
|
||||||
|
}
|
||||||
|
|
||||||
|
render_status_format()
|
||||||
|
{
|
||||||
|
label="$1"
|
||||||
|
fmt="$2"
|
||||||
|
|
||||||
|
tmux_run "$label clear status-left" set-option -g status-left '' >/dev/null
|
||||||
|
tmux_run "$label clear status-right" set-option -g status-right '' >/dev/null
|
||||||
|
tmux_run "$label status-format" \
|
||||||
|
set-option -g status-format[0] "SF$label: $fmt" >/dev/null
|
||||||
|
wait_for "SF$label"
|
||||||
|
assert_alive "$label status-format"
|
||||||
|
}
|
||||||
|
|
||||||
|
render_message()
|
||||||
|
{
|
||||||
|
label="$1"
|
||||||
|
fmt="$2"
|
||||||
|
|
||||||
|
tmux_run "$label display-message" \
|
||||||
|
display-message -t fmt:0 -d 1000 "DM$label: $fmt" >/dev/null
|
||||||
|
wait_for "DM$label"
|
||||||
|
assert_alive "$label display-message"
|
||||||
|
}
|
||||||
|
|
||||||
|
render_choose_tree()
|
||||||
|
{
|
||||||
|
label="$1"
|
||||||
|
fmt="$2"
|
||||||
|
|
||||||
|
tmux_run "$label choose-tree" \
|
||||||
|
choose-tree -t fmt:0 -F "CT$label: $fmt" >/dev/null
|
||||||
|
wait_for "CT$label"
|
||||||
|
tmux_run "$label quit choose-tree" send-keys -t fmt:0 q >/dev/null
|
||||||
|
assert_alive "$label choose-tree"
|
||||||
|
}
|
||||||
|
|
||||||
|
render_customize()
|
||||||
|
{
|
||||||
|
label="$1"
|
||||||
|
fmt="$2"
|
||||||
|
|
||||||
|
tmux_run "$label customize-mode" \
|
||||||
|
customize-mode -t fmt:0 -F "CM$label: $fmt" >/dev/null
|
||||||
|
sleep 0.5
|
||||||
|
out=$(capture)
|
||||||
|
bounded "$label customize-mode capture" "$out"
|
||||||
|
tmux_run "$label quit customize-mode" send-keys -t fmt:0 q >/dev/null
|
||||||
|
assert_alive "$label customize-mode"
|
||||||
|
}
|
||||||
|
|
||||||
|
render_list_output()
|
||||||
|
{
|
||||||
|
label="$1"
|
||||||
|
fmt="$2"
|
||||||
|
|
||||||
|
tmux_run "$label bind-key" \
|
||||||
|
bind-key -T root F12 display-message "LK$label: $fmt" >/dev/null
|
||||||
|
out=$(tmux_run "$label list-keys" list-keys -T root F12)
|
||||||
|
bounded "$label list-keys output" "$out"
|
||||||
|
|
||||||
|
tmux_run "$label option value" \
|
||||||
|
set-option -g status-left "LO$label: $fmt" >/dev/null
|
||||||
|
out=$(tmux_run "$label list-options" show-options -g status-left)
|
||||||
|
bounded "$label list-options output" "$out"
|
||||||
|
|
||||||
|
assert_alive "$label list-keys/list-options"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_sgr_sanity()
|
||||||
|
{
|
||||||
|
tmux_run "sgr status style" \
|
||||||
|
set-option -g status-style fg=default,bg=default >/dev/null
|
||||||
|
tmux_run "sgr status-format" \
|
||||||
|
set-option -g status-format[0] \
|
||||||
|
'#[fg=colour1,bg=default]SGR-STATUS#[default]' >/dev/null
|
||||||
|
wait_for "SGR-STATUS"
|
||||||
|
out=$(capture_esc | tail -n 1)
|
||||||
|
bounded "sgr status capture" "$out"
|
||||||
|
case "$out" in
|
||||||
|
*SGR-STATUS*) ;;
|
||||||
|
*) fail "status SGR capture lost text: $out" ;;
|
||||||
|
esac
|
||||||
|
case "$out" in
|
||||||
|
*"\\033["*) ;;
|
||||||
|
*) fail "status SGR capture has no escape reset/style data: $out" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
tmux_run "sgr message style" \
|
||||||
|
set-option -g message-style fg=colour2,bg=default >/dev/null
|
||||||
|
tmux_run "sgr display-message" \
|
||||||
|
display-message -t fmt:0 -d 1000 \
|
||||||
|
'#[bg=default]SGR-MESSAGE#[default]' >/dev/null
|
||||||
|
wait_for "SGR-MESSAGE"
|
||||||
|
out=$(capture_esc | tail -n 1)
|
||||||
|
bounded "sgr message capture" "$out"
|
||||||
|
case "$out" in
|
||||||
|
*SGR-MESSAGE*) ;;
|
||||||
|
*) fail "message SGR capture lost text: $out" ;;
|
||||||
|
esac
|
||||||
|
case "$out" in
|
||||||
|
*"\\033["*) ;;
|
||||||
|
*) fail "message SGR capture has no escape reset/style data: $out" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
assert_alive "SGR sanity"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_corpus()
|
||||||
|
{
|
||||||
|
label="$1"
|
||||||
|
fmt="$2"
|
||||||
|
|
||||||
|
render_status_options "$label" "$fmt"
|
||||||
|
render_status_format "$label" "$fmt"
|
||||||
|
render_message "$label" "$fmt"
|
||||||
|
render_choose_tree "$label" "$fmt"
|
||||||
|
render_customize "$label" "$fmt"
|
||||||
|
render_list_output "$label" "$fmt"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup 0 1 15
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
tmux_run "new inner session" \
|
||||||
|
new-session -d -s fmt -x 100 -y 30 "exec sleep 1000" >/dev/null
|
||||||
|
tmux_run "new inner window" \
|
||||||
|
new-window -t fmt -n second "exec sleep 1000" >/dev/null
|
||||||
|
tmux_run "select visible window" select-window -t fmt:0 >/dev/null
|
||||||
|
tmux_run "set status interval" set-option -g status-interval 1 >/dev/null
|
||||||
|
tmux_run "set base message style" \
|
||||||
|
set-option -g message-style fg=default,bg=default >/dev/null
|
||||||
|
tmux_run "set nested option" \
|
||||||
|
set-option -g @nested 'NESTED-#{session_name}-#{window_index}' >/dev/null
|
||||||
|
|
||||||
|
run_cmd $TMUX2 new-session -d -s out -x 100 -y 30 "$TMUX attach -t fmt" \
|
||||||
|
>/dev/null 2>&1 || fail "failed to start outer client"
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 50 ]; do
|
||||||
|
c=$(tmux_run "wait clients" list-clients -F x | grep -c x)
|
||||||
|
[ "$c" -eq 1 ] && break
|
||||||
|
sleep 0.2
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
[ "$i" -lt 50 ] || fail "inner client did not attach"
|
||||||
|
|
||||||
|
run_corpus A \
|
||||||
|
'#[bold,dim,underscore,blink,reverse,italics,strikethrough,double-underscore,curly-underscore,dotted-underscore,dashed-underscore,overline,fg=colour196,bg=colour22,us=colour45]LONGSTYLE#[default]plain'
|
||||||
|
run_corpus B \
|
||||||
|
'wide: Ελληνικά 中文 😀 #{=12:中文😀abc}'
|
||||||
|
run_corpus C \
|
||||||
|
'#[fg=colour2,bg=colour4]base#[push-default]#[fg=colour1,bg=default]push#[pop-default]pop#[default]'
|
||||||
|
run_corpus D \
|
||||||
|
'#[list=on]list#[list=focus]focus#[nolist] #[align=centre]centre#[noalign] #[range=left]L#[range=right]R#[norange]'
|
||||||
|
run_corpus E \
|
||||||
|
'#{E:@nested}:#{T:%%H:%%M}:#{?#{==:#{session_name},fmt},yes,no}:#{?0,bad,}'
|
||||||
|
run_corpus F \
|
||||||
|
'job:#(printf job-ok)'
|
||||||
|
run_corpus G \
|
||||||
|
'empty:#{E:}:#{T:}:#{definitely_not_a_variable}:#{?0,no,}'
|
||||||
|
|
||||||
|
check_sgr_sanity
|
||||||
|
|
||||||
|
cleanup
|
||||||
|
exit 0
|
||||||
281
regress/input-reflow-stress.sh
Normal file
281
regress/input-reflow-stress.sh
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
WIDTHS="80 40 20 10 7 5 4 3 2 1 2 3 4 5 7 10 20 40 80"
|
||||||
|
HISTORY_LIMIT=220
|
||||||
|
HISTORY_BOUND=12000
|
||||||
|
JOINED_BOUND=500000
|
||||||
|
RAW_BOUND=5000000
|
||||||
|
|
||||||
|
record_fail()
|
||||||
|
{
|
||||||
|
echo "FAIL: $1"
|
||||||
|
exit_status=1
|
||||||
|
}
|
||||||
|
|
||||||
|
make_payload()
|
||||||
|
{
|
||||||
|
n=0
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 16 ]; do
|
||||||
|
printf 'L%04d|ascii|abcdefghijklmnopqrstuvwxyz\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|wrap|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|wide|AあB界C\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|wide-edge|abcdあZ\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|combining|é é é\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|orphan-combining|́A\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|variation|✔️ ⚠️ 🏝️\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|emoji|🙂🙂🙂\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|flag|🇬🇧 🇺🇸 🇯🇵\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|mixed|Aあé✔️B\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|style|plain \033[31mred\033[0m plain\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|hyperlink|\033]8;;https://example.com/%04d\033\\LINK\033]8;;\033\\\n' "$n" "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|tabs|a\tb\tc\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'L%04d|backspace|abc\bX\n' "$n"; n=$((n + 1))
|
||||||
|
printf 'carriage-return-%04d|abcdef\rL%04d|carriage-return|XY\n' "$n" "$n"; n=$((n + 1))
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
make_alternate_payload()
|
||||||
|
{
|
||||||
|
printf '\033[?1049h'
|
||||||
|
printf 'ALT000|wide|AあB界C\n'
|
||||||
|
printf 'ALT001|combining|é é é\n'
|
||||||
|
printf 'ALT002|style|plain \033[32mgreen\033[0m plain\n'
|
||||||
|
printf 'ALT003|emoji|🙂🙂🙂\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
load_and_paste()
|
||||||
|
{
|
||||||
|
buffer=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
"$@" | $TMUX load-buffer -b "$buffer" - || exit 1
|
||||||
|
$TMUX paste-buffer -d -b "$buffer" -t stress:0.0 || exit 1
|
||||||
|
sleep 0.3
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_alive()
|
||||||
|
{
|
||||||
|
alive=$($TMUX display-message -p -t stress: alive 2>&1) || {
|
||||||
|
record_fail "server died after $1"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
[ "$alive" = alive ] || record_fail "server died after $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
capture_joined()
|
||||||
|
{
|
||||||
|
$TMUX capture-pane -pNJ -t stress: -S - -E - >"$TMP"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_joined_sane()
|
||||||
|
{
|
||||||
|
label=$1
|
||||||
|
check_sentinels=${2:-yes}
|
||||||
|
|
||||||
|
capture_joined || {
|
||||||
|
record_fail "joined capture failed after $label"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes=$(wc -c <"$TMP")
|
||||||
|
if [ "$bytes" -gt "$JOINED_BOUND" ]; then
|
||||||
|
record_fail "joined capture too large after $label: $bytes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "$(printf '\357\277\275')" "$TMP"; then
|
||||||
|
record_fail "replacement character in joined capture after $label"
|
||||||
|
fi
|
||||||
|
|
||||||
|
awk -v label="$label" '
|
||||||
|
{
|
||||||
|
line = $0
|
||||||
|
seen_on_line = 0
|
||||||
|
while (match(line, /L[0-9][0-9][0-9][0-9]\|/)) {
|
||||||
|
id = substr(line, RSTART + 1, 4) + 0
|
||||||
|
seen_on_line++
|
||||||
|
seen[id]++
|
||||||
|
if (id < last) {
|
||||||
|
printf("IDs out of order after %s: L%04d after L%04d\n",
|
||||||
|
label, id, last)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if (seen[id] > 1) {
|
||||||
|
printf("duplicate ID after %s: L%04d\n", label, id)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
last = id
|
||||||
|
found = 1
|
||||||
|
line = substr(line, RSTART + RLENGTH)
|
||||||
|
}
|
||||||
|
if (seen_on_line > 1) {
|
||||||
|
printf("fused IDs after %s: %s\n", label, $0)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
if (!found) {
|
||||||
|
printf("no line IDs after %s\n", label)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$TMP" || {
|
||||||
|
cp "$TMP" "$EXP"
|
||||||
|
record_fail "joined structure failed after $label"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$check_sentinels" = yes ]; then
|
||||||
|
for expected in \
|
||||||
|
'L0234|mixed|' \
|
||||||
|
'L0236|hyperlink|' \
|
||||||
|
'L0239|carriage-return|XY'; do
|
||||||
|
if ! grep -Fq "$expected" "$TMP"; then
|
||||||
|
printf '%s\n' "$expected" >"$EXP"
|
||||||
|
record_fail "missing sentinel after $label"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_raw_sane()
|
||||||
|
{
|
||||||
|
label=$1
|
||||||
|
width=$2
|
||||||
|
|
||||||
|
$TMUX capture-pane -pR -t stress: >"$TMP" || {
|
||||||
|
record_fail "raw capture failed after $label"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes=$(wc -c <"$TMP")
|
||||||
|
if [ "$bytes" -gt "$RAW_BOUND" ]; then
|
||||||
|
record_fail "raw capture too large after $label: $bytes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
awk -v label="$label" -v width="$width" '
|
||||||
|
/^C / {
|
||||||
|
cell = $0
|
||||||
|
sub(/^C /, "", cell)
|
||||||
|
split(cell, fields, " ")
|
||||||
|
split(fields[1], position, ",")
|
||||||
|
row = position[1] + 0
|
||||||
|
col = position[2] + 0
|
||||||
|
if (col >= width) {
|
||||||
|
printf("cell column outside pane after %s: %s\n", label, $0)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
data = $0
|
||||||
|
if (data !~ /data=\(/)
|
||||||
|
next
|
||||||
|
sub(/^.*data=\(/, "", data)
|
||||||
|
split(data, data_fields, ",")
|
||||||
|
cell_width = data_fields[1] + 0
|
||||||
|
padding = ($0 ~ /flags=PADDING/)
|
||||||
|
|
||||||
|
if (!padding && cell_width == 0) {
|
||||||
|
printf("zero-width non-padding cell after %s: %s\n", label, $0)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if (padding && !(last_row == row && last_width > 1 && !last_padding)) {
|
||||||
|
printf("padding without preceding wide cell after %s: %s\n", label, $0)
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
last_row = row
|
||||||
|
last_width = cell_width
|
||||||
|
last_padding = padding
|
||||||
|
}
|
||||||
|
' "$TMP" || {
|
||||||
|
cp "$TMP" "$EXP"
|
||||||
|
record_fail "raw structure failed after $label"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_history_sane()
|
||||||
|
{
|
||||||
|
label=$1
|
||||||
|
|
||||||
|
size=$($TMUX display-message -p -t stress: '#{history_size}') || {
|
||||||
|
record_fail "history-size failed after $label"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "$size" in
|
||||||
|
''|*[!0-9]*)
|
||||||
|
record_fail "bad history size after $label: $size"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$size" -gt "$HISTORY_BOUND" ]; then
|
||||||
|
record_fail "history too large after $label: $size"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_copy_mode_sane()
|
||||||
|
{
|
||||||
|
label=$1
|
||||||
|
|
||||||
|
$TMUX capture-pane -pM -t stress: >"$TMP" || {
|
||||||
|
record_fail "copy-mode capture failed after $label"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes=$(wc -c <"$TMP")
|
||||||
|
if [ "$bytes" -gt 20000 ]; then
|
||||||
|
record_fail "copy-mode capture too large after $label"
|
||||||
|
fi
|
||||||
|
if grep -q "$(printf '\357\277\275')" "$TMP"; then
|
||||||
|
record_fail "replacement character in copy-mode after $label"
|
||||||
|
fi
|
||||||
|
if ! grep -Eq 'L[0-9][0-9][0-9][0-9]\|' "$TMP"; then
|
||||||
|
record_fail "no line ID in copy-mode after $label"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_resize_checks()
|
||||||
|
{
|
||||||
|
for width in $WIDTHS; do
|
||||||
|
$TMUX resize-window -t stress: -x "$width" -y 8 || exit 1
|
||||||
|
sleep 0.1
|
||||||
|
assert_alive "resize to $width"
|
||||||
|
assert_joined_sane "resize to $width"
|
||||||
|
assert_raw_sane "resize to $width" "$width"
|
||||||
|
assert_history_sane "resize to $width"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
sleep 0.1
|
||||||
|
$TMUX new-session -d -x 1 -y 1 -s test-setup "sleep 2" || exit 1
|
||||||
|
$TMUX set-option -g history-limit "$HISTORY_LIMIT" || exit 1
|
||||||
|
$TMUX new-session -d -x 80 -y 8 -s stress "stty -echo; cat" || exit 1
|
||||||
|
$TMUX kill-session -t test-setup
|
||||||
|
sleep 0.3
|
||||||
|
|
||||||
|
load_and_paste stress-data make_payload
|
||||||
|
run_resize_checks
|
||||||
|
|
||||||
|
$TMUX copy-mode -H -t stress: || exit 1
|
||||||
|
for cmd in history-top page-down halfpage-down halfpage-up page-up history-bottom; do
|
||||||
|
$TMUX send-keys -t stress: -X "$cmd" || exit 1
|
||||||
|
sleep 0.1
|
||||||
|
assert_copy_mode_sane "$cmd"
|
||||||
|
done
|
||||||
|
$TMUX send-keys -t stress: -X cancel || exit 1
|
||||||
|
|
||||||
|
load_and_paste stress-alt make_alternate_payload
|
||||||
|
for width in 10 4 1 4 10 80; do
|
||||||
|
$TMUX resize-window -t stress: -x "$width" -y 8 || exit 1
|
||||||
|
sleep 0.1
|
||||||
|
assert_alive "alternate resize to $width"
|
||||||
|
assert_raw_sane "alternate resize to $width" "$width"
|
||||||
|
done
|
||||||
|
printf '\033[?1049l' | $TMUX load-buffer -b stress-alt-exit - || exit 1
|
||||||
|
$TMUX paste-buffer -d -b stress-alt-exit -t stress:0.0 || exit 1
|
||||||
|
sleep 0.3
|
||||||
|
assert_joined_sane "alternate screen exit" no
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
exit $exit_status
|
||||||
216
regress/lifecycle-deferred.sh
Normal file
216
regress/lifecycle-deferred.sh
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
#!/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 -Llifecycle-deferred -f/dev/null"
|
||||||
|
TMUX2="$TEST_TMUX -Llifecycle-deferred-outer -f/dev/null"
|
||||||
|
|
||||||
|
TMPDIR=$(mktemp -d)
|
||||||
|
IN="$TMPDIR/in"
|
||||||
|
OUT="$TMPDIR/out"
|
||||||
|
CONTROL_PID=
|
||||||
|
|
||||||
|
cleanup()
|
||||||
|
{
|
||||||
|
exec 3>&- 2>/dev/null
|
||||||
|
[ -n "$CONTROL_PID" ] && kill "$CONTROL_PID" 2>/dev/null
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
rm -rf "$TMPDIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail()
|
||||||
|
{
|
||||||
|
echo "$1" >&2
|
||||||
|
[ -s "$OUT" ] && sed -n '1,120p' "$OUT" >&2
|
||||||
|
cleanup
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
run_tmux()
|
||||||
|
{
|
||||||
|
out=
|
||||||
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
|
out=$(timeout 10 $TMUX "$@" 2>&1)
|
||||||
|
else
|
||||||
|
out=$($TMUX "$@" 2>&1)
|
||||||
|
fi
|
||||||
|
rc=$?
|
||||||
|
[ "$rc" -eq 0 ] || fail "tmux $* failed ($rc): $out"
|
||||||
|
printf '%s' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
send_control()
|
||||||
|
{
|
||||||
|
printf '%s\n' "$1" >&3 || fail "failed to write control command: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_clients()
|
||||||
|
{
|
||||||
|
want=$1
|
||||||
|
i=0
|
||||||
|
|
||||||
|
while [ "$i" -lt 50 ]; do
|
||||||
|
have=$($TMUX list-clients -F x 2>/dev/null | grep -c x)
|
||||||
|
[ "$have" -eq "$want" ] && return 0
|
||||||
|
sleep 0.2
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_format()
|
||||||
|
{
|
||||||
|
target=$1
|
||||||
|
format=$2
|
||||||
|
want=$3
|
||||||
|
i=0
|
||||||
|
|
||||||
|
while [ "$i" -lt 50 ]; do
|
||||||
|
have=$($TMUX display-message -p -t "$target" "$format" 2>/dev/null)
|
||||||
|
[ "$have" = "$want" ] && return 0
|
||||||
|
sleep 0.2
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_alive()
|
||||||
|
{
|
||||||
|
run_tmux has-session -t life >/dev/null
|
||||||
|
fields=$(run_tmux display-message -p -t life \
|
||||||
|
'#{session_name}:#{window_id}:#{pane_id}:#{session_windows}:#{window_panes}')
|
||||||
|
case "$fields" in
|
||||||
|
life:@*:%*:*) ;;
|
||||||
|
*) fail "bad current fields after $1: $fields" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
check_control_output()
|
||||||
|
{
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
if grep -E '(^%error |server exited|lost server|\(null\)|no current)' \
|
||||||
|
"$OUT" >/dev/null 2>&1; then
|
||||||
|
fail "control client reported an error or invalid object"
|
||||||
|
fi
|
||||||
|
|
||||||
|
awk '
|
||||||
|
$1 == "%session-window-changed" {
|
||||||
|
if (NF != 3 || $2 !~ /^\$[0-9]+$/ || $3 !~ /^@[0-9]+$/)
|
||||||
|
bad = 1
|
||||||
|
}
|
||||||
|
$1 == "%subscription-changed" {
|
||||||
|
colon = 0
|
||||||
|
for (i = 2; i <= NF; i++)
|
||||||
|
if ($i == ":")
|
||||||
|
colon = 1
|
||||||
|
if (NF < 7 || !colon)
|
||||||
|
bad = 1
|
||||||
|
}
|
||||||
|
END { exit bad }
|
||||||
|
' "$OUT" || fail "control client received a malformed notification"
|
||||||
|
}
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
|
run_tmux new-session -d -s life -n prompt -x 80 -y 24 'sleep 1000' \
|
||||||
|
>/dev/null
|
||||||
|
run_tmux set-option -g detach-on-destroy off >/dev/null
|
||||||
|
run_tmux new-window -t life -n tree 'sleep 1000' >/dev/null
|
||||||
|
run_tmux new-window -t life -n work 'sleep 1000' >/dev/null
|
||||||
|
run_tmux select-window -t life:prompt >/dev/null
|
||||||
|
|
||||||
|
run_tmux set-hook -g after-new-window \
|
||||||
|
'display-message -p "hook-new #{session_name}:#{window_id}:#{pane_id}"' \
|
||||||
|
>/dev/null
|
||||||
|
run_tmux set-hook -g after-split-window \
|
||||||
|
'display-message -p "hook-split #{session_name}:#{window_id}:#{pane_id}"' \
|
||||||
|
>/dev/null
|
||||||
|
run_tmux set-hook -g after-kill-pane \
|
||||||
|
'display-message -p "hook-kill #{session_name}:#{window_id}:#{pane_id}"' \
|
||||||
|
>/dev/null
|
||||||
|
run_tmux set-hook -g pane-exited \
|
||||||
|
'display-message -p "hook-exit #{session_name}:#{window_id}:#{pane_id}"' \
|
||||||
|
>/dev/null
|
||||||
|
run_tmux set-hook -g window-layout-changed \
|
||||||
|
'display-message -p "hook-layout #{session_name}:#{window_id}:#{pane_id}"' \
|
||||||
|
>/dev/null
|
||||||
|
run_tmux set-hook -g session-window-changed \
|
||||||
|
'display-message -p "hook-current #{session_name}:#{window_id}:#{pane_id}"' \
|
||||||
|
>/dev/null
|
||||||
|
run_tmux bind-key -n M-p command-prompt -P -p '(life)' \
|
||||||
|
"set -g @lifecycle-prompt '%% #{session_name}:#{window_id}:#{pane_id}'" \
|
||||||
|
>/dev/null
|
||||||
|
|
||||||
|
$TMUX2 new-session -d -s outer -n prompt -x 80 -y 24 "$TMUX attach -t life" \
|
||||||
|
|| fail "failed to start first attached client"
|
||||||
|
$TMUX2 new-window -t outer -n tree "$TMUX attach -t life" \
|
||||||
|
|| fail "failed to start second attached client"
|
||||||
|
wait_clients 2 || fail "normal clients did not attach"
|
||||||
|
|
||||||
|
$TMUX2 send-keys -t outer:prompt M-p || fail "failed to open command prompt"
|
||||||
|
sleep 1
|
||||||
|
run_tmux choose-tree -t life:tree.0 \
|
||||||
|
-F 'tree #{session_name}:#{window_id}:#{pane_id}' >/dev/null
|
||||||
|
wait_format life:tree.0 '#{pane_mode}' tree-mode || \
|
||||||
|
fail "choose-tree did not enter tree-mode"
|
||||||
|
|
||||||
|
mkfifo "$IN" || fail "failed to create control fifo"
|
||||||
|
(cat "$IN" | $TMUX -C attach -t life >"$OUT" 2>&1) &
|
||||||
|
CONTROL_PID=$!
|
||||||
|
exec 3>"$IN"
|
||||||
|
wait_clients 3 || fail "control client did not attach"
|
||||||
|
|
||||||
|
CONTROL_CLIENT=$($TMUX list-clients -F '#{client_name} #{client_control_mode}' |
|
||||||
|
awk '$2 == 1 { print $1; exit }')
|
||||||
|
[ -n "$CONTROL_CLIENT" ] || fail "missing control client"
|
||||||
|
|
||||||
|
send_control "refresh-client -B 'all:%*:#{session_name}:#{window_id}:#{pane_id}:#{session_windows}:#{window_panes}'"
|
||||||
|
send_control "refresh-client -B 'windows:@*:#{session_name}:#{window_id}:#{window_index}:#{window_panes}'"
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
run_tmux kill-pane -t life:prompt.0 >/dev/null
|
||||||
|
run_tmux kill-window -t life:tree >/dev/null
|
||||||
|
assert_alive "killing prompt and tree panes"
|
||||||
|
|
||||||
|
i=1
|
||||||
|
while [ "$i" -le 20 ]; do
|
||||||
|
# Keep this sequence fixed: failures should reproduce on the same pass.
|
||||||
|
s=ld$i
|
||||||
|
ctl=ctl$i
|
||||||
|
idx=$((50 + i))
|
||||||
|
|
||||||
|
run_tmux new-session -d -s "$s" -n base 'sleep 1000' >/dev/null
|
||||||
|
run_tmux split-window -t "$s:base" 'sleep 1000' >/dev/null
|
||||||
|
run_tmux respawn-pane -k -t "$s:base.1" 'sleep 1000' >/dev/null
|
||||||
|
run_tmux kill-pane -t "$s:base.1" >/dev/null
|
||||||
|
|
||||||
|
run_tmux new-window -t "$s" -n second 'sleep 1000' >/dev/null
|
||||||
|
run_tmux link-window -s "$s:second" -t "life:$idx" >/dev/null
|
||||||
|
run_tmux unlink-window -t "life:$idx" >/dev/null
|
||||||
|
|
||||||
|
run_tmux new-window -t "$s" -n single 'sleep 1000' >/dev/null
|
||||||
|
run_tmux kill-pane -t "$s:single.0" >/dev/null
|
||||||
|
run_tmux kill-window -t "$s:base" >/dev/null
|
||||||
|
|
||||||
|
run_tmux new-session -d -s "$ctl" -n ctl 'sleep 1000' >/dev/null
|
||||||
|
run_tmux switch-client -c "$CONTROL_CLIENT" -t "$ctl" >/dev/null
|
||||||
|
run_tmux kill-session -t "$ctl" >/dev/null
|
||||||
|
|
||||||
|
run_tmux kill-session -t "$s" >/dev/null
|
||||||
|
assert_alive "iteration $i"
|
||||||
|
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
check_control_output
|
||||||
|
cleanup
|
||||||
|
exit 0
|
||||||
297
regress/mode-mutation.sh
Normal file
297
regress/mode-mutation.sh
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Exercise modes while their backing objects are changed from outside the
|
||||||
|
# client displaying the mode. This catches stale selection indexes and pointers
|
||||||
|
# after a mode list is shrunk or rebuilt.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
|
||||||
|
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||||
|
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||||
|
|
||||||
|
cleanup()
|
||||||
|
{
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
sleep 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
fail()
|
||||||
|
{
|
||||||
|
echo "$1"
|
||||||
|
cleanup
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
capture()
|
||||||
|
{
|
||||||
|
$TMUX2 capture-pane -p -t out:0 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_alive()
|
||||||
|
{
|
||||||
|
$TMUX display-message -p 'alive' >/dev/null 2>&1 || \
|
||||||
|
fail "$1: server exited"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_clients()
|
||||||
|
{
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 50 ]; do
|
||||||
|
c=$($TMUX list-clients -F x 2>/dev/null | grep -c x)
|
||||||
|
[ "$c" -eq "$1" ] && return 0
|
||||||
|
sleep 0.2
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
fail "expected $1 clients, have $c"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for()
|
||||||
|
{
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 50 ]; do
|
||||||
|
capture | grep -q "$1" && return 0
|
||||||
|
sleep 0.2
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
fail "timed out waiting for '$1'"
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat_key()
|
||||||
|
{
|
||||||
|
t=$1
|
||||||
|
key=$2
|
||||||
|
count=$3
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt "$count" ]; do
|
||||||
|
$TMUX send-keys -t "$t" "$key" || \
|
||||||
|
fail "failed to send $key to $t"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
start_client()
|
||||||
|
{
|
||||||
|
s=$1
|
||||||
|
cmd=${2:-cat}
|
||||||
|
|
||||||
|
cleanup
|
||||||
|
$TMUX new-session -d -s "$s" -n main -x 80 -y 24 "$cmd" || \
|
||||||
|
fail "$s: new-session failed"
|
||||||
|
$TMUX2 new-session -d -s out -x 80 -y 24 "$TMUX attach -t $s" || \
|
||||||
|
fail "$s: outer client failed"
|
||||||
|
wait_clients 1
|
||||||
|
}
|
||||||
|
|
||||||
|
new_outer_client()
|
||||||
|
{
|
||||||
|
s=$1
|
||||||
|
|
||||||
|
$TMUX2 new-window -d -t out: "$TMUX attach -t $s" || \
|
||||||
|
fail "$s: outer client failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
client_for_session()
|
||||||
|
{
|
||||||
|
$TMUX list-clients -F '#{client_name} #{client_session}' |
|
||||||
|
awk -v s="$1" '$2 == s { print $1; exit }'
|
||||||
|
}
|
||||||
|
|
||||||
|
test_choose_tree()
|
||||||
|
{
|
||||||
|
start_client tree-a
|
||||||
|
$TMUX new-session -d -s tree-b -n one 'cat' || fail "tree-b failed"
|
||||||
|
$TMUX new-window -d -t tree-b -n two 'cat' || fail "tree-b:1 failed"
|
||||||
|
$TMUX new-session -d -s tree-c -n one 'cat' || fail "tree-c failed"
|
||||||
|
$TMUX new-session -d -s tree-d -n one 'cat' || fail "tree-d failed"
|
||||||
|
$TMUX split-window -d -t tree-a:0 'cat' || fail "tree split failed"
|
||||||
|
|
||||||
|
$TMUX choose-tree -t tree-a:0 -O index -F 'MT #{session_name}:#{window_index}.#{pane_index}' || \
|
||||||
|
fail "choose-tree failed"
|
||||||
|
wait_for 'MT '
|
||||||
|
repeat_key tree-a:0 j 40
|
||||||
|
|
||||||
|
$TMUX kill-session -t tree-d || fail "tree kill-session failed"
|
||||||
|
$TMUX kill-session -t tree-c || fail "tree kill-session failed"
|
||||||
|
$TMUX rename-session -t tree-b tree-renamed || fail "tree rename failed"
|
||||||
|
$TMUX rename-window -t tree-renamed:0 renamed || fail "tree rename-window failed"
|
||||||
|
$TMUX kill-window -t tree-renamed:1 || fail "tree kill-window failed"
|
||||||
|
side=$($TMUX split-window -d -P -F '#{pane_id}' -t tree-a:0 'cat') || \
|
||||||
|
fail "tree side split failed"
|
||||||
|
$TMUX break-pane -d -s "$side" || fail "tree break-pane failed"
|
||||||
|
$TMUX join-pane -d -s "$side" -t tree-a:0.0 || \
|
||||||
|
fail "tree join-pane failed"
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 12 ]; do
|
||||||
|
$TMUX new-window -d -t tree-a -n "new$i" 'cat' || \
|
||||||
|
fail "tree new-window failed"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
assert_alive "choose-tree mutation"
|
||||||
|
$TMUX send-keys -t tree-a:0 k j l h Enter || \
|
||||||
|
fail "choose-tree keys failed"
|
||||||
|
wait_mode tree-a:0 0
|
||||||
|
assert_alive "choose-tree exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_choose_buffer()
|
||||||
|
{
|
||||||
|
start_client buffer-a
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 30 ]; do
|
||||||
|
$TMUX set-buffer -b "mbuf$i" "buffer mutation $i" || \
|
||||||
|
fail "set-buffer failed"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
$TMUX choose-buffer -t buffer-a:0 -F 'MB #{buffer_name}' || \
|
||||||
|
fail "choose-buffer failed"
|
||||||
|
wait_for 'MB '
|
||||||
|
repeat_key buffer-a:0 j 40
|
||||||
|
|
||||||
|
i=8
|
||||||
|
while [ "$i" -lt 30 ]; do
|
||||||
|
$TMUX delete-buffer -b "mbuf$i" || fail "delete-buffer failed"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
i=30
|
||||||
|
while [ "$i" -lt 50 ]; do
|
||||||
|
$TMUX set-buffer -b "mbuf$i" "new buffer mutation $i" || \
|
||||||
|
fail "new set-buffer failed"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
assert_alive "choose-buffer mutation"
|
||||||
|
$TMUX send-keys -t buffer-a:0 k j Enter || \
|
||||||
|
fail "choose-buffer keys failed"
|
||||||
|
wait_mode buffer-a:0 0
|
||||||
|
assert_alive "choose-buffer exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_choose_client()
|
||||||
|
{
|
||||||
|
start_client client-a
|
||||||
|
$TMUX new-session -d -s client-b -n main 'cat' || fail "client-b failed"
|
||||||
|
$TMUX new-session -d -s client-c -n main 'cat' || fail "client-c failed"
|
||||||
|
new_outer_client client-b
|
||||||
|
new_outer_client client-c
|
||||||
|
wait_clients 3
|
||||||
|
|
||||||
|
$TMUX choose-client -t client-a:0 -F 'MC #{client_session}' || \
|
||||||
|
fail "choose-client failed"
|
||||||
|
wait_for 'MC '
|
||||||
|
repeat_key client-a:0 j 20
|
||||||
|
|
||||||
|
c=$(client_for_session client-c)
|
||||||
|
[ -n "$c" ] || fail "client-c client not found"
|
||||||
|
$TMUX detach-client -t "$c" || fail "detach client-c failed"
|
||||||
|
c=$(client_for_session client-b)
|
||||||
|
[ -n "$c" ] || fail "client-b client not found"
|
||||||
|
$TMUX detach-client -t "$c" || fail "detach client-b failed"
|
||||||
|
|
||||||
|
$TMUX new-session -d -s client-d -n main 'cat' || fail "client-d failed"
|
||||||
|
new_outer_client client-d
|
||||||
|
wait_clients 2
|
||||||
|
|
||||||
|
assert_alive "choose-client mutation"
|
||||||
|
$TMUX send-keys -t client-a:0 k j Enter || \
|
||||||
|
fail "choose-client keys failed"
|
||||||
|
wait_mode client-a:0 0
|
||||||
|
assert_alive "choose-client exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_customize_mode()
|
||||||
|
{
|
||||||
|
start_client option-a
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt 30 ]; do
|
||||||
|
$TMUX set-option -g "@mode_mut_$i" "$i" || \
|
||||||
|
fail "set option failed"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
$TMUX customize-mode -t option-a:0 -F 'MO #{option_name}=#{option_value}' || \
|
||||||
|
fail "customize-mode failed"
|
||||||
|
wait_mode option-a:0 1
|
||||||
|
repeat_key option-a:0 j 80
|
||||||
|
|
||||||
|
i=10
|
||||||
|
while [ "$i" -lt 30 ]; do
|
||||||
|
$TMUX set-option -gu "@mode_mut_$i" || fail "unset option failed"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
i=30
|
||||||
|
while [ "$i" -lt 55 ]; do
|
||||||
|
$TMUX set-option -g "@mode_mut_$i" "$i" || \
|
||||||
|
fail "new option failed"
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
$TMUX set-option -g status-left 'mutated' || fail "status-left failed"
|
||||||
|
$TMUX rename-session -t option-a option-renamed || fail "option rename failed"
|
||||||
|
|
||||||
|
assert_alive "customize-mode mutation"
|
||||||
|
$TMUX send-keys -t option-renamed:0 k j C-d C-u q || \
|
||||||
|
fail "customize-mode keys failed"
|
||||||
|
wait_mode option-renamed:0 0
|
||||||
|
assert_alive "customize-mode exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_copy_mode()
|
||||||
|
{
|
||||||
|
start_client copy-a 'i=0; while [ $i -lt 200 ]; do echo "copy mutation line $i"; i=$((i + 1)); done; cat'
|
||||||
|
$TMUX set-window-option -g mode-keys vi || fail "mode-keys failed"
|
||||||
|
$TMUX split-window -d -t copy-a:0 'cat' || fail "copy split failed"
|
||||||
|
|
||||||
|
$TMUX copy-mode -t copy-a:0 || fail "copy-mode failed"
|
||||||
|
wait_mode copy-a:0 1
|
||||||
|
repeat_key copy-a:0 k 20
|
||||||
|
|
||||||
|
$TMUX rename-window -t copy-a:0 renamed || fail "copy rename-window failed"
|
||||||
|
side=$($TMUX split-window -d -P -F '#{pane_id}' -t copy-a:renamed 'cat') || \
|
||||||
|
fail "copy side split failed"
|
||||||
|
$TMUX break-pane -d -s "$side" || fail "copy break-pane failed"
|
||||||
|
$TMUX join-pane -d -s "$side" -t copy-a:renamed.0 || \
|
||||||
|
fail "copy join-pane failed"
|
||||||
|
$TMUX kill-pane -t copy-a:renamed.1 || fail "copy kill-pane failed"
|
||||||
|
$TMUX new-window -d -t copy-a -n extra 'cat' || fail "copy new-window failed"
|
||||||
|
$TMUX kill-window -t copy-a:extra || fail "copy kill-window failed"
|
||||||
|
$TMUX rename-session -t copy-a copy-renamed || fail "copy rename failed"
|
||||||
|
|
||||||
|
assert_alive "copy-mode mutation"
|
||||||
|
$TMUX send-keys -t copy-renamed:renamed.0 j k C-d C-u q || \
|
||||||
|
fail "copy-mode keys failed"
|
||||||
|
wait_mode copy-renamed:renamed.0 0
|
||||||
|
assert_alive "copy-mode exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup
|
||||||
|
test_choose_tree
|
||||||
|
test_choose_buffer
|
||||||
|
test_choose_client
|
||||||
|
test_customize_mode
|
||||||
|
test_copy_mode
|
||||||
|
cleanup
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user