name: "Options: functrace (-T)"
cases:
  #
  # Basic functrace option behavior
  #
  - name: "functrace can be enabled and disabled"
    stdin: |
      set -T
      echo "enabled: $-" | grep -q T && echo "T is set"
      set +T
      echo "disabled: $-" | grep -qv T && echo "T is unset"

  #
  # DEBUG trap inheritance in functions
  #
  - name: "DEBUG trap - does not fire in function without set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      trap 'echo "[debug: $BASH_COMMAND]"' DEBUG
      myfunc() {
        echo "in func"
      }
      echo "before func"
      myfunc
      echo "after func"

  - name: "DEBUG trap - fires in function with set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      set -T
      trap 'echo "[debug: $BASH_COMMAND]"' DEBUG
      myfunc() {
        echo "in func"
      }
      echo "before func"
      myfunc
      echo "after func"

  #
  # DEBUG trap inheritance in subshells
  #
  - name: "DEBUG trap - does not fire in subshell without set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      trap 'echo "[debug: $BASH_COMMAND]"' DEBUG
      echo "before subshell"
      (echo "in subshell")
      echo "after subshell"

  - name: "DEBUG trap - fires in subshell with set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      set -T
      trap 'echo "[debug: $BASH_COMMAND]"' DEBUG
      echo "before subshell"
      (echo "in subshell")
      echo "after subshell"

  #
  # DEBUG trap inheritance in command substitution
  #
  - name: "DEBUG trap - does not fire in command substitution without set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      trap 'echo "[debug: $BASH_COMMAND]" >&2' DEBUG
      echo "before"
      result=$(echo "in substitution")
      echo "result: $result"

  - name: "DEBUG trap - fires in command substitution with set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      set -T
      trap 'echo "[debug: $BASH_COMMAND]" >&2' DEBUG
      echo "before"
      result=$(echo "in substitution")
      echo "result: $result"

  #
  # DEBUG trap inheritance in pipelines
  #
  - name: "DEBUG trap - does not fire in pipeline without set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      trap 'echo "[debug: $BASH_COMMAND]" >&2' DEBUG
      echo "before"
      echo "hello" | cat | cat
      echo "after"

  - name: "DEBUG trap - fires in pipeline with set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      set -T
      trap 'echo "[debug: $BASH_COMMAND]" >&2' DEBUG
      echo "before"
      echo "hello" | cat | cat
      echo "after"

  #
  # RETURN trap inheritance in functions
  #
  - name: "RETURN trap - does not fire in called function without set -T"
    stdin: |
      trap 'echo "[return: $FUNCNAME]"' RETURN
      inner() {
        echo "in inner"
      }
      outer() {
        echo "in outer"
        inner
        echo "outer continuing"
      }
      outer
      echo "after"

  - name: "RETURN trap - fires in called function with set -T"
    known_failure: true # TODO(functrace): RETURN trap inheritance not implemented
    stdin: |
      set -T
      trap 'echo "[return: ${FUNCNAME:-main}]"' RETURN
      inner() {
        echo "in inner"
      }
      outer() {
        echo "in outer"
        inner
        echo "outer continuing"
      }
      outer
      echo "after"

  - name: "RETURN trap - fires for each nested function return with set -T"
    known_failure: true # TODO(functrace): RETURN trap inheritance not implemented
    stdin: |
      set -T
      trap 'echo "[return: ${FUNCNAME:-main} -> $?]"' RETURN
      level3() { echo "level3"; return 3; }
      level2() { echo "level2"; level3; return 2; }
      level1() { echo "level1"; level2; return 1; }
      level1
      echo "done"

  #
  # Function-specific trace attribute (declare -t)
  #
  - name: "declare -t - enables trace for specific function"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      trap 'echo "[debug: $BASH_COMMAND]"' DEBUG
      traced_func() {
        echo "in traced"
      }
      untraced_func() {
        echo "in untraced"
      }
      declare -t traced_func
      echo "calling untraced"
      untraced_func
      echo "calling traced"
      traced_func
      echo "done"

  - name: "declare +t - disables trace for specific function"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      set -T
      trap 'echo "[debug: $BASH_COMMAND]"' DEBUG
      myfunc() {
        echo "in func"
      }
      declare +t myfunc
      echo "calling func"
      myfunc
      echo "done"

  - name: "declare -f - shows trace attribute"
    stdin: |
      myfunc() { echo hi; }
      declare -t myfunc
      declare -f myfunc | head -1

  #
  # Toggling set -T mid-script
  #
  - name: "set -T enabled mid-script affects subsequent calls"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      trap 'echo "[debug: $BASH_COMMAND]"' DEBUG
      func1() { echo "in func1"; }
      func2() { echo "in func2"; }
      echo "calling func1 without -T"
      func1
      set -T
      echo "calling func2 with -T"
      func2
      echo "done"

  - name: "set +T disables inheritance mid-script"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      set -T
      trap 'echo "[debug: $BASH_COMMAND]"' DEBUG
      func1() { echo "in func1"; }
      func2() { echo "in func2"; }
      echo "calling func1 with -T"
      func1
      set +T
      echo "calling func2 without -T"
      func2
      echo "done"

  #
  # DEBUG trap inheritance in background jobs
  #
  - name: "DEBUG trap - in background job with set -T"
    stdin: |
      set -T
      trap 'echo "[debug]" >&2' DEBUG
      {
        echo "in background"
      } &
      wait
      echo "done"

  #
  # DEBUG trap inheritance in process substitution
  #
  - name: "DEBUG trap - in process substitution with set -T"
    stdin: |
      set -T
      trap 'echo "[debug]" >&2' DEBUG
      cat <(echo "from procsub")
      echo "done"

  #
  # BASH_COMMAND visibility in DEBUG trap with functrace
  #
  - name: "BASH_COMMAND in function with set -T"
    known_failure: true # TODO(BASH_COMMAND): quotes differ
    stdin: |
      set -T
      trap 'echo "cmd: $BASH_COMMAND"' DEBUG
      myfunc() {
        local v=10
        echo "v=$v"
      }
      myfunc

  #
  # Nested functions with varying trace states
  #
  - name: "Outer function traced, inner function not traced"
    stdin: |
      trap 'echo "[debug in ${FUNCNAME:-main}]"' DEBUG
      inner() {
        echo "inner"
      }
      outer() {
        echo "outer start"
        inner
        echo "outer end"
      }
      declare -t outer
      outer
      echo "done"

  - name: "Only inner function traced"
    stdin: |
      trap 'echo "[debug in ${FUNCNAME:-main}]"' DEBUG
      inner() {
        echo "inner"
      }
      outer() {
        echo "outer start"
        inner
        echo "outer end"
      }
      declare -t inner
      outer
      echo "done"

  #
  # RETURN trap with sourced scripts and set -T
  #
  - name: "RETURN trap - fires for function in sourced script with set -T"
    known_failure: true # TODO(functrace): RETURN trap inheritance not implemented
    test_files:
      - path: "sourced.sh"
        contents: |
          sourced_func() {
            echo "in sourced_func"
          }
          sourced_func
    stdin: |
      set -T
      trap 'echo "[return: ${FUNCNAME:-main}]"' RETURN
      . ./sourced.sh
      echo "after source"

  #
  # Edge cases
  #
  - name: "DEBUG trap - count in deeply nested function calls with set -T"
    known_failure: true # TODO(functrace): DEBUG trap count differs
    stdin: |
      set -T
      count=0
      trap 'count=$((count + 1))' DEBUG
      a() { b; }
      b() { c; }
      c() { echo "deep"; }
      a
      echo "debug count: $count"

