Bash · 3297 bytes Raw Blame History
1 #!/bin/sh
2 TEST_PREFIX="[int-subshell]"
3 SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
4 FORTSH_BIN="${FORTSH_BIN:-$SCRIPT_DIR/../../../bin/fortsh}"
5 export FORTSH_BIN
6 . "$SCRIPT_DIR/../test_harness.sh"
7
8 # Integration tests: builtins in subshells
9
10 section "1. variable isolation"
11 compare_output "assignment doesnt leak" 'X=outer; (X=inner); echo $X'
12 compare_output "export doesnt leak" '(export FOO=bar); echo ${FOO:-unset}'
13 compare_output "unset doesnt affect parent" 'X=val; (unset X); echo $X'
14 compare_output "declare doesnt leak" '(declare -i N=5); echo ${N:-unset}'
15 compare_output "readonly persists in parent" 'readonly RO=val; (echo $RO)'
16 compare_output "array in subshell doesnt leak" '(arr=(a b c)); echo ${arr:-unset}'
17 compare_output "multiple vars in subshell" '(A=1; B=2; C=3); echo ${A:-x} ${B:-y} ${C:-z}'
18
19 section "2. directory isolation"
20 compare_output "cd doesnt affect parent" '(cd /tmp); pwd'
21 compare_output "pushd doesnt affect parent" '(pushd /tmp >/dev/null 2>&1); pwd'
22 compare_output "multiple cd in subshell" '(cd /tmp; cd /var); pwd'
23 compare_output "pwd reflects subshell cd" '(cd /tmp; pwd)'
24 compare_output "cd and var in subshell" '(cd /tmp; X=$(pwd)); echo ${X:-unset}'
25
26 section "3. option isolation"
27 compare_output "set -e doesnt leak" '(set -e); echo ok'
28 compare_output "set in subshell only" '(set -- a b c; echo $#); echo $#'
29 compare_output "shopt doesnt leak" '(shopt -s nullglob 2>/dev/null); echo ok'
30 compare_output "set -u in subshell" '(set -u; echo ${SETVAR:-default})'
31
32 section "4. trap isolation"
33 compare_output "separate EXIT traps" 'trap "echo parent_bye" EXIT; (trap "echo child_bye" EXIT; echo sub_body)'
34 compare_output "subshell EXIT fires at end" '(trap "echo inner_bye" EXIT; echo body); echo after'
35 compare_output "trap in subshell independent" '(trap "echo sub_bye" EXIT; echo sub)'
36 compare_output "parent trap survives subshell" 'trap "echo parent_exit" EXIT; (echo sub); echo main'
37
38 section "5. nesting"
39 compare_output "double nested subshell" '( (echo deep) )'
40 compare_output "cmd sub inside subshell" '(echo $(echo nested))'
41 compare_output "layered scope" '(X=1; (X=2; echo $X); echo $X)'
42 compare_output "triple nested cmd sub" 'echo $(echo $(echo triple))'
43 compare_output "nested with variable" '(A=outer; (A=inner; echo $A); echo $A)'
44 compare_output "three level nesting" '(echo 1; (echo 2; (echo 3)))'
45
46 section "6. exit status"
47 compare_output "zero exit" '(exit 0); echo $?'
48 compare_output "non-zero exit" '(exit 42); echo $?'
49 compare_output "implicit exit status" '(false); echo $?'
50 compare_output "OR chain with subshell failure" '(exit 1) || echo recovered'
51 compare_output "AND chain with subshell success" '(exit 0) && echo continued'
52 compare_output "nested subshell exit status" '( (exit 3) ); echo $?'
53 compare_output "exit in nested" '(exit 0); (exit 1); echo $?'
54
55 section "7. command substitution as implicit subshell"
56 compare_output "cmd sub scope" 'X=outer; Y=$(X=inner; echo $X); echo $X $Y'
57 compare_output "cd in cmd sub" 'Y=$(cd /tmp; pwd); pwd; echo $Y'
58 compare_output "export in cmd sub" 'Y=$(export EV=val; echo $EV); echo ${EV:-unset} $Y'
59 compare_output "cmd sub exit status" 'X=$(true); echo $?'
60 compare_output "cmd sub false status" 'X=$(false); echo $?'
61 compare_output "nested cmd sub" 'echo $(echo $(echo nested))'
62
63 print_summary