name: "Options: set -u" cases: # Basic behavior - name: "Basic set variable access" stdin: | set -u var="value" echo "$var" - name: "Unset variable triggers error" ignore_stderr: true stdin: | set -u echo "$unset_var" echo "should not print" - name: "Command line -u" args: ["-u"] ignore_stderr: true stdin: | echo "$unset_var" echo "should not print" # Special parameters - should NOT error even when unset - name: "Special parameter $@ does not error" stdin: | set -u echo "args: $@" - name: "Special parameter $* does not error" stdin: | set -u echo "args: $*" - name: "Special parameter $# does not error" stdin: | set -u echo "count: $#" - name: "Special parameter $? does not error" stdin: | set -u true echo "status: $?" - name: "Special parameter $$ does not error" stdin: | set -u echo "pid: $$" > /dev/null echo "ok" - name: "Special parameter $! does not error when no background jobs" known_failure: true ignore_stderr: true stdin: | set -u echo "last bg: ${!}" || echo "ok" - name: "Special parameter $0 does not error" stdin: | set -u echo "shell: $0" > /dev/null echo "ok" - name: "Special parameter $- does not error" stdin: | set -u echo "flags: $-" > /dev/null echo "ok" # Positional parameters - name: "Unset positional parameter triggers error" ignore_stderr: true stdin: | set -u myfunc() { echo "$1" } myfunc echo "should not print" - name: "Set positional parameter does not error" stdin: | set -u myfunc() { echo "$1" } myfunc "arg" - name: "Positional parameters beyond provided args error" ignore_stderr: true stdin: | set -u myfunc() { echo "$2" } myfunc "only_one_arg" echo "should not print" # Parameter expansion forms - name: "Unset variable with default does not error" stdin: | set -u echo "${unset_var:-default}" - name: "Empty vs unset with :- operator" stdin: | set -u empty="" echo "${empty:-default}" echo "${unset:-default}" - name: "Empty vs unset with - operator" stdin: | set -u empty="" echo "${empty-default}" echo "${unset-default}" # Arrays (if supported) - name: "Unset array element with default" stdin: | set -u arr=(a b c) echo "${arr[10]:-default}" - name: "Unset array treated as unset variable" stdin: | set -u echo "${unset_array[@]}" echo "should not print" - name: "Unset array with default does not error" stdin: | set -u echo "${unset_array[@]:-default}" # Conditionals - name: "Unset variable in conditional test errors" ignore_stderr: true stdin: | set -u if [ "$unset_var" = "value" ]; then echo "then" fi echo "should not print" - name: "Unset variable in [[ test errors" ignore_stderr: true stdin: | set -u if [[ $unset_var = "value" ]]; then echo "then" fi echo "should not print" - name: "Unset variable with default in conditional works" stdin: | set -u if [ "${unset_var:-}" = "" ]; then echo "empty" fi - name: "test -v for unset variable" stdin: | set -u if test -v unset_var; then echo "set" else echo "unset" fi - name: "test -z with unset variable errors" ignore_stderr: true stdin: | set -u if test -z "$unset_var"; then echo "empty" fi echo "should not print" # Command substitution - name: "Unset variable in command substitution errors" ignore_stderr: true stdin: | set -u result=$(echo "$unset_var") echo "should not print" - name: "Unset variable with default in command substitution" stdin: | set -u result=$(echo "${unset_var:-default}") echo "$result" # Arithmetic expansion - name: "Unset variable in arithmetic defaults to zero" ignore_stderr: true stdin: | set -u result=$((unset_var + 5)) echo "$result" # set +u to disable - name: "set +u disables unset variable check" stdin: | set -u set +u echo "$unset_var" echo "ok" - name: "set -u can be re-enabled" ignore_stderr: true stdin: | set -u set +u echo "$unset_var" set -u echo "$another_unset" echo "should not print" - name: "set +u in function does not affect parent" stdin: | set -u myfunc() { set +u echo "$unset_in_func" } myfunc echo "$unset_in_parent" echo "should not print" # Functions - name: "Unset variable in function body errors" ignore_stderr: true stdin: | set -u myfunc() { echo "$unset_var" } myfunc echo "should not print" - name: "Local unset variable errors" ignore_stderr: true stdin: | set -u myfunc() { local unset_local echo "$unset_local" } myfunc echo "should not print" - name: "Local variable declaration with value works" stdin: | set -u myfunc() { local my_var="value" echo "$my_var" } myfunc - name: "Function parameter shadows unset global" stdin: | set -u myfunc() { local var="$1" echo "$var" } myfunc "arg" # Subshells - name: "Unset variable in subshell errors" ignore_stderr: true stdin: | set -u (echo "$unset_var") echo "should not print" - name: "set +u in subshell does not affect parent" ignore_stderr: true stdin: | set -u ( set +u echo "$unset_in_subshell" ) echo "$unset_in_parent" echo "should not print" # Variable assignment and unset - name: "Variable set then unset errors on access" ignore_stderr: true stdin: | set -u var="value" echo "$var" unset var echo "$var" echo "should not print" - name: "Variable set then unset with default works" stdin: | set -u var="value" unset var echo "${var:-default}" - name: "Unsetting non-existent variable does not error" stdin: | set -u unset non_existent echo "ok" # Export and environment - name: "Exported unset variable errors" ignore_stderr: true stdin: | set -u export unset_exported echo "$unset_exported" echo "should not print" - name: "Exported variable with value works" stdin: | set -u export exported_var="value" echo "$exported_var" # Pattern expansion - name: "Unset variable in pattern errors" ignore_stderr: true stdin: | set -u echo ${unset_var#prefix} echo "should not print" # Length operator - name: "Length of unset variable errors" ignore_stderr: true stdin: | set -u echo ${#unset_var} echo "should not print" - name: "Length of empty variable works" stdin: | set -u empty="" echo ${#empty} # Indirect expansion - name: "Indirect expansion of unset variable errors" ignore_stderr: true stdin: | set -u ref="unset_target" echo ${!ref} echo "should not print" - name: "Indirect expansion to set variable works" stdin: | set -u target="value" ref="target" echo ${!ref} # Case statements - name: "Unset variable in case pattern errors" ignore_stderr: true stdin: | set -u case "$unset_var" in *) echo "matched" ;; esac echo "should not print" - name: "Unset variable with default in case works" stdin: | set -u case "${unset_var:-default}" in default) echo "matched" ;; esac # For loops - name: "Unset variable in for loop errors" ignore_stderr: true stdin: | set -u for item in $unset_var; do echo "$item" done echo "should not print" - name: "Unset variable with default in for loop works" stdin: | set -u for item in ${unset_var:-a b c}; do echo "$item" done # While loops with unset variables - name: "Unset variable in while condition errors" ignore_stderr: true stdin: | set -u while [ "$unset_var" != "stop" ]; do echo "loop" break done echo "should not print" # Read command - name: "read into variable then access works" stdin: | set -u echo "value" | read my_var || true echo "${my_var:-default}" - name: "Variable unset before read then set works" stdin: | set -u echo "test" | { read input echo "$input" } # Compound assignments - name: "Associative array unset key with default" stdin: | set -u declare -A assoc echo "${assoc[key]:-default}" # Pipelines - name: "Unset variable with default in pipeline works" stdin: | set -u echo "${unset_var:-default}" | cat # Here documents and here strings - name: "Unset variable in here doc errors" ignore_stderr: true stdin: | set -u cat <