refactor(cli): group theme browser files

This commit is contained in:
Robby Russell
2026-09-09 05:48:02 -07:00
parent 2e0c643117
commit 3bf157dc77
9 changed files with 74 additions and 137 deletions
+350
View File
@@ -0,0 +1,350 @@
#!/usr/bin/env zsh
# Run with: zsh -df tools/theme-browser/tests/browser_test.zsh
# Optionally pass one group, e.g. `slow-interrupt`, to run it alone.
# Each browser runs under a real controlling PTY, with no user startup files.
emulate -R zsh
if [[ $1 == --child ]]; then
if [[ $2 == completion ]]; then
function compdef { print -r -- "REGISTERED:${(j.:.)@}"; }
fi
source "$ZSH/lib/cli.zsh"
# Match normal OMZ sessions without sourcing any user startup/configuration.
setopt promptsubst
print -r -- "LAZY:$+functions[_omz_theme_browser]:$+functions[_omz_theme_preview]"
if [[ $2 == completion ]]; then
# Capture the real completion function's candidates without loading the
# user's completion setup or replacing any CLI/backend functions.
function _describe { print -rl -- "DESCRIBE:$1" "${(@P)2}"; }
CURRENT=3 words=(omz theme '')
print -r -- SUBCOMMANDS
_omz
print -r -- END_SUBCOMMANDS
for action in browse preview set use; do
CURRENT=4 words=(omz theme "$action" '')
print -r -- "CANDIDATES:$action"
_omz
print -r -- "END:$action"
done
print -r -- "STILL_LAZY:$+functions[_omz_theme_browser]:$+functions[_omz_theme_preview]"
print -r -- COMPLETIONS_FINISHED
exit
fi
if [[ $2 == reject* ]]; then
case $2 in
reject-stdin) omz theme browse </dev/null ;;
reject-stdout) omz theme browse >/dev/null ;;
*) omz theme browse ;;
esac
result=$?
print -r -- "REJECT:$result:$+functions[_omz_theme_browser]:$+functions[_omz_theme_preview]"
exit
fi
function _omz::theme::use { calls+=("use:$1"); ZSH_THEME=$1; }
function _omz::theme::set { calls+=("set:$1"); ZSH_THEME=$1; }
function browser_test_hook { : parent-hook; }
function precmd { : parent-precmd; }
typeset -a calls=() precmd_functions=(browser_test_hook) chpwd_functions=(browser_test_hook)
ZSH_THEME=parent-theme PROMPT=parent-prompt RPROMPT=parent-rprompt
typeset original_hook=$functions[browser_test_hook] original_precmd=$functions[precmd]
typeset original_options=$(setopt) original_pwd=$PWD
stty rows 24 cols 100
# PENDIN is a transient kernel input-reprocessing flag, not a user mode.
typeset original_tty=$(stty -a)
original_tty=${${original_tty//-pendin/}//pendin/}
tty > "$TEST_SCRATCH/tty"
print -r -- READY
# An interactive script otherwise aborts on SIGINT instead of returning to
# the next prompt as an interactive command loop would.
trap ':' INT
omz theme browse "$2"
result=$?
typeset restored_tty=$(stty -a)
restored_tty=${${restored_tty//-pendin/}//pendin/}
if [[ $restored_tty == "$original_tty" ]]; then
print -r -- TTY_RESTORED
else
print -r -- "TTY_MISMATCH:before=$original_tty after=$restored_tty"
fi
if [[ $PROMPT == parent-prompt && $RPROMPT == parent-rprompt &&
$functions[browser_test_hook] == "$original_hook" &&
$functions[precmd] == "$original_precmd" &&
${(j:,:)precmd_functions} == browser_test_hook &&
${(j:,:)chpwd_functions} == browser_test_hook &&
-o promptsubst && $(setopt) == "$original_options" && $PWD == "$original_pwd" &&
${BROWSER_TEST_LEAK-unset} == unset ]]; then
print -r -- PARENT_UNCHANGED
fi
print -r -- "RESULT:$result:${(j:,:)calls}:$ZSH_THEME"
print -r -- FINISHED
exit 0
fi
setopt err_exit pipe_fail
[[ -n $BROWSER_TEST_TRACE ]] && setopt xtrace
zmodload zsh/zpty
zmodload zsh/datetime
zmodload zsh/zselect
typeset -r repo=${0:A:h:h:h:h} self=${0:A}
typeset scratch=$(mktemp -d "${TMPDIR:-/tmp}/omz-browser-test.XXXXXXXX")
scratch=${scratch:A}
trap 'zpty -d 2>/dev/null; command rm -rf -- "$scratch"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
mkdir -p "$scratch/home" "$scratch/custom/themes/nested" "$scratch/tmp"
export ZSH=$repo ZSH_CUSTOM=$scratch/custom HOME=$scratch/home ZDOTDIR=$scratch/home
export TMPDIR=$scratch/tmp TEST_SCRATCH=$scratch TERM=xterm-256color
unset ZSH_THEME
# Even a mistakenly enabled startup-file load must never reach real dotfiles.
print -r -- 'print STARTUP_RAN; exit 99' > "$HOME/.zshenv"
print -r -- 'PROMPT="nested fixture"' > "$ZSH_CUSTOM/themes/nested/browser-fixture.zsh-theme"
for number in {01..10}; do
print -r -- 'typeset -g BROWSER_TEST_LEAK=bad
ZSH_THEME=fixture-theme
precmd_functions=() chpwd_functions=()
function precmd { PROMPT="%F{red}FIXTURE_PREVIEW%f" }
RPROMPT="fixture-right"' > "$ZSH_CUSTOM/zz-omz-test-$number.zsh-theme"
done
print -r -- 'sleep 30 &
print -r -- $! > "$TEST_SCRATCH/slow-pid"
wait
PROMPT="SLOW_FINISHED"' > "$ZSH_CUSTOM/zz-omz-test-slow.zsh-theme"
typeset filter_probe='$(print HIT > $TEST_SCRATCH/filter-executed)'
typeset preview_probe='$(print HIT > $TEST_SCRATCH/preview-executed)'
# Emit literal preview output, rather than asking the worker to evaluate a
# prompt expression. Only a second evaluation by the browser can execute it.
print -rl -- "print -r -- ${(q)preview_probe}" 'PROMPT="literal-preview-ready"' > "$ZSH_CUSTOM/literal-browser.zsh-theme"
typeset buffer='' transcript='' chunk='' label=''
typeset -F browser_finished_at=0
function cleanup_pty {
local record group
for record in "${(@f)$(zpty)}"; do
[[ $record == \(<->\)\ browser:* ]] || continue
group=${${record#\(}%%\)*}
kill -HUP -- -$group 2>/dev/null || true
zselect -t 20 || true
# A renderer regression can loop without checking its cancellation flag.
kill -KILL -- -$group 2>/dev/null || true
done
zpty -d 2>/dev/null || true
return 0
}
function fail {
print -u2 -r -- "FAIL: $label: $1"
print -u2 -r -- "PTY transcript, last 4000 characters (escaped): ${(V)transcript[-4000,-1]}"
exit 1
}
function check {
"$@" || fail "$1 assertion failed"
}
function await {
local wanted=$1
local -F deadline=$(( EPOCHREALTIME + ${2:-6} ))
[[ $buffer == *"$wanted"* ]] && return 0
while (( EPOCHREALTIME < deadline )); do
if zpty -r browser chunk; then
buffer+=$chunk transcript+=$chunk
[[ $buffer == *"$wanted"* ]] && return 0
else
zselect -t 1 || true
fi
done
fail "timed out waiting for ${(V)wanted}"
}
function send {
buffer=''
zpty -w -n browser "$1"
}
function start {
label=$1 buffer='' transcript=''
local -a launch=("$commands[zsh]" -dfi "$self" --child "$2")
zpty -b browser exec "${(@q)launch}"
await 'LAZY:0:0'
await "$3"
}
function finish {
await FINISHED
# zpty -d can spend a second reaping an already-completed child. It is
# harness teardown, not browser cancellation/terminal-restoration latency.
browser_finished_at=$EPOCHREALTIME
check test "${transcript#*TTY_RESTORED}" != "$transcript"
check test "${transcript#*PARENT_UNCHANGED}" != "$transcript"
check test "${transcript#*RESULT:$1}" != "$transcript"
check test "${transcript#*$'\e[?1049l'}" != "$transcript"
check test "${transcript#*$'\e[?25h'}" != "$transcript"
check test "${transcript#*STARTUP_RAN}" = "$transcript"
zpty -d browser
[[ -z $BROWSER_TEST_TIMING ]] || print -r -- "TIMING: PTY deletion $(( EPOCHREALTIME - browser_finished_at ))s"
}
function test_completion {
start 'completion registration, commands, theme candidates, lazy loading' completion COMPLETIONS_FINISHED
check test "${transcript#*REGISTERED:_omz:omz}" != "$transcript"
local section=${${transcript#*SUBCOMMANDS}%END_SUBCOMMANDS*} action
check test "${section#*browse:Browse theme previews}" != "$section"
check test "${section#*preview:Preview a theme without applying it}" != "$section"
for action in browse preview set use; do
section=${${transcript#*CANDIDATES:$action}%END:$action*}
check test "${section#*DESCRIBE:theme}" != "$section"
for name in robbyrussell zz-omz-test-01 nested/browser-fixture; do
check test "${section#*$name}" != "$section"
done
done
check test "${transcript#*STILL_LAZY:0:0}" != "$transcript"
check test "${transcript#*STARTUP_RAN}" = "$transcript"
zpty -d browser
}
function test_rejection {
# Noninteractive rejection even with both descriptors attached to a PTY.
label=noninteractive
typeset -a launch=("$commands[zsh]" -df "$self" --child reject)
zpty -b browser exec "${(@q)launch}"
await 'REJECT:1:0:0'
check test "${transcript#*requires an interactive terminal}" != "$transcript"
zpty -d browser
for mode in stdin stdout; do
start "redirected $mode" "reject-$mode" 'REJECT:1:0:0'
check test "${transcript#*requires an interactive terminal}" != "$transcript"
zpty -d browser
done
label='noninteractive and redirected-I/O rejection'
}
function test_navigation {
start 'filter, navigation, actions/back, Esc isolation' zz-omz-test- '> zz-omz-test-01'
await FIXTURE_PREVIEW
send $'\e[B'; await '> zz-omz-test-02'
send $'\e[A'; await '> zz-omz-test-01'
send $'\x0e'; await '> zz-omz-test-02'
send $'\x10'; await '> zz-omz-test-01'
send $'\e[6~'; await '> zz-omz-test-05'
send $'\e[5~'; await '> zz-omz-test-01'
send '09'; await '> zz-omz-test-09'
send $'\x7f'; await '(9 themes)'
send $'\x15'; await 'Filter: ('
send 'ZZ-OMZ-TEST-03'; await '> zz-omz-test-03'
send $'\r'; await '[u] Use in session'
send b; await 'Enter: actions'
send $'\x15no-such-omz-fixture'; await 'No matching themes.'
send $'\r'; await 'No matching themes.'
send $'\e'
finish '0::parent-theme'
}
function test_use {
start 'explicit use dispatch' zz-omz-test-01 '> zz-omz-test-01'
send $'\r'; await '[u] Use in session'
send u
finish '0:use:zz-omz-test-01:zz-omz-test-01'
}
function test_promptsubst {
start 'literal filter/preview substitutions with parent promptsubst enabled' literal-browser '> literal-browser'
await "$preview_probe"
await literal-preview-ready
check test ! -e "$scratch/preview-executed"
send $'\x15'"$filter_probe"
await "Filter: $filter_probe"
await 'No matching themes.'
check test ! -e "$scratch/filter-executed"
send $'\x15literal-browser'
await "$preview_probe"
await literal-preview-ready
send $'\e'
finish '0::parent-theme'
check test ! -e "$scratch/filter-executed"
check test ! -e "$scratch/preview-executed"
}
function test_save {
start 'explicit save dispatch (stubbed)' zz-omz-test-02 '> zz-omz-test-02'
send $'\r'; await '[u] Use in session'
send s
finish '0:set:zz-omz-test-02:zz-omz-test-02'
}
function test_interrupt {
start 'Ctrl-C restores terminal' zz-omz-test-01 '> zz-omz-test-01'
send $'\x03'
finish '130::parent-theme'
}
function test_resize {
start 'resize small and back' zz-omz-test-01 '> zz-omz-test-01'
typeset terminal=$(<"$scratch/tty")
terminal=${terminal//$'\r'/}
buffer=''
stty rows 10 cols 30 < "$terminal"
await '40 columns x 16 rows.'
buffer=''
stty rows 24 cols 100 < "$terminal"
await '> zz-omz-test-01'
send $'\e'
finish '0::parent-theme'
}
function test_slow {
local cancellation=$1
command rm -f "$scratch/slow-pid"
start "slow preview cancellation: $cancellation" zz-omz-test-slow '> zz-omz-test-slow'
for attempt in {1..150}; do
[[ -s "$scratch/slow-pid" ]] && break
zselect -t 1 || true
done
check test -s "$scratch/slow-pid"
typeset -F started=$EPOCHREALTIME
case $cancellation in
navigation)
send $'\x15zz-omz-test-01'
await FIXTURE_PREVIEW 2
[[ -z $BROWSER_TEST_TIMING ]] || print -r -- "TIMING: navigation preview $(( EPOCHREALTIME - started ))s"
(( EPOCHREALTIME - started < 2 )) || fail 'replacement preview exceeded 2 seconds'
send $'\e'
finish '0::parent-theme'
;;
escape) send $'\e'; finish '0::parent-theme' ;;
interrupt) send $'\x03'; finish '130::parent-theme' ;;
esac
[[ -z $BROWSER_TEST_TIMING ]] || print -r -- "TIMING: browser completed $(( browser_finished_at - started ))s; including teardown $(( EPOCHREALTIME - started ))s"
(( browser_finished_at - started < 2 )) || fail "browser completion exceeded 2 seconds: $(( browser_finished_at - started ))s"
typeset child=$(<"$scratch/slow-pid") child_state
for attempt in {1..100}; do
child_state=$(command ps -o stat= -p "$child" 2>/dev/null || true)
[[ -z "${child_state//[ ZN+]/}" ]] && break
zselect -t 1 || true
done
[[ -z $BROWSER_TEST_TIMING ]] || print -r -- "TIMING: descendant $child state=${child_state:-absent}, cleanup polls=$attempt"
[[ -z "${child_state//[ ZN+]/}" ]] || fail "preview descendant $child still running: $child_state"
}
# Keep independent regressions running after a failed UI session.
unsetopt err_exit
typeset -i failures=0
for scenario in rejection completion navigation promptsubst use save interrupt resize slow-navigation slow-escape slow-interrupt; do
[[ -z $1 || $scenario == "$1" ]] || continue
(
setopt err_exit
trap 'cleanup_pty' EXIT
if [[ $scenario == slow-* ]]; then
test_slow "${scenario#slow-}"
else
test_$scenario
fi
print -r -- "PASS: $label"
)
(( $? == 0 )) || (( failures++ ))
done
typeset -a leftovers
for attempt in {1..100}; do
leftovers=("$TMPDIR"/omz-preview.*(N))
(( $#leftovers == 0 )) && break
zselect -t 1 || true
done
if (( $#leftovers )); then
print -u2 -r -- "FAIL: $#leftovers preview temporary directories remain"
(( failures++ ))
fi
print -r -- "Theme browser regression groups failed: $failures"
(( failures == 0 ))
+282
View File
@@ -0,0 +1,282 @@
#!/usr/bin/env zsh
# Run with: zsh -df tools/theme-browser/tests/preview_test.zsh
emulate -R zsh
setopt err_exit pipe_fail
typeset -r repo=${0:A:h:h:h:h}
source "$repo/tools/theme-browser/preview.zsh"
typeset scratch=$(mktemp -d "${TMPDIR:-/tmp}/omz-preview-test.XXXXXXXX")
scratch=${scratch:A}
trap 'command rm -rf -- "$scratch"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
mkdir "$scratch/tmp"
export TMPDIR=$scratch/tmp
function check {
if ! "$@"; then
print -u2 -r -- "FAIL: ${(j: :)@}"
exit 1
fi
}
export ZSH=$scratch/omz ZSH_CUSTOM=$scratch/custom
mkdir -p "$ZSH/themes" "$ZSH_CUSTOM/themes/nested" "$scratch/home" "$scratch/work"
print -r -- "PROMPT='bundled'" > "$ZSH/themes/same.zsh-theme"
print -r -- "PROMPT='custom themes'" > "$ZSH_CUSTOM/themes/same.zsh-theme"
print -r -- "PROMPT='custom root'" > "$ZSH_CUSTOM/same.zsh-theme"
print -r -- "PROMPT='z'" > "$ZSH/themes/zebra.zsh-theme"
print -r -- "PROMPT='a'" > "$ZSH/themes/alpha.zsh-theme"
print -r -- "PROMPT='bad'" > "$ZSH/themes/"$'bad\nname.zsh-theme'
print -r -- "PROMPT='random'" > "$ZSH/themes/random.zsh-theme"
print -r -- "PROMPT='nested'" > "$ZSH_CUSTOM/themes/nested/example.zsh-theme"
check test "$(_omz_theme_names)" = $'alpha\nnested/example\nsame\nzebra'
check test "$(_omz_theme_resolve nested/example)" = "$ZSH_CUSTOM/themes/nested/example.zsh-theme"
check test "$(_omz_theme_resolve same)" = "$ZSH_CUSTOM/same.zsh-theme"
rm "$ZSH_CUSTOM/same.zsh-theme"
check test "$(_omz_theme_resolve same)" = "$ZSH_CUSTOM/themes/same.zsh-theme"
rm "$ZSH_CUSTOM/themes/same.zsh-theme"
check test "$(_omz_theme_resolve same)" = "$ZSH/themes/same.zsh-theme"
for name in ../same /same . .. nested/../same nested/./example nested//example random $'bad\nname' 'bad\name' missing ''; do
if _omz_theme_resolve "$name" > /dev/null 2>&1; then
print -u2 -r -- 'FAIL: accepted invalid/missing name'
exit 1
fi
done
# The fixtures intentionally write only inside this private, always-cleaned tree.
print -r -- 'print STARTUP_RAN; exit 99' > "$scratch/home/.zshenv"
export ZDOTDIR=$scratch/home PREVIEW_ENV=preserved
print -r -- '
typeset -g PREVIEW_LEAK=bad
export PREVIEW_ENV=changed
alias preview_leak=true
setopt noclobber
function precmd { PROMPT="hook:$PWD:$PREVIEW_ENV:%?" }
function second_hook { RPROMPT="second-hook:%?" }
precmd_functions=(second_hook)
' > "$ZSH_CUSTOM/isolation.zsh-theme"
typeset before_pwd=$PWD before_options=$(setopt) before_env=$PREVIEW_ENV
typeset output=$(_omz_theme_preview isolation 7)
check test "$PWD" = "$before_pwd"
check test "$(setopt)" = "$before_options"
check test "$PREVIEW_ENV" = "$before_env"
check test "${PREVIEW_LEAK-unset}" = unset
check test "${aliases[preview_leak]-unset}" = unset
check test "${functions[second_hook]-unset}" = unset
check test "${output#*hook:${PWD}:changed:7}" != "$output"
check test "${output#*second-hook:7}" != "$output"
check test "${output#*STARTUP_RAN}" = "$output"
print -r -- 'PROMPT="env:$PREVIEW_ENV cwd:$PWD %(?.success.failure)"' > "$ZSH_CUSTOM/status.zsh-theme"
output=$(_omz_theme_preview status)
check test "${output#*env:preserved cwd:${PWD} success}" != "$output"
output=$(_omz_theme_preview status 1)
check test "${output#*failure}" != "$output"
if _omz_theme_preview status nope >/dev/null 2>&1; then exit 1; fi
# Values produced by parameters or helpers are prompt text, not shell code for
# a second substitution pass. Check both sides and the helper's incoming status.
export PREVIEW_REEXECUTED=$scratch/reexecuted
export PREVIEW_LITERAL='$(print reexecuted > "$PREVIEW_REEXECUTED")'
print -r -- '
function literal_helper { print -r -- "helper-status:$? $PREVIEW_LITERAL" }
PROMPT='"'"'$PREVIEW_LITERAL $(literal_helper) %?'"'"'
RPROMPT='"'"'$(literal_helper) $PREVIEW_LITERAL %?'"'"'
' > "$ZSH_CUSTOM/literal.zsh-theme"
output=$(_omz_theme_preview literal 7)
check test ! -e "$PREVIEW_REEXECUTED"
check test "${output#*"$PREVIEW_LITERAL"}" != "$output"
check test "${output#*helper-status:7}" != "$output"
check test "${output#*"$PREVIEW_LITERAL 7"}" != "$output"
print -r -- 'unsetopt promptsubst; PROMPT='"'"'$PREVIEW_LITERAL %?'"'" > "$ZSH_CUSTOM/no-subst.zsh-theme"
output=$(_omz_theme_preview no-subst 7)
check test "${output#*'$PREVIEW_LITERAL 7'}" != "$output"
print -r -- 'PROMPT="conditional prompt"; [[ -n ${OMZ_PREVIEW_UNSET_SSH-} ]] && RPROMPT="remote"' > "$ZSH_CUSTOM/final-false.zsh-theme"
output=$(_omz_theme_preview final-false)
check test "${output#*conditional prompt}" != "$output"
print -r -- 'PROMPT=""' > "$ZSH_CUSTOM/empty.zsh-theme"
output=$(_omz_theme_preview empty)
print -r -- 'RPROMPT="right-only"; false' > "$ZSH_CUSTOM/right-only.zsh-theme"
output=$(_omz_theme_preview right-only)
check test "${output#*right-only}" != "$output"
# A helper can fail inside command substitution without making print -P fail.
# Its runtime diagnostic must remain visible in the sanitized partial preview.
print -r -- 'PROMPT='"'"'$( _omz_preview_missing_helper )'"'" > "$ZSH_CUSTOM/helper-failure.zsh-theme"
output=$(_omz_theme_preview helper-failure 2>&1)
check test "${output#*command not found: _omz_preview_missing_helper}" != "$output"
# A failing precmd (or array hook) stops later hooks, as in interactive zsh.
# Preserve any partial preview, but report failure rather than silently claiming
# that an incomplete initialization is a faithful preview.
for hook_setup in 'precmd() { return 3 }; precmd_functions=(must_not_run)' \
'failed_hook() { return 4 }; precmd_functions=(failed_hook must_not_run)' \
'failed_hook() { _omz_preview_missing_command }; precmd_functions=(failed_hook must_not_run)'; do
print -rl -- 'PROMPT="partial prompt"; must_not_run() { print UNEXPECTED_HOOK; }' "$hook_setup" > "$ZSH_CUSTOM/hook-failure.zsh-theme"
if _omz_theme_preview hook-failure >"$scratch/hook-error" 2>&1; then
print -u2 -r -- 'FAIL: accepted failing precmd hook'
exit 1
fi
output=$(<"$scratch/hook-error")
check test "${output#*UNEXPECTED_HOOK}" = "$output"
check test "${output#*remaining hooks skipped}" != "$output"
check test "${output#*partial prompt}" != "$output"
done
# No language runtime, timeout utility, or process-inspection utility is needed
# by the backend. The worker still has zsh's usual autoload/module search paths.
mkdir "$scratch/bin"
for name in zsh mktemp mkfifo rm; do
ln -s "$commands[$name]" "$scratch/bin/$name"
done
output=$(PATH="$scratch/bin" _omz_theme_preview status)
check test "${output#*success}" != "$output"
print -r -- '[[ ! -t 0 && ! -t 1 && ! -t 2 && ! -o interactive ]] || exit 9; PROMPT="non-tty"' > "$ZSH_CUSTOM/non-tty.zsh-theme"
output=$(_omz_theme_preview non-tty)
check test "${output#*non-tty}" != "$output"
print -r -- 'print -n -- "\e]52;c;SECRET\a\e[2J\r\b\ePSECRET\e\\"; PROMPT="%F{red}safe%f"' > "$ZSH_CUSTOM/escapes.zsh-theme"
output=$(_omz_theme_preview escapes)
check test "${output#*SECRET}" = "$output"
check test "${output#*$'\e[2J'}" = "$output"
check test "${output#*$'\r'}" = "$output"
check test "${output#*$'\e[31m'safe}" != "$output"
for code in 'return 1' 'exit 0' 'exit 7' 'if then' 'PROMPT="partial"; if then' \
'PROMPT="partial"; return 2' 'PROMPT="partial"; _omz_preview_missing_command'; do
print -r -- "$code" > "$ZSH_CUSTOM/broken.zsh-theme"
if _omz_theme_preview broken >"$scratch/error" 2>&1; then
print -u2 -r -- "FAIL: accepted broken theme: $code"
exit 1
fi
done
print -r -- 'while true; do print -r -- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; done' > "$ZSH_CUSTOM/flood.zsh-theme"
if _omz_theme_preview flood >"$scratch/flood" 2>&1; then exit 1; fi
check test "$(wc -c < "$scratch/flood")" -le 32768
print -r -- 'printf "\377%.0s" {1..11000}; PROMPT="safe"' > "$ZSH_CUSTOM/bytes.zsh-theme"
_omz_theme_preview bytes >"$scratch/bytes" 2>&1
check test "$(wc -c < "$scratch/bytes")" -le 32768
check test "${$(<"$scratch/bytes")#*$'\xff'}" = "$(<"$scratch/bytes")"
print -r -- 'printf "\233m%.0s" {1..12000}; PROMPT="safe"' > "$ZSH_CUSTOM/csi-bytes.zsh-theme"
_omz_theme_preview csi-bytes >"$scratch/csi-bytes" 2>&1
check test "$(wc -c < "$scratch/csi-bytes")" -le 32768
print -r -- 'sleep 30 & print -r -- $! > "$PREVIEW_PID_FILE"; wait' > "$ZSH_CUSTOM/slow.zsh-theme"
export PREVIEW_PID_FILE=$scratch/child
zmodload zsh/datetime
typeset -F started=$EPOCHREALTIME
if _omz_theme_preview slow >"$scratch/timeout" 2>&1; then exit 1; fi
check test $(( EPOCHREALTIME - started < 5 )) = 1
check test "${$(<"$scratch/timeout")#*timed out}" != "$(<"$scratch/timeout")"
typeset child=$(<"$scratch/child")
# A killed orphan may briefly remain a zombie until the system reaps it.
typeset child_state=$(command ps -o stat= -p "$child" 2>/dev/null || true)
check test -z "${child_state//[ ZN+]/}"
for signal in INT TERM HUP; do
rm -f "$PREVIEW_PID_FILE"
_omz_theme_preview slow >"$scratch/cancel" 2>&1 &
typeset preview_job=$!
for attempt in {1..100}; do
[[ -s "$PREVIEW_PID_FILE" ]] && break
sleep 0.01
done
check test -s "$PREVIEW_PID_FILE"
# zsh adds a waiting wrapper around a backgrounded subshell function.
# Signal the supervisor itself; terminal interrupts reach it via the job group.
typeset supervisor='' candidate='' parent=''
for candidate parent in ${(z)$(command ps -A -o pid= -o ppid=)}; do
if [[ $parent == $preview_job ]]; then
supervisor=$candidate
break
fi
done
check test -n "$supervisor"
kill -$signal "$supervisor"
typeset result=0
wait "$preview_job" || result=$?
if (( result != 130 && result != 143 && result != 129 )); then
print -u2 -r -- "Unexpected cancellation result: $result: $(<"$scratch/cancel")"
fi
if [[ $signal == INT ]]; then
check test "$result" = 130
elif [[ $signal == TERM ]]; then
check test "$result" = 143
else
check test "$result" = 129
fi
child=$(<"$PREVIEW_PID_FILE")
child_state=$(command ps -o stat= -p "$child" 2>/dev/null || true)
check test -z "${child_state//[ ZN+]/}"
done
print -r -- 'sleep 30 & print -r -- $! > "$PREVIEW_PID_FILE"; PROMPT="background"' > "$ZSH_CUSTOM/background.zsh-theme"
output=$(_omz_theme_preview background)
child=$(<"$PREVIEW_PID_FILE")
child_state=$(command ps -o stat= -p "$child" 2>/dev/null || true)
check test -z "${child_state//[ ZN+]/}"
# Match the browser's nested-PTY invocation, preserving other owned PTYs.
zmodload zsh/zpty
zpty -b unrelated 'exec sleep 30'
typeset -a nested_command=("$commands[zsh]" -dfc 'source "$1"; _omz_theme_preview status' zsh "$repo/tools/theme-browser/preview.zsh")
zpty -b browser exec "${(@q)nested_command}"
output=''
for attempt in {1..300}; do
if zpty -r browser chunk; then
output+=$chunk
elif ! zpty -t browser; then
break
else
sleep 0.01
fi
done
check test "${output#*success}" != "$output"
check zpty -t unrelated
zpty -d browser unrelated
# Cancellation by the browser's outer process group must also clean the
# backend's separate inner PTY group and private FIFO directory.
rm -f "$PREVIEW_PID_FILE"
nested_command=("$commands[zsh]" -dfc 'source "$1"; _omz_theme_preview slow' zsh "$repo/tools/theme-browser/preview.zsh")
zpty -b browser exec "${(@q)nested_command}"
typeset browser_group record
for record in "${(@f)$(zpty)}"; do
[[ $record == \(<->\)\ browser:* ]] && browser_group=${${record#\(}%%\)*}
done
check test -n "$browser_group"
for attempt in {1..100}; do
[[ -s "$PREVIEW_PID_FILE" ]] && break
sleep 0.01
done
check test -s "$PREVIEW_PID_FILE"
child=$(<"$PREVIEW_PID_FILE")
kill -TERM -- -$browser_group
for attempt in {1..100}; do
child_state=$(command ps -o stat= -p "$child" 2>/dev/null || true)
[[ -z "${child_state//[ ZN+]/}" ]] && break
sleep 0.01
done
check test -z "${child_state//[ ZN+]/}"
zpty -d browser
# Real themes exercise synchronous git, top-level locals, command substitution,
# and hook-driven prompt construction against an isolated repository.
export ZSH=$repo
git -C "$scratch/work" init -q
git -C "$scratch/work" symbolic-ref HEAD refs/heads/preview-branch
output=$(zsh -dfc 'builtin cd "$1"; source tools/theme-browser/preview.zsh; builtin cd "$2"; _omz_theme_preview robbyrussell' zsh "$repo" "$scratch/work")
check test "${output#*preview-branch}" != "$output"
for name in robbyrussell dieter agnoster bira nicoulaj half-life; do
output=$(builtin cd "$scratch/work"; _omz_theme_preview "$name" 7)
check test "${output#*Left prompt}" != "$output"
check test "${output#*Right prompt}" != "$output"
check test "${output#*preview-branch}" != "$output"
if [[ $name == dieter || $name == bira ]]; then
check test "${output#*7 }" != "$output"
fi
done
typeset -a leftovers=("$TMPDIR"/omz-preview.*(N))
check test "$#leftovers" = 0
print -r -- 'PASS: theme preview resolution, isolation, single-pass expansion, conditional loads, hook failures, status, sanitization, limits, cancellation, descendant cleanup, and six bundled themes'