%prep

  mkdir funcdef.tmp
  cd funcdef.tmp
  setopt chaselinks
  cd .
  unsetopt chaselinks
  mydir=$PWD

%test

  fn1() { return 1; }
  fn2() {
      fn1
      print $?
      return 2
  }
  fn2
2:Basic status returns from functions
>1

  fnz() { }
  false
  fnz
0:Empty function body resets status

  fn3() { return 3; }
  fnstat() { print $?; }
  fn3
  fnstat
0:Status is not reset on non-empty function body
>3

  function f$$ () {
    print regress expansion of function names
  }
  f$$
0:Regression test: 'function f$$ () { ... }'
>regress expansion of function names

  function foo () print bar
  foo
0:Function definition without braces
>bar

  a a b() {
    read word
    print $0: $word
  } <<<redirection
  b
  a
0:Multiple function definition with duplicate name and redirection
>b: redirection
>a: redirection

  functions -M m1
  m1() { (( $# )) }
  print $(( m1() ))
  print $(( m1(1) ))
  print $(( m1(1,2) ))
0:User-defined math functions, argument handling
>0
>1
>2

  functions -M m2
  m2() {
    integer sum
    local val
    for val in $*; do
      (( sum += $val ))
    done
  }
  print $(( m2(1) ))
  print $(( m2(1,3+3,4**2) ))
0:User-defined math functions, complex argument handling
>1
>23

  functions -M m3 1 2
  m3() { (( 1 )) }
  print zero
  (print $(( m3() )))
  print one
  print $(( m3(1) ))
  print two
  print $(( m3(1,2) ))
  print three
  (print $(( m3(1,2,3) )))
1:User-defined math functions, argument checking
>zero
>one
>1
>two
>1
>three
?(eval):4: wrong number of arguments: m3()
?(eval):10: wrong number of arguments: m3(1,2,3)

  functions -M m4 0 0 testmathfunc
  functions -M m5 0 0 testmathfunc
  testmathfunc() {
    if [[ $0 = m4 ]]; then
      (( 4 ))
    else
      (( 5 ))
    fi
  }
  print $(( m4() ))
  print $(( m5() ))
0:User-defined math functions, multiple interfaces
>4
>5

  strmathfunc() {
    if [[ $0 = stralpha ]]; then
       set -- ${1//[^[:alpha:]]}
    fi
    (( $#1 ))
  }
  functions -Ms strlen 1 1 strmathfunc
  functions -Ms stralpha 1 1 strmathfunc
  print $(( strlen(this, is, a, raw, string) ))
  print $(( strlen() ))
  print $(( stralpha(this, is, a, raw, string) ))
  print $(( stralpha() ))
0:User-defined math functions, string arguments
>24
>0
>16
>0

  command_not_found_handler() {
    print "Great News!  I've handled the command:"
    print "$1"
    print "with arguments:"
    print -l ${argv[2,-1]}
  }
  ACommandWhichHadBetterNotExistOnTheSystem and some "really useful" args
0:Command not found handler, success
>Great News!  I've handled the command:
>ACommandWhichHadBetterNotExistOnTheSystem
>with arguments:
>and
>some
>really useful
>args

# ' deconfuse emacs

  command_not_found_handler() {
     print "Your command:" >&2
     print "$1" >&2
     print "has gone down the tubes.  Sorry." >&2
     return 42
  }
  ThisCommandDoesNotExistEither
42:Command not found handler, failure
?Your command:
?ThisCommandDoesNotExistEither
?has gone down the tubes.  Sorry.

  local variable=outside
  print "I am $variable"
  function {
    local variable=inside
    print "I am $variable"
  }
  print "I am $variable"
  () {
    local variable="inside again"
    print "I am $variable"
  }
  print "I am $variable"
0:Anonymous function scope
>I am outside
>I am inside
>I am outside
>I am inside again
>I am outside

  integer i
  for (( i = 0; i < 10; i++ )); do function {
    case $i in
    ([13579])
    print $i is odd
    ;|
    ([2468])
    print $i is even
    ;|
    ([2357])
    print $i is prime
    ;;
    esac
  }; done
0:Anonymous function with patterns in loop
>1 is odd
>2 is even
>2 is prime
>3 is odd
>3 is prime
>4 is even
>5 is odd
>5 is prime
>6 is even
>7 is odd
>7 is prime
>8 is even
>9 is odd

  echo stuff in file >file.in
  function {
    sed 's/stuff/rubbish/'
  } <file.in >file.out
  cat file.out
0:Anonymous function redirection
>rubbish in file

  variable="Do be do"
  print $variable
  function {
     print $variable
     local variable="Da de da"
     print $variable
     function {
       print $variable
       local variable="Dum da dum"
       print $variable
     }
     print $variable
  }
  print $variable
0:Nested anonymous functions
>Do be do
>Do be do
>Da de da
>Da de da
>Dum da dum
>Da de da
>Do be do

  () (cat $1 $2) <(print process expanded) =(print expanded to file)
0:Process substitution with anonymous functions
>process expanded
>expanded to file

  () { print This has arguments $*; } of all sorts; print After the function
  function { print More stuff $*; } and why not; print Yet more
0:Anonymous function with arguments
>This has arguments of all sorts
>After the function
>More stuff and why not
>Yet more

  fn() {
    (){ print Anonymous function 1 $*; } with args
    function { print Anonymous function 2 $*; } with more args
    print Following bit
  }
  functions fn
0:Text representation of anonymous function with arguments
>fn () {
>	() {
>		print Anonymous function 1 $*
>	} with args
>	() {
>		print Anonymous function 2 $*
>	} with more args
>	print Following bit
>}

  touch yes no
  () { echo $1 } (y|z)*
  (echo here)
  () { echo $* } some (y|z)*
  () { echo empty };(echo here)
0:Anonymous function arguments and command arguments
>yes
>here
>some yes
>empty
>here

  if true; then f() { echo foo1; } else f() { echo bar1; } fi; f
  if false; then f() { echo foo2; } else f() { echo bar2; } fi; f
0:Compatibility with other shells when not anonymous functions
>foo1
>bar2

  (
  setopt ignorebraces
  fpath=(.)
  print "{ echo OK }\n[[ -o ignorebraces ]] || print 'ignorebraces is off'" \
      >emufunctest
  (autoload -z emufunctest; emufunctest) 2>&1
  emulate zsh -c 'autoload -Uz emufunctest'
  emufunctest
  [[ -o ignorebraces ]] && print 'ignorebraces is still on here'
  )
0:sticky emulation applies to autoloads and autoloaded function execution
>emufunctest:3: parse error near `\n'
>OK
>ignorebraces is off
>ignorebraces is still on here
#` (matching error message for editors parsing the file)

# lsfoo should not be expanded as an anonymous function argument
 alias lsfoo='This is not ls.'
 () (echo anon func; echo "$@") lsfoo
0:Anonmous function with arguments in a form nobody sane would ever use but unfortunately we have to support anyway
>anon func
>lsfoo

 print foo | () cat
0:Simple anonymous function should not simplify enclosing pipeline
>foo

 alias fooalias=barexpansion
 funcwithalias() { echo $(fooalias); }
 functions funcwithalias
 barexpansion() { print This is the correct output.; }
 funcwithalias
0:Alias expanded in command substitution does not appear expanded in text
>funcwithalias () {
>	echo $(fooalias)
>}
>This is the correct output.

 unfunction command_not_found_handler # amusing but unhelpful
 alias first='firstfn1 firstfn2' second='secondfn1 secondfn2'
 function first second { print This is function $0; }
 first
 second
 firstfn1
 secondfn1
127:No alias expansion after "function" keyword
>This is function first
>This is function second
?(eval):6: command not found: firstfn1
?(eval):7: command not found: secondfn1

  (
    fpath=(.)
    print  "print oops was successfully autoloaded" >oops
    oops() { eval autoload -X }
    oops
    which -x2 oops
  )
0:autoload containing eval
>oops was successfully autoloaded
>oops () {
>  print oops was successfully autoloaded
>}

  (
    fpath=(.)
    printf '%s\n' 'oops(){}' 'ninjas-earring(){}' 'oops "$@"' >oops
    autoload oops
    oops
    whence -v oops
  )
0q:whence -v of zsh-style autoload
>oops is a shell function from $mydir/oops

  (
    fpath=(.)
    mkdir extra
    print 'print "I have been loaded by explicit path."' >extra/spec
    autoload -Uz $PWD/extra/spec
    spec
  )
0:autoload with explicit path
>I have been loaded by explicit path.

  (
    fpath=(.)
    print 'print "I have been loaded by default path."' >def
    autoload -Uz $PWD/extra/def
    def
  )
1:autoload with explicit path with function in normal path, no -d
?(eval):5: def: function definition file not found

  (
    fpath=(.)
    autoload -dUz $PWD/extra/def
    def
  )
0:autoload with explicit path with function in normal path, with -d
>I have been loaded by default path.

  (
    cd extra
    fpath=(.)
    autoload -r spec
    cd ..
    spec
  )
0:autoload -r
>I have been loaded by explicit path.

  (
    cd extra
    fpath=(.)
    autoload -r def
    cd ..
    def
  )
0:autoload -r is permissive
>I have been loaded by default path.

  (
    cd extra
    fpath=(.)
    autoload -R def
  )
1:autoload -R is not permissive
?(eval):4: def: function definition file not found

  (
    spec() { autoload -XUz $PWD/extra; }
    spec
  )
0:autoload -X with path
>I have been loaded by explicit path.

# The line number 1 here and in the next test seems suspect,
# but this example proves it's not down to the new features
# being tested here.
  (
    fpath=(.)
    cod() { autoload -XUz; }
    cod
  )
1:autoload -X with no path, failure
?(eval):1: cod: function definition file not found

  (
    fpath=(.)
    def() { autoload -XUz $PWD/extra; }
    def
  )
1:autoload -X with wrong path and no -d
?(eval):1: def: function definition file not found

  (
    fpath=(.)
    def() { autoload -dXUz $PWD/extra; }
    def
  )
0:autoload -dX with path
>I have been loaded by default path.

  (
    fpath=(.)
    print 'loadthisfunc() { autoload -X }' >loadthisfunc_sourceme
    print 'print Function was loaded correctly.' >loadthisfunc
    source $PWD/loadthisfunc_sourceme
    loadthisfunc
  )
0: autoload -X interaction with absolute filename used for source location
>Function was loaded correctly.

  (
    fpath=()
    mkdir extra2
    for f in fun2a fun2b; do
      print "print $f" >extra2/$f
    done
    repeat 3; do
      autoload $PWD/extra2/fun2{a,b} $PWD/extra/spec
      fun2a
      fun2b
      spec
      unfunction fun2a fun2b spec
      autoload $PWD/extra2/fun2{a,b} $PWD/extra/spec
      spec
      fun2b
      fun2a
      unfunction fun2a fun2b spec
    done
  )
0: Exercise the directory name cache for autoloads
>fun2a
>fun2b
>I have been loaded by explicit path.
>I have been loaded by explicit path.
>fun2b
>fun2a
>fun2a
>fun2b
>I have been loaded by explicit path.
>I have been loaded by explicit path.
>fun2b
>fun2a
>fun2a
>fun2b
>I have been loaded by explicit path.
>I have been loaded by explicit path.
>fun2b
>fun2a

  not_trashed() { print This function was not trashed; }
  autoload -Uz /foo/bar/not_trashed
  not_trashed
0:autoload with absolute path doesn't trash loaded function
>This function was not trashed

  # keep spec from getting loaded in parent shell for simplicity
  (
    if whence spec; then print spec already loaded >&2; exit 1; fi
    autoload -Uz $PWD/spec
    autoload -Uz $PWD/extra/spec
    spec
  )
0:autoload with absolute path can be overridden if not yet loaded
>I have been loaded by explicit path.

  (
    if whence spec; then print spec already loaded >&2; exit 1; fi
    autoload -Uz $PWD/extra/spec
    autoload spec
    spec
  )
0:autoload with absolute path not cancelled by bare autoload
>I have been loaded by explicit path.

  (
    FUNCNEST=0
    fn() { true; }
    fn
  )
1:
?fn:4: maximum nested function level reached; increase FUNCNEST?

  (
     fpath=(.)
     print "foo-bar() { print this should run automatically; }" >foo-bar
     autoload -Uz foo-bar
     foo-bar
  )
0:autoload containing dash
>this should run automatically

%clean

 rm -f file.in file.out
