%prep

  storepath=($path)

  mkdir command.tmp command.tmp/dir1 command.tmp/dir2

  cd command.tmp

  print '#!/bin/sh\necho This is top' >tstcmd

  print '#!/bin/sh\necho This is dir1' >dir1/tstcmd

  print '#!/bin/sh\necho This is dir2' >dir2/tstcmd

  chmod 755 tstcmd dir1/tstcmd dir2/tstcmd

%test
  ./tstcmd
0:./prog execution
>This is top

  path=($ZTST_testdir/command.tmp/dir1
        $ZTST_testdir/command.tmp/dir2
        .)
  tstcmd
  path=($storepath)
0:path (1)
>This is dir1

  path=(. command.tmp/dir{1,2})
  tstcmd
  path=($storepath)
0:path (2)
>This is top

  functst() { print $# arguments:; print -l $*; }
  functst "Eines Morgens" "als Gregor Samsa"
  functst ""
  functst "aus unrühigen Träumen erwachte"
  foo="fand er sich in seinem Bett"
  bar=
  rod="zu einem ungeheuren Ungeziefer verwandelt."
  functst $foo $bar $rod
# set up alias for next test
  alias foo='print This is alias one'
0:function argument passing
>2 arguments:
>Eines Morgens
>als Gregor Samsa
>1 arguments:
>
>1 arguments:
>aus unrühigen Träumen erwachte
>2 arguments:
>fand er sich in seinem Bett
>zu einem ungeheuren Ungeziefer verwandelt.

  alias foo='print This is alias two'
  fn() { foo; }
  fn
0:Aliases in functions
>This is alias one

  foo='Global foo'
  traptst() { local foo="Local foo"; trap 'print $foo' EXIT; }
  traptst
0:EXIT trap environment
>Global foo

  functst() { return 0; print Ha ha; return 1; }
  functst
0:return (1)

  functst() { return 1; print Ho ho; return 0; }
  functst
1:return (2)

  unfunction functst
  fpath=(.)
  print "print This is functst." >functst
  autoload functst
  functst
0:autoloading (1)
>This is functst.

  unfunction functst
  print "functst() { print This, too, is functst; }; print Hello." >functst
  typeset -fu functst
  functst
  functst
0:autoloading with initialization
>Hello.
>This, too, is functst

  unfunction functst
  print "print Yet another version" >functst
  functst() { autoload -X; }
  functst
0:autoloading via -X
>Yet another version

  chpwd() { print Changed to $PWD; }
  cd .
  unfunction chpwd
0q:chpwd
>Changed to $ZTST_testdir/command.tmp

  chpwd() { print chpwd: changed to $PWD; }
  chpwdfn1()  { print chpwdfn1: changed to $PWD; }
  chpwdfn2()  { print chpwdfn2: changed to $PWD; }
  chpwd_functions=(chpwdfn1 '' chpwdnonexistentfn chpwdfn2)
  cd .
  unfunction chpwd
  unset chpwd_functions
0q:chpwd_functions
>chpwd: changed to $ZTST_testdir/command.tmp
>chpwdfn1: changed to $ZTST_testdir/command.tmp
>chpwdfn2: changed to $ZTST_testdir/command.tmp

# Hard to test periodic, precmd and preexec non-interactively.

  fn() { TRAPEXIT() { print Exit; }; }
  fn
0:TRAPEXIT
>Exit

  unsetopt DEBUG_BEFORE_CMD
  unfunction fn
  print 'TRAPDEBUG() {
      print Line $LINENO
    }
    :
    unfunction TRAPDEBUG
  ' > fn
  autoload fn
  fn
  rm fn
0:TRAPDEBUG
>Line 1
>Line 1

  unsetopt DEBUG_BEFORE_CMD
  unfunction fn
  print 'trap '\''print Line $LINENO'\'' DEBUG
    :
    trap - DEBUG
  ' > fn
  autoload fn
  fn
  rm fn
0:trap DEBUG
>Line 1
>Line 2

  TRAPZERR() { print Command failed; }
  true
  false
  true
  false
  unfunction TRAPZERR
