1#
2# This file contains tests corresponding to the `Shell Grammar' texinfo node.
3#
4
5%prep
6
7  mkdir basic.tmp && cd basic.tmp
8
9  touch foo bar
10  echo "'" >unmatched_quote.txt
11
12%test
13#
14# Tests for `Simple Commands and Pipelines'
15#
16  echo foo | cat | sed 's/foo/bar/'
170:Basic pipeline handling
18>bar
19
20  false | true
210:Exit status of pipeline with builtins (true)
22
23  true | false
241:Exit status of pipeline with builtins (false)
25
26  false
27  $nonexistent_variable
280:Executing command that evaluates to empty resets status
29
30  false
31  sleep 1 &
32  print $?
33  # a tidy test is a happy test
34  wait $!
350:Starting background command resets status
36>0
37
38  false
39  . /dev/null
400:Sourcing empty file resets status
41
42  fn() { local foo; read foo; print $foo; }
43  coproc fn
44  print -p coproc test output
45  read -p bar
46  print $bar
470:Basic coprocess handling
48>coproc test output
49
50  true | false && print true || print false
510:Basic sublist (i)
52>false
53
54  false | true && print true || print false
550:Basic sublist (ii)
56>true
57
58  (cd /NonExistentDirectory >&/dev/null) || print false
590:Basic subshell list with error
60>false
61
62  { cd /NonExistentDirectory >&/dev/null } || print false
630:Basic current shell list with error
64>false
65
66#
67# Tests for `Precommand Modifiers'
68#
69  - $ZTST_testdir/../Src/zsh -fc "[[ \$0 = \"-$ZTST_testdir/../Src/zsh\" ]]"
700:`-' precommand modifier
71
72  echo f*
73  noglob echo f*
740:`noglob' precommand modifier
75>foo
76>f*
77
78  (exec /bin/sh; echo bar)
790:`exec' precommand modifier
80
81  (exec -l $ZTST_testdir/../Src/zsh -fc 'echo $0' | sed 's%/.*/%%' )
820:`exec' with -l option
83>-zsh
84
85  (exec -a /bin/SPLATTER /bin/sh -c 'echo $0')
860:`exec' with -a option
87>/bin/SPLATTER
88
89  (exec -a/bin/SPLOOSH /bin/sh -c 'echo $0')
900:`exec' with -a option, no space
91>/bin/SPLOOSH
92
93  (export FOO=bar; exec -c /bin/sh -c 'echo x${FOO}x')
940:`exec' with -c option
95>xx
96
97  cat() { echo Function cat executed; }
98  command cat && unfunction cat
990:`command' precommand modifier
100<External command cat executed
101>External command cat executed
102
103  cd() { echo Not cd at all; }
104  builtin cd . && unfunction cd
1050:`builtin' precommand modifier
106
107#
108# Tests for `Complex Commands'
109#
110
111  if true; then
112    print true-1
113  elif true; then
114    print true-2
115  else
116    print false
117  fi
1180:`if ...' (i)
119>true-1
120
121  if false; then
122    print true-1
123  elif true; then
124    print true-2
125  else
126    print false
127  fi
1280:`if ...' (ii)
129>true-2
130
131  if false; then
132    print true-1
133  elif false; then
134    print true-2
135  else
136    print false
137  fi
1380:`if ...' (iii)
139>false
140
141  if true;
142    :
143  fi
1441d:`if ...' (iv)
145?(eval):3: parse error near `fi'
146
147  for name in word to term; do
148    print $name
149  done
1500:`for' loop
151>word
152>to
153>term
154
155  for name
156  in word to term; do
157    print $name
158  done
1590:`for' loop with newline before in keyword
160>word
161>to
162>term
163
164  for (( name = 0; name < 3; name++ )); do
165    print $name
166  done
1670:arithmetic `for' loop
168>0
169>1
170>2
171
172  for keyvar valvar in key1 val1 key2 val2; do
173     print key=$keyvar val=$valvar
174  done
1750:enhanced `for' syntax with two loop variables
176>key=key1 val=val1
177>key=key2 val=val2
178
179  for keyvar valvar stuffvar in keyA valA stuffA keyB valB stuffB; do
180     print key=$keyvar val=$valvar stuff=$stuffvar
181  done
1820:enhanced `for' syntax with three loop variables
183>key=keyA val=valA stuff=stuffA
184>key=keyB val=valB stuff=stuffB
185
186  for in in in in in stop; do
187    print in=$in
188  done
1890:compatibility of enhanced `for' syntax with standard syntax
190>in=in
191>in=in
192>in=in
193>in=stop
194
195  name=0
196  while (( name < 3 )); do
197    print $name
198    (( name++ ))
199  done
2000:`while' loop
201>0
202>1
203>2
204
205  name=0
206  until (( name == 3 )); do
207    print $name
208    (( name++ ))
209  done
2100:`until' loop
211>0
212>1
213>2
214
215  repeat 3 do
216    echo over and over
217  done
2180:`repeat' loop
219>over and over
220>over and over
221>over and over
222
223  word=Trinity
224  case $word in
225    Michaelmas) print 0
226                ;;
227    Hilary) print 1
228            ;;
229    Trinity) print 2
230             ;;
231    *) print 3
232       ;;
233  esac
2340:`case', old syntax
235>2
236
237  word=Trinity
238  case $word in
239    (Michaelmas) print 0
240                ;;
241    (Hilary) print 1
242            ;;
243    (Trinity) print 2
244             ;;
245    (*) print 3
246       ;;
247  esac
2480:`case', new syntax
249>2
250
251  word=Hilary
252  case $word in
253    (Michaelmas) print 0
254                ;;
255    (Hilary) print 1
256            ;&
257    (Trinity) print 2
258             ;&
259    (*) print 3
260       ;;
261  esac
2620:`case', new syntax, cascaded
263>1
264>2
265>3
266
267## Select now reads from stdin if the shell is not interactive.
268## Its own output goes to stderr.
269  (COLUMNS=80 LINES=3
270  PS3="input> "
271  select name in one two three; do
272    print $name
273  done)
2740:`select' loop
275<2
276?1) one     2) two     3) three   
277?input> input> 
278>two
279
280  function name1 name2 () { print This is $0; }
281  name2
282  name1 name2() { print This is still $0; }
283  name2
2840:`function' keyword
285>This is name2
286>This is still name2
287
288  (time cat) >&/dev/null
2890:`time' keyword (status only)
290
291  if [[ -f foo && -d . && -n $ZTST_testdir ]]; then
292    true
293  else
294    false
295  fi
2960:basic [[ ... ]] test
297
298#
299# Current shell execution with try/always form.
300# We put those with errors in subshells so that any unhandled error doesn't
301# propagate.
302#
303
304  {
305     print The try block.
306  } always {
307     print The always block.
308  }
309  print After the always block.
3100:Basic `always' syntax
311>The try block.
312>The always block.
313>After the always block.
314
315  ({
316    print Position one.
317    print ${*this is an error*}
318    print Position two.
319  } always {
320    if (( TRY_BLOCK_ERROR )); then
321      print An error occurred.
322    else
323      print No error occurred.
324    fi
325  }
326  print Position three)
3271:Always block with error not reset
328>Position one.
329>An error occurred.
330?(eval):3: bad substitution
331
332  ({
333    print Stelle eins.
334    print ${*voici une erreur}
335    print Posizione due.
336  } always {
337    if (( TRY_BLOCK_ERROR )); then
338      print Erratum factum est. Retro ponetur.
339      (( TRY_BLOCK_ERROR = 0 ))
340    else
341      print unray touay foay anguageslay
342    fi
343  }
344  print Status after always block is $?.)
3450:Always block with error reset
346>Stelle eins.
347>Erratum factum est. Retro ponetur.
348>Status after always block is 1.
349?(eval):3: bad substitution
350
351  fn() { { return } always { echo always 1 }; echo not executed }
352  fn
353  fn() { { echo try 2 } always { return }; echo not executed }
354  fn
3550:Always block interaction with return
356>always 1
357>try 2
358
359# Outputting of structures from the wordcode is distinctly non-trivial,
360# we probably ought to have more like the following...
361  fn1() { { echo foo; } }
362  fn2() { { echo foo; } always { echo bar; } }
363  fn3() { ( echo foo; ) }
364  functions fn1 fn2 fn3
3650:Output of syntactic structures with and without always blocks
366>fn1 () {
367>	{
368>		echo foo
369>	}
370>}
371>fn2 () {
372>	{
373>		echo foo
374>	} always {
375>		echo bar
376>	}
377>}
378>fn3 () {
379>	(
380>		echo foo
381>	)
382>}
383
384
385#
386# Tests for `Alternate Forms For Complex Commands'
387#
388
389  if (true) { print true-1 } elif (true) { print true-2 } else { print false }
390  if (false) { print true-1 } elif (true) { print true-2 } else { print false }
391  if (false) { print true-1 } elif (false) { print true-2 } else { print false }
3920:Alternate `if' with braces
393>true-1
394>true-2
395>false
396
397  if { true } print true
398  if { false } print false
3990:Short form of `if'
400>true
401
402  eval "if"
4031:Short form of `if' can't be too short
404?(eval):1: parse error near `if'
405
406  for name ( word1 word2 word3 ) print $name
4070:Form of `for' with parentheses.
408>word1
409>word2
410>word3
411
412  for name in alpha beta gamma; print $name
4130:Short form of `for'
414>alpha
415>beta
416>gamma
417
418  for (( val = 2; val < 10; val *= val )) print $val
4190:Short arithmetic `for'
420>2
421>4
422
423  foreach name ( verbiage words periphrasis )
424    print $name
425  end
4260:Csh-like `for'
427>verbiage
428>words
429>periphrasis
430
431# see comment with braces used in if loops
432  val=0;
433  while (( val < 2 )) { print $((val++)); }
4340:Alternative `while'
435>0
436>1
437
438  val=2;
439  until (( val == 0 )) { print $((val--)); }
4400:Alternative `until'
441>2
442>1
443
444  repeat 3 print Hip hip hooray
4450:Short `repeat'
446>Hip hip hooray
447>Hip hip hooray
448>Hip hip hooray
449
450  case bravo {
451    (alpha) print schmalpha
452	    ;;
453    (bravo) print schmavo
454	    ;;
455    (charlie) print schmarlie
456	    ;;
457  }
4580:`case' with braces
459>schmavo
460
461  for word in artichoke bladderwort chrysanthemum Zanzibar
462  case $word in
463    (*der*) print $word contains the forbidden incantation der
464         ;;
465    (a*) print $word begins with a
466         ;&
467    ([[:upper:]]*) print $word either begins with a or an upper case letter
468         ;|
469    ([[:lower:]]*) print $word begins with a lower case letter
470         ;|
471    (*e*) print $word contains an e
472         ;;
473  esac
4740:`case' with mixed ;& and ;|
475>artichoke begins with a
476>artichoke either begins with a or an upper case letter
477>artichoke begins with a lower case letter
478>artichoke contains an e
479>bladderwort contains the forbidden incantation der
480>chrysanthemum begins with a lower case letter
481>chrysanthemum contains an e
482>Zanzibar either begins with a or an upper case letter
483
484  print -u $ZTST_fd 'This test hangs the shell when it fails...'
485  name=0
486# The number 4375 here is chosen to produce more than 16384 bytes of output
487  while (( name < 4375 )); do
488    print -n $name
489    (( name++ ))
490  done < /dev/null | { read name; print done }
4910:Bug regression: `while' loop with redirection and pipeline
492>done
493
494# This used to be buggy and print X at the end of each iteration.
495  for f in 1 2 3 4; do
496    print $f || break
497  done && print X
4980:Handling of ||'s and &&'s with a for loop in between
499>1
500>2
501>3
502>4
503>X
504
505# Same bug for &&, used to print `no' at the end of each iteration
506  for f in 1 2 3 4; do
507    false && print strange
508  done || print no
5090:Handling of &&'s and ||'s with a for loop in between
510>no
511
512  $ZTST_testdir/../Src/zsh -f unmatched_quote.txt
5131:Parse error with file causes non-zero exit status
514?unmatched_quote.txt:2: unmatched '
515
516  $ZTST_testdir/../Src/zsh -f <unmatched_quote.txt
5171:Parse error on standard input causes non-zero exit status
518?zsh: unmatched '
519
520  $ZTST_testdir/../Src/zsh -f -c "'"
5211:Parse error on inline command causes non-zero exit status
522?zsh:1: unmatched '
523
524  $ZTST_testdir/../Src/zsh -f NonExistentScript
525127q:Non-existent script causes exit status 127
526?$ZTST_testdir/../Src/zsh: can't open input file: NonExistentScript
527
528  (setopt nonomatch
529  # use this to get stuff at start of line
530  contents=$'# comment \'\necho value #with " stuff\n# comment\n#comment
531  echo not#comment\n'
532  eval 'VAR=$('"$contents"')'
533  print -l $VAR)
5340:comments within $(...)
535>value
536>not#comment
537
538  . ./nonexistent
539127: Attempt to "." non-existent file.
540?(eval):.:1: no such file or directory: ./nonexistent
541
542  echo '[[' >bad_syntax
543  . ./bad_syntax
544126: Attempt to "." file with bad syntax.
545?./bad_syntax:2: parse error near `\n'
546
547  echo 'false' >dot_false
548  . ./dot_false
549  print $?
550  echo 'true' >dot_true
551  . ./dot_true
552  print $?
5530:Last status of successfully executed "." file is retained
554>1
555>0
556
557  echo 'echo $?' >dot_status
558  false
559  . ./dot_status
5600:"." file sees status from previous command
561>1
562
563  mkdir test_path_script
564  print "#!/bin/sh\necho Found the script." >test_path_script/myscript
565  chmod u+x test_path_script/myscript
566  path=($PWD/test_path_script $path)
567  export PATH
568  $ZTST_testdir/../Src/zsh -f -o pathscript myscript
5690:PATHSCRIPT option
570>Found the script.
571
572  $ZTST_testdir/../Src/zsh -f myscript
573127q:PATHSCRIPT option not used.
574?$ZTST_testdir/../Src/zsh: can't open input file: myscript
575
576  $ZTST_testdir/../Src/zsh -fc 'echo $0; echo $1' myargzero myargone
5770:$0 is traditionally if bizarrely set to the first argument with -c
578>myargzero
579>myargone
580
581  (setopt shglob
582  eval '
583  if ! (echo success1); then echo failure1; fi
584  if !(echo success2); then echo failure2; fi
585  print -l one two | while(read foo)do(print read it)done
586  ')
5870:Parentheses in shglob
588>success1
589>success2
590>read it
591>read it
592