t_syntax.sh revision 1.10 1 # $NetBSD: t_syntax.sh,v 1.10 2018/11/14 02:37:51 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
218 cat <<- 'DONE' | atf_check -s exit:0 -o inline:'2\n' ${TEST_SH}
219 l\
220 s=7 bi\
221 n\
222 =\
223 3
224 echo $(\
225 ( ls /bin )\
226 )
227 DONE
228
229 # Inspired by src/etc/MAKEDEV.tmpl failure with (broken)
230 # sh LINENO code... avoid it happening again...
231 for VARS in 1:0:0:0 0:1:0:0 0:0:1:0 0:0:0:1 \
232 1:0:0:1 1:0:1:0 1:1:0:0 0:1:1:0 \
233 0:0:0:0 1:1:0:1 0:1:1:1 1:1:1:1
234 do
235 eval $(
236 IFS=:
237 set -- $VARS
238 test $(( $1 + $2 + $3 + $4 )) -eq 1 &&
239 R=OK || R=BAD
240 printf "R=%s;" $R
241 for v in a b c d
242 do
243 case $1 in
244 (0) printf "export %s=false;" $v;;
245 (1) printf "export %s=true;" $v;;
246 esac
247 shift
248 done
249 )
250
251 cat <<- 'DONE' | atf_check -s exit:0 -o inline:"${R}" ${TEST_SH}
252 case $(( $($a && echo 1 || echo 0) + \
253 $($b && echo 1 || echo 0) + \
254 $($c && echo 1 || echo 0) + \
255 $($d && echo 1 || echo 0) ))
256 in
257 (1) printf OK ;;
258 (*) printf BAD ;;
259 esac
260 DONE
261 done
262
263 # inspired by pkgsrc/pkgtools/cwrappers :: libnbcompat/configure
264 # failure with (broken) sh LINENO code .. avoid recurrence
265 # This test would have failed.
266 cat <<- 'DONE' | atf_check -s exit:0 -o inline:'/tmp\n' ${TEST_SH}
267 dn=/tmp/foo
268
269 D=`dirname -- "${dn}" ||
270 expr X"${dn}" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
271 X"${dn}" : 'X\(//\)[^/]' \| \
272 X"${dn}" : 'X\(//\)$' \| \
273 X"${dn}" : 'X\(/\)' \| . 2>/dev/null ||
274 echo X"${dn}" |
275 sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
276 s//\1/
277 q
278 }
279 /^X\(\/\/\)[^/].*/{
280 s//\1/
281 q
282 }
283 /^X\(\/\/\)$/{
284 s//\1/
285 q
286 }
287 /^X\(\/\).*/{
288 s//\1/
289 q
290 }
291 s/.*/./; q'`
292
293 echo "${D}"
294 DONE
295 return 0
296 }
297
298 atf_test_case d_cstrings
299 d_cstrings_head() {
300 atf_set "descr" "Check processing of $' ' quoting (C style strings)"
301 }
302 d_cstrings_body() {
303 unset ENV
304
305 if ! ${TEST_SH} -c ": \$'abc'" ||
306 test $( ${TEST_SH} -c "printf %s \$'abc'" ) != abc
307 then
308 atf_skip "\$'...' (C style quoted strings) not supported"
309 fi
310
311 # simple stuff
312 atf_check -s exit:0 -e empty -o inline:'abc\tdef\n' ${TEST_SH} -c \
313 "printf '%s\\n' \$'abc\tdef'"
314 atf_check -s exit:0 -e empty -o inline:'abc\tdef\n' ${TEST_SH} -c \
315 "printf '%s\\n' \$'abc\011def'"
316 atf_check -s exit:0 -e empty -o inline:'abc\tdef\n' ${TEST_SH} -c \
317 "printf '%s\\n' \$'abc\x09'def"
318 atf_check -s exit:0 -e empty -o inline:'abc$def\n' ${TEST_SH} -c \
319 "def=xyz; printf '%s\\n' \$'abc\$def'"
320
321 # control chars (\c) and unicode \u
322 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
323 "test \$'\\1-\\2-\\3' = \$'\\ca-\\cb-\\cc'"
324 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
325 "test \$'\\r-\\n-\\f' = \$'\\cm-\\cj-\\cl'"
326 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
327 "unset LC_ALL; export LC_CTYPE=en_AU.UTF-8;
328 test \$'\\u0123' = \$'\\304\\243'"
329 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
330 "test \$'\\u0123' = \$'\\xC4\\xA3'"
331 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
332 "test \$'\\c\\\\' = \$'\\x1C'"
333 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
334 "test \$'\\c[\\c]\\c^\\c_\\c?' = \$'\\x1B\\x1D\\x1E\\x1F\\x7F'"
335
336 # all the \X sequences for a single char X (ie: not hex/octal/unicode)
337 atf_check -s exit:0 -e empty -o inline:'\n\r\t\n' \
340 ${TEST_SH} -c "printf '%s\\n' \$'\\a\\b\\e\\f\\n\\r\\t\\v'"
341 atf_check -s exit:0 -e empty -o inline:'\n\r\t\n' \
344 ${TEST_SH} -c "printf '%s\\n' \$'\\cG\\cH\\x1b\\cl\\cJ\\cm\\cI\\ck'"
345 atf_check -s exit:0 -e empty -o inline:"'"'"\\\n' \
346 ${TEST_SH} -c "printf '%s\\n' \$'\\'\\\"\\\\'"
347
348 # various invalid $'...' sequences
349 atf_check -s not-exit:0 -e not-empty -o ignore ${TEST_SH} -c \
350 ": \$'\\q'"
351 atf_check -s not-exit:0 -e not-empty -o ignore ${TEST_SH} -c \
352 ": \$'\\c\\q'"
353 atf_check -s not-exit:0 -e not-empty -o ignore ${TEST_SH} -c \
354 ": \$'\\uDEFF'"
355 atf_check -s not-exit:0 -e not-empty -o ignore ${TEST_SH} -c \
356 ": \$'abcd"
357 atf_check -s not-exit:0 -e not-empty -o ignore ${TEST_SH} -c \
358 ": \$'abcd\\"
359
360 # anything that generates \0 ends the $'...' immediately
361 atf_check -s exit:0 -e empty -o inline:'aAaA' ${TEST_SH} -c \
362 "printf '%s' \$'a\\0x'\$'A\\x00X'\$'a\\c@x'\$'A\\u0000X'"
363
364 # \newline in a $'...' is dropped (just like in "" strings)
365 atf_check -s exit:0 -e empty -o inline:'abcdef' ${TEST_SH} -c \
366 "printf '%s' \$'abc\\
367 def'"
368 # but a normal newline in a $'...' is just a newline
369 atf_check -s exit:0 -e empty -o inline:'abc\ndef' ${TEST_SH} -c \
370 "printf '%s' \$'abc
371 def'"
372 # and should work when elided line wrap occurs between $ and '
373 atf_check -s exit:0 -e empty -o inline:'abc\ndef' ${TEST_SH} -c \
374 "printf '%s' \$\\
375 'abc\\ndef'"
376
377 # $'...' only works when the $ is unquoted.
378 atf_check -s exit:0 -e empty -o inline:"abc\$'def'g" ${TEST_SH} -c \
379 "printf '%s' \"abc\$'def'g\""
380 atf_check -s exit:0 -e empty -o inline:'abc$defg' ${TEST_SH} -c \
381 "printf '%s' abc\\\$'def'g"
382 atf_check -s exit:0 -e empty -o inline:'abc$def' ${TEST_SH} -c \
383 "printf '%s' abc'\$'def"
384 }
385
386 atf_test_case f_redirects
387 f_redirects_head() {
388 atf_set "descr" "Check parsing of redirect operators"
389 }
390 f_redirects_body() {
391
392 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
393 '>/dev/null'
394 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
395 '</dev/null'
396 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
397 '>>/dev/null'
398 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
399 '<>/dev/null'
400 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
401 '</dev/null>/dev/null'
402 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
403 '>|/dev/null'
404 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
405 '>/dev/null>/dev/null>/dev/null'
406
407 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
408 'echo hello >/dev/null'
409 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
410 'echo >/dev/null hello'
411 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
412 '>/dev/null echo hello'
413 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
414 'echo hello >/dev/null world'
415 atf_check -s exit:0 -o 'inline:hello world\n' -e empty ${TEST_SH} -c \
416 'echo hello </dev/null world'
417
418 atf_check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
419 'echo hello </dev/null'
420 atf_check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
421 'echo hello 3</dev/null'
422 atf_check -s exit:0 -o 'inline:hello 3\n' -e empty ${TEST_SH} -c \
423 'echo hello 3 </dev/null'
424 atf_check -s exit:0 -o 'inline:hello 3\n' -e empty ${TEST_SH} -c \
425 'echo hello \3</dev/null'
426 atf_check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
427 'echo hello</dev/null'
428 atf_check -s exit:0 -o 'inline:3\n' -e empty ${TEST_SH} -c \
429 'hello=3; echo ${hello}</dev/null'
430
431 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
432 '2>&1'
433 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
434 '2>& 1'
435 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
436 'FD=1; 2>&"${FD}"'
437 atf_check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
438 'FD=1; echo hello 2>&"${FD}" >&2'
439
440 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
441 '2>&- 3<&- 4>&-'
442
443 return 0
444 }
445
446 atf_test_case g_variable_syntax
447 g_variable_syntax_head() {
448 atf_set "descr" "Check that var names of all legal forms work"
449 }
450 g_variable_syntax_body() {
451 # don't test _ as a variable, it can be "unusual"
452 for vname in a ab _a _9 a123 a_1_2_3 __ ___ ____ __1__ _0 \
453 A AA AAA AaBb _A_a A_a_ a1_ abc_123 ab_12_cd_ef_34_99 \
454 abcdefghijklmnopqrstuvwzyz ABCDEFGHIJKLMNOPQRSTUVWXYZ_ \
455 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 \
456 Then_Make_it_Even_Longer_by_Multiplying_it___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__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__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__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 \
457 xyzzy __0123454321__ _0_1_2_3_4_5_6_7_8_9_ ABBA X_ Y__ Z___ \
458 _____________________________________________________________
459 do
460 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
461 "unset ${vname}"
462 atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -c \
463 "unset ${vname}; printf %s \${${vname}-OK}"
464 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
465 "${vname}=GOOD; printf %s \${${vname}-OK}"
466 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
467 "${vname}=GOOD; printf %s \$${vname}"
468 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
469 "unset ${vname};${vname}=GOOD;printf %s \${${vname}-OK}"
470 atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -c \
471 "${vname}=GOOD;unset ${vname};printf %s \${${vname}-OK}"
472 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
473 "${vname}=GOOD; unset ${vname}x; printf %s \$${vname}"
474 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
475 "unset ${vname}x; ${vname}=GOOD; printf %s \$${vname}x"
476 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
477 "${vname}=GOOD; ${vname}_=BAD; printf %s \$${vname}"
478
479 case "${vname}" in
480 ?) continue;;
481 esac
482
483 # The following tests do not work for 1 char var names.
484 # hence the check and "continue" above to skip the remaining
485 # tests for that case
486
487 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
488 "${vname}=GOOD; unset ${vname%?}; printf %s \$${vname}"
489
490 # (this next would work, but becomes just a duplicate of
491 # an earlier test, so is pointless for 1 ch names)
492 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
493 "${vname}=GOOD; unset ${vname}x ${vname%?}; printf %s \$${vname}"
494
495 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
496 "unset ${vname%?};${vname}=GOOD; printf %s \$${vname%?}"
497
498 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
499 "${vname}=GOOD; ${vname%?}=BAD; printf %s \$${vname}"
500
501 # all the remaining tests require the 2nd char of the
502 # variable name to be a legal first character. That
503 # is, not a digit, so skip the rest if we have a digit
504 # second...
505 case "${vname}" in
506 ?[0-9]*) continue;;
507 esac
508
509 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
510 "${vname}=GOOD; unset ${vname#?}; printf %s \$${vname}"
511 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
512 "unset ${vname#?};${vname}=GOOD; printf %s \$${vname#?}"
513
514 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
515 "${vname}=GOOD; ${vname#?}=BAD; printf %s \$${vname}"
516
517 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
518 "unset ${vname%?} ${vname#?} ${vname}x; ${vname}=GOOD;
519 printf %s \$${vname%?}\$${vname#?}\$${vname}x"
520
521 atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
522 "${vname}=GOOD; ${vname%?}=BAD; ${vname}_=BAD;
523 ${vname#?}=BAD; printf %s \$${vname}"
524 done
525
526 # don't test '.' in var names, some shells permit that (in ${} anyway)
527 # this test also cannot check for embedded - + ? = : % or #
528 for vname in ,x -p +h :def 0_1 'x*x' '()' '"' "'" 'a b c' '?!' ';'
529 do
530 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
531 "echo \${${vname}}"
532 done
533
534 for vname in ,x -p +h :def 0_1 'x*x' '()' '"' "'" 'a b c' x,y,z '?!' \
535 ';' a-b a+b 'a?b' 'a:b' 'a%b' 'a#b' 0 1 99 @ '*' '!' '?'
536 do
537 # failure modes will differ, but they should all fail somehow
538 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
539 "${vname}="
540 done
541
542 }
543
544 atf_test_case h_var_assign
545 h_var_assign_head() {
546 atf_set "descr" "Check var assignments "
547 }
548 h_var_assign_body() {
549 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
550 'a=b'
551 atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
552 '\a=b'
553 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
554 'a=b c=d'
555 atf_check -s exit:0 -e empty -o 'inline:e=f\n' ${TEST_SH} -c \
556 'a=b c=d echo e=f'
557 atf_check -s exit:0 -e empty -o 'inline:e=f\n' ${TEST_SH} -c \
558 'a=b 2>/dev/null c=d </dev/null echo e=f'
559
560 # We need to make sure that we do not accidentally
561 # find a command called 'a=b' ...
562
563 for d in /foo /foo/bar /not-dir /no/such/directory '/!!!' \
564 '/-/--/#' '/"/""/"""' -
565 do
566 test -d "${d}" || break
567 done
568 test "${#d}" -gt 1 || atf-skip 'Wacky directories seem to exist!'
569
570 atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
571 "PATH='${d}';"'a=\b'
572 atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
573 "PATH='${d}';"'a\=b'
574 atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
575 "PATH='${d}';"'\a=b'
576 atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
577 "PATH='${d}';"'X=; c=d ${X} a=b'
578 }
579
580 atf_test_case i_pipelines
581 i_pipelines_head() {
582 atf_set "descr" "Check pipelines"
583 }
584 i_pipelines_body() {
585
586 cmd='printf "%s\n" foo'
587 for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
588 do
589 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
590 "${cmd}"
591 cmd="${cmd} | cat"
592 done
593
594 cmd='printf "%s\n" foo'
595 for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
596 do
597 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
598 "${cmd}"
599 cmd="${cmd} |
600 cat"
601 done
602
603 cmd='printf "%s\n" foo'
604 for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
605 do
606 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
607 "${cmd}"
608 cmd="${cmd} |
609
610
611
612
613 cat"
614 done
615
616 cmd='! printf "%s\n" foo'
617 for n in 1 2 3 4 5 6 7 8 9 10
618 do
619 atf_check -s exit:1 -o inline:'foo\n' -e empty ${TEST_SH} -c \
620 "${cmd}"
621 cmd="${cmd} | cat"
622 done
623
624 cmd='exec 4>&2 3<&0; printf "%s\n" foo'
625 for n in 1 2 3
626 do
627 pfx=
628 for xtra in 'x=y' 'a=b' '6>&1' '5<&3'
629 do
630 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
631 "${cmd} | ${xtra} cat"
632
633 atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
634 "${cmd} | ${pfx} cat"
635
636 pfx="${pfx} ${xtra}"
637 done
638 cmd="${cmd} | ${pfx} cat"
639 done
640
641 # pipelines are not required to contain commands ...
642 # they don't do anything useful (at all) but the syntax is legal
643 base='4>&2'; cmd="${base}"
644 for pipe in 'a=b' '3<&0' '>>/dev/null' 'a= b= c=' '${x}' 'cat'
645 do
646 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
647 "${base} | ${pipe}"
648
649 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
650 "${cmd} | ${pipe}"
651
652 cmd="${cmd} | ${pipe}"
653 done
654
655 # but the command cannot be empty, or a reserved word used improperly
656 base='printf "%s\n" foo'; cmd="${base}"
657 for pipe in '' do done then else fi esac
658 do
659 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
660 "${base} | ${pipe}"
661
662 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
663 "${pipe} | ${base}"
664
665 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
666 "${cmd} | ${pipe}"
667
668 cmd="${cmd} | ${pipe}"
669 done
670 }
671
672 atf_test_case j_and_or_lists
673 j_and_or_lists_head() {
674 atf_set "descr" "Check && and || command lists"
675 }
676 j_and_or_lists_body() {
677 and=true
678 or=false
679 and_or=false
680 for i in 1 2 3 4 5 6 7 8 9 10
681 do
682 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
683 "${and}"
684
685 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
686 "${or}"
687
688 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
689 "${and_or}"
690
691 and="${and} && true"
692 or="${or} || false"
693 and_or="${and_or} || true && false"
694 done
695
696 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
697 'true &&'
698 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
699 '&& true'
700 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
701 '|| true'
702 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
703 'true ||'
704 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
705 'true || && false'
706 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
707 'false || && true'
708
709 cmd='printf "%s" foo | cat | cat>/dev/null'
710 line="${cmd}"
711 for i in 1 2 3 4
712 do
713 line="${line} && ! ${cmd} || ${cmd}"
714
715 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
716 "${line}"
717 done
718
719 }
720
721 atf_test_case k_lists
722 k_lists_head() {
723 atf_set "descr" "Check ; command lists"
724 }
725 k_lists_body() {
726 line=
727 for N in 1 2 3 4
728 do
729 for cmd in \
730 true false : 'cat</dev/null>/dev/null' x=3 'exec 4>&-'
731 do
732 line="${line}${line:+;}${cmd}"
733 atf_check -s exit:0 -o 'inline:hello\nworld\n' \
734 -e empty ${TEST_SH} -c \
735 "echo hello; ${line}; echo world"
736 atf_check -s exit:0 -o 'inline:hello\nworld\n' \
737 -e empty ${TEST_SH} -c \
738 "echo hello; ${line}; echo world;"
739 done
740 done
741
742 for cmd in ';' ';;' 'false ;; true' 'false; ;true' '; true'
743 do
744 atf_check -s not-exit:0 -o ignore -e not-empty \
745 ${TEST_SH} -c "${cmd}"
746 done
747 }
748
749 atf_test_case l_async_lists
750 l_async_lists_head() {
751 atf_set "descr" "Check & command lists"
752 }
753 l_async_lists_body() {
754 line=
755 for N in 1 2 3 4
756 do
757 for cmd in \
758 true false : 'cat</dev/null>/dev/null' x=3 'exec 4>&-'
759 do
760 line="${line:+${line}&}${cmd}"
761 atf_check -s exit:0 -o 'inline:hello\nworld\n' \
762 -e empty ${TEST_SH} -c \
763 "echo hello; ${line}& echo world"
764 atf_check -s exit:0 -o 'inline:hello\nworld\n' \
765 -e empty ${TEST_SH} -c \
766 "echo hello; ${line}& echo world"
767 done
768 done
769
770 for cmd in '&' ';&' '&;' '& true' 'false& &true'
771 do
772 atf_check -s not-exit:0 -o ignore -e not-empty \
773 ${TEST_SH} -c "${cmd}"
774 done
775 }
776
777 atf_test_case m_compound_lists
778 m_compound_lists_head() {
779 atf_set "descr" "Check subshells () and { ;} command grouping"
780 }
781 m_compound_lists_body() {
782 # Note: (( is an unspecified (reserved) operator, don't use it...
783 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
784 '( true )'
785 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
786 '( false )'
787 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
788 '( (:) )'
789 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
790 '( ( true ))'
791 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
792 '( ( ( ( ( true )))))'
793 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
794 '( ( ( ( (true);:));true))'
795
796 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
797 '()'
798 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
799 '( )'
800
801 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
802 '{ true; }'
803 atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
804 '{ false; }'
805 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
806 '{ { :; };}'
807 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
808 '{ { { { { :;};};};};}'
809
810 atf_check -s exit:0 -o 'inline:}\n' -e empty ${TEST_SH} -c \
811 '{ echo } ; }'
812 atf_check -s exit:0 -o 'inline:{\n' -e empty ${TEST_SH} -c \
813 '{ echo { ; }'
814 }
815
816 atf_test_case q_for_loop
817 q_for_loop_head() {
818 atf_set "descr" "Check for loop parsing"
819 }
820 q_for_loop_body() {
821 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
822 'for x; do : ; done'
823 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
824 'for x in ; do : ; done'
825 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
826 'for x in a b c ; do : ; done'
827
828 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
829 'for x in in;do : ; done'
830 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
831 'for x in for;do : ; done'
832 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
833 'for x in do;do : ; done'
834 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
835 'for for in in;do :;done'
836 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
837 'for for in for;do :; done'
838 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
839 'for for in do;do : ;done'
840 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
841 'for in in in;do : ; done'
842 atf_check -s exit:0 -o 'inline:do\nin\ndo\n' -e empty ${TEST_SH} -c \
843 'for in in in do in;do case $in in in)echo do;;do)echo in;;esac; done'
844 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
845 'for in in for;do : ; done'
846 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
847 'for in in do;do : ; done'
848 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
849 'for do in in;do : ; done'
850 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
851 'for do in for;do : ; done'
852 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
853 'for do in do;do : ; done'
854 atf_check -s exit:0 -o 'inline:dodo\n' -e empty ${TEST_SH} -c \
855 'for do in do;do echo ${do}do ; done'
856 }
857
858 atf_test_case r_case
859 r_case_head() {
860 atf_set "descr" "Check case statement parsing"
861 }
862 r_case_body() {
863 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
864 'case x in esac'
865 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
866 'case x in x) esac'
867 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
868 'case x in (x) esac'
869 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
870 'case x in x) ;; esac'
871 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
872 'case x in (x) ;; esac'
873 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
874 'case x in x|y) ;; esac'
875 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
876 'case x in (x|y) ;; esac'
877
878 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
879 'case x in x|esac) ;; esac'
880 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
881 'case x in x|esac|y) ;; esac'
882 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
883 'case x in (x|esac) ;; esac'
884 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
885 'case x in (x|esac|y) ;; esac'
886
887 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
888 'case x in in) esac'
889 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
890 'case x in in) ;; esac'
891 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
892 'case x in x|in) ;; esac'
893 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
894 'case x in x|in|y) ;; esac'
895 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
896 'case x in (x|in) ;; esac'
897 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
898 'case x in (in|x) ;; esac'
899 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
900 'case x in (x|in|y) ;; esac'
901
902 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
903 'case case in case) esac'
904 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
905 'case in in in) esac'
906 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
907 'case esac in (in) esac'
908 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
909 'case in in esac|cat'
910 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
911 'case esac in esac|cat'
912 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
913 'case in in esac|case x in u) echo foo;; esac'
914 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
915 'case esac in esac|case x in u) echo foo;; esac'
916 atf_check -s exit:0 -o 'inline:foo\n' -e empty ${TEST_SH} -c \
917 'case in in esac|case x in x) echo foo;; esac'
918
919 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
920 'case in in (esac|cat'
921
922 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
923 'case x in x );;esac'
924 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
925 'case x in ( x );;esac'
926 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
927 'case x in x | y );;esac'
928 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
929 'case x in ( x | y );;esac'
930
931 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
932 'case x
933 in
934 ( x | y )
935
936 ;;
937
938
939 esac
940 '
941 }
942
943 atf_test_case s_if
944 s_if_head() {
945 atf_set "descr" "Check if statement parsing"
946 }
947 s_if_body() {
948 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
949 'if :; then :; fi'
950 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
951 'if :; then :; else :; fi'
952 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
953 'if :; then :; elif :; then :; else :; fi'
954 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
955 'if :; then :; elif :; then :; elif :; then :; else :; fi'
956
957 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
958 'if :; then : else :; fi'
959 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
960 'if : then :; then :; fi'
961
962 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
963 'if if :;then :;fi then :;fi'
964 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
965 'if if :;then if :;then :;fi fi;then :;fi'
966 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
967 'if if :;then :;fi;then :;else if :;then :;fi fi'
968
969 for a in true false; do
970 for b in true false; do
971 for c in true false; do
972
973 $a && out=a || {
974 $b && out=b || {
975 $c && out=c || {
976 out=d; };};}
977
978 atf_check -s exit:0 -e empty \
979 -o "inline:${out}"'\n' \
980 ${TEST_SH} -c \
981 "if $a; then echo a
982 elif $b; then echo b
983 elif $c; then echo c
984 else echo d
985 fi"
986 done
987 done
988 done
989 }
990
991 atf_test_case t_loops
992 t_loops_head() {
993 atf_set "descr" "Check while/until loop parsing"
994 }
995 t_loops_body() {
996 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
997 'while false; do :; done'
998 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
999 'while false; do \done; done'
1000 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1001 'until :; do :; done'
1002 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1003 'until :; do \done; done'
1004
1005 atf_check -s exit:0 -o 'inline:x\n1\n' -e empty ${TEST_SH} -c \
1006 ':; while (exit) do echo x; false; done; echo $?'
1007 atf_check -s exit:0 -o 'inline:x\n0\n' -e empty ${TEST_SH} -c \
1008 'false; until (exit) do echo x; done; echo $?'
1009 }
1010
1011 atf_test_case u_case_cont
1012 u_case_cont_head() {
1013 atf_set "descr" "Check case stmt parsing using ;& [optional]"
1014 }
1015 u_case_cont_body() {
1016
1017 ${TEST_SH} -c 'case x in (x) false ;& (y) : ;; esac' 2>/dev/null ||
1018 atf_skip ";& case list terminator unsupported in ${TEST_SH}"
1019
1020 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1021 'case x in x) ;& esac'
1022 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1023 'case x in (x) ;& esac'
1024 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1025 'case x in x|y) ;& esac'
1026 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1027 'case x in (x|y) ;& esac'
1028
1029 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1030 'case x in x );&esac'
1031 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1032 'case x in ( x );&esac'
1033 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1034 'case x in x | y );&esac'
1035 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1036 'case x in ( x | y );&esac'
1037
1038 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1039 'case x in x) ;& (y) esac'
1040 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1041 'case x in (x) ;& esac'
1042 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1043 'case x in x|y) ;& esac'
1044 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1045 'case x in (x|y) ;& esac'
1046 }
1047
1048 atf_test_case x_functions
1049 x_functions_head() {
1050 atf_set "descr" "Check function definition parsing"
1051 }
1052 x_functions_body() {
1053 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1054 'func() { :; }'
1055 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1056 'func() { :; }; func'
1057 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1058 'func()(:)'
1059 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1060 'func()if :; then false; else true; fi'
1061 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1062 'func()while false; do :;done'
1063 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1064 'func () for a in b c; do :; done'
1065 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1066 'func() case x in (y) esac'
1067
1068 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1069 'f1() { f2() { :; }; }; f1; f2'
1070
1071 # f2 should be not found, but f1 clears $?
1072 atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} -c \
1073 'f1() { f2() { :; }; }; f2; f1'
1074
1075 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1076 'f1() { eval "$1() { :; }"; }; f1 f2; f2'
1077 }
1078
1079 atf_test_case z_PR_48498
1080 z_PR_48498_head() {
1081 atf_set "descr" "Check for detecting the syntax error from PR bin/48498"
1082 }
1083 z_PR_48498_body() {
1084
1085 # reserved words/operators that end things,
1086 # were completely ignored after a ';' or '&'
1087 # many of these tests lifted directly from the PR
1088
1089 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1090 'true; fi'
1091 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1092 'false; fi'
1093 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1094 'false; then echo wut'
1095 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1096 'true; then echo wut'
1097 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1098 'true; do echo wut'
1099 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1100 'true; then'
1101 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1102 'true; else'
1103 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1104 'true; do'
1105 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1106 'true; done'
1107 # {
1108 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1109 ': ; }'
1110 # (
1111 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1112 ':;)'
1113
1114 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1115 'true& fi'
1116 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1117 'false& fi'
1118 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1119 'false& then echo wut'
1120 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1121 'true& then echo wut'
1122 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1123 'true& do echo wut'
1124 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1125 'true& then'
1126 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1127 'true& else'
1128 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1129 'true& do'
1130 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1131 'true&done'
1132 # {
1133 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1134 ':&}'
1135 # (
1136 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1137 ':&)'
1138 }
1139
1140 atf_test_case z_PR_52426
1141 z_PR_52426_head() {
1142 atf_set "descr" "Check for detecting the syntax error from PR bin/52426"
1143 }
1144 z_PR_52426_body() {
1145 # Absoluely anything was permitted as a pattern of a case
1146 # statement, any token (except 'esac') would serve
1147 # What follows are a few "pretty" examples that were accepted.
1148 # The first is the example from the PR
1149
1150 # Note we use only ;; type case lists, ;& should do the same, but
1151 # only for shells that support it, we do not want the shell to
1152 # object to any of these just because it does not support ;&
1153
1154 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1155 'case x in <|() ;; esac'
1156
1157 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1158 'case x in ((|)) ;; esac'
1159 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1160 'case x in _|() ;; esac'
1161 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1162 'case x in ()|() ;; esac'
1163 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1164 'case x in -|;) ;; esac'
1165 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1166 'case x in (;|-) ;; esac'
1167 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1168 'case x in ;;|;) ;; esac'
1169 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1170 'case x in (|| | ||) ;; esac'
1171 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1172 'case x in (<<|>>) ;; esac'
1173 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1174 'case x in (&&|&) ;; (|||>&) ;; &) esac'
1175 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1176 'case x in (>||<) ;; esac'
1177 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1178 'case x in( || | || | || | || | || );; esac'
1179 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1180 'case x in (||| ||| ||| ||| ||) ;; esac'
1181 atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
1182 'case x in <> |
1183 ) ;; esac'
1184
1185 # now check some similar looking cases that are supposed to work
1186 # That is, make sure the fix for the PR does not break valid cases.
1187
1188 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1189 'case fi in ({|}) ;; (!) ;; esac'
1190 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1191 'case esac in ([|]);; (][);; !!!|!!!|!!!|!!!);; esac'
1192 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1193 'case then in ({[]]}) ;; (^^);; (^|^);; ([!]);; (-);; esac'
1194 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1195 'case while in while );;(if|then|elif|fi);;(do|done);; esac'
1196 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1197 'case until in($);;($$);;($4.50);;(1/2);;0.3333);;esac'
1198 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1199 'case return in !);; !$);; $!);; !#);; (@);; esac'
1200 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
1201 'case break in (/);; (\/);; (/\|/\));; (\\//);; esac'
1202 }
1203
1204 atf_test_case z_PR_53712
1205 z_PR_53712_head() {
1206 atf_set "descr" "Check for avoiding the core dump from PR bin/53712"
1207 }
1208 z_PR_53712_body() {
1209 atf_require_prog sysctl
1210 atf_require_prog rm
1211
1212 # Don't want to have to deal with all the possible ways
1213 # that the systcm might be configured to drop core files...
1214 sysctl -w proc.$$.corename=core ||
1215 atf_skip "Unable to set file name for core dump file"
1216 rm -f core
1217
1218 ${TEST_SH} -c '{ } > out'; S=$?
1219 test -f core &&
1220 atf_fail "PR bin/53712: ${TEST_SH} dumps core: status=$S"
1221 test "$S" -lt 128 ||
1222 atf_fail "PR bin/53712: ${TEST_SH} reported status $S (core?)"
1223
1224 # It doesn't matter here whether or not there was an error
1225 # from the empty compound, or whether "out" was created
1226 # just that no core dump appeared, and the shell did not
1227 # exit because of a signal.
1228
1229 return 0
1230 }
1231
1232 atf_init_test_cases() {
1233 atf_add_test_case a_basic_tokenisation
1234 atf_add_test_case b_comments
1235 atf_add_test_case c_line_wrapping
1236 atf_add_test_case d_cstrings
1237 atf_add_test_case f_redirects
1238 atf_add_test_case g_variable_syntax
1239 atf_add_test_case h_var_assign
1240 atf_add_test_case i_pipelines
1241 atf_add_test_case j_and_or_lists
1242 atf_add_test_case k_lists
1243 atf_add_test_case l_async_lists
1244 atf_add_test_case m_compound_lists
1245 atf_add_test_case q_for_loop
1246 atf_add_test_case r_case
1247 atf_add_test_case s_if
1248 atf_add_test_case t_loops
1249 atf_add_test_case u_case_cont
1250 atf_add_test_case x_functions
1251
1252 atf_add_test_case z_PR_48498
1253 atf_add_test_case z_PR_52426
1254 atf_add_test_case z_PR_53712
1255 }
1256