t_syntax.sh revision 1.1 1 # $NetBSD: t_syntax.sh,v 1.1 2017/05/20 16:35:55 kre Exp $
2 #
3 # Copyright (c) 2017 The NetBSD Foundation, Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 # POSSIBILITY OF SUCH DAMAGE.
26 #
27 : ${TEST_SH:=/bin/sh}
28
29 # This set of tests verifies various requirementgs relating to correct
30 # (and incorrect) syntax of shell input
31 #
32 # There is no intent in these tests to verify correct operation
33 # (though that sometimes cannot be separated from correct parsing.)
34 # That is (or should be) verified elsewhere.
35 #
36 # Also, some very basic syntax is tested in almost every test
37 # (they cannot work without basic parsing of elementary commands)
38 # so that is also not explicitly tested here.
39 #
40 # Similarly word expansion, field splitting, redirection, all have
41 # tests of their own (though we do test parsing of redirect ops).
42 #
43 # Note that in order to test the basic facilities, other shell operations
44 # are used - a test failure here does not necessarily mean that the
45 # operation intended to be tested is faulty, just that something is.
46
47 atf_test_case a_basic_tokenisation
48 a_basic_tokenisation_head() {
49 atf_set "descr" "Test the shell correctly finds various tokens"
50 }
51 a_basic_tokenisation_body() {
52 atf_check -s exit:0 -o 'inline:3\n' -e empty ${TEST_SH} -c \
53 'set -- a b c; echo $#'
54 atf_check -s exit:0 -o 'inline:2\n' -e empty ${TEST_SH} -c \
55 'set -- a""b c; echo $#'
56 atf_check -s exit:0 -o 'inline:3\n' -e empty ${TEST_SH} -c \
57 'set -- a"" b c; echo $#'
58 atf_check -s exit:0 -o 'inline:3\n' -e empty ${TEST_SH} -c \
59 'set -- ""a b c\;; echo $#'
60
61 atf_check -s exit:0 -o 'inline:3\n' -e empty ${TEST_SH} -c \
62 'set -- set -- c; echo $#'
63 atf_check -s exit:0 -o 'inline:1\n' -e empty ${TEST_SH} -c \
64 'set --;set -- c; echo $#'
65 atf_check -s exit:0 -o 'inline:1\n' -e empty ${TEST_SH} -c \
66 'set --&set -- c; echo $#'
67 atf_check -s exit:0 -o 'inline:1\n' -e empty ${TEST_SH} -c \
68 'set -- a b&&set -- c; echo $#'
69 atf_check -s exit:0 -o 'inline:2\n' -e empty ${TEST_SH} -c \
70 'set -- a b||set -- c; echo $#'
71 }
72
73 atf_test_case b_comments
74 b_comments_head() {
75 atf_set "descr" "Test the shell correctly handles comments"
76 }
77 b_comments_body() {
78
79 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '#'
80 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '# exit 1'
81 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'true # exit 1'
82 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c 'false # exit 0'
83
84 atf_check -s exit:0 -o 'inline:foo\n' -e empty ${TEST_SH} -c \
85 'echo foo # bar'
86 atf_check -s exit:0 -o 'inline:foo # bar\n' -e empty ${TEST_SH} -c \
87 'echo foo \# bar'
88 atf_check -s exit:0 -o 'inline:foo\n' -e empty ${TEST_SH} -c \
89 'echo foo; # echo bar'
90 atf_check -s exit:0 -o 'inline:foo#bar\n' -e empty ${TEST_SH} -c \
91 'echo foo#bar'
92 atf_check -s exit:0 -o 'inline:foo# bar\n' -e empty ${TEST_SH} -c \
93 'echo foo# bar'
94 atf_check -s exit:0 -o 'inline:foo\n' -e empty ${TEST_SH} -c \
95 'x=foo; echo ${x#bar}'
96
97 atf_check -s exit:0 -o 'inline:#\n' -e empty ${TEST_SH} -c \
98 'echo "#"'
99 atf_check -s exit:0 -o 'inline:#\n' -e empty ${TEST_SH} -c \
100 "echo '#'"
101 atf_check -s exit:0 -o 'inline:#\n' -e empty ${TEST_SH} -c \
102 'echo \#'
103 atf_check -s exit:0 -o 'inline:##\n' -e empty ${TEST_SH} -c \
104 'echo "#"#'
105 atf_check -s exit:0 -o 'inline:##\n' -e empty ${TEST_SH} -c \
106 "echo '#'#"
107 atf_check -s exit:0 -o 'inline:##\n' -e empty ${TEST_SH} -c \
108 'echo \##'
109 atf_check -s exit:0 -o 'inline:##\n' -e empty ${TEST_SH} -c \
110 'echo "#"# #"#"'
111 atf_check -s exit:0 -o 'inline:##\n' -e empty ${TEST_SH} -c \
112 "echo '#'# #'#'"
113 atf_check -s exit:0 -o 'inline:##\n' -e empty ${TEST_SH} -c \
114 'echo \## #\#'
115
116 cat <<-'DONE'|atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH}
117 # test comments do not provoke synax errors !\
118 echo foo # ( { " hello
119 while : # that's forever
120 do # the following command list
121 # starting with nothing ${unset?error}
122 break # done loop terminate $( echo bar; exit 1 )
123 done #####################################################
124 # "hello
125 exit 0
126 DONE
127 }
128
129 atf_test_case c_line_wrapping
130 c_line_wrapping_head() {
131 atf_set "descr" "check aspects of command line wrapping"
132 }
133 c_line_wrapping_body() {
134 atf_require_prog ls
135 atf_require_prog printf
136
137 cat <<- 'DONE' | atf_check -s exit:0 -o ignore -e empty ${TEST_SH} -e
138 l\
139 s
140 DONE
141
142 cat <<- 'DONE' | atf_check -s exit:7 -o empty -e empty ${TEST_SH}
143 e\
144 x\
145 it \
146 7
147 DONE
148
149 # Have to do this twice as cannot say "any exit code but 0 or 7" ...
150 cat <<- 'DONE' | atf_check -s not-exit:0 -o empty -e not-empty \
151 ${TEST_SH}
152 e\
153 x\
154 it\
155 7
156 DONE
157 cat <<- 'DONE' | atf_check -s not-exit:7 -o empty -e not-empty \
158 ${TEST_SH}
159 e\
160 x\
161 it\
162 7
163 DONE
164
165 cat <<- 'DONE' | atf_check -s exit:0 -o empty -e empty ${TEST_SH}
166 wh\
167 il\
168 e \
169 f\a\
170 \l\s\e
171 do
172 :\
173 ;
174 done
175 DONE
176
177 cat <<- 'DONE' | atf_check -s exit:0 -o inline:'hellohellohellohello' \
178 -e empty ${TEST_SH}
179 V\
180 AR=hel\
181 lo
182 unset U V1
183 pri\
184 ntf '%s' ${\
185 VAR\
186 }
187 p\
188 r\
189 i\
190 n\
191 t\
192 f\
193 \
194 '%s' \
195 $\
196 {\
197 V\
198 A\
199 R}
200 printf '%s' ${U\
201 -\
202 "$\
203 {V\
204 1:\
205 =$\
206 {V\
207 AR+\
208 ${V\
209 AR}\
210 }\
211 }}
212 printf '%s' ${V\
213 1?V1\
214 \
215 FAIL}
216 DONE
217 cat <<- 'DONE' | atf_check -s exit:0 -o inline:'2\n' ${TEST_SH}
218 l\
219 s=7 bi\
220 n\
221 =\
222 3
223 echo $(\
224 ( ls /bin )\
225 )
226 DONE
227 }
228
229 atf_test_case d_redirects
230 d_redirects_head() {
231 atf_set "descr" "Check parsing of redirect operators"
232 }
233 d_redirects_body() {
234
235 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
236 '>/dev/null'
237 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
238 '</dev/null'
239 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
240 '>>/dev/null'
241 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
242 '<>/dev/null'
243 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
244 '</dev/null>/dev/null'
245 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
246 '>|/dev/null'
247 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
248 '>/dev/null>/dev/null>/dev/null'
249
250 atf-check -s exit:0 -o empty -e empty ${TEST_SH} -c \
251 'echo hello >/dev/null'
252 atf-check -s exit:0 -o empty -e empty ${TEST_SH} -c \
253 'echo >/dev/null hello'
254 atf-check -s exit:0 -o empty -e empty ${TEST_SH} -c \
255 '>/dev/null echo hello'
256 atf-check -s exit:0 -o empty -e empty ${TEST_SH} -c \
257 'echo hello >/dev/null world'
258 atf-check -s exit:0 -o 'inline:hello world\n' -e empty ${TEST_SH} -c \
259 'echo hello </dev/null world'
260
261 atf-check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
262 'echo hello </dev/null'
263 atf-check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
264 'echo hello 3</dev/null'
265 atf-check -s exit:0 -o 'inline:hello 3\n' -e empty ${TEST_SH} -c \
266 'echo hello 3 </dev/null'
267 atf-check -s exit:0 -o 'inline:hello 3\n' -e empty ${TEST_SH} -c \
268 'echo hello \3</dev/null'
269 atf-check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
270 'echo hello</dev/null'
271 atf-check -s exit:0 -o 'inline:3\n' -e empty ${TEST_SH} -c \
272 'hello=3; echo ${hello}</dev/null'
273
274 atf-check -s exit:0 -o empty -e empty ${TEST_SH} -c \
275 '2>&1'
276 atf-check -s exit:0 -o empty -e empty ${TEST_SH} -c \
277 '2>& 1'
278 atf-check -s exit:0 -o empty -e empty ${TEST_SH} -c \
279 'FD=1; 2>&"${FD}"'
280 atf-check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
281 'FD=1; echo hello 2>&"${FD}" >&2'
282
283 atf-check -s exit:0 -o empty -e empty ${TEST_SH} -c \
284 '2>&- 3<&- 4>&-'
285
286 return 0
287 }
288
289 atf_test_case f_variable_syntax
290 f_variable_syntax_head() {
291 atf_set "descr" "Check that var names of all legal forms work"
292 }
293 f_variable_syntax_body() {
294 # don't test _ as a variable, it can be "unusual"
295 for vname in a ab _a _9 a123 a_1_2_3 __ ___ ____ __1__ _0 \
296 A AA AAA AaBb _A_a A_a_ a1_ abc_123 ab_12_cd_ef_34_99 \
297 abcdefghijklmnopqrstuvwzyz ABCDEFGHIJKLMNOPQRSTUVWXYZ_ \
298 A_VERY_LONG_VARIABLE_NAME_that_is_probably_longer_than_most_used_in_the_average_shell_script_already_about_100_chars_in_this_one_but_there_is_not_supposed_to_be_any_limit_on_the_length_at_all xyzzy \
299 _____________________________________________________________
300 do
301 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
302 "unset ${vname}"
303 atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -c \
304 "unset ${vname}; printf %s \${${vname}-OK}"
305 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
306 "${vname}=GOOD; printf %s \${${vname}-OK}"
307 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
308 "${vname}=GOOD; printf %s \$${vname}"
309 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
310 "unset ${vname};${vname}=GOOD;printf %s \${${vname}-OK}"
311 atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -c \
312 "${vname}=GOOD;unset ${vname};printf %s \${${vname}-OK}"
313 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
314 "${vname}=GOOD; unset ${vname}x; printf %s \$${vname}"
315 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
316 "unset ${vname}x; ${vname}=GOOD; printf %s \$${vname}x"
317 done
318
319 # don't test '.' in var names, some shells permit that (in ${} anyway)
320 # this test also cannot check for embedded - + ? = : % or #
321 for vname in ,x -p +h :def 0_1 'x*x' '()' '"' "'" 'a b c' '?!' ';'
322 do
323 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
324 "echo \${${vname}}"
325 done
326
327 for vname in ,x -p +h :def 0_1 'x*x' '()' '"' "'" 'a b c' x,y,z '?!' \
328 ';' a-b a+b 'a?b' 'a:b' 'a%b' 'a#b' 0 1 99 @ '*' '!' '?'
329 do
330 # failure modes will differ, but they should all fail somehow
331 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
332 "${vname}="
333 done
334
335 }
336
337 atf_test_case g_var_assign
338 g_var_assign_head() {
339 atf_set "descr" "Check var assignments "
340 }
341 g_var_assign_body() {
342 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
343 'a=b'
344 atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
345 '\a=b'
346 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
347 'a=b c=d'
348 atf_check -s exit:0 -e empty -o 'inline:e=f\n' ${TEST_SH} -c \
349 'a=b c=d echo e=f'
350 atf_check -s exit:0 -e empty -o 'inline:e=f\n' ${TEST_SH} -c \
351 'a=b 2>/dev/null c=d </dev/null echo e=f'
352
353 # We need to make sure that we do not accidentally
354 # find a command called 'a=b' ...
355
356 for d in /foo /foo/bar /not-dir /no/such/directory '/!!!' \
357 '/-/--/#' '/"/""/"""' -
358 do
359 test -d "${d}" || break
360 done
361 test "${#d}" -gt 1 || atf-skip 'Wacky directories seem to exist!'
362
363 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
364 "PATH='${d}';"'a=\b'
365 atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
366 "PATH='${d}';"'a\=b'
367 atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
368 "PATH='${d}';"'\a=b'
369 atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
370 "PATH='${d}';"'X=; c=d ${X} a=b'
371 }
372
373 atf_test_case i_pipelines
374 i_pipelines_head() {
375 atf_set "descr" "Check pipelines"
376 }
377 i_pipelines_body() {
378
379 cmd='printf "%s\n" foo'
380 for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
381 do
382 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
383 "${cmd}"
384 cmd="${cmd} | cat"
385 done
386
387 cmd='printf "%s\n" foo'
388 for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
389 do
390 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
391 "${cmd}"
392 cmd="${cmd} |
393 cat"
394 done
395
396 cmd='printf "%s\n" foo'
397 for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
398 do
399 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
400 "${cmd}"
401 cmd="${cmd} |
402
403
404
405
406 cat"
407 done
408
409 cmd='! printf "%s\n" foo'
410 for n in 1 2 3 4 5 6 7 8 9 10
411 do
412 atf_check -s exit:1 -o inline:'foo\n' -e empty ${TEST_SH} -c \
413 "${cmd}"
414 cmd="${cmd} | cat"
415 done
416
417 cmd='exec 4>&2 3<&0; printf "%s\n" foo'
418 for n in 1 2 3
419 do
420 pfx=
421 for xtra in 'x=y' 'a=b' '6>&1' '5<&3'
422 do
423 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
424 "${cmd} | ${xtra} cat"
425
426 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
427 "${cmd} | ${pfx} cat"
428
429 pfx="${pfx} ${xtra}"
430 done
431 cmd="${cmd} | ${pfx} cat"
432 done
433
434 # pipelines are not required to contain commands ...
435 # they don't do anything useful (at all) but the syntax is legal
436 base='4>&2'; cmd="${base}"
437 for pipe in 'a=b' '3<&0' '>>/dev/null' 'a= b= c=' '${x}' 'cat'
438 do
439 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
440 "${base} | ${pipe}"
441
442 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
443 "${cmd} | ${pipe}"
444
445 cmd="${cmd} | ${pipe}"
446 done
447
448 # but the command cannot be empty, or a reserved word used improperly
449 base='printf "%s\n" foo'; cmd="${base}"
450 for pipe in '' do done then else fi esac
451 do
452 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
453 "${base} | ${pipe}"
454
455 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
456 "${pipe} | ${base}"
457
458 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
459 "${cmd} | ${pipe}"
460
461 cmd="${cmd} | ${pipe}"
462 done
463 }
464
465 atf_test_case j_and_or_lists
466 j_and_or_lists_head() {
467 atf_set "descr" "Check && and || command lists"
468 }
469 j_and_or_lists_body() {
470 and=true
471 or=false
472 and_or=false
473 for i in 1 2 3 4 5 6 7 8 9 10
474 do
475 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
476 "${and}"
477
478 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
479 "${or}"
480
481 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
482 "${and_or}"
483
484 and="${and} && true"
485 or="${or} || false"
486 and_or="${and_or} || true && false"
487 done
488
489 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
490 'true &&'
491 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
492 '&& true'
493 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
494 '|| true'
495 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
496 'true ||'
497 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
498 'true || && false'
499 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
500 'false || && true'
501
502 cmd='printf "%s" foo | cat | cat>/dev/null'
503 line="${cmd}"
504 for i in 1 2 3 4
505 do
506 line="${line} && ! ${cmd} || ${cmd}"
507
508 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
509 "${line}"
510 done
511
512 }
513
514 atf_test_case k_lists
515 k_lists_head() {
516 atf_set "descr" "Check ; command lists"
517 }
518 k_lists_body() {
519 line=
520 for N in 1 2 3 4
521 do
522 for cmd in \
523 true false : 'cat</dev/null>/dev/null' x=3 'exec 4>&-'
524 do
525 line="${line}${line:+;}${cmd}"
526 atf_check -s exit:0 -o 'inline:hello\nworld\n' \
527 -e empty ${TEST_SH} -c \
528 "echo hello; ${line}; echo world"
529 atf_check -s exit:0 -o 'inline:hello\nworld\n' \
530 -e empty ${TEST_SH} -c \
531 "echo hello; ${line}; echo world;"
532 done
533 done
534
535 for cmd in ';' ';;' 'false ;; true' 'false; ;true' '; true'
536 do
537 atf_check -s not-exit:0 -o ignore -e not-empty \
538 ${TEST_SH} -c "${cmd}"
539 done
540 }
541
542 atf_test_case l_async_lists
543 l_async_lists_head() {
544 atf_set "descr" "Check & command lists"
545 }
546 l_async_lists_body() {
547 line=
548 for N in 1 2 3 4
549 do
550 for cmd in \
551 true false : 'cat</dev/null>/dev/null' x=3 'exec 4>&-'
552 do
553 line="${line:+${line}&}${cmd}"
554 atf_check -s exit:0 -o 'inline:hello\nworld\n' \
555 -e empty ${TEST_SH} -c \
556 "echo hello; ${line}& echo world"
557 atf_check -s exit:0 -o 'inline:hello\nworld\n' \
558 -e empty ${TEST_SH} -c \
559 "echo hello; ${line}& echo world"
560 done
561 done
562
563 for cmd in '&' ';&' '&;' '& true' 'false& &true'
564 do
565 atf_check -s not-exit:0 -o ignore -e not-empty \
566 ${TEST_SH} -c "${cmd}"
567 done
568 }
569
570 atf_test_case m_compound_lists
571 m_compound_lists_head() {
572 atf_set "descr" "Check subshells () and { ;} command grouping"
573 }
574 m_compound_lists_body() {
575 # Note: (( is an unspecified (reserved) operator, don't use it...
576 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
577 '( true )'
578 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
579 '( false )'
580 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
581 '( (:) )'
582 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
583 '( ( true ))'
584 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
585 '( ( ( ( ( true )))))'
586 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
587 '( ( ( ( (true);:));true))'
588
589 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
590 '()'
591 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
592 '( )'
593
594 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
595 '{ true; }'
596 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
597 '{ false; }'
598 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
599 '{ { :; };}'
600 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
601 '{ { { { { :;};};};};}'
602
603 atf_check -s exit:0 -o 'inline:}\n' -e empty ${TEST_SH} -c \
604 '{ echo } ; }'
605 atf_check -s exit:0 -o 'inline:{\n' -e empty ${TEST_SH} -c \
606 '{ echo { ; }'
607 }
608
609 atf_test_case q_for_loop
610 q_for_loop_head() {
611 atf_set "descr" "Check for loop parsing"
612 }
613 q_for_loop_body() {
614 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
615 'for x; do : ; done'
616 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
617 'for x in ; do : ; done'
618 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
619 'for x in a b c ; do : ; done'
620
621 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
622 'for x in in;do : ; done'
623 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
624 'for x in for;do : ; done'
625 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
626 'for x in do;do : ; done'
627 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
628 'for for in in;do :;done'
629 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
630 'for for in for;do :; done'
631 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
632 'for for in do;do : ;done'
633 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
634 'for in in in;do : ; done'
635 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
636 'for in in for;do : ; done'
637 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
638 'for in in do;do : ; done'
639 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
640 'for do in in;do : ; done'
641 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
642 'for do in for;do : ; done'
643 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
644 'for do in do;do : ; done'
645 atf_check -s exit:0 -o 'inline:dodo\n' -e empty ${TEST_SH} -c \
646 'for do in do;do echo ${do}do ; done'
647 }
648
649 atf_test_case r_case
650 r_case_head() {
651 atf_set "descr" "Check case statement parsing"
652 }
653 r_case_body() {
654 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
655 'case x in esac'
656 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
657 'case x in x) esac'
658 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
659 'case x in (x) esac'
660 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
661 'case x in x) ;; esac'
662 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
663 'case x in (x) ;; esac'
664 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
665 'case x in x|y) ;; esac'
666 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
667 'case x in (x|y) ;; esac'
668
669 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
670 'case x in x|esac) ;; esac'
671 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
672 'case x in x|esac|y) ;; esac'
673 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
674 'case x in (x|esac) ;; esac'
675 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
676 'case x in (x|esac|y) ;; esac'
677
678 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
679 'case x in in) esac'
680 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
681 'case x in in) ;; esac'
682 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
683 'case x in x|in) ;; esac'
684 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
685 'case x in x|in|y) ;; esac'
686 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
687 'case x in (x|in) ;; esac'
688 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
689 'case x in (in|x) ;; esac'
690 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
691 'case x in (x|in|y) ;; esac'
692
693 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
694 'case case in case) esac'
695 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
696 'case in in in) esac'
697 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
698 'case esac in (in) esac'
699 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
700 'case in in esac|cat'
701 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
702 'case esac in esac|cat'
703 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
704 'case in in esac|case x in u) echo foo;; esac'
705 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
706 'case esac in esac|case x in u) echo foo;; esac'
707 atf_check -s exit:0 -o 'inline:foo\n' -e empty ${TEST_SH} -c \
708 'case in in esac|case x in x) echo foo;; esac'
709
710 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
711 'case in in (esac|cat'
712
713 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
714 'case x in x );;esac'
715 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
716 'case x in ( x );;esac'
717 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
718 'case x in x | y );;esac'
719 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
720 'case x in ( x | y );;esac'
721
722 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
723 'case x
724 in
725 ( x | y )
726
727 ;;
728
729
730 esac
731 '
732 }
733
734 atf_test_case s_if
735 s_if_head() {
736 atf_set "descr" "Check if statement parsing"
737 }
738 s_if_body() {
739 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
740 'if :; then :; fi'
741 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
742 'if :; then :; else :; fi'
743 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
744 'if :; then :; elif :; then :; else :; fi'
745 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
746 'if :; then :; elif :; then :; elif :; then :; else :; fi'
747
748 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
749 'if :; then : else :; fi'
750 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
751 'if : then :; then :; fi'
752
753 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
754 'if if :;then :;fi then :;fi'
755 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
756 'if if :;then if :;then :;fi fi;then :;fi'
757 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
758 'if if :;then :;fi;then :;else if :;then :;fi fi'
759
760 for a in true false; do
761 for b in true false; do
762 for c in true false; do
763
764 $a && out=a || {
765 $b && out=b || {
766 $c && out=c || {
767 out=d; };};}
768
769 atf_check -s exit:0 -e empty \
770 -o "inline:${out}"'\n' \
771 ${TEST_SH} -c \
772 "if $a; then echo a
773 elif $b; then echo b
774 elif $c; then echo c
775 else echo d
776 fi"
777 done
778 done
779 done
780 }
781
782 atf_test_case t_loops
783 t_loops_head() {
784 atf_set "descr" "Check while/until loop parsing"
785 }
786 t_loops_body() {
787 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
788 'while false; do :; done'
789 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
790 'while false; do \done; done'
791 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
792 'until :; do :; done'
793 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
794 'until :; do \done; done'
795
796 atf_check -s exit:0 -o 'inline:x\n1\n' -e empty ${TEST_SH} -c \
797 ':; while (exit) do echo x; false; done; echo $?'
798 atf_check -s exit:0 -o 'inline:x\n0\n' -e empty ${TEST_SH} -c \
799 'false; until (exit) do echo x; done; echo $?'
800 }
801
802 atf_test_case u_case_cont
803 u_case_cont_head() {
804 atf_set "descr" "Check case stmt parsing using ;& [optional]"
805 }
806 u_case_cont_body() {
807
808 ${TEST_SH} -c 'case x in (x) false ;& (y) : ;; esac' 2>/dev/null ||
809 atf_skip ";& case list terminator unsupported in ${TEST_SH}"
810
811 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
812 'case x in x) ;& esac'
813 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
814 'case x in (x) ;& esac'
815 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
816 'case x in x|y) ;& esac'
817 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
818 'case x in (x|y) ;& esac'
819
820 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
821 'case x in x );&esac'
822 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
823 'case x in ( x );&esac'
824 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
825 'case x in x | y );&esac'
826 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
827 'case x in ( x | y );&esac'
828
829 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
830 'case x in x) ;& (y) esac'
831 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
832 'case x in (x) ;& esac'
833 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
834 'case x in x|y) ;& esac'
835 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
836 'case x in (x|y) ;& esac'
837 }
838
839 atf_test_case x_functions
840 x_functions_head() {
841 atf_set "descr" "Check function definition parsing"
842 }
843 x_functions_body() {
844 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
845 'func() { :; }'
846 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
847 'func() { :; }; func'
848 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
849 'func()(:)'
850 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
851 'func()if :; then false; else true; fi'
852 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
853 'func()while false; do :;done'
854 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
855 'func () for a in b c; do :; done'
856 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
857 'func() case x in (y) esac'
858
859 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
860 'f1() { f2() { :; }; }; f1; f2'
861
862 # f2 should be not found, but f1 clears $?
863 atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} -c \
864 'f1() { f2() { :; }; }; f2; f1'
865
866 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
867 'f1() { eval "$1() { :; }"; }; f1 f2; f2'
868 }
869
870 atf_init_test_cases() {
871 atf_add_test_case a_basic_tokenisation
872 atf_add_test_case b_comments
873 atf_add_test_case c_line_wrapping
874 atf_add_test_case d_redirects
875 atf_add_test_case f_variable_syntax
876 atf_add_test_case g_var_assign
877 atf_add_test_case i_pipelines
878 atf_add_test_case j_and_or_lists
879 atf_add_test_case k_lists
880 atf_add_test_case l_async_lists
881 atf_add_test_case m_compound_lists
882 atf_add_test_case q_for_loop
883 atf_add_test_case r_case
884 atf_add_test_case s_if
885 atf_add_test_case t_loops
886 atf_add_test_case u_case_cont
887 atf_add_test_case x_functions
888 }
889