Home | History | Annotate | Line # | Download | only in sh
      1 # $NetBSD: t_cmdsub.sh,v 1.6 2023/05/11 00:32:48 gutteridge Exp $
      2 #
      3 # Copyright (c) 2016 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 # the implementation of "sh" to test
     28 : ${TEST_SH:="/bin/sh"}
     29 
     30 #
     31 # This file tests command substitutions ( `...` and $( ... ) )
     32 #
     33 # CAUTION:
     34 #	Be careful attempting running these tests outside the ATF environment
     35 #	Some of the tests run "rm *" in the current directory to clean up
     36 #	An ATF test directory should be empty already, outside ATF, anything
     37 
     38 atf_test_case a_basic_cmdsub
     39 a_basic_cmdsub_head() {
     40 	atf_set "descr" 'Test operation of simple $( ) substitutions'
     41 }
     42 a_basic_cmdsub_body() {
     43 	atf_check -s exit:0 -o match:'Result is true today' -e empty \
     44 	    ${TEST_SH} -c \
     45 		'echo Result is $( true && echo true || echo false ) today'
     46 
     47 	atf_check -s exit:0 -o match:'Result is false today' -e empty \
     48 	    ${TEST_SH} -c \
     49 		'echo Result is $( false && echo true || echo false ) today'
     50 
     51 	atf_check -s exit:0 -o match:'aaabbbccc' -e empty \
     52 	    ${TEST_SH} -c 'echo aaa$( echo bbb )ccc'
     53 	atf_check -s exit:0 -o match:'aaabbb cccddd' -e empty \
     54 	    ${TEST_SH} -c 'echo aaa$( echo bbb ccc )ddd'
     55 	atf_check -s exit:0 -o inline:'aaabbb cccddd\n' -e empty \
     56 	    ${TEST_SH} -c 'echo aaa$( echo bbb; echo ccc )ddd'
     57 	atf_check -s exit:0 -o inline:'aaabbb\ncccddd\n' -e empty \
     58 	    ${TEST_SH} -c 'echo "aaa$( echo bbb; echo ccc )ddd"'
     59 
     60 	atf_check -s exit:0 -o inline:'some string\n' -e empty \
     61 	    ${TEST_SH} -c 'X=$( echo some string ); echo "$X"'
     62 	atf_check -s exit:0 -o inline:'weird; string *\n' -e empty \
     63 	    ${TEST_SH} -c 'X=$( echo "weird; string *" ); echo "$X"'
     64 
     65 	rm -f * 2>/dev/null || :
     66 	for f in file-1 file-2
     67 	do
     68 		cp /dev/null "$f"
     69 	done
     70 
     71 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
     72 	    ${TEST_SH} -c 'echo Found $( echo * )'
     73 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
     74 	    ${TEST_SH} -c 'echo Found "$( echo * )"'
     75 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
     76 	    ${TEST_SH} -c 'echo Found $('" echo '*' )"
     77 	atf_check -s exit:0 -o match:'Found \*' -e empty \
     78 	    ${TEST_SH} -c 'echo Found "$('" echo '*' "')"'
     79 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
     80 	    ${TEST_SH} -c 'echo Found $('" echo \\* )"
     81 	atf_check -s exit:0 -o match:'Found \*' -e empty \
     82 	    ${TEST_SH} -c 'echo Found "$('" echo \\* )"\"
     83 }
     84 
     85 atf_test_case b_basic_backticks
     86 b_basic_backticks_head() {
     87 	atf_set "descr" 'Test operation of old style ` ` substitutions'
     88 }
     89 b_basic_backticks_body() {
     90 	atf_check -s exit:0 -o match:'Result is true today' -e empty \
     91 	    ${TEST_SH} -c \
     92 		'echo Result is `true && echo true || echo false` today'
     93 
     94 	atf_check -s exit:0 -o match:'Result is false today' -e empty \
     95 	    ${TEST_SH} -c \
     96 		'echo Result is `false && echo true || echo false` today'
     97 
     98 	atf_check -s exit:0 -o match:'aaabbbccc' -e empty \
     99 	    ${TEST_SH} -c 'echo aaa` echo bbb `ccc'
    100 	atf_check -s exit:0 -o match:'aaabbb cccddd' -e empty \
    101 	    ${TEST_SH} -c 'echo aaa` echo bbb ccc `ddd'
    102 	atf_check -s exit:0 -o inline:'aaabbb cccddd\n' -e empty \
    103 	    ${TEST_SH} -c 'echo aaa` echo bbb; echo ccc `ddd'
    104 	atf_check -s exit:0 -o inline:'aaabbb\ncccddd\n' -e empty \
    105 	    ${TEST_SH} -c 'echo "aaa` echo bbb; echo ccc `ddd"'
    106 
    107 	atf_check -s exit:0 -o inline:'some string\n' -e empty \
    108 	    ${TEST_SH} -c 'X=` echo some string `; echo "$X"'
    109 	atf_check -s exit:0 -o inline:'weird; string *\n' -e empty \
    110 	    ${TEST_SH} -c 'X=` echo "weird; string *" `; echo "$X"'
    111 
    112 	rm -f * 2>/dev/null || :
    113 	for f in file-1 file-2
    114 	do
    115 		cp /dev/null "$f"
    116 	done
    117 
    118 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
    119 	    ${TEST_SH} -c 'echo Found ` echo * `'
    120 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
    121 	    ${TEST_SH} -c 'echo Found "` echo * `"'
    122 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
    123 	    ${TEST_SH} -c 'echo Found `'" echo '*' "'`'
    124 	atf_check -s exit:0 -o match:'Found \*' -e empty \
    125 	    ${TEST_SH} -c 'echo Found "`'" echo '*' "'`"'
    126 	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
    127 	    ${TEST_SH} -c 'echo Found `'" echo \\* "'`'
    128 	atf_check -s exit:0 -o match:'Found \*' -e empty \
    129 	    ${TEST_SH} -c 'echo Found "`'" echo \\* "'`"'
    130 }
    131 
    132 atf_test_case c_nested_cmdsub
    133 c_nested_cmdsub_head() {
    134 	atf_set "descr" "Test that cmd substitutions can be nested"
    135 }
    136 c_nested_cmdsub_body() {
    137 	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
    138 	    ${TEST_SH} -c 'echo __$( echo foo$(echo bar)bletch )__'
    139 	atf_check -s exit:0 -o match:'_abcde_' -e empty \
    140 	    ${TEST_SH} -c 'echo _$(echo a$(echo $(echo b)c$(echo d))e )_'
    141 	atf_check -s exit:0 -o match:'123454321' -e empty \
    142 	    ${TEST_SH} -c 'echo 1$(echo 2$(echo 3$(echo 4$(echo 5)4)3)2)1'
    143 }
    144 
    145 atf_test_case d_nested_backticks
    146 d_nested_backticks_head() {
    147 	atf_set "descr" "Tests that old style backtick cmd subs can be nested"
    148 }
    149 d_nested_backticks_body() {
    150 	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
    151 	    ${TEST_SH} -c 'echo __` echo foo\`echo bar\`bletch `__'
    152 	atf_check -s exit:0 -o match:'_abcde_' -e empty \
    153 	    ${TEST_SH} -c \
    154 		'echo _`echo a\`echo \\\`echo b\\\`c\\\`echo d\\\`\`e `_'
    155 	atf_check -s exit:0 -o match:'123454321' -e empty \
    156 	    ${TEST_SH} -c \
    157 	    'echo 1`echo 2\`echo 3\\\`echo 4\\\\\\\`echo 5\\\\\\\`4\\\`3\`2`1'
    158 }
    159 
    160 atf_test_case e_perverse_mixing
    161 e_perverse_mixing_head() {
    162 	atf_set "descr" \
    163 		"Checks various mixed new and old style cmd substitutions"
    164 }
    165 e_perverse_mixing_body() {
    166 	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
    167 	    ${TEST_SH} -c 'echo __$( echo foo`echo bar`bletch )__'
    168 	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
    169 	    ${TEST_SH} -c 'echo __` echo foo$(echo bar)bletch `__'
    170 	atf_check -s exit:0 -o match:'_abcde_' -e empty \
    171 	    ${TEST_SH} -c 'echo _$(echo a`echo $(echo b)c$(echo d)`e )_'
    172 	atf_check -s exit:0 -o match:'_abcde_' -e empty \
    173 	    ${TEST_SH} -c 'echo _`echo a$(echo \`echo b\`c\`echo d\`)e `_'
    174 	atf_check -s exit:0 -o match:'12345654321' -e empty \
    175 	    ${TEST_SH} -c \
    176 		'echo 1`echo 2$(echo 3\`echo 4\\\`echo 5$(echo 6)5\\\`4\`3)2`1'
    177 }
    178 
    179 atf_test_case f_redirect_in_cmdsub
    180 f_redirect_in_cmdsub_head() {
    181 	atf_set "descr" "Checks that redirects work in command substitutions"
    182 }
    183 f_redirect_in_cmdsub_body() {
    184 	atf_require_prog cat
    185 	atf_require_prog rm
    186 
    187 	rm -f file 2>/dev/null || :
    188 	atf_check -s exit:0 -o match:'_aa_' -e empty \
    189 	    ${TEST_SH} -c 'echo _$( echo a$( echo b > file )a)_'
    190 	atf_check -s exit:0 -o match:b -e empty ${TEST_SH} -c 'cat file'
    191 	atf_check -s exit:0 -o match:'_aba_' -e empty \
    192 	    ${TEST_SH} -c 'echo _$( echo a$( cat < file )a)_'
    193 	atf_check -s exit:0 -o match:'_aa_' -e empty \
    194 	    ${TEST_SH} -c 'echo _$( echo a$( echo d >> file )a)_'
    195 	atf_check -s exit:0 -o inline:'b\nd\n' -e empty ${TEST_SH} -c 'cat file'
    196 	atf_check -s exit:0 -o match:'_aa_' -e match:'not error' \
    197 	    ${TEST_SH} -c 'echo _$( echo a$( echo not error >&2 )a)_'
    198 }
    199 
    200 atf_test_case g_redirect_in_backticks
    201 g_redirect_in_backticks_head() {
    202 	atf_set "descr" "Checks that redirects work in old style cmd sub"
    203 }
    204 g_redirect_in_backticks_body() {
    205 	atf_require_prog cat
    206 	atf_require_prog rm
    207 
    208 	rm -f file 2>/dev/null || :
    209 	atf_check -s exit:0 -o match:'_aa_' -e empty \
    210 	    ${TEST_SH} -c 'echo _` echo a\` echo b > file \`a`_'
    211 	atf_check -s exit:0 -o match:b -e empty ${TEST_SH} -c 'cat file'
    212 	atf_check -s exit:0 -o match:'_aba_' -e empty \
    213 	    ${TEST_SH} -c 'echo _` echo a\` cat < file \`a`_'
    214 	atf_check -s exit:0 -o match:'_aa_' -e empty \
    215 	    ${TEST_SH} -c 'echo _` echo a\` echo d >> file \`a`_'
    216 	atf_check -s exit:0 -o inline:'b\nd\n' -e empty ${TEST_SH} -c 'cat file'
    217 	atf_check -s exit:0 -o match:'_aa_' -e match:'not error' \
    218 	    ${TEST_SH} -c 'echo _` echo a\` echo not error >&2 \`a`_'
    219 }
    220 
    221 atf_test_case h_vars_in_cmdsub
    222 h_vars_in_cmdsub_head() {
    223 	atf_set "descr" "Check that variables work in command substitutions"
    224 }
    225 h_vars_in_cmdsub_body() {
    226 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    227 	    ${TEST_SH} -c 'X=abc; echo __$( echo ${X} )__'
    228 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    229 	    ${TEST_SH} -c 'X=abc; echo __$( echo "${X}" )__'
    230 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    231 	    ${TEST_SH} -c 'X=abc; echo "__$( echo ${X} )__"'
    232 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    233 	    ${TEST_SH} -c 'X=abc; echo "__$( echo "${X}" )__"'
    234 
    235 	atf_check -s exit:0 -o inline:'a\n\nb\n\nc\n' -e empty \
    236 	    ${TEST_SH} -c "for X in a '' b '' c"'; do echo $( echo "$X" ); done'
    237 
    238 	atf_check -s exit:0 -o match:'__acd__' -e empty \
    239 	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X-b}${Y-c}d)__"'
    240 	atf_check -s exit:0 -o match:'__abcd__' -e empty \
    241 	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X:-b}${Y:-c}d)__"'
    242 	atf_check -s exit:0 -o match:'__XYX__' -e empty \
    243 	    ${TEST_SH} -c 'X=X; echo "__${X}$( X=Y; echo ${X} )${X}__"'
    244 	atf_check -s exit:0 -o match:'__def__' -e empty \
    245 	    ${TEST_SH} -c 'X=abc; echo "__$(X=def; echo "${X}" )__"'
    246 	atf_check -s exit:0 -o inline:'abcdef\nabc\n' -e empty \
    247 	    ${TEST_SH} -c 'X=abc; echo "$X$(X=def; echo ${X} )"; echo $X'
    248 }
    249 
    250 atf_test_case i_vars_in_backticks
    251 i_vars_in_backticks_head() {
    252 	atf_set "descr" "Checks that variables work in old style cmd sub"
    253 }
    254 i_vars_in_backticks_body() {
    255 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    256 	    ${TEST_SH} -c 'X=abc; echo __` echo ${X} `__'
    257 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    258 	    ${TEST_SH} -c 'X=abc; echo __` echo "${X}" `__'
    259 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    260 	    ${TEST_SH} -c 'X=abc; echo "__` echo ${X} `__"'
    261 	atf_check -s exit:0 -o match:'__abc__' -e empty \
    262 	    ${TEST_SH} -c 'X=abc; echo "__` echo \"${X}\" `__"'
    263 
    264 	atf_check -s exit:0 -o inline:'a\n\nb\n\nc\n' -e empty \
    265 	    ${TEST_SH} -c "for X in a '' b '' c"'; do echo $( echo "$X" ); done'
    266 
    267 	atf_check -s exit:0 -o match:'__acd__' -e empty \
    268 	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X-b}${Y-c}d)__"'
    269 	atf_check -s exit:0 -o match:'__abcd__' -e empty \
    270 	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X:-b}${Y:-c}d)__"'
    271 	atf_check -s exit:0 -o match:'__XYX__' -e empty \
    272 	    ${TEST_SH} -c 'X=X; echo "__${X}$( X=Y; echo ${X} )${X}__"'
    273 	atf_check -s exit:0 -o inline:'abcdef\nabc\n' -e empty \
    274 	    ${TEST_SH} -c 'X=abc; echo "$X`X=def; echo \"${X}\" `";echo $X'
    275 
    276 	# The following is nonsense, so is not included ...
    277 	# atf_check -s exit:0 -o match:'__abc__' -e empty \
    278 	#                              oV             cV   oV   cV
    279 	#    ${TEST_SH} -c 'X=abc; echo "__`X=def echo "${X}" `__"'
    280 	#				   `start in " ^ " ends, ` not yet
    281 }
    282 
    283 atf_test_case j_cmdsub_in_varexpand
    284 j_cmdsub_in_varexpand_head() {
    285 	atf_set "descr" "Checks that command sub can be used in var expansion"
    286 }
    287 j_cmdsub_in_varexpand_body() {
    288 	atf_check -s exit:0 -o match:'foo' -e empty \
    289 	    ${TEST_SH} -c 'X=set; echo ${X+$(echo foo)}'
    290 	atf_check -s exit:0 -o match:'set' -e empty \
    291 	    ${TEST_SH} -c 'X=set; echo ${X-$(echo foo)}'
    292 	rm -f bar 2>/dev/null || :
    293 	atf_check -s exit:0 -o match:'set' -e empty \
    294 	    ${TEST_SH} -c 'X=set; echo ${X-$(echo foo > bar)}'
    295 	test -f bar && atf_fail "bar should not exist, but does"
    296 	atf_check -s exit:0 -o inline:'\n' -e empty \
    297 	    ${TEST_SH} -c 'X=set; echo ${X+$(echo foo > bar)}'
    298 	test -f bar || atf_fail "bar should exist, but does not"
    299 }
    300 
    301 atf_test_case k_backticks_in_varexpand
    302 k_backticks_in_varexpand_head() {
    303 	atf_set "descr" "Checks that old style cmd sub works in var expansion"
    304 }
    305 k_backticks_in_varexpand_body() {
    306 	atf_check -s exit:0 -o match:'foo' -e empty \
    307 	    ${TEST_SH} -c 'X=set; echo ${X+`echo foo`}'
    308 	atf_check -s exit:0 -o match:'set' -e empty \
    309 	    ${TEST_SH} -c 'X=set; echo ${X-`echo foo`}'
    310 	rm -f bar 2>/dev/null || :
    311 	atf_check -s exit:0 -o match:'set' -e empty \
    312 	    ${TEST_SH} -c 'X=set; echo ${X-`echo foo > bar`}'
    313 	test -f bar && atf_fail "bar should not exist, but does"
    314 	atf_check -s exit:0 -o inline:'\n' -e empty \
    315 	    ${TEST_SH} -c 'X=set; echo ${X+`echo foo > bar`}'
    316 	test -f bar || atf_fail "bar should exist, but does not"
    317 }
    318 
    319 atf_test_case l_arithmetic_in_cmdsub
    320 l_arithmetic_in_cmdsub_head() {
    321 	atf_set "descr" "Checks that arithmetic works in cmd substitutions"
    322 }
    323 l_arithmetic_in_cmdsub_body() {
    324 	atf_check -s exit:0 -o inline:'1 + 1 = 2\n' -e empty \
    325 	    ${TEST_SH} -c 'echo 1 + 1 = $( echo $(( 1 + 1 )) )'
    326 	atf_check -s exit:0 -o inline:'X * Y = 6\n' -e empty \
    327 	    ${TEST_SH} -c 'X=2; Y=3; echo X \* Y = $( echo $(( X * Y )) )'
    328 	atf_check -s exit:0 -o inline:'Y % X = 1\n' -e empty \
    329 	    ${TEST_SH} -c 'X=2; Y=3; echo Y % X = $( echo $(( $Y % $X )) )'
    330 }
    331 
    332 atf_test_case m_arithmetic_in_backticks
    333 m_arithmetic_in_backticks_head() {
    334 	atf_set "descr" "Checks that arithmetic works in old style cmd sub"
    335 }
    336 m_arithmetic_in_backticks_body() {
    337 	atf_check -s exit:0 -o inline:'2 + 3 = 5\n' -e empty \
    338 	    ${TEST_SH} -c 'echo 2 + 3 = ` echo $(( 2 + 3 )) `'
    339 	atf_check -s exit:0 -o inline:'X * Y = 6\n' -e empty \
    340 	    ${TEST_SH} -c 'X=2; Y=3; echo X \* Y = ` echo $(( X * Y )) `'
    341 	atf_check -s exit:0 -o inline:'Y % X = 1\n' -e empty \
    342 	    ${TEST_SH} -c 'X=2; Y=3; echo Y % X = ` echo $(( $Y % $X )) `'
    343 }
    344 
    345 atf_test_case n_cmdsub_in_arithmetic
    346 n_cmdsub_in_arithmetic_head() {
    347 	atf_set "descr" "Tests uses of command substitutions in arithmetic"
    348 }
    349 n_cmdsub_in_arithmetic_body() {
    350 	atf_check -s exit:0 -o inline:'7\n' -e empty \
    351 	    ${TEST_SH} -c 'echo $(( $( echo 3 ) $( echo + ) $( echo 4 ) ))'
    352 	atf_check -s exit:0 -o inline:'11\n7\n18\n4\n1\n' -e empty \
    353 	    ${TEST_SH} -c \
    354 		 'for op in + - \* / %
    355 		  do
    356 		      echo $(( $( echo 9 ) $( echo "${op}" ) $( echo 2 ) ))
    357 		  done'
    358 }
    359 
    360 atf_test_case o_backticks_in_arithmetic
    361 o_backticks_in_arithmetic_head() {
    362 	atf_set "descr" "Tests old style cmd sub used in arithmetic"
    363 }
    364 o_backticks_in_arithmetic_body() {
    365 	atf_check -s exit:0 -o inline:'33\n' -e empty \
    366 	    ${TEST_SH} -c 'echo $(( `echo 77` `echo -` `echo 44`))'
    367 	atf_check -s exit:0 -o inline:'14\n8\n33\n3\n2\n' -e empty \
    368 	    ${TEST_SH} -c \
    369 		 'for op in + - \* / %
    370 		  do
    371 		      echo $((`echo 11``echo "${op}"``echo 3`))
    372 		  done'
    373 }
    374 
    375 atf_test_case p_cmdsub_in_heredoc
    376 p_cmdsub_in_heredoc_head() {
    377 	atf_set "descr" "Checks that cmdsubs work inside a here document"
    378 }
    379 p_cmdsub_in_heredoc_body() {
    380 	atf_require_prog cat
    381 
    382 	atf_check -s exit:0 -o inline:'line 1+1\nline 2\nline 3\n' -e empty \
    383 	    ${TEST_SH} -c \
    384 		'cat <<- EOF
    385 			$( echo line 1 )$( echo +1 )
    386 			$( echo line 2;echo line 3 )
    387 		EOF'
    388 }
    389 
    390 atf_test_case q_backticks_in_heredoc
    391 q_backticks_in_heredoc_head() {
    392 	atf_set "descr" "Checks that old style cmdsubs work in here docs"
    393 }
    394 q_backticks_in_heredoc_body() {
    395 	atf_require_prog cat
    396 
    397 	atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
    398 	    ${TEST_SH} -c \
    399 		'cat <<- EOF
    400 			`echo Mary ` `echo had a `
    401 			` echo little; echo lamb `
    402 		EOF'
    403 }
    404 
    405 atf_test_case r_heredoc_in_cmdsub
    406 r_heredoc_in_cmdsub_head() {
    407 	atf_set "descr" "Checks that here docs work inside cmd subs"
    408 }
    409 r_heredoc_in_cmdsub_body() {
    410 	atf_require_prog cat
    411 
    412 	atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
    413 	    ${TEST_SH} -c 'echo "$( cat <<- \EOF
    414 				Mary had a
    415 				little
    416 				lamb
    417 			EOF
    418 			)"'
    419 
    420 	atf_check -s exit:0 -e empty \
    421 	    -o inline:'Mary had 1\nlittle\nlamb\nMary had 4\nlittle\nlambs\n' \
    422 	    ${TEST_SH} -c 'for N in 1 4; do echo "$( cat <<- EOF
    423 				Mary had ${N}
    424 				little
    425 				lamb$( [ $N -gt 1 ] && echo s )
    426 			EOF
    427 			)"; done'
    428 
    429 
    430 	atf_check -s exit:0 -o inline:'A Calculation:\n2 * 7 = 14\n' -e empty \
    431 	    ${TEST_SH} -c 'echo "$( cat <<- EOF
    432 				A Calculation:
    433 					2 * 7 = $(( 2 * 7 ))
    434 			EOF
    435 			)"'
    436 }
    437 
    438 atf_test_case s_heredoc_in_backticks
    439 s_heredoc_in_backticks_head() {
    440 	atf_set "descr" "Checks that here docs work inside old style cmd subs"
    441 }
    442 s_heredoc_in_backticks_body() {
    443 	atf_require_prog cat
    444 
    445 	atf_check -s exit:0 -o inline:'Mary had a little lamb\n' -e empty \
    446 	    ${TEST_SH} -c 'echo ` cat <<- \EOF
    447 				Mary had a
    448 				little
    449 				lamb
    450 			EOF
    451 			`'
    452 
    453 	atf_check -s exit:0 -o inline:'A Calculation:\n17 / 3 = 5\n' -e empty \
    454 	    ${TEST_SH} -c 'echo "` cat <<- EOF
    455 				A Calculation:
    456 					17 / 3 = $(( 17 / 3 ))
    457 			EOF
    458 			`"'
    459 }
    460 
    461 atf_test_case t_nested_cmdsubs_in_heredoc
    462 t_nested_cmdsubs_in_heredoc_head() {
    463 	atf_set "descr" "Checks nested command substitutions in here docs"
    464 }
    465 t_nested_cmdsubs_in_heredoc_body() {
    466 	atf_require_prog cat
    467 	atf_require_prog rm
    468 
    469 	rm -f * 2>/dev/null || :
    470 	echo "Hello" > File
    471 
    472 	atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
    473 	    ${TEST_SH} -c 'cat <<- EOF
    474 		$(cat File) U
    475 		$( V=$(cat File); echo "${V%lo}p" ) me!
    476 		EOF'
    477 
    478 	rm -f * 2>/dev/null || :
    479 	echo V>V ; echo A>A; echo R>R
    480 	echo Value>VAR
    481 
    482 	atf_check -s exit:0 -o inline:'$2.50\n' -e empty \
    483 	    ${TEST_SH} -c 'cat <<- EOF
    484 	$(Value='\''$2.50'\'';eval echo $(eval $(cat V)$(cat A)$(cat R)=\'\''\$$(cat $(cat V)$(cat A)$(cat R))\'\''; eval echo \$$(set -- *;echo ${3}${1}${2})))
    485 		EOF'
    486 }
    487 
    488 atf_test_case u_nested_backticks_in_heredoc
    489 u_nested_backticks_in_heredoc_head() {
    490 	atf_set "descr" "Checks nested old style cmd subs in here docs"
    491 }
    492 u_nested_backticks_in_heredoc_body() {
    493 	atf_require_prog cat
    494 	atf_require_prog rm
    495 
    496 	rm -f * 2>/dev/null || :
    497 	echo "Hello" > File
    498 
    499 	atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
    500 	    ${TEST_SH} -c 'cat <<- EOF
    501 		`cat File` U
    502 		`V=\`cat File\`; echo "${V%lo}p" ` me!
    503 		EOF'
    504 
    505 	rm -f * 2>/dev/null || :
    506 	echo V>V ; echo A>A; echo R>R
    507 	echo Value>VAR
    508 
    509 	atf_check -s exit:0 -o inline:'$5.20\n' -e empty \
    510 	    ${TEST_SH} -c 'cat <<- EOF
    511 	`Value='\''$5.20'\'';eval echo \`eval \\\`cat V\\\`\\\`cat A\\\`\\\`cat R\\\`=\\\'\''\\\$\\\`cat \\\\\\\`cat V\\\\\\\`\\\\\\\`cat A\\\\\\\`\\\\\\\`cat R\\\\\\\`\\\`\\\'\''; eval echo \\\$\\\`set -- *;echo \\\\\${3}\\\\\${1}\\\\\${2}\\\`\``
    512 		EOF'
    513 }
    514 
    515 atf_test_case v_cmdsub_paren_tests
    516 v_cmdsub_paren_tests_head() {
    517 	atf_set "descr" "tests with cmdsubs containing embedded ')'"
    518 }
    519 v_cmdsub_paren_tests_body() {
    520 
    521 	# Tests from:
    522 	#	http://www.in-ulm.de/~mascheck/various/cmd-subst/
    523 	# (slightly modified.)
    524 
    525 	atf_check -s exit:0 -o inline:'A.1\n' -e empty ${TEST_SH} -c \
    526 		'echo $(
    527 			case x in  x) echo A.1;; esac
    528 		)'
    529 
    530 	atf_check -s exit:0 -o inline:'A.2\n' -e empty ${TEST_SH} -c \
    531 		'echo $(
    532 			case x in  x) echo A.2;; esac # comment
    533 		)'
    534 
    535 	atf_check -s exit:0 -o inline:'A.3\n' -e empty ${TEST_SH} -c \
    536 		'echo $(
    537 			case x in (x) echo A.3;; esac
    538 		)'
    539 
    540 	atf_check -s exit:0 -o inline:'A.4\n' -e empty ${TEST_SH} -c \
    541 		'echo $(
    542 			case x in (x) echo A.4;; esac # comment
    543 		)'
    544 
    545 	atf_check -s exit:0 -o inline:'A.5\n' -e empty ${TEST_SH} -c \
    546 		'echo $(
    547 			case x in (x) echo A.5
    548 			esac
    549 		)'
    550 
    551 	atf_check -s exit:0 -o inline:'B: quoted )\n' -e empty ${TEST_SH} -c \
    552 		'echo $(
    553 			echo '\''B: quoted )'\''
    554 		)'
    555 
    556 	atf_check -s exit:0 -o inline:'C: comment then closing paren\n' \
    557 		-e empty ${TEST_SH} -c \
    558 			'echo $(
    559 				echo C: comment then closing paren # )
    560 			)'
    561 
    562 	atf_check -s exit:0 -o inline:'D.1: here-doc with )\n' \
    563 		-e empty ${TEST_SH} -c \
    564 			'echo $(
    565 				cat <<-\eof
    566 				D.1: here-doc with )
    567 				eof
    568 			)'
    569 
    570 	# D.2 is a bogus test.
    571 
    572 	atf_check -s exit:0 -o inline:'D.3: here-doc with \()\n' \
    573 		-e empty ${TEST_SH} -c \
    574 			'echo $(
    575 				cat <<-\eof
    576 				D.3: here-doc with \()
    577 				eof
    578 			)'
    579 
    580 	atf_check -s exit:0 -e empty \
    581 	  -o inline:'E: here-doc terminated with a parenthesis ("academic")\n' \
    582 		${TEST_SH} -c \
    583 		'echo $(
    584 			cat <<-\)
    585 			E: here-doc terminated with a parenthesis ("academic")
    586 			)
    587 		)'
    588 
    589 	atf_check -s exit:0 -e empty \
    590 -o inline:'F.1: here-doc embed with unbal single, back- or doublequote '\''\n' \
    591 		${TEST_SH} -c \
    592 		'echo $(
    593 			cat <<-"eof"
    594 		F.1: here-doc embed with unbal single, back- or doublequote '\''
    595 			eof
    596 		)'
    597 	atf_check -s exit:0 -e empty \
    598  -o inline:'F.2: here-doc embed with unbal single, back- or doublequote "\n' \
    599 		${TEST_SH} -c \
    600 		'echo $(
    601 			cat <<-"eof"
    602 		F.2: here-doc embed with unbal single, back- or doublequote "
    603 			eof
    604 		)'
    605 	atf_check -s exit:0 -e empty \
    606  -o inline:'F.3: here-doc embed with unbal single, back- or doublequote `\n' \
    607 		${TEST_SH} -c \
    608 		'echo $(
    609 			cat <<-"eof"
    610 		F.3: here-doc embed with unbal single, back- or doublequote `
    611 			eof
    612 		)'
    613 
    614 	atf_check -s exit:0 -e empty -o inline:'G: backslash at end of line\n' \
    615 		${TEST_SH} -c \
    616 			'echo $(
    617 				echo G: backslash at end of line # \
    618 			)'
    619 
    620 	atf_check -s exit:0 -e empty \
    621 		-o inline:'H: empty command-substitution\n' \
    622 		${TEST_SH} -c 'echo H: empty command-substitution $( )'
    623 }
    624 
    625 atf_test_case w_heredoc_outside_cmdsub
    626 w_heredoc_outside_cmdsub_head() {
    627 	atf_set "descr" "Checks that here docs work inside cmd subs"
    628 }
    629 w_heredoc_outside_cmdsub_body() {
    630 	atf_require_prog cat
    631 
    632 	atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
    633 	    ${TEST_SH} -c 'echo "$( cat <<- \EOF )"
    634 				Mary had a
    635 				little
    636 				lamb
    637 			EOF
    638 			'
    639 
    640 	atf_check -s exit:0 -e empty \
    641 	    -o inline:'Mary had 1\nlittle\nlamb\nMary had 4\nlittle\nlambs\n' \
    642 	    ${TEST_SH} -c 'for N in 1 4; do echo "$( cat <<- EOF )"
    643 				Mary had ${N}
    644 				little
    645 				lamb$( [ $N -gt 1 ] && echo s )
    646 			EOF
    647 			done'
    648 
    649 
    650 	atf_check -s exit:0 -o inline:'A Calculation:\n2 * 7 = 14\n' -e empty \
    651 	    ${TEST_SH} -c 'echo "$( cat <<- EOF)"
    652 				A Calculation:
    653 					2 * 7 = $(( 2 * 7 ))
    654 			EOF
    655 			'
    656 }
    657 
    658 atf_test_case x_heredoc_outside_backticks
    659 x_heredoc_outside_backticks_head() {
    660 	atf_set "descr" "Checks that here docs work inside old style cmd subs"
    661 }
    662 x_heredoc_outside_backticks_body() {
    663 	atf_require_prog cat
    664 
    665 	atf_check -s exit:0 -o inline:'Mary had a little lamb\n' -e empty \
    666 	    ${TEST_SH} -c 'echo ` cat <<- \EOF `
    667 				Mary had a
    668 				little
    669 				lamb
    670 			EOF
    671 			'
    672 
    673 	atf_check -s exit:0 -o inline:'A Calculation:\n17 / 3 = 5\n' -e empty \
    674 	    ${TEST_SH} -c 'echo "` cat <<- EOF `"
    675 				A Calculation:
    676 					17 / 3 = $(( 17 / 3 ))
    677 			EOF
    678 			'
    679 }
    680 
    681 atf_test_case y_many_embedded_nl
    682 y_many_embedded_nl_head() {
    683 	atf_set "descr" "Checks command substitutions that return many lines"
    684 }
    685 y_many_embedded_nl_body() {
    686 	atf_require_prog wc
    687 	atf_require_prog seq
    688 
    689 	# first make sure it should work
    690 	atf_check -s exit:0 -o match:'1002' -e empty \
    691 	    ${TEST_SH} -c "{ printf '%s\n' x
    692 		for a in \$( seq 1000 ); do printf '\n'; done
    693 		printf '%s\n' y; } | wc -l"
    694 
    695 	# then use a cmd-sub to get the same thing
    696 	atf_check -s exit:0 -o match:'1002' -e empty \
    697 	    ${TEST_SH} -c "printf '%s\n' \"\$( printf '%s\n' x
    698 		for a in \$( seq 1000 ); do printf '\n'; done
    699 		printf '%s\n' y )\" | wc -l"
    700 
    701 	# and a much bigger one.
    702 	atf_check -s exit:0 -o match:'10002' -e empty \
    703 	    ${TEST_SH} -c "printf '%s\n' \"\$( printf '%s\n' x
    704 		for a in \$( seq 10000 ); do printf '\n'; done
    705 		printf '%s\n' y )\" | wc -l"
    706 }
    707 
    708 atf_test_case z_absurd_heredoc_cmdsub_combos
    709 z_absurd_heredoc_cmdsub_combos_head() {
    710 	atf_set "descr" "perverse and unusual cmd substitutions & more"
    711 }
    712 z_absurd_heredoc_cmdsub_combos_body() {
    713 
    714 	echo "Help!" > help
    715 
    716 	# This version works in NetBSD (& FreeBSD)'s sh (and most others)
    717 	atf_check -s exit:0 -o inline:'Help!\nMe 2\n' -e empty ${TEST_SH} -c '
    718 			cat <<- EOF
    719 				$(
    720 					cat <<- STOP
    721 						$(
    722 							cat `echo help`
    723 						)
    724 					STOP
    725 				)
    726 				$(
    727 					cat <<- END 4<<-TRASH
    728 						Me $(( 1 + 1 ))
    729 					END
    730 					This is unused noise!
    731 					TRASH
    732 				)
    733 			EOF
    734 		'
    735 
    736 	# atf_expect_fail "PR bin/50993 - heredoc parsing done incorrectly"
    737 	atf_check -s exit:0 -o inline:'Help!\nMe 2\n' -e empty ${TEST_SH} -c '
    738 			cat <<- EOF
    739 				$(
    740 					cat << STOP
    741 						$(
    742 							cat `echo help`
    743 						)
    744 					STOP
    745 				)
    746 				$(
    747 					cat <<- END 4<<TRASH
    748 						Me $(( 1 + 1 ))
    749 					END
    750 					This is unused noise!
    751 					TRASH
    752 				)
    753 			EOF
    754 		'
    755 }
    756 
    757 atf_init_test_cases() {
    758 	atf_add_test_case a_basic_cmdsub
    759 	atf_add_test_case b_basic_backticks
    760 	atf_add_test_case c_nested_cmdsub
    761 	atf_add_test_case d_nested_backticks
    762 	atf_add_test_case e_perverse_mixing
    763 	atf_add_test_case f_redirect_in_cmdsub
    764 	atf_add_test_case g_redirect_in_backticks
    765 	atf_add_test_case h_vars_in_cmdsub
    766 	atf_add_test_case i_vars_in_backticks
    767 	atf_add_test_case j_cmdsub_in_varexpand
    768 	atf_add_test_case k_backticks_in_varexpand
    769 	atf_add_test_case l_arithmetic_in_cmdsub
    770 	atf_add_test_case m_arithmetic_in_backticks
    771 	atf_add_test_case n_cmdsub_in_arithmetic
    772 	atf_add_test_case o_backticks_in_arithmetic
    773 	atf_add_test_case p_cmdsub_in_heredoc
    774 	atf_add_test_case q_backticks_in_heredoc
    775 	atf_add_test_case r_heredoc_in_cmdsub
    776 	atf_add_test_case s_heredoc_in_backticks
    777 	atf_add_test_case t_nested_cmdsubs_in_heredoc
    778 	atf_add_test_case u_nested_backticks_in_heredoc
    779 	atf_add_test_case v_cmdsub_paren_tests
    780 	atf_add_test_case w_heredoc_outside_cmdsub
    781 	atf_add_test_case x_heredoc_outside_backticks
    782 	atf_add_test_case y_many_embedded_nl
    783 	atf_add_test_case z_absurd_heredoc_cmdsub_combos
    784 }
    785