E01options.ztst   [plain text]


# Test various shell options.
# Interactive options not tested here:
#    ALWAYS_LAST_PROMPT
#    ALWAYS_TO_END
#    APPEND_HISTORY (history not maintained)
#    AUTO_LIST
#    AUTO_MENU
#    AUTO_NAME_DIRS  (named directory table not maintained)
#    AUTO_PARAM_KEYS
#    AUTO_PARAM_SLASH
#    AUTO_REMOVE_SLASH
#    AUTO_RESUME
#    BANG_HIST
#    BASH_AUTO_LIST
#    BEEP (!)
#    BG_NICE
#    CHECK_JOBS
#    COMPLETE_ALIASES
#    COMPLETE_IN_WORD
#    CORRECT
#    CORRECT_ALL
#    CSH_JUNKIE_HISTORY
#    DVORAK
#    EXTENDED_HISTORY
#    FLOW_CONTROL
#    GLOB_COMPLETE
#    HIST_ALLOW_CLOBBER
#    HIST_BEEP
#    HIST_EXPIRE_DUPS_FIRST
#    HIST_FIND_NO_DUPS
#    HIST_IGNORE_ALL_DUPS
#    HIST_IGNORE_DUPS (-h)
#    HIST_IGNORE_SPACE (-g)
#    HIST_NO_FUNCTIONS
#    HIST_NO_STORE
#    HIST_REDUCE_BLANKS
#    HIST_SAVE_NO_DUPS
#    HIST_VERIFY
#    HUP
#    IGNORE_EOF
#    INC_APPEND_HISTORY
#    INTERACTIVE
#    INTERACTIVE_COMMENTS
#    LIST_AMBIGUOUS
#    LIST_BEEP
#    LIST_PACKED
#    LIST_ROWS_FIRST
#    LIST_TYPES
#    LOGIN
#    LONG_LIST_JOBS
#    MAIL_WARNING
#    MENU_COMPLETE
#    MONITOR
#    NOTIFY
#    OVERSTRIKE
#    PRINT_EIGHT_BIT
#    PROMPT_CR
#    PUSHD_SILENT
#    REC_EXACT
#    RM_STAR_SILENT
#    RM_STAR_WAIT
#    SHARE_HISTORY
#    SINGLE_LINE_ZLE
#    SUN_KEYBOARD_HACK
#    ZLE
# The following require SHINSTDIN and are not (yet) tested:
#    AUTO_CD
#    SHINSTDIN
#
# Other difficult things I haven't done:
#    GLOBAL_RCS (uses fixed files outside build area)
#    HASH_CMDS     )
#    HASH_DIRS     )  fairly seriously internal, hard to test at all
#    HASH_LIST_ALL )
#    PRINT_EXIT_STATUS   haven't worked out what this does yet, although
#                        Bart suggested a fix.
#    PRIVILEGED (similar to GLOBAL_RCS)
#    RCS        (  "      "    "    " )
#    SH_OPTION_LETTERS   even I found this too dull to set up a test for
#    SINGLE_COMMAND      kills shell
#    VERBOSE             hard because done on input (c.f. SHINSTDIN).

%prep
  mkdir options.tmp && cd options.tmp

  mkdir tmpcd

  touch tmpfile1 tmpfile2

  mydir=$PWD
  mydirt=`print -P %~`
  catpath=$(which cat)
  lspath==ls

%test

  alias echo='print foo'
  unsetopt aliases
  # use eval else aliases are all parsed at start
  eval echo bar
  setopt aliases
  eval echo bar
  unalias echo
0:ALIASES option
>bar
>foo bar

  setopt allexport
  testpm1=exported
  unsetopt allexport
  testpm2=unexported
  print ${(t)testpm1}
  print ${(t)testpm2}
0:ALL_EXPORT option
>scalar-export
>scalar
  
  # Count the number of directories on the stack.  Don't care what they are.
  dircount() { dirs -v | tail -1 | awk '{ print $1 + 1}'; }
  unsetopt autopushd
  cd tmpcd
  dircount
  cd ..
  setopt autopushd
  cd tmpcd
  dircount
  unsetopt autopushd
  popd >/dev/null
0:AUTO_PUSHD option
>1
>2

  unsetopt badpattern
  print [a
  setopt badpattern
  print [b
1:BAD_PATTERN option
>[a
?(eval):4: bad pattern: [b

  unsetopt bareglobqual nomatch
  print *(.)
  setopt bareglobqual nomatch
  print *(.)
0:BARE_GLOB_QUAL option
>*(.)
>tmpfile1 tmpfile2

  setopt braceccl
  print {abcd}
  unsetopt braceccl
  print {abcd}
0:BRACE_CCL option
>a b c d
>{abcd}

# Don't use NUL as a field separator in the following.
  setopt braceccl
  print {$'\0'-$'\5'} | IFS=' ' read -A chars
  for c in $chars; do print $(( #c )); done
  unsetopt braceccl
0:BRACE_CCL option starting from NUL
>0
>1
>2
>3
>4
>5

  setopt bsdecho
  echo "histon\nimpington"
  echo -e "girton\ncottenham"
  unsetopt bsdecho
  echo "newnham\ncomberton"
0:BSD_ECHO option
>histon\nimpington
>girton
>cottenham
>newnham
>comberton

  unsetopt c_bases
  print $(( [#16]15 ))
  print $(( [#8]9 ))
  setopt c_bases
  print $(( [#16]31 ))
  print $(( [#8]17 ))
  setopt octal_zeroes
  print $(( [#8]19 ))
  unsetopt c_bases octal_zeroes
0:C_BASES option
>16#F
>8#11
>0x1F
>8#21
>023

  setopt cdablevars
  # only absolute paths are eligible for ~-expansion
  cdablevar1=tmpcd
  (cd cdablevar1)
  cdablevar2=$PWD/tmpcd
  cd cdablevar2
  cd ..
  print back in ${PWD:t}
  unsetopt cdablevars
  cd cdablevar2
1q:CDABLE_VARS option
>back in options.tmp
?(eval):cd:4: no such file or directory: cdablevar1
?(eval):cd:10: no such file or directory: cdablevar2

# CHASE_DOTS should go with CHASE_LINKS in B01cd.ztst
# which saves me having to write it here.

  setopt noclobber
  rm -f foo1 bar1 rod1
  echo waterbeach >foo1
  (echo landbeach >foo1)
  cat foo1
  (echo lode >>bar1)
  [[ -f bar1 ]] && print That shouldn\'t be there.
  echo denny >rod1
  echo wicken >>rod1
  cat rod1
  unsetopt noclobber
  rm -f foo2 bar2 rod2
  echo ely >foo2
  echo march >foo2
  cat foo2
  echo wimpole >>bar2
  cat bar2
  echo royston >rod2
  echo foxton >>rod2
  cat rod2
  rm -f foo* bar* rod*
0:CLOBBER option
>waterbeach
>denny
>wicken
>march
>wimpole
>royston
>foxton
?(eval):4: file exists: foo1
?(eval):6: no such file or directory: bar1

   setopt cshjunkieloops
   eval 'for f in swaffham bulbeck; print $f; end'
   print next one should fail >&2
   unsetopt cshjunkieloops
   eval 'for f in chesterton arbury; print $f; end'
1:CSH_JUNKIE_LOOPS option (for loop)
>swaffham
>bulbeck
?next one should fail
?(eval):1: parse error near `end'

  setopt cshjunkiequotes
  print this should cause an error >&2
  eval "print 'line one
  line two'"
  print this should not >&2
  eval "print 'line three\\
  line four'"
  unsetopt cshjunkiequotes
0:CSH_JUNKIE_QUOTES option
>line three
>  line four
?this should cause an error
?(eval):1: unmatched '
?this should not

  nullcmd() { print '$NULLCMD run'; }
  readnullcmd() { print 'Running $READNULLCMD'; cat; }
  NULLCMD=nullcmd
  READNULLCMD=readnullcmd
  setopt cshnullcmd
  rm -f foo
  print "This should fail" >&2
  (>foo)
  print "This should succeed" >&2
  print "These are the contents of foo" >foo
  cat foo
  print "This should also fail" >&2
  (<foo)
  unsetopt cshnullcmd
  rm -f foo
  >foo
  <foo
  rm -f foo
0:CSH_NULL_CMD option
>These are the contents of foo
>Running $READNULLCMD
>$NULLCMD run
?This should fail
?(eval):8: redirection with no command
?This should succeed
?This should also fail
?(eval):13: redirection with no command

# nomatch should be overridden by cshnullglob
  setopt nomatch cshnullglob
  print tmp* nothing* blah
  print -n 'hoping for no match: ' >&2
  (print nothing* blah)
  print >&2
  unsetopt cshnullglob nomatch
  print tmp* nothing* blah
  print nothing* blah
0:CSH_NULL_GLOB option
>tmpcd tmpfile1 tmpfile2 blah
>tmpcd tmpfile1 tmpfile2 nothing* blah
>nothing* blah
?hoping for no match: (eval):4: no match
?

# The trick is to avoid =cat being expanded in the output while $catpath is.
  setopt NO_equals
  print -n trick; print =cat
  setopt equals
  print -n trick; print =cat
0q:EQUALS option
>trick=cat
>trick$catpath

# explanation of expected TRAPZERR output:  from false and from
# testfn() with ERR_EXIT on (hmm, should we really get a second one from
# the function exiting?), then from the false only with ERR_EXIT off.
  TRAPZERR() { print ZERR trapped; }
  testfn() { setopt localoptions $2; print $1 before; false; print $1 after; }
  (testfn on errexit)
  testfn off
  unfunction TRAPZERR testfn
0:ERR_EXIT option
>on before
>ZERR trapped
>ZERR trapped
>off before
>ZERR trapped
>off after

  (print before; setopt noexec; print after)
0:NO_EXEC option
>before

  setopt NO_eval_lineno
  eval 'print $LINENO'
  setopt eval_lineno
  eval 'print $LINENO'
0:EVAL_LINENO option
>2
>1

  # The EXTENDED_GLOB test doesn't test globbing fully --- it just tests
  # that certain patterns are treated literally with the option off
  # and as patterns with the option on.
  testfn() { print -n "$1 $2 $3 "; if [[ $1 = ${~2} ]];
             then print yes; else print no; fi; }
  tests=('a#' '?~b' '^aa')
  strings=('a' 'aa' 'b' 'a#' '?~b' '^aa')
  for opt in noextendedglob extendedglob; do
    setopt $opt
    for test in $tests; do
      for string in $strings; do
         testfn $string $test $opt
      done
    done
  done
0:EXTENDED_GLOB option
>a a# noextendedglob no
>aa a# noextendedglob no
>b a# noextendedglob no
>a# a# noextendedglob yes
>?~b a# noextendedglob no
>^aa a# noextendedglob no
>a ?~b noextendedglob no
>aa ?~b noextendedglob no
>b ?~b noextendedglob no
>a# ?~b noextendedglob no
>?~b ?~b noextendedglob yes
>^aa ?~b noextendedglob no
>a ^aa noextendedglob no
>aa ^aa noextendedglob no
>b ^aa noextendedglob no
>a# ^aa noextendedglob no
>?~b ^aa noextendedglob no
>^aa ^aa noextendedglob yes
>a a# extendedglob yes
>aa a# extendedglob yes
>b a# extendedglob no
>a# a# extendedglob no
>?~b a# extendedglob no
>^aa a# extendedglob no
>a ?~b extendedglob yes
>aa ?~b extendedglob no
>b ?~b extendedglob no
>a# ?~b extendedglob no
>?~b ?~b extendedglob no
>^aa ?~b extendedglob no
>a ^aa extendedglob yes
>aa ^aa extendedglob no
>b ^aa extendedglob yes
>a# ^aa extendedglob yes
>?~b ^aa extendedglob yes
>^aa ^aa extendedglob yes

  foo() { print My name is $0; }
  unsetopt functionargzero
  foo
  setopt functionargzero
  foo
  unfunction foo
0:FUNCTION_ARGZERO option
>My name is ZTST_execchunk
>My name is foo

  setopt _NO_glob_
  print tmp*
  set -o glob
  print tmp*
0:GLOB option
>tmp*
>tmpcd tmpfile1 tmpfile2

  showit() { local v;
             for v in first second third; do
               eval print \$$v \$\{\(t\)$v\}
	     done;
           }      
  setit() { typeset -x first=inside1;
            typeset +g -x second=inside2;
            typeset -g -x third=inside3;
            showit;
          }
  first=outside1 second=outside2 third=outside3
  unsetopt globalexport
  setit
  showit
  setopt globalexport
  setit
  showit
  unfunction setit showit
0:GLOBAL_EXPORT option
>inside1 scalar-local-export
>inside2 scalar-local-export
>inside3 scalar-export
>outside1 scalar
>outside2 scalar
>inside3 scalar-export
>inside1 scalar-export
>inside2 scalar-local-export
>inside3 scalar-export
>inside1 scalar-export
>outside2 scalar
>inside3 scalar-export

  setopt globassign
  foo=tmp*
  print $foo
  unsetopt globassign
  foo=tmp*
  print $foo
0:GLOB_ASSIGN option
>tmpcd tmpfile1 tmpfile2
>tmp*

  mkdir onlysomefiles
  touch onlysomefiles/.thisfile onlysomefiles/thatfile
  setopt globdots
  print onlysomefiles/*
  unsetopt globdots
  print onlysomefiles/*
  rm -rf onlysomefiles
0:GLOB_DOTS option
>onlysomefiles/.thisfile onlysomefiles/thatfile
>onlysomefiles/thatfile

  # we've tested this enough times already...
  # could add some stuff for other sorts of expansion
  foo='tmp*'
  setopt globsubst
  print ${foo}
  unsetopt globsubst
  print ${foo}
0:GLOB_SUBST option
>tmpcd tmpfile1 tmpfile2
>tmp*

  setopt histsubstpattern
  print *(:s/t??/TING/)
  foo=(tmp*)
  print ${foo:s/??p/THUMP/}
  foo=(one.c two.c three.c)
  print ${foo:s/#%(#b)t(*).c/T${match[1]}.X/}
  print *(#q:s/#(#b)tmp(*e)/'scrunchy${match[1]}'/)
  unsetopt histsubstpattern
0:HIST_SUBST_PATTERN option
>TINGcd TINGfile1 TINGfile2
>THUMPcd THUMPfile1 THUMPfile2
>one.c Two.X Three.X
>scrunchyfile1 scrunchyfile2 tmpcd

  setopt ignorebraces
  echo X{a,b}Y
  unsetopt ignorebraces
  echo X{a,b}Y
0:IGNORE_BRACES option
>X{a,b}Y
>XaY XbY

  setopt ksh_arrays
  array=(one two three)
  print $array $array[2]
  print ${array[0]} ${array[1]} ${array[2]} ${array[3]}
  unsetopt ksh_arrays
  print $array $array[2]
  print ${array[0]} ${array[1]} ${array[2]} ${array[3]}
  unset array
0:KSH_ARRAYS option
>one one[2]
>one two three
>one two three two
>one two three

  fpath=(.)
  echo >foo 'echo foo loaded; foo() { echo foo run; }'
  echo >bar 'bar() { echo bar run; }'
  setopt kshautoload
  autoload foo bar
  foo
  bar
  unfunction foo bar
  unsetopt kshautoload
  autoload foo bar
  foo
  bar
0:KSH_AUTOLOAD option
>foo loaded
>foo run
>bar run
>foo loaded
>bar run

# ksh_glob is tested by the glob tests.

  setopt kshoptionprint globassign
  print set
  setopt | grep kshoptionprint
  setopt | grep globassign
  unsetopt kshoptionprint
  print unset
  setopt | grep kshoptionprint
  setopt | grep globassign
  unsetopt globassign
0:KSH_OPTION_PRINT option
>set
>kshoptionprint        on
>globassign            on
>unset
>globassign

  setopt kshtypeset
  ktvars=(ktv1 ktv2)
  typeset ktfoo=`echo arg1 arg2` $ktvars
  print $+ktv1 $+ktv2 $+ktv3
  print $ktfoo
  unsetopt kshtypeset
  typeset noktfoo=`echo noktarg1 noktarg2`
  print $noktfoo
  print $+noktarg1 $+noktarg2
  unset ktfoo ktv1 ktv2 noktfoo noktarg2
0:KSH_TYPESET option
>1 1 0
>arg1 arg2
>noktarg1
>0 1

  showopt() { setopt | egrep 'localoptions|ksharrays'; }
  f1() { setopt localoptions ksharrays; showopt }
  f2() { setopt ksharrays; showopt }
  setopt kshoptionprint
  showopt
  f1
  showopt
  f2
  showopt
  unsetopt ksh_arrays
0:LOCAL_OPTIONS option
>ksharrays             off
>localoptions          off
>ksharrays             on
>localoptions          on
>ksharrays             off
>localoptions          off
>ksharrays             on
>localoptions          off
>ksharrays             on
>localoptions          off

# LOCAL_TRAPS was tested in C03traps (phew).

  fn() {
    local HOME=/any/old/name
    print -l var=~ 'anything goes/here'=~ split=`echo maybe not`;
  }
  setopt magicequalsubst
  fn
  setopt kshtypeset
  fn
  unsetopt magicequalsubst kshtypeset
  fn
0:MAGIC_EQUAL_SUBST option
>var=/any/old/name
>anything goes/here=/any/old/name
>split=maybe
>not
>var=/any/old/name
>anything goes/here=/any/old/name
>split=maybe not
>var=~
>anything goes/here=~
>split=maybe
>not

  setopt MARK_DIRS
  print tmp*
  unsetopt MARK_DIRS
  print tmp*
0:MARK_DIRS option
>tmpcd/ tmpfile1 tmpfile2
>tmpcd tmpfile1 tmpfile2

# maybe should be in A04redirect
  print "This is in1" >in1
  print "This is in2" >in2
  unsetopt multios
  print Test message >foo1 >foo2
  print foo1: $(<foo1)
  print foo2: $(<foo2)
  cat <in1 <in2
  setopt multios
  print Test message >foo1 >foo2
  sleep 1   # damn, race in multios
  print foo1: $(<foo1)
  print foo2: $(<foo2)
  cat <in1 <in2
  rm -f foo1 foo2 in1 in2
0:MULTIOS option
>foo1:
>foo2: Test message
>This is in2
>foo1: Test message
>foo2: Test message
>This is in1
>This is in2

# This is trickier than it looks.  There's a hack at the end of
# execcmd() to catch the multio processes attached to the
# subshell, which otherwise sort of get lost in the general turmoil.
# Without that, the multios aren't synchronous with the subshell
# or the main shell starting the "cat", so the output files appear
# empty.
  setopt multios
  ( echo hello ) >multio_out1 >multio_out2 && cat multio_out*
0:Multios attached to a subshell
>hello
>hello

# This tests for another race in multios.
  print -u $ZTST_fd 'This test hangs the shell when it fails...'
  setopt multios
  echo These are the contents of the file >multio_race.out
  multio_race_fn() { cat; }
  multio_race_fn <$(echo multio_race.out multio_race.out)
0:Fix for race with input multios
>These are the contents of the file
>These are the contents of the file

# tried this with other things, but not on its own, so much.
  unsetopt nomatch
  print with nonomatch: flooble*
  setopt nomatch
  print with nomatch flooble*
1:NOMATCH option
>with nonomatch: flooble*
?(eval):4: no matches found: flooble*

# NULL_GLOB should override NONOMATCH...
  setopt nullglob nomatch
  print frooble* tmp*
  unsetopt nullglob nomatch
  print frooble* tmp*
0:NULL_GLOB option
>tmpcd tmpfile1 tmpfile2
>frooble* tmpcd tmpfile1 tmpfile2

  touch ngs1.txt ngs2.txt ngs10.txt ngs20.txt ngs100.txt ngs200.txt
  setopt numericglobsort
  print -l ngs*
  unsetopt numericglobsort
  print -l ngs*
0:NUMERIC_GLOB_SORT option
>ngs1.txt
>ngs2.txt
>ngs10.txt
>ngs20.txt
>ngs100.txt
>ngs200.txt
>ngs1.txt
>ngs10.txt
>ngs100.txt
>ngs2.txt
>ngs20.txt
>ngs200.txt

  typeset -i 10 oznum
  setopt octalzeroes
  (( oznum = 012 + 013 ))
  print $oznum
  unsetopt octalzeroes
  (( oznum = 012 + 013 ))
  print $oznum
  unset oznum
0:OCTAL_ZEROES options
>21
>25

  typeset -a oldpath
  oldpath=($path)
  mkdir pdt_topdir pathtestdir pdt_topdir/pathtestdir
  print "#!/bin/sh\necho File in upper dir" >pathtestdir/findme
  print "#!/bin/sh\necho File in lower dir" >pdt_topdir/pathtestdir/findme
  chmod u+x pathtestdir/findme pdt_topdir/pathtestdir/findme
  pathtestdir/findme
  rm -f pathtestdir/findme
  setopt pathdirs
  path=($PWD $PWD/pdt_topdir)
  pathtestdir/findme
  print unsetting option...
  unsetopt pathdirs
  pathtestdir/findme
  path=($oldpath)
  unset $oldpath
  rm -rf pdt_topdir pathtestdir
0:PATH_DIRS option
>File in upper dir
>File in lower dir
>unsetting option...
?(eval):14: no such file or directory: pathtestdir/findme

  setopt posixbuiltins
  PATH= command -v print
  PATH= command -V print
  PATH= command print foo
  unsetopt posixbuiltins
  print unsetting...
  PATH= command -V print
  PATH= command print foo
127:POSIX_BUILTINS option
>print
>print is a shell builtin
>foo
>unsetting...
>print is a shell builtin
?(eval):8: command not found: print

# This option seems to be problematic.  I don't quite know how it works.
##   func() {
##     setopt localoptions printexitvalue
##     false
##   }
##   func
## 1:PRINT_EXIT_VALUE option
## ?(eval):2: exit 1

  setopt promptbang
  print -P !
  setopt nopromptbang
  print -P !
0:PROMPT_BANG option
>0
>!

  unsetopt promptpercent
  print -P '%/'
  setopt promptpercent
  print -P '%/'
0q:PROMPT_PERCENT option
>%/
>$mydir

  setopt promptsubst
  print -P '`echo waaah`'
  unsetopt promptsubst
  print -P '`echo waaah`'
0:PROMPT_SUBST option
>waaah
>`echo waaah`

  dirs
  pushd $mydir/tmpcd
  dirs
  pushd $mydir/tmpcd
  dirs
  setopt pushdignoredups
  pushd $mydir/tmpcd
  dirs
  unsetopt pushdignoredups
  popd >/dev/null
  popd >/dev/null
0q:PUSHD_IGNOREDUPS option
>$mydirt
>$mydirt/tmpcd $mydirt
>$mydirt/tmpcd $mydirt/tmpcd $mydirt
>$mydirt/tmpcd $mydirt/tmpcd $mydirt

  mkdir newcd
  cd $mydir
  pushd $mydir/tmpcd
  pushd $mydir/newcd
  dirs
  pushd -0
  dirs
  setopt pushdminus pushdsilent
  pushd -0
  dirs
  unsetopt pushdminus
  popd >/dev/null
  popd >/dev/null
  cd $mydir  
0q:PUSHD_MINUS option
>$mydirt/newcd $mydirt/tmpcd $mydirt
>$mydirt $mydirt/newcd $mydirt/tmpcd
>$mydirt $mydirt/newcd $mydirt/tmpcd

# Do you have any idea how dull this is?

  pushd $mydir/tmpcd
  pushd
  dirs
  setopt pushdtohome
  pushd
  dirs
  unsetopt pushdtohome
  popd
  pushd
  popd
  dirs
0q:PUSHD_TO_HOME option
>$mydirt $mydirt/tmpcd
>~ $mydirt $mydirt/tmpcd
>$mydirt

  array=(one two three four)
  setopt rcexpandparam
  print aa${array}bb
  unsetopt rcexpandparam
  print aa${array}bb
0:RC_EXPAND_PARAM option
>aaonebb aatwobb aathreebb aafourbb
>aaone two three fourbb

  setopt rcquotes
  # careful, this is done when parsing a complete block
  eval "print 'one''quoted''expression'"
  unsetopt rcquotes
  eval "print 'another''quoted''expression'"
0:RC_QUOTES option
>one'quoted'expression
>anotherquotedexpression

# too lazy to test jobs -Z and ARGV0.
  (setopt restricted; cd /)
  (setopt restricted; PATH=/bin:/usr/bin)
  (setopt restricted; /bin/ls)
  (setopt restricted; hash ls=/bin/ls)
  (setopt restricted; print ha >outputfile)
  (setopt restricted; exec ls)
  (setopt restricted; unsetopt restricted)
  :
0:RESTRICTED option
?(eval):cd:1: restricted
?(eval):2: PATH: restricted
?(eval):3: /bin/ls: restricted
?(eval):hash:4: restricted: /bin/ls
?(eval):5: writing redirection not allowed in restricted mode
?(eval):exec:6: ls: restricted
?(eval):unsetopt:7: can't change option: restricted

  fn() {
    print =ls ={ls,}
    local foo='=ls'
    print ${~foo}
  }
  setopt shfileexpansion
  fn
  unsetopt shfileexpansion
  fn
0q:SH_FILE_EXPANSION option
>$lspath =ls =
>=ls
>$lspath $lspath =
>$lspath

  testpat() {
    if [[ $1 = ${~2} ]]; then print $1 $2 yes; else print $1 $2 no; fi
  }
  print option on
  setopt shglob
  repeat 2; do
    for str in 'a(b|c)' ab; do
      testpat $str 'a(b|c)'
    done
    for str in 'a<1-10>' a9; do
      testpat $str 'a<1-10>'
    done
    [[ ! -o shglob ]] && break
    print option off
    unsetopt shglob
  done
0:SH_GLOB option
>option on
>a(b|c) a(b|c) yes
>ab a(b|c) no
>a<1-10> a<1-10> yes
>a9 a<1-10> no
>option off
>a(b|c) a(b|c) no
>ab a(b|c) yes
>a<1-10> a<1-10> no
>a9 a<1-10> yes

  print this is bar >bar
  fn() {
    local NULLCMD=cat READNULLCMD=cat
    echo hello | >foo
    cat foo
    <bar
  }
  setopt shnullcmd
  print option set
  fn
  unsetopt shnullcmd
  print option unset
  fn
  rm -f foo bar
0:SH_NULLCMD option
>option set
>option unset
>hello
>this is bar

  fn() { 
    eval 'for f in foo bar; print $f'
    eval 'for f (word1 word2) print $f'
    eval 'repeat 3 print nonsense'
  }
  unsetopt shortloops
  print option unset
  fn
  setopt shortloops
  print option set
  fn
0:SHORT_LOOPS option
>option unset
>option set
>foo
>bar
>word1
>word2
>nonsense
>nonsense
>nonsense
?(eval):1: parse error near `print'
?(eval):1: parse error near `print'
?(eval):1: parse error near `print'

  fn() { print -l $*; }
  setopt shwordsplit
  print option set
  repeat 2; do
    foo='two words'
    fn $foo
    fn "${=foo}"
    [[ ! -o shwordsplit ]] && break
    unsetopt shwordsplit
    print option unset
  done
0:SH_WORD_SPLIT option
>option set
>two
>words
>two
>words
>option unset
>two words
>two
>words

  fn() { unset foo; print value is $foo; }
  setopt nounset
  print option unset unset by setting nounset
  eval fn
  print option unset reset
  setopt unset
  fn
0:UNSET option
>option unset unset by setting nounset
>option unset reset
>value is
?fn: foo: parameter not set

  fn1() { unset foo; print value 1 is ${foo#bar}; }
  fn2() { unset foo; print value 2 is ${foo%bar}; }
  fn3() { unset foo; print value 3 is ${foo/bar}; }
  setopt nounset
  print option unset unset by setting nounset
  eval fn1
  eval fn2
  eval fn3
  print option unset reset
  setopt unset
  fn1
  fn2
  fn3
0:UNSET option with operators
>option unset unset by setting nounset
>option unset reset
>value 1 is
>value 2 is
>value 3 is
?fn1: foo: parameter not set
?fn2: foo: parameter not set
?fn3: foo: parameter not set

  fn() {
    emulate -L zsh
    setopt warncreateglobal
    foo1=bar1
    unset foo1
    foo1=bar2
    local foo2=bar3
    unset foo2
    foo2=bar4
    typeset -g foo3
    foo3=bar5
    fn2() {
      foo3=bar6
    }
  }
  fn
0:WARN_CREATE_GLOBAL option
?fn:3: scalar parameter foo1 created globally in function
?fn:5: scalar parameter foo1 created globally in function

# This really just tests if XTRACE is egregiously broken.
# To test it properly would need a full set of its own.
  fn() { print message; }
  PS4='+%N:%i> '
  setopt xtrace
  fn
  unsetopt xtrace
  fn
0:XTRACE option
>message
>message
?+(eval):4> fn
?+fn:0> print message
?+(eval):5> unsetopt xtrace