name: "Functions"
cases:
  - name: "Basic function invocation"
    test_files:
      - path: "script.sh"
        contents: |
          myfunc() {
              echo "In myfunc()."
          }
          echo "Calling myfunc()..."
          myfunc
          echo "Returned."
    args: ["./script.sh"]

  - name: "Function invocation with args"
    test_files:
      - path: "script.sh"
        contents: |
          myfunc() {
              echo "In myfunc()"
              echo "1: $1"
              echo "*: $*"
          }
          echo "Calling myfunc()..."
          myfunc a b c
          echo "Returned."
    args: ["./script.sh"]

  - name: "Function invocation with empty arg"
    stdin: |
      myfunc() {
          echo "count: ${#*}"
          echo "\$1: $1"
          echo "\$2: $2"
          echo "\$3: $3"
      }

      myfunc a b c
      myfunc a "" c

  - name: "Function definition with output redirection"
    stdin: |
      myfunc() {
          echo "In myfunc()"
      } >>./test.txt

      myfunc
      myfunc

  - name: "Function call with env variables"
    stdin: |
      myfunc() {
          echo ${myvar}
      }

      myvar="default"
      myfunc
      myvar="overridden" myfunc
      myfunc

  - name: "Function definition without braces"
    stdin: |
      myfunc()
      if true; then
        echo true
      else
        echo false
      fi

      myfunc

  - name: "Nested function definition"
    stdin: |
      outer() {
        echo "Entered outer"

        inner() {
          echo "In inner"
        }

        echo "Invoking inner"

        inner

        echo "Returning from outer"
      }

      echo "Calling outer from toplevel"
      outer

      echo "Calling inner from toplevel"
      inner

  - name: "Exporting functions to child instance"
    stdin: |
      mytestfunc() {
          echo "In mytestfunc"
      }

      export -f mytestfunc

      $0 -c 'mytestfunc'

  - name: "Function names with interesting characters"
    stdin: |
      my/func() {
          echo "In my/func"
      }

      my/func

  - name: "Functions shadowing builtins"
    stdin: |
      .() {
          echo "In custom dot function"
      }

      echo "Func result: $?"

      .
      echo "Call result: $?"

  - name: "Reserved words cannot be used as function names without function keyword"
    ignore_stderr: true
    stdin: |
      for (){ :; }
      echo "exit: $?"

  - name: "Reserved words can be used as function names with function keyword"
    stdin: |
      function for { echo "custom for"; }
      for x in 1; do echo "normal for: $x"; done

  - name: "Reserved words can be used as function names with function keyword and parens"
    stdin: |
      function while() { echo "custom while"; }
      while false; do echo "nope"; done
      echo "done"

  - name: "Functions shadowing builtins (POSIX mode)"
    ignore_stderr: true
    stdin: |
      set -o posix

      .() {
          echo "In custom dot function"
      }

      echo "Func result: $?"

      .
      echo "Call result: $?"

  - name: "Empty string arguments preserved with nullglob"
    stdin: |
      shopt -s nullglob
      
      myfunc() {
          echo "arg count: $#"
          for arg in "$@"; do
              echo "arg: '$arg'"
          done
      }
      
      myfunc 3 - 2 "" 1.2.3b_alpha4

  - name: "Multiple empty string arguments"
    stdin: |
      myfunc() {
          echo "count: $#"
          echo "1: '$1'"
          echo "2: '$2'"
          echo "3: '$3'"
          echo "4: '$4'"
      }
      
      myfunc "" "non-empty" "" "last"
