name: "Special parameters"
cases:
  - name: "$_ - initial value matches $0"
    stdin: |
      [[ "$0" == "$_" ]] && echo "matches on start"

  - name: "$_ - last argument tracked across simple commands"
    stdin: |
      : one
      echo "[$_]"
      : two three four
      echo "[$_]"
      echo last_echo_arg
      echo "[$_]"

  - name: "$_ - zero-arg command uses command name"
    stdin: |
      echo seed1 seed2
      :
      echo "after colon: [$_]"
      true
      echo "after true: [$_]"
      echo
      echo "after bare echo: [$_]"

  - name: "$_ - args with spaces and special chars"
    stdin: |
      echo "seed last"
      echo "[$_]"
      echo "arg with spaces" 'arg-with-dashes' "arg:with:colons"
      echo "[$_]"
      echo "" trailing
      echo "[$_]"

  - name: "$_ - builtin dispatch path"
    stdin: |
      echo seed last
      : bu1 bu2 bu3
      echo "[$_]"
      printf '%s\n' pf1 pf2
      echo "[$_]"

  - name: "$_ - external command dispatch path"
    stdin: |
      echo seed last
      /usr/bin/true ext1 ext2
      echo "[$_]"
      /usr/bin/env ENV=1 /usr/bin/true external_final
      echo "[$_]"

  - name: "$_ - external command exports resolved path via env"
    stdin: |
      # When invoking an external command, it should see _ set
      # to the resolved pathname of the command (not "last arg").
      /usr/bin/env | grep '^_='

  - name: "$_ - function dispatch sets to call-site last arg"
    stdin: |
      f() { :; }
      echo seed_last
      f call_a call_b
      echo "[$_]"

  - name: "$_ - function body sees pre-invocation value on entry"
    stdin: |
      f() {
        echo "entry: [$_]"
        echo new_inner
        echo "after inner echo: [$_]"
      }
      echo pre_seed
      f call_arg
      echo "after return: [$_]"

  - name: "$_ - nested function dispatch"
    stdin: |
      inner() { echo innerdone; }
      outer() { inner ia ib; }
      echo seed
      outer oa ob
      echo "[$_]"

  - name: "$_ - assignment-only function body"
    stdin: |
      f() { a=1; b=2; }
      echo seed_last
      f foo bar
      echo "[$_]"

  - name: "$_ - cleared by assignment-only statements"
    stdin: |
      echo seed_last
      x=assigned
      echo "after assign: [$_]"
      y=another
      echo "after second assign: [$_]"
      : colonarg
      echo "after colon: [$_]"

  - name: "$_ - cleared by assignment with command substitution"
    stdin: |
      echo seed_last
      z=$(echo subst_inner)
      echo "after assignment: [$_]"

  - name: "$_ - single-stage pipeline does not update parent"
    stdin: |
      echo prev_a prev_b
      echo pipe_a pipe_b | cat
      echo "[$_]"

  - name: "$_ - multi-stage pipeline does not update parent"
    stdin: |
      echo prev_a prev_b
      echo pipe_a pipe_b | cat | cat
      echo "[$_]"

  - name: "$_ - and-chain tracks last arg of last executed command"
    stdin: |
      echo seed_last
      true && echo a1 a2
      echo "[$_]"
      true && true t1 t2
      echo "[$_]"

  - name: "$_ - or-chain tracks last arg of last executed command"
    stdin: |
      echo seed_last
      false || echo or1 or2
      echo "[$_]"

  - name: "$_ - command-not-found update"
    ignore_stderr: true
    stdin: |
      echo seed_last
      nosuchcmd_xyzzy fail_a fail_b
      echo "[$_]"

  - name: "$_ - for loop body"
    stdin: |
      echo seed_last
      for i in 1 2 3; do :; done
      echo "[$_]"
      for i in a b c; do echo "loop $i"; done
      echo "[$_]"

  - name: "$_ - while loop body"
    stdin: |
      echo seed_last
      i=0
      while [ $i -lt 2 ]; do echo "iter $i"; i=$((i+1)); done
      echo "[$_]"

  - name: "$_ - until loop body"
    stdin: |
      echo seed_last
      i=0
      until [ $i -ge 2 ]; do i=$((i+1)); done
      echo "[$_]"

  - name: "$_ - if/then body"
    stdin: |
      echo seed_last
      if true; then echo then_a then_b; fi
      echo "[$_]"

  - name: "$_ - case body"
    stdin: |
      echo seed_last
      case x in
        x) echo match_a match_b ;;
      esac
      echo "[$_]"

  - name: "$_ - eval tracks eval's last arg"
    stdin: |
      echo seed_last
      eval "echo evaled one two"
      echo "[$_]"

  - name: "$_ - source tracks sourced script's commands"
    test_files:
      - path: sourced.sh
        contents: |
          echo sourced_a sourced_b
    stdin: |
      echo seed_last
      . ./sourced.sh
      echo "[$_]"

  - name: "$_ - subshell does not leak into parent"
    stdin: |
      echo outer_a outer_b
      (echo inner1 inner2; echo "sub: [$_]")
      echo "parent: [$_]"

  - name: "$_ - background job + wait"
    stdin: |
      echo seed_last
      (:) &
      wait
      echo "[$_]"

  - name: "$_ - exported attribute after update"
    stdin: |
      export _=initial_value
      echo first last
      # After commands have run, does _ still have the -x attribute?
      declare -p _ | grep -c '^declare -x'

  - name: "$_ - declare -p reflects updated value"
    stdin: |
      export _=initial_value
      echo first last
      declare -p _

  - name: "$_ - readonly is honored"
    ignore_stderr: true
    stdin: |
      readonly _=frozen
      echo hi there
      echo "[$_]"

  - name: "$_ - exec does not override _ in child env"
    known_failure: true # exec builtin goes through compose_std_command which unconditionally sets _
    stdin: |
      # bash does not set _ in the child's env for exec; the child inherits
      # the parent's _ value. brush currently sets _ to the resolved command
      # path (same as a normal external command), which is wrong for exec.
      (exec /usr/bin/env) | grep '^_='

  - name: "$@ and $*"
    stdin: |
      function myfunc() {
          echo "--myfunc called--"

          echo "COUNT: $#"
          echo "AT-SIGN VALUE: '$@'"
          echo "STAR VALUE: '$*'"

          for arg in $@; do
              echo "AT-SIGN ELEMENT: '${arg}'"
          done

          for arg in $*; do
              echo "STAR ELEMENT: '${arg}'"
          done

          for arg in "$@"; do
            echo "DOUBLE-QUOTED AT-SIGN ELEMENT: '${arg}'"
          done

          for arg in "$*"; do
            echo "DOUBLE-QUOTED STAR ELEMENT: '${arg}'"
          done
      }

      myfunc
      myfunc 1
      myfunc 1 2
      myfunc "a b c" 2
