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"