0:TRAPZERR
>Command failed
>Command failed

  trap 'print Command failed again.' ZERR
  true
  false
  true
  false
  trap - ZERR
0:trap ZERR
>Command failed again.
>Command failed again.

  false
  sleep 1000 &
  print $?
  kill $!
0:Status reset by starting a backgrounded command
>0

  { setopt MONITOR } 2>/dev/null
  [[ -o MONITOR ]] || print -u $ZTST_fd 'Unable to change MONITOR option'
  repeat 2048; do (return 2 |
                   return 1 |
                   while true; do
                             false
                             break
                           done;
                   print "${pipestatus[@]}")
	ZTST_hashmark
  done | sort | uniq -c | sed 's/^ *//'
0:Check whether '$pipestatus[]' behaves.
>2048 2 1 0
F:This test checks for a bug in '$pipestatus[]' handling.  If it breaks then
F:the bug is still there or it reappeared. See workers-29973 for details.

  { setopt MONITOR } 2>/dev/null
  externFunc() { awk >/dev/null 2>&1; true; }
  false | true | false | true | externFunc
  echo $pipestatus
0:Check $pipestatus with a known difficult case
>1 0 1 0 0
F:This similar test was triggering a reproducible failure with pipestatus.

  { unsetopt MONITOR } 2>/dev/null
  coproc { read -et 5 || { print -u $ZTST_fd KILLED; kill -HUP -$$ } }
  print -u $ZTST_fd 'This test takes 5 seconds to fail...'
  { printf "%d\n" {1..20000} } | ( read -e )
  hang(){ printf "%d\n" {2..20000} | cat }; hang | ( read -e )
  print -p done
  read -et 6 -p
0:Bug regression: piping a shell construct to an external process may hang
>1
>2
>done
F:This test checks for a file descriptor leak that could cause the left
F:side of a pipe to block on write after the right side has exited

  { setopt MONITOR } 2>/dev/null
  if [[ -o MONITOR ]]
  then
   ( while :; do print "This is a line"; done ) | () : &
   sleep 1
   jobs -l
  else
   print -u $ZTST_fd "Skipping pipe leak test, requires MONITOR option"
   print "[0] 0 0"
  fi
0:Bug regression: piping to anonymous function; piping to backround function
*>\[<->\] <-> <->
F:This test checks for two different bugs, a parser segfault piping to an
F:anonymous function, and a descriptor leak when backgrounding a pipeline

  print "autoload_redir() { print Autoloaded ksh style; } >autoload.log" >autoload_redir
  autoload -Uk autoload_redir
  autoload_redir
  print No output yet
  cat autoload.log
  functions autoload_redir
0:
>No output yet
>Autoloaded ksh style
>autoload_redir () {
>	print Autoloaded ksh style
>} > autoload.log

# This tests that we record the status of processes that have already exited
# for when we wait for them.
#
# Actually, we don't guarantee here that the jobs have already exited, but
# the order of the waits means it's highly likely we do need to recall a
# previous status, barring accidents which shouldn't happen very often.  In
# other words, we rely on the test working repeatedly rather than just
# once.  The monitor option is irrelevant to the logic, so we'll make
# our job easier by turning it off.
  { unsetopt MONITOR } 2>/dev/null
  (exit 1) &
  one=$!
  (exit 2) &
  two=$!
  (exit 3) &
  three=$!
  wait $three
  print $?
  wait $two
  print $?
  wait $one
  print $?
0:The status of recently exited background jobs is recorded
>3
>2
>1

# Regression test for workers/34060 (patch in 34065)
  setopt ERR_EXIT NULL_GLOB
  if false; then :; else echo if:$?; fi
  if false; then :; else for x in _*_; do :; done; echo for:$?; fi
0:False "if" condition handled correctly by "for" loops with ERR_EXIT
>if:1
>for:0

# Regression test for workers/34065 (uses setopt from preceding test)
  select x; do :; done; echo $?
  select x in; do :; done; echo $?
  select x in _*_; do :; done; echo $?
0:The status of "select" is zero when the loop body does not execute
>0
>0
>0
