| 1 | #!/bin/sh |
| 2 | TEST_PREFIX="[int-error-handling]" |
| 3 | SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) |
| 4 | SHELL_BIN="${SHELL_BIN:?ERROR: SHELL_BIN must be set}" |
| 5 | export SHELL_BIN |
| 6 | . "$SCRIPT_DIR/../test_harness.sh" |
| 7 | |
| 8 | # Integration tests: error handling with set -e, pipefail, and error propagation |
| 9 | |
| 10 | section "1. set -e (errexit) basics" |
| 11 | compare_output "no error continues" 'set -e; true; echo reached' |
| 12 | compare_exit "error exits" 'set -e; false; echo unreachable' |
| 13 | compare_output "OR suppresses errexit" 'set -e; false || true; echo reached' |
| 14 | compare_output "if condition doesnt trigger" 'set -e; if false; then :; fi; echo reached' |
| 15 | compare_output "while condition doesnt trigger" 'set -e; while false; do :; done; echo reached' |
| 16 | compare_output "negation doesnt trigger" 'set -e; ! false; echo reached' |
| 17 | compare_output "AND left fail doesnt exit alone" 'set -e; false && true; echo reached' |
| 18 | compare_output "set +e disables" 'set -e; set +e; false; echo reached' |
| 19 | compare_output "errexit with command sub" 'set -e; echo $(true); echo reached' |
| 20 | |
| 21 | section "2. set -e in subshells" |
| 22 | compare_output "subshell error exits subshell" 'set -e; (false) || echo recovered' |
| 23 | compare_exit "errexit in subshell" '(set -e; false; echo unreachable)' |
| 24 | compare_output "errexit subshell status" '(set -e; false; echo unreachable); echo $?' |
| 25 | compare_output "parent errexit child fails" 'set -e; (false) || true; echo reached' |
| 26 | |
| 27 | section "3. set -e in functions" |
| 28 | compare_exit "errexit function fails" 'set -e; f() { false; echo unreachable; }; f; echo after' |
| 29 | compare_exit "errexit inside function" 'f() { set -e; false; echo unreachable; }; f' |
| 30 | compare_output "errexit function in conditional" 'set -e; f() { false; }; if f; then echo yes; else echo no; fi; echo after' |
| 31 | compare_output "errexit with return" 'set -e; f() { return 1; }; f || echo caught; echo after' |
| 32 | |
| 33 | section "4. pipefail" |
| 34 | compare_output "pipefail first fails" 'set -o pipefail; false | true; echo $?' |
| 35 | compare_output "pipefail middle fails" 'set -o pipefail; true | false | true; echo $?' |
| 36 | compare_output "pipefail all succeed" 'set -o pipefail; true | true; echo $?' |
| 37 | compare_output "pipefail all fail" 'set -o pipefail; false | false; echo $?' |
| 38 | compare_exit "errexit plus pipefail" 'set -eo pipefail; false | true; echo unreachable' |
| 39 | compare_output "pipefail disabled by default" 'false | true; echo $?' |
| 40 | compare_output "pipefail with echo" 'set -o pipefail; echo hello | true; echo $?' |
| 41 | |
| 42 | section "5. error propagation" |
| 43 | compare_output "function return status" 'f() { return 1; }; f; echo $?' |
| 44 | compare_output "subshell exit status" '(exit 2); echo $?' |
| 45 | compare_output "eval preserves status" 'eval "false"; echo $?' |
| 46 | compare_output "eval true status" 'eval "true"; echo $?' |
| 47 | compare_output "source preserves status" "echo 'false' > $TEST_TMPDIR/efalse.sh; source $TEST_TMPDIR/efalse.sh; echo \$?" |
| 48 | compare_output "cmd sub status" 'X=$(false); echo $?' |
| 49 | compare_output "cmd sub true status" 'X=$(true); echo $?' |
| 50 | compare_output "last in pipeline" 'true | false; echo $?' |
| 51 | compare_output "negated status" '! true; echo $?' |
| 52 | compare_output "negated false status" '! false; echo $?' |
| 53 | |
| 54 | section "6. builtin error handling" |
| 55 | compare_output "cd failure" 'cd /nonexistent_xyz 2>/dev/null; echo $?' |
| 56 | compare_output "source failure" 'source /nonexistent_file.sh 2>/dev/null; echo $?' |
| 57 | compare_exit "readonly violation" 'readonly ERX=1; ERX=2 2>/dev/null' |
| 58 | compare_output "unset readonly" 'readonly ERY=1; unset ERY 2>/dev/null; echo $?' |
| 59 | compare_output "command not found" 'nonexistent_cmd_xyz 2>/dev/null; echo $?' |
| 60 | compare_output "read with no input" 'read VAR < /dev/null; echo $?' |
| 61 | compare_output "test failure" 'test 1 -eq 2; echo $?' |
| 62 | compare_output "false builtin" 'false; echo $?' |
| 63 | compare_output "true builtin" 'true; echo $?' |
| 64 | |
| 65 | section "7. set -e with conditionals (should NOT exit)" |
| 66 | compare_output "set -e if false" 'set -e; if false; then echo yes; fi; echo reached' |
| 67 | compare_output "set -e while false" 'set -e; while false; do echo no; done; echo reached' |
| 68 | compare_output "set -e until true" 'set -e; until true; do echo no; done; echo reached' |
| 69 | compare_output "set -e test in if" 'set -e; if test 1 -eq 2; then echo no; fi; echo reached' |
| 70 | compare_output "set -e bracket in if" 'set -e; if [ 1 -eq 2 ]; then echo no; fi; echo reached' |
| 71 | compare_output "set -e negation" 'set -e; ! false; echo reached' |
| 72 | |
| 73 | print_summary |