Skip to content

Instantly share code, notes, and snippets.

@lhns
Last active April 3, 2023 10:57
Show Gist options
  • Save lhns/4ce68fb18979cbf4262fc87f1bff45b1 to your computer and use it in GitHub Desktop.
Save lhns/4ce68fb18979cbf4262fc87f1bff45b1 to your computer and use it in GitHub Desktop.
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