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