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