Home | History | Annotate | Line # | Download | only in sh
t_syntax.sh revision 1.5
      1 # $NetBSD: t_syntax.sh,v 1.5 2017/06/24 11:09:42 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 core .. 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_redirects
    299 d_redirects_head() {
    300 	atf_set "descr" "Check parsing of redirect operators"
    301 }
    302 d_redirects_body() {
    303 
    304 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    305 		'>/dev/null'
    306 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    307 		'</dev/null'
    308 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    309 		'>>/dev/null'
    310 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    311 		'<>/dev/null'
    312 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    313 		'</dev/null>/dev/null'
    314 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    315 		'>|/dev/null'
    316 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    317 		'>/dev/null>/dev/null>/dev/null'
    318 
    319 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    320 		'echo hello >/dev/null'
    321 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    322 		'echo >/dev/null hello'
    323 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    324 		'>/dev/null echo hello'
    325 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    326 		'echo hello >/dev/null world'
    327 	atf_check -s exit:0 -o 'inline:hello world\n' -e empty ${TEST_SH} -c \
    328 		'echo hello </dev/null world'
    329 
    330 	atf_check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
    331 		'echo hello </dev/null'
    332 	atf_check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
    333 		'echo hello 3</dev/null'
    334 	atf_check -s exit:0 -o 'inline:hello 3\n' -e empty ${TEST_SH} -c \
    335 		'echo hello 3 </dev/null'
    336 	atf_check -s exit:0 -o 'inline:hello 3\n' -e empty ${TEST_SH} -c \
    337 		'echo hello \3</dev/null'
    338 	atf_check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
    339 		'echo hello</dev/null'
    340 	atf_check -s exit:0 -o 'inline:3\n' -e empty ${TEST_SH} -c \
    341 		'hello=3; echo ${hello}</dev/null'
    342 
    343 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    344 		'2>&1'
    345 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    346 		'2>& 1'
    347 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    348 		'FD=1; 2>&"${FD}"'
    349 	atf_check -s exit:0 -o 'inline:hello\n' -e empty ${TEST_SH} -c \
    350 		'FD=1; echo hello 2>&"${FD}" >&2'
    351 
    352 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    353 		'2>&- 3<&- 4>&-'
    354 
    355 	return 0
    356 }
    357 
    358 atf_test_case f_variable_syntax
    359 f_variable_syntax_head() {
    360 	atf_set "descr" "Check that var names of all legal forms work"
    361 }
    362 f_variable_syntax_body() {
    363 	# don't test _ as a variable, it can be "unusual"
    364 	for vname in a ab _a _9 a123 a_1_2_3 __ ___ ____ __1__ _0 \
    365 	    A AA AAA AaBb _A_a A_a_ a1_ abc_123 ab_12_cd_ef_34_99 \
    366 	    abcdefghijklmnopqrstuvwzyz ABCDEFGHIJKLMNOPQRSTUVWXYZ_ \
    367 	    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 \
    368 	    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 \
    369 	    xyzzy __0123454321__ _0_1_2_3_4_5_6_7_8_9_ ABBA X_ Y__ Z___ \
    370 	    _____________________________________________________________
    371 	do
    372 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    373 			"unset ${vname}"
    374 		atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -c \
    375 			"unset ${vname}; printf %s \${${vname}-OK}"
    376 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    377 			"${vname}=GOOD; printf %s \${${vname}-OK}"
    378 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    379 			"${vname}=GOOD; printf %s \$${vname}"
    380 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    381 			"unset ${vname};${vname}=GOOD;printf %s \${${vname}-OK}"
    382 		atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -c \
    383 			"${vname}=GOOD;unset ${vname};printf %s \${${vname}-OK}"
    384 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    385 			"${vname}=GOOD; unset ${vname}x; printf %s \$${vname}"
    386 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    387 			"unset ${vname}x; ${vname}=GOOD; printf %s \$${vname}x"
    388 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    389 			"${vname}=GOOD; ${vname}_=BAD; printf %s \$${vname}"
    390 
    391 		case "${vname}" in
    392 		?)	continue;;
    393 		esac
    394 
    395 		# The following tests do not work for 1 char var names.
    396 		# hence the check and "continue" above to skip the remaining
    397 		# tests for that case
    398 
    399 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    400 			"${vname}=GOOD; unset ${vname%?}; printf %s \$${vname}"
    401 
    402 		# (this next would work, but becomes just a duplicate of
    403 		# an earlier test, so is pointless for 1 ch names)
    404 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    405 	"${vname}=GOOD; unset ${vname}x ${vname%?}; printf %s \$${vname}"
    406 
    407 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    408 			"unset ${vname%?};${vname}=GOOD; printf %s \$${vname%?}"
    409 
    410 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    411 			"${vname}=GOOD; ${vname%?}=BAD; printf %s \$${vname}"
    412 
    413 		# all the remaining tests require the 2nd char of the
    414 		# variable name to be a legal first character.  That
    415 		# is, not a digit, so skip the rest if we have a digit
    416 		# second...
    417 		case "${vname}" in
    418 		?[0-9]*)	continue;;
    419 		esac
    420 
    421 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    422 			"${vname}=GOOD; unset ${vname#?}; printf %s \$${vname}"
    423 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    424 			"unset ${vname#?};${vname}=GOOD; printf %s \$${vname#?}"
    425 
    426 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    427 			"${vname}=GOOD; ${vname#?}=BAD; printf %s \$${vname}"
    428 
    429 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    430 			"unset ${vname%?} ${vname#?} ${vname}x; ${vname}=GOOD;
    431 			printf %s \$${vname%?}\$${vname#?}\$${vname}x"
    432 
    433 		atf_check -s exit:0 -o match:GOOD -e empty ${TEST_SH} -c \
    434 			"${vname}=GOOD; ${vname%?}=BAD; ${vname}_=BAD;
    435 			${vname#?}=BAD; printf %s \$${vname}"
    436 	done
    437 
    438 	# don't test '.' in var names, some shells permit that (in ${} anyway)
    439 	# this test also cannot check for embedded - + ? = : % or #
    440 	for vname in ,x -p +h :def 0_1 'x*x' '()' '"' "'" 'a b c' '?!' ';'
    441 	do
    442 		atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
    443 			"echo \${${vname}}"
    444 	done
    445 
    446 	for vname in ,x -p +h :def 0_1 'x*x' '()' '"' "'" 'a b c' x,y,z '?!' \
    447 	    ';' a-b a+b 'a?b' 'a:b' 'a%b' 'a#b' 0 1 99 @ '*' '!' '?'
    448 	do
    449 		# failure modes will differ, but they should all fail somehow
    450 		atf_check -s not-exit:0 -o ignore -e not-empty ${TEST_SH} -c \
    451 			"${vname}="
    452 	done
    453 
    454 }
    455 
    456 atf_test_case g_var_assign
    457 g_var_assign_head() {
    458 	atf_set "descr" "Check var assignments "
    459 }
    460 g_var_assign_body() {
    461 	atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
    462 		'a=b'
    463 	atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
    464 		'\a=b'
    465 	atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
    466 		'a=b c=d'
    467 	atf_check -s exit:0 -e empty -o 'inline:e=f\n' ${TEST_SH} -c \
    468 		'a=b c=d echo e=f'
    469 	atf_check -s exit:0 -e empty -o 'inline:e=f\n' ${TEST_SH} -c \
    470 		'a=b 2>/dev/null c=d </dev/null echo e=f'
    471 
    472 	# We need to make sure that we do not accidentally
    473 	# find a command called 'a=b' ...
    474 
    475 	for d in /foo /foo/bar /not-dir /no/such/directory '/!!!' \
    476 		'/-/--/#' '/"/""/"""' - 
    477 	do
    478 		test -d "${d}" || break
    479 	done
    480 	test "${#d}" -gt 1 || atf-skip 'Wacky directories seem to exist!'
    481 
    482 	atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \
    483 		"PATH='${d}';"'a=\b'
    484 	atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
    485 		"PATH='${d}';"'a\=b'
    486 	atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
    487 		"PATH='${d}';"'\a=b'
    488 	atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \
    489 		"PATH='${d}';"'X=; c=d ${X} a=b'
    490 }
    491 
    492 atf_test_case i_pipelines
    493 i_pipelines_head() {
    494 	atf_set "descr" "Check pipelines"
    495 }
    496 i_pipelines_body() {
    497 
    498 	cmd='printf "%s\n" foo'
    499 	for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    500 	do
    501 		atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
    502 			"${cmd}"
    503 		cmd="${cmd} | cat"
    504 	done
    505 
    506 	cmd='printf "%s\n" foo'
    507 	for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    508 	do
    509 		atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
    510 			"${cmd}"
    511 		cmd="${cmd} |
    512 		cat"
    513 	done
    514 
    515 	cmd='printf "%s\n" foo'
    516 	for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    517 	do
    518 		atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
    519 			"${cmd}"
    520 		cmd="${cmd} |
    521 
    522 
    523 
    524 
    525 		cat"
    526 	done
    527 
    528 	cmd='! printf "%s\n" foo'
    529 	for n in 1 2 3 4 5 6 7 8 9 10
    530 	do
    531 		atf_check -s exit:1 -o inline:'foo\n' -e empty ${TEST_SH} -c \
    532 			"${cmd}"
    533 		cmd="${cmd} | cat"
    534 	done
    535 
    536 	cmd='exec 4>&2 3<&0; printf "%s\n" foo'
    537 	for n in 1 2 3
    538 	do
    539 	    pfx=
    540 	    for xtra in 'x=y' 'a=b' '6>&1' '5<&3'
    541 	    do
    542 		atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
    543 			"${cmd} | ${xtra} cat"
    544 
    545 		atf_check -s exit:0 -o inline:'foo\n' -e empty ${TEST_SH} -c \
    546 			"${cmd} | ${pfx} cat"
    547 
    548 		pfx="${pfx} ${xtra}"
    549 	    done
    550 	    cmd="${cmd} | ${pfx} cat"
    551 	done
    552 
    553 	# pipelines are not required to contain commands ...
    554 	# they don't do anything useful (at all) but the syntax is legal
    555 	base='4>&2'; cmd="${base}"
    556 	for pipe in 'a=b' '3<&0' '>>/dev/null' 'a= b= c=' '${x}' 'cat'
    557 	do
    558 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    559 			"${base} | ${pipe}"
    560 
    561 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    562 			"${cmd} | ${pipe}"
    563 
    564 		cmd="${cmd} | ${pipe}"
    565 	done
    566 
    567 	# but the command cannot be empty, or a reserved word used improperly
    568 	base='printf "%s\n" foo'; cmd="${base}"
    569 	for pipe in '' do done then else fi esac
    570 	do
    571 		atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    572 			"${base} | ${pipe}"
    573 
    574 		atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    575 			"${pipe} | ${base}"
    576 
    577 		atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    578 			"${cmd} | ${pipe}"
    579 
    580 		cmd="${cmd} | ${pipe}"
    581 	done
    582 }
    583 
    584 atf_test_case j_and_or_lists
    585 j_and_or_lists_head() {
    586 	atf_set "descr" "Check && and || command lists"
    587 }
    588 j_and_or_lists_body() {
    589 	and=true
    590 	or=false
    591 	and_or=false
    592 	for i in 1 2 3 4 5 6 7 8 9 10
    593 	do
    594 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    595 			"${and}"
    596 
    597 		atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
    598 			"${or}"
    599 
    600 		atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
    601 			"${and_or}"
    602 
    603 		and="${and} && true"
    604 		or="${or} || false"
    605 		and_or="${and_or} || true && false"
    606 	done
    607 
    608 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    609 		'true &&'
    610 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    611 		'&& true'
    612 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    613 		'|| true'
    614 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    615 		'true ||'
    616 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    617 		'true || && false'
    618 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    619 		'false || && true'
    620 
    621 	cmd='printf "%s" foo | cat | cat>/dev/null'
    622 	line="${cmd}"
    623 	for i in 1 2 3 4
    624 	do
    625 		line="${line} && ! ${cmd} || ${cmd}"
    626 
    627 		atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    628 			"${line}"
    629 	done
    630 
    631 }
    632 
    633 atf_test_case k_lists
    634 k_lists_head() {
    635 	atf_set "descr" "Check ; command lists"
    636 }
    637 k_lists_body() {
    638 	line=
    639 	for N in 1 2 3 4
    640 	do
    641 		for cmd in \
    642 			true false : 'cat</dev/null>/dev/null' x=3 'exec 4>&-'
    643 		do
    644 			line="${line}${line:+;}${cmd}"
    645 			atf_check -s exit:0 -o 'inline:hello\nworld\n' \
    646 				-e empty ${TEST_SH} -c \
    647 					"echo hello; ${line}; echo world"
    648 			atf_check -s exit:0 -o 'inline:hello\nworld\n' \
    649 				-e empty ${TEST_SH} -c \
    650 					"echo hello; ${line}; echo world;"
    651 		done
    652 	done
    653 
    654 	for cmd in ';' ';;' 'false ;; true' 'false; ;true' '; true'
    655 	do
    656 		atf_check -s not-exit:0 -o ignore -e not-empty \
    657 			${TEST_SH} -c "${cmd}"
    658 	done
    659 }
    660 
    661 atf_test_case l_async_lists
    662 l_async_lists_head() {
    663 	atf_set "descr" "Check & command lists"
    664 }
    665 l_async_lists_body() {
    666 	line=
    667 	for N in 1 2 3 4
    668 	do
    669 		for cmd in \
    670 			true false : 'cat</dev/null>/dev/null' x=3 'exec 4>&-'
    671 		do
    672 			line="${line:+${line}&}${cmd}"
    673 			atf_check -s exit:0 -o 'inline:hello\nworld\n' \
    674 				-e empty ${TEST_SH} -c \
    675 					"echo hello; ${line}& echo world"
    676 			atf_check -s exit:0 -o 'inline:hello\nworld\n' \
    677 				-e empty ${TEST_SH} -c \
    678 					"echo hello; ${line}& echo world"
    679 		done
    680 	done
    681 
    682 	for cmd in '&' ';&' '&;'  '& true' 'false& &true'
    683 	do
    684 		atf_check -s not-exit:0 -o ignore -e not-empty \
    685 			${TEST_SH} -c "${cmd}"
    686 	done
    687 }
    688 
    689 atf_test_case m_compound_lists
    690 m_compound_lists_head() {
    691 	atf_set "descr" "Check subshells () and { ;} command grouping"
    692 }
    693 m_compound_lists_body() {
    694 	# Note: (( is an unspecified (reserved) operator, don't use it...
    695 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    696 		'( true )'
    697 	atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
    698 		'( false )'
    699 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    700 		'( (:) )'
    701 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    702 		'( ( true ))'
    703 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    704 		'( ( ( ( (  true )))))'
    705 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    706 		'( ( ( ( (true);:));true))'
    707 
    708 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    709 		'()'
    710 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    711 		'(   )'
    712 
    713 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    714 		'{ true; }'
    715 	atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
    716 		'{ false; }'
    717 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    718 		'{ { :; };}'
    719 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    720 		'{ { { { {  :;};};};};}'
    721 
    722 	atf_check -s exit:0 -o 'inline:}\n' -e empty ${TEST_SH} -c \
    723 		'{ echo } ; }'
    724 	atf_check -s exit:0 -o 'inline:{\n' -e empty ${TEST_SH} -c \
    725 		'{ echo { ; }'
    726 }
    727 
    728 atf_test_case q_for_loop
    729 q_for_loop_head() {
    730 	atf_set "descr" "Check for loop parsing"
    731 }
    732 q_for_loop_body() {
    733 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    734 		'for x; do : ; done'
    735 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    736 		'for x in ; do : ; done'
    737 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    738 		'for x in a b c ; do : ; done'
    739 
    740 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    741 		'for x in in;do : ; done'
    742 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    743 		'for x in for;do : ; done'
    744 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    745 		'for x in do;do : ; done'
    746 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    747 		'for for in in;do :;done'
    748 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    749 		'for for in for;do :; done'
    750 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    751 		'for for in do;do : ;done'
    752 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    753 		'for in in in;do : ; done'
    754 	atf_check -s exit:0 -o 'inline:do\nin\ndo\n' -e empty ${TEST_SH} -c \
    755    'for in in in do in;do case $in in in)echo do;;do)echo in;;esac; done'
    756 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    757 		'for in in for;do : ; done'
    758 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    759 		'for in in do;do : ; done'
    760 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    761 		'for do in in;do : ; done'
    762 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    763 		'for do in for;do : ; done'
    764 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    765 		'for do in do;do : ; done'
    766 	atf_check -s exit:0 -o 'inline:dodo\n' -e empty ${TEST_SH} -c \
    767 		'for do in do;do echo ${do}do ; done'
    768 }
    769 
    770 atf_test_case r_case
    771 r_case_head() {
    772 	atf_set "descr" "Check case statement parsing"
    773 }
    774 r_case_body() {
    775 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    776 		'case x in  esac'
    777 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    778 		'case x in x) esac'
    779 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    780 		'case x in (x) esac'
    781 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    782 		'case x in x) ;; esac'
    783 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    784 		'case x in (x) ;; esac'
    785 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    786 		'case x in x|y) ;; esac'
    787 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    788 		'case x in (x|y) ;; esac'
    789 
    790 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    791 		'case x in x|esac) ;; esac'
    792 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    793 		'case x in x|esac|y) ;; esac'
    794 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    795 		'case x in (x|esac) ;; esac'
    796 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    797 		'case x in (x|esac|y) ;; esac'
    798 
    799 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    800 		'case x in in) esac'
    801 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    802 		'case x in in) ;; esac'
    803 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    804 		'case x in x|in) ;; esac'
    805 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    806 		'case x in x|in|y) ;; esac'
    807 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    808 		'case x in (x|in) ;; esac'
    809 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    810 		'case x in (in|x) ;; esac'
    811 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    812 		'case x in (x|in|y) ;; esac'
    813 
    814 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    815 		'case case in case) esac'
    816 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    817 		'case in in in) esac'
    818 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    819 		'case esac in (in) esac'
    820 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    821 		'case in in esac|cat'
    822 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    823 		'case esac in esac|cat'
    824 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    825 		'case in in esac|case x in u) echo foo;; esac'
    826 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    827 		'case esac in esac|case x in u) echo foo;; esac'
    828 	atf_check -s exit:0 -o 'inline:foo\n' -e empty ${TEST_SH} -c \
    829 		'case in in esac|case x in x) echo foo;; esac'
    830 
    831 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    832 		'case in in (esac|cat'
    833 
    834 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    835 		'case x in x );;esac'
    836 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    837 		'case x in ( x );;esac'
    838 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    839 		'case x in x | y );;esac'
    840 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    841 		'case x in ( x | y );;esac'
    842 
    843 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    844 		'case x
    845 		 in
    846 		 (    x    |    y    )
    847 
    848 			;;
    849 
    850 
    851 		esac
    852 		'
    853 }
    854 
    855 atf_test_case s_if
    856 s_if_head() {
    857 	atf_set "descr" "Check if statement parsing"
    858 }
    859 s_if_body() {
    860 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    861 		'if :; then :; fi'
    862 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    863 		'if :; then :; else :; fi'
    864 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    865 		'if :; then :; elif :; then :; else :; fi'
    866 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    867 		'if :; then :; elif :; then :; elif :; then :; else :; fi'
    868 
    869 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    870 		'if :; then : else :; fi'
    871 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    872 		'if : then :; then :; fi'
    873 
    874 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    875 		'if if :;then :;fi then :;fi'
    876 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    877 		'if if :;then if :;then :;fi fi;then :;fi'
    878 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    879 		'if if :;then :;fi;then :;else if :;then :;fi fi'
    880 
    881 	for a in true false; do
    882 		for b in true false; do
    883 			for c in true false; do
    884 
    885 				$a && out=a || {
    886 				$b && out=b || {
    887 				$c && out=c || {
    888 				out=d; };};}
    889 
    890 				atf_check -s exit:0 -e empty \
    891 					-o "inline:${out}"'\n' \
    892 					${TEST_SH} -c \
    893 						"if $a; then echo a
    894 						elif $b; then echo b
    895 						elif $c; then echo c
    896 						else echo d
    897 						fi"
    898 			done
    899 		done
    900 	done
    901 }
    902 
    903 atf_test_case t_loops
    904 t_loops_head() {
    905 	atf_set "descr" "Check while/until loop parsing"
    906 }
    907 t_loops_body() {
    908 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    909 		'while false; do :; done'
    910 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    911 		'while false; do \done; done'
    912 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    913 		'until :; do :; done'
    914 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    915 		'until :; do \done; done'
    916 
    917 	atf_check -s exit:0 -o 'inline:x\n1\n' -e empty ${TEST_SH} -c \
    918 		':; while (exit) do echo x; false; done; echo $?'
    919 	atf_check -s exit:0 -o 'inline:x\n0\n' -e empty ${TEST_SH} -c \
    920 		'false; until (exit) do echo x; done; echo $?'
    921 }
    922 
    923 atf_test_case u_case_cont
    924 u_case_cont_head() {
    925 	atf_set "descr" "Check case stmt parsing using ;& [optional]"
    926 }
    927 u_case_cont_body() {
    928 
    929 	${TEST_SH} -c 'case x in (x) false ;& (y) : ;; esac' 2>/dev/null ||
    930 		atf_skip ";& case list terminator unsupported in ${TEST_SH}"
    931 
    932 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    933 		'case x in x) ;& esac'
    934 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    935 		'case x in (x) ;& esac'
    936 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    937 		'case x in x|y) ;& esac'
    938 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    939 		'case x in (x|y) ;& esac'
    940 
    941 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    942 		'case x in x );&esac'
    943 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    944 		'case x in ( x );&esac'
    945 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    946 		'case x in x | y );&esac'
    947 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    948 		'case x in ( x | y );&esac'
    949 
    950 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    951 		'case x in x) ;& (y) esac'
    952 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    953 		'case x in (x) ;& esac'
    954 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    955 		'case x in x|y) ;& esac'
    956 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    957 		'case x in (x|y) ;& esac'
    958 }
    959 
    960 atf_test_case x_functions
    961 x_functions_head() {
    962 	atf_set "descr" "Check function definition parsing"
    963 }
    964 x_functions_body() {
    965 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    966 		'func() { :; }'
    967 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    968 		'func() { :; }; func'
    969 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    970 		'func()(:)'
    971 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    972 		'func()if :; then false; else true; fi'
    973 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    974 		'func()while false; do :;done'
    975 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    976 		'func () for a in b c; do :; done'
    977 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    978 		'func() case x in (y) esac'
    979 
    980 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    981 		'f1() { f2() { :; }; }; f1; f2'
    982 
    983 	# f2 should be not found, but f1 clears $?
    984 	atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} -c \
    985 		'f1() { f2() { :; }; }; f2; f1'
    986 
    987 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    988 		'f1() { eval "$1() { :; }"; }; f1 f2; f2'
    989 }
    990 
    991 atf_init_test_cases() {
    992 	atf_add_test_case a_basic_tokenisation
    993 	atf_add_test_case b_comments
    994 	atf_add_test_case c_line_wrapping
    995 	atf_add_test_case d_redirects
    996 	atf_add_test_case f_variable_syntax
    997 	atf_add_test_case g_var_assign
    998 	atf_add_test_case i_pipelines
    999 	atf_add_test_case j_and_or_lists
   1000 	atf_add_test_case k_lists
   1001 	atf_add_test_case l_async_lists
   1002 	atf_add_test_case m_compound_lists
   1003 	atf_add_test_case q_for_loop
   1004 	atf_add_test_case r_case
   1005 	atf_add_test_case s_if
   1006 	atf_add_test_case t_loops
   1007 	atf_add_test_case u_case_cont
   1008 	atf_add_test_case x_functions
   1009 }
   1010