Last active
April 3, 2023 10:57
-
-
Save lhns/4ce68fb18979cbf4262fc87f1bff45b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set -e -o pipefail | |
shopt -s expand_aliases | |
throw() { return "${1:-1}"; } | |
trystderr() { printf %s "$TRY_INTERNAL_STDERR" | base64 -d >&2; } | |
alias try='TRY_INTERNAL_F() { ' | |
alias catch=' }; [[ $- = *e* ]]; TRY_INTERNAL_E="$?"; set +e; exec {TRY_INTERNAL_STDOUT_FD}>&1; TRY_INTERNAL_=$(set -e -o pipefail; TRY_INTERNAL_F >&${TRY_INTERNAL_STDOUT_FD}-); ERR="$?"; exec {TRY_INTERNAL_STDOUT_FD}<&-; if [[ "$TRY_INTERNAL_E" == 0 ]]; then set -e; fi; if [[ "$ERR" != 0 ]]; then ' | |
alias catchvars=' }; [[ $- = *e* ]]; TRY_INTERNAL_E="$?"; set +e; exec {TRY_INTERNAL_STDOUT_FD}>&1; TRY_INTERNAL_VARS="$(set -e -o pipefail; TRY_INTERNAL_TRAP() { declare -p "" $(compgen -v | grep -v "^ERR\$\\|^TRY_INTERNAL_" | while IFS= read -r TRY_INTERNAL_VAR; do if unset "$TRY_INTERNAL_VAR" 2>/dev/null; then printf "%s\\n" "$TRY_INTERNAL_VAR"; fi; done) 2>/dev/null || true; }; trap TRY_INTERNAL_TRAP EXIT; TRY_INTERNAL_F >&${TRY_INTERNAL_STDOUT_FD}-)"; ERR="$?"; exec {TRY_INTERNAL_STDOUT_FD}<&-; eval "$TRY_INTERNAL_VARS"; unset TRY_INTERNAL_VARS; if [[ "$TRY_INTERNAL_E" == 0 ]]; then set -e; fi; if [[ "$ERR" != 0 ]]; then ' | |
alias catcherr=' }; [[ $- = *e* ]]; TRY_INTERNAL_E="$?"; set +e; unset TRY_INTERNAL_STDERR; exec {TRY_INTERNAL_STDOUT_FD}>&1; TRY_INTERNAL_VARS="$(TRY_INTERNAL_TRAP() { declare -p "" $(compgen -v | grep -v "^ERR\$\\|^TRY_INTERNAL_" | while IFS= read -r TRY_INTERNAL_VAR; do if unset "$TRY_INTERNAL_VAR" 2>/dev/null; then printf "%s\\n" "$TRY_INTERNAL_VAR"; fi; done) >&${TRY_INTERNAL_VARS_FD}- 2>/dev/null || true; }; exec {TRY_INTERNAL_VARS_FD}>&1; (TRY_INTERNAL_=$(set -e -o pipefail; trap TRY_INTERNAL_TRAP EXIT; TRY_INTERNAL_F >&${TRY_INTERNAL_STDOUT_FD}-)) 2>&1 | printf "%s\\n" "declare -- TRY_INTERNAL_STDERR=$(base64 -w 0)")"; ERR="$?"; exec {TRY_INTERNAL_STDOUT_FD}<&-; eval "$TRY_INTERNAL_VARS"; unset TRY_INTERNAL_VARS; if [[ "$TRY_INTERNAL_E" == 0 ]]; then set -e; fi; if [[ "$ERR" = 0 ]]; then trystderr; fi; if [[ "$ERR" != 0 ]]; then ' | |
# Tests | |
assert() { | |
local expected_exit="$1" | |
local expected_out="$2" | |
local expected_err="$3" | |
shift 3 | |
( | |
set +e | |
obtained="$( | |
exec {tmp}>&1 | |
( | |
( | |
"$@" | |
echo "exit: $?" >&${tmp} | |
) | while IFS= read -r line; do echo "stdout: $line"; done >&${tmp} | |
) 2>&1 | while IFS= read -r line; do echo "stderr: $line"; done | |
exec {tmp}<&- | |
)" | |
obtained_exit="$(printf %s "$obtained" | grep "^exit: " | sed -e 's/^exit: //')" | |
obtained_out="$(printf %s "$obtained" | grep "^stdout: " | sed -e 's/^stdout: //')" | |
obtained_err="$(printf %s "$obtained" | grep "^stderr: " | sed -e 's/^stderr: //')" | |
error=0 | |
if [[ "$expected_exit" != "$obtained_exit" ]]; then error=1; echo "unexpected exit code! expected: $expected_exit, obtained: $obtained_exit"; fi | |
if [[ "$expected_out" != "$obtained_out" ]]; then error=1; echo "unexpected stdout! expected: '$expected_out', obtained: '$obtained_out'"; fi | |
if [[ "$expected_err" != "$obtained_err" ]]; then error=1; echo "unexpected stderr! expected: '$expected_err', obtained: '$obtained_err'"; fi | |
return "$error" | |
) | |
} | |
F() { test=0; try test=1; echo testout; echo testerr >&2; true; catch echo "error $ERR"; fi; echo "test $test"; }; assert 0 $'testout\ntest 0' $'testerr' F | |
F() { test=0; try test=1; echo testout; echo testerr >&2; throw 2; catch echo "error $ERR"; fi; echo "test $test"; }; assert 0 $'testout\nerror 2\ntest 0' $'testerr' F | |
F() { test=0; try test=1; echo testout; echo testerr >&2; true; catchvars echo "error $ERR"; fi; echo "test $test"; }; assert 0 $'testout\ntest 1' $'testerr' F | |
F() { test=0; try test=1; echo testout; echo testerr >&2; throw 2; catchvars echo "error $ERR"; fi; echo "test $test"; }; assert 0 $'testout\nerror 2\ntest 1' $'testerr' F | |
F() { test=0; try test=1; echo testout; echo testerr >&2; true; catcherr echo "error $ERR"; fi; echo "test $test"; }; assert 0 $'testout\ntest 1' $'testerr' F | |
F() { test=0; try test=1; echo testout; echo testerr >&2; throw 2; catcherr echo "error $ERR"; fi; echo "test $test"; }; assert 0 $'testout\nerror 2\ntest 1' $'' F | |
F() { test=0; try test=1; echo testout; echo testerr >&2; throw 2; catcherr echo "error $ERR"; fi; echo "test $test"; echo "stderr $(trystderr 2>&1)"; }; assert 0 $'testout\nerror 2\ntest 1\nstderr testerr' $'' F |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment