abra zsh config 2.0
This commit is contained in:
263
.zprezto/modules/prompt/external/async/test.zsh
vendored
Executable file
263
.zprezto/modules/prompt/external/async/test.zsh
vendored
Executable file
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env zsh
|
||||
#
|
||||
# zsh-async test runner.
|
||||
# Checks for test files named *_test.zsh or *_test.sh and runs all functions
|
||||
# named test_*.
|
||||
#
|
||||
emulate -R zsh
|
||||
|
||||
zmodload zsh/datetime
|
||||
zmodload zsh/parameter
|
||||
zmodload zsh/zutil
|
||||
zmodload zsh/system
|
||||
zmodload zsh/zselect
|
||||
|
||||
TEST_GLOB=.
|
||||
TEST_RUN=
|
||||
TEST_VERBOSE=0
|
||||
TEST_TRACE=1
|
||||
TEST_CODE_SKIP=100
|
||||
TEST_CODE_ERROR=101
|
||||
TEST_CODE_TIMEOUT=102
|
||||
|
||||
show_help() {
|
||||
print "usage: ./test.zsh [-v] [-x] [-run pattern] [search pattern]"
|
||||
}
|
||||
|
||||
parse_opts() {
|
||||
local -a verbose debug trace help run
|
||||
|
||||
local out
|
||||
zparseopts -E -D \
|
||||
v=verbose verbose=verbose -verbose=verbose \
|
||||
d=debug debug=debug -debug=debug \
|
||||
x=trace trace=trace -trace=trace \
|
||||
h=help -help=help \
|
||||
\?=help \
|
||||
run:=run -run:=run
|
||||
|
||||
(( $? )) || (( $+help[1] )) && show_help && exit 0
|
||||
|
||||
if (( $#@ > 1 )); then
|
||||
print -- "unknown arguments: $@"
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[[ -n $1 ]] && TEST_GLOB=$1
|
||||
TEST_VERBOSE=$+verbose[1]
|
||||
TEST_TRACE=$+trace[1]
|
||||
ZTEST_DEBUG=$+debug[1]
|
||||
(( $+run[2] )) && TEST_RUN=$run[2]
|
||||
}
|
||||
|
||||
t_runner_init() {
|
||||
emulate -L zsh
|
||||
|
||||
zmodload zsh/parameter
|
||||
|
||||
# _t_runner is the main loop that waits for tests,
|
||||
# used to abort test execution by exec.
|
||||
_t_runner() {
|
||||
local -a _test_defer_funcs
|
||||
integer _test_errors=0
|
||||
while read -r; do
|
||||
eval "$REPLY"
|
||||
done
|
||||
}
|
||||
|
||||
_t_log() {
|
||||
local trace=$1; shift
|
||||
local -a lines indent
|
||||
lines=("${(@f)@}")
|
||||
indent=($'\t\t'${^lines[2,$#lines]})
|
||||
print -u7 -lr - $'\t'"$trace: $lines[1]" ${(F)indent}
|
||||
}
|
||||
|
||||
# t_log is for printing log output, visible in verbose (-v) mode.
|
||||
t_log() {
|
||||
local line=$funcfiletrace[1]
|
||||
[[ ${line%:[0-9]*} = "" ]] && line=ztest:$functrace[1] # Not from a file.
|
||||
_t_log $line "$*"
|
||||
}
|
||||
|
||||
# t_skip is for skipping a test.
|
||||
t_skip() {
|
||||
_t_log $funcfiletrace[1] "$*"
|
||||
() { return 100 }
|
||||
t_done
|
||||
}
|
||||
|
||||
# t_error logs the error and fails the test without aborting.
|
||||
t_error() {
|
||||
(( _test_errors++ ))
|
||||
_t_log $funcfiletrace[1] "$*"
|
||||
}
|
||||
|
||||
# t_fatal fails the test and halts execution immediately.
|
||||
t_fatal() {
|
||||
_t_log $funcfiletrace[1] "$*"
|
||||
() { return 101 }
|
||||
t_done
|
||||
}
|
||||
|
||||
# t_defer takes a function (and optionally, arguments)
|
||||
# to be executed after the test has completed.
|
||||
t_defer() {
|
||||
_test_defer_funcs+=("$*")
|
||||
}
|
||||
|
||||
# t_done completes the test execution, called automatically after a test.
|
||||
# Can also be called manually when the test is done.
|
||||
t_done() {
|
||||
local ret=$? w=${1:-1}
|
||||
(( _test_errors )) && ret=101
|
||||
|
||||
(( w )) && wait # Wait for test children to exit.
|
||||
for d in $_test_defer_funcs; do
|
||||
eval "$d"
|
||||
done
|
||||
print -n -u8 $ret # Send exit code to ztest.
|
||||
exec _t_runner # Replace shell, wait for new test.
|
||||
}
|
||||
|
||||
source $1 # Load the test module.
|
||||
|
||||
# Send available test functions to main process.
|
||||
print -u7 ${(R)${(okM)functions:#test_*}:#test_main}
|
||||
|
||||
# Run test_main.
|
||||
if [[ -n $functions[test_main] ]]; then
|
||||
test_main
|
||||
fi
|
||||
|
||||
exec _t_runner # Wait for commands.
|
||||
}
|
||||
|
||||
# run_test_module runs all the tests from a test module (asynchronously).
|
||||
run_test_module() {
|
||||
local module=$1
|
||||
local -a tests
|
||||
float start module_time
|
||||
|
||||
# Create fd's for communication with test runner.
|
||||
integer run_pid cmdoutfd cmdinfd outfd infd doneoutfd doneinfd
|
||||
|
||||
coproc cat; exec {cmdoutfd}>&p; exec {cmdinfd}<&p
|
||||
coproc cat; exec {outfd}>&p; exec {infd}<&p
|
||||
coproc cat; exec {doneoutfd}>&p; exec {doneinfd}<&p
|
||||
|
||||
# No need to keep coproc (&p) open since we
|
||||
# have redirected the outputs and inputs.
|
||||
coproc exit
|
||||
|
||||
# Launch a new interactive zsh test runner. We don't capture stdout
|
||||
typeset -a run_args
|
||||
(( TEST_TRACE )) && run_args+=('-x')
|
||||
zsh -s $run_args <&$cmdinfd 7>&$outfd 8>&$doneoutfd &
|
||||
run_pid=$!
|
||||
|
||||
# Initialize by sending function body from t_runner_init
|
||||
# and immediately execute it as an anonymous function.
|
||||
syswrite -o $cmdoutfd "() { ${functions[t_runner_init]} } $module"$'\n'
|
||||
sysread -i $infd
|
||||
tests=(${(@)=REPLY})
|
||||
[[ -n $TEST_RUN ]] && tests=(${(M)tests:#*$TEST_RUN*})
|
||||
|
||||
integer mod_exit=0
|
||||
float mod_start mod_time
|
||||
|
||||
mod_start=$EPOCHREALTIME # Store the module start time.
|
||||
|
||||
# Run all tests.
|
||||
local test_out
|
||||
float test_start test_time
|
||||
integer text_exit
|
||||
|
||||
for test in $tests; do
|
||||
(( TEST_VERBOSE )) && print "=== RUN $test"
|
||||
|
||||
test_start=$EPOCHREALTIME # Store the test start time.
|
||||
|
||||
# Start the test.
|
||||
syswrite -o $cmdoutfd "$test; t_done"$'\n'
|
||||
|
||||
test_out=
|
||||
test_exit=-1
|
||||
while (( test_exit == -1 )); do
|
||||
# Block until there is data to be read.
|
||||
zselect -r $doneinfd -r $infd
|
||||
|
||||
if [[ $reply[2] = $doneinfd ]]; then
|
||||
sysread -i $doneinfd
|
||||
test_exit=$REPLY # Store reply from sysread
|
||||
# Store the test execution time.
|
||||
test_time=$(( EPOCHREALTIME - test_start ))
|
||||
fi
|
||||
|
||||
# Read all output from the test output channel.
|
||||
while sysread -i $infd -t 0; do
|
||||
test_out+=$REPLY
|
||||
unset REPLY
|
||||
done
|
||||
done
|
||||
|
||||
case $test_exit in
|
||||
(0|1) state=PASS;;
|
||||
(100) state=SKIP;;
|
||||
(101|102) state=FAIL; mod_exit=1;;
|
||||
*) state="????";;
|
||||
esac
|
||||
|
||||
if [[ $state = FAIL ]] || (( TEST_VERBOSE )); then
|
||||
printf -- "--- $state: $test (%.2fs)\n" $test_time
|
||||
print -n $test_out
|
||||
fi
|
||||
done
|
||||
|
||||
# Store module execution time.
|
||||
mod_time=$(( EPOCHREALTIME - mod_start ))
|
||||
|
||||
# Perform cleanup.
|
||||
kill -HUP $run_pid
|
||||
exec {outfd}>&-
|
||||
exec {infd}<&-
|
||||
exec {cmdinfd}>&-
|
||||
exec {cmdoutfd}<&-
|
||||
exec {doneinfd}<&-
|
||||
exec {doneoutfd}>&-
|
||||
|
||||
if (( mod_exit )); then
|
||||
print "FAIL"
|
||||
(( TEST_VERBOSE )) && print "exit code $mod_exit"
|
||||
printf "FAIL\t$module\t%.3fs\n" $mod_time
|
||||
else
|
||||
(( TEST_VERBOSE )) && print "PASS"
|
||||
printf "ok\t$module\t%.3fs\n" $mod_time
|
||||
fi
|
||||
|
||||
return $mod_exit
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
trap - HUP
|
||||
kill -HUP $$ 2>/dev/null
|
||||
kill -HUP -$$ 2>/dev/null
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT HUP QUIT TERM USR1
|
||||
|
||||
# Parse command arguments.
|
||||
parse_opts $@
|
||||
|
||||
(( ZTEST_DEBUG )) && setopt xtrace
|
||||
|
||||
# Execute tests modules.
|
||||
failed=0
|
||||
for tf in ${~TEST_GLOB}/*_test.(zsh|sh); do
|
||||
run_test_module $tf &
|
||||
wait $!
|
||||
(( $? )) && failed=1
|
||||
done
|
||||
|
||||
exit $failed
|
Reference in New Issue
Block a user