name: "Options: extdebug" cases: # # extdebug implies functrace (-T) # - name: "extdebug implies functrace - DEBUG inherited in functions" known_failure: true # TODO(BASH_COMMAND): quotes differ stdin: | shopt -s extdebug trap 'echo "[debug: $BASH_COMMAND]"' DEBUG myfunc() { echo "in func" } echo "before" myfunc echo "after" - name: "extdebug implies functrace - DEBUG inherited in subshells" known_failure: true # TODO(BASH_COMMAND): quotes differ stdin: | shopt -s extdebug trap 'echo "[debug: $BASH_COMMAND]"' DEBUG echo "before" (echo "in subshell") echo "after" # # DEBUG trap return value effects (extdebug-specific) # - name: "DEBUG trap - returns 0 command executes normally" known_failure: true # TODO(extdebug): return in trap handler not supported stdin: | shopt -s extdebug trap 'return 0' DEBUG echo "line 1" echo "line 2" echo "line 3" - name: "DEBUG trap - returns 1 command is skipped" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug skip_next=false trap ' if $skip_next; then skip_next=false return 1 fi return 0 ' DEBUG echo "line 1" skip_next=true echo "this should be skipped" echo "line 3" - name: "DEBUG trap - returns 2 simulates return from function" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug trap ' if [[ "${FUNCNAME[0]}" == "myfunc" && "$BASH_COMMAND" == *"should not"* ]]; then return 2 fi return 0 ' DEBUG myfunc() { echo "start of func" echo "this should not print" echo "also should not print" } myfunc echo "after func: $?" - name: "DEBUG trap - return value ignored without extdebug" known_failure: true # TODO(extdebug): return in trap handler error message differs stdin: | shopt -u extdebug trap 'return 1' DEBUG echo "line 1" echo "line 2" echo "line 3" # # Command skipping scenarios (extdebug-specific) # - name: "Skip simple command" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug trap '[[ "$BASH_COMMAND" == *"skip"* ]] && return 1; return 0' DEBUG echo "keep this" echo "skip this" echo "keep this too" - name: "Skip in loop - iteration skipped but loop continues" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug trap '[[ "$BASH_COMMAND" == *"skip"* ]] && return 1; return 0' DEBUG for i in 1 2 3; do echo "iter $i" echo "skip $i" echo "after skip $i" done echo "done" - name: "Skip in conditional" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug trap '[[ "$BASH_COMMAND" == *"skip"* ]] && return 1; return 0' DEBUG if true; then echo "in then" echo "skip in then" echo "after skip in then" fi echo "after if" - name: "Return 2 in nested function - unwinds to caller" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug trap ' if [[ "${FUNCNAME[0]}" == "inner" && "$BASH_COMMAND" == *"inner cmd"* ]]; then return 2 fi return 0 ' DEBUG inner() { echo "inner start" echo "inner cmd" echo "inner end" } outer() { echo "outer start" inner echo "outer after inner" } outer echo "main after outer" # # BASH_ARGC and BASH_ARGV (extdebug-specific) # - name: "BASH_ARGC - contains argument counts per call frame" stdin: | shopt -s extdebug show_argc() { echo "BASH_ARGC: ${BASH_ARGC[*]}" } func_with_args() { show_argc } func_with_args a b c - name: "BASH_ARGV - contains arguments in reverse order" stdin: | shopt -s extdebug show_argv() { echo "BASH_ARGV: ${BASH_ARGV[*]}" } func_with_args() { show_argv } func_with_args a b c - name: "BASH_ARGC/ARGV - in nested calls" stdin: | shopt -s extdebug inner() { echo "inner ARGC: ${BASH_ARGC[*]}" echo "inner ARGV: ${BASH_ARGV[*]}" } outer() { inner x y } outer a b c - name: "BASH_ARGC/ARGV - empty when no arguments" stdin: | shopt -s extdebug no_args() { echo "BASH_ARGC: '${BASH_ARGC[*]}'" echo "BASH_ARGV: '${BASH_ARGV[*]}'" } no_args # # declare -F shows source info (extdebug-specific) # - name: "declare -F - shows function name only without extdebug" stdin: | myfunc() { echo hi; } declare -F myfunc - name: "declare -F - shows filename and line number with extdebug" known_failure: true # TODO(extdebug): declare -F not showing source info test_files: - path: "funcs.sh" contents: | myfunc() { echo hi } stdin: | shopt -s extdebug . ./funcs.sh declare -F myfunc | sed 's/[0-9]*/N/' # # Interaction with other options # - name: "extdebug with errexit - skipped command doesn't trigger errexit" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug set -e trap '[[ "$BASH_COMMAND" == "false" ]] && return 1; return 0' DEBUG echo "before" false echo "after - should print because false was skipped" - name: "extdebug disabled after being enabled" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug trap 'return 1' DEBUG echo "line 1 - should be skipped" shopt -u extdebug echo "line 2 - should print" echo "line 3 - should print" - name: "extdebug with set -T - both affect DEBUG inheritance" known_failure: true # TODO(BASH_COMMAND): quotes differ stdin: | shopt -s extdebug set -T trap 'echo "[debug: $BASH_COMMAND]"' DEBUG myfunc() { echo "in func" } myfunc echo "done" # # DEBUG trap with extdebug in various contexts # - name: "DEBUG trap with extdebug in function" known_failure: true # TODO(extdebug): return in trap handler not supported stdin: | shopt -s extdebug count=0 trap ' ((count++)) echo "debug $count: $BASH_COMMAND" return 0 ' DEBUG myfunc() { local x=1 echo "x=$x" } myfunc - name: "DEBUG trap with extdebug controls command execution" known_failure: true # TODO(extdebug): DEBUG trap return value not implemented stdin: | shopt -s extdebug should_skip=false trap ' if $should_skip; then should_skip=false echo "[skipping: $BASH_COMMAND]" return 1 fi return 0 ' DEBUG echo "first" should_skip=true echo "second - will be skipped" echo "third" # # Edge cases # - name: "extdebug with recursive function" known_failure: true # TODO(extdebug): DEBUG trap firing count differs stdin: | shopt -s extdebug trap 'echo "depth: ${#FUNCNAME[@]}"' DEBUG recurse() { local n=$1 if ((n > 0)); then recurse $((n - 1)) fi } recurse 3 - name: "BASH_COMMAND shows compound command" known_failure: true # TODO(BASH_COMMAND): quotes differ stdin: | shopt -s extdebug trap 'echo "cmd: $BASH_COMMAND"' DEBUG if true; then echo "in if"; fi - name: "DEBUG trap can modify variables" known_failure: true # TODO(extdebug): return in trap handler not supported stdin: | shopt -s extdebug counter=0 trap '((counter++)); return 0' DEBUG echo "a" echo "b" echo "c" echo "counter: $counter"