1*ccfbc41cSkre# $NetBSD: t_here.sh,v 1.9 2021/11/22 05:21:54 kre Exp $ 228604916Sjruoho# 328604916Sjruoho# Copyright (c) 2007 The NetBSD Foundation, Inc. 428604916Sjruoho# All rights reserved. 528604916Sjruoho# 628604916Sjruoho# Redistribution and use in source and binary forms, with or without 728604916Sjruoho# modification, are permitted provided that the following conditions 828604916Sjruoho# are met: 928604916Sjruoho# 1. Redistributions of source code must retain the above copyright 1028604916Sjruoho# notice, this list of conditions and the following disclaimer. 1128604916Sjruoho# 2. Redistributions in binary form must reproduce the above copyright 1228604916Sjruoho# notice, this list of conditions and the following disclaimer in the 1328604916Sjruoho# documentation and/or other materials provided with the distribution. 1428604916Sjruoho# 1528604916Sjruoho# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 1628604916Sjruoho# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1728604916Sjruoho# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1828604916Sjruoho# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 1928604916Sjruoho# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2028604916Sjruoho# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2128604916Sjruoho# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2228604916Sjruoho# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2328604916Sjruoho# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2428604916Sjruoho# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2528604916Sjruoho# POSSIBILITY OF SUCH DAMAGE. 2628604916Sjruoho# 271843eb8cSchristos# the implementation of "sh" to test 281843eb8cSchristos: ${TEST_SH:="/bin/sh"} 2928604916Sjruoho 3028604916Sjruohonl=' 3128604916Sjruoho' 3228604916Sjruoho 33bb5046e5Schristosreset() 34bb5046e5Schristos{ 35bb5046e5Schristos TEST_NUM=0 36bb5046e5Schristos TEST_FAILURES='' 37bb5046e5Schristos TEST_FAIL_COUNT=0 38bb5046e5Schristos TEST_ID="$1" 39bb5046e5Schristos} 40bb5046e5Schristos 4128604916Sjruohocheck() 4228604916Sjruoho{ 431843eb8cSchristos fail=false 441843eb8cSchristos TEMP_FILE=$( mktemp OUT.XXXXXX ) 45bb5046e5Schristos TEST_NUM=$(( $TEST_NUM + 1 )) 461843eb8cSchristos 471843eb8cSchristos # our local shell (ATF_SHELL) better do quoting correctly... 481843eb8cSchristos # some of the tests expect us to expand $nl internally... 491843eb8cSchristos CMD="nl='${nl}'; $1" 501843eb8cSchristos 511843eb8cSchristos result="$( ${TEST_SH} -c "${CMD}" 2>"${TEMP_FILE}" )" 521843eb8cSchristos STATUS=$? 531843eb8cSchristos 541843eb8cSchristos if [ "${STATUS}" -ne "$3" ]; then 55bb5046e5Schristos echo >&2 "[$TEST_NUM] expected exit code $3, got ${STATUS}" 561843eb8cSchristos 571843eb8cSchristos # don't actually fail just because of wrong exit code 581843eb8cSchristos # unless we either expected, or received "good" 591843eb8cSchristos case "$3/${STATUS}" in 601843eb8cSchristos (*/0|0/*) fail=true;; 611843eb8cSchristos esac 621843eb8cSchristos fi 631843eb8cSchristos 641843eb8cSchristos if [ "$3" -eq 0 ]; then 651843eb8cSchristos if [ -s "${TEMP_FILE}" ]; then 66bb5046e5Schristos echo >&2 \ 67bb5046e5Schristos "[$TEST_NUM] Messages produced on stderr unexpected..." 681843eb8cSchristos cat "${TEMP_FILE}" >&2 691843eb8cSchristos fail=true 701843eb8cSchristos fi 711843eb8cSchristos else 721843eb8cSchristos if ! [ -s "${TEMP_FILE}" ]; then 73bb5046e5Schristos echo >&2 \ 74bb5046e5Schristos "[$TEST_NUM] Expected messages on stderr, nothing produced" 751843eb8cSchristos fail=true 761843eb8cSchristos fi 771843eb8cSchristos fi 781843eb8cSchristos rm -f "${TEMP_FILE}" 791843eb8cSchristos 801843eb8cSchristos # Remove newlines (use local shell for this) 818d9df45bSkre result="$( 8228604916Sjruoho IFS="$nl" 838d9df45bSkre set -f 848d9df45bSkre set -- $result 858d9df45bSkre IFS=' ' 868d9df45bSkre printf %s "$*" 878d9df45bSkre )" 8828604916Sjruoho if [ "$2" != "$result" ] 8928604916Sjruoho then 90bb5046e5Schristos echo >&2 "[$TEST_NUM] Expected output '$2', received '$result'" 911843eb8cSchristos fail=true 9228604916Sjruoho fi 931843eb8cSchristos 94de3efde9Schristos if $fail 95de3efde9Schristos then 96de3efde9Schristos echo >&2 "[$TEST_NUM] Full command: <<${CMD}>>" 97de3efde9Schristos fi 98de3efde9Schristos 99bb5046e5Schristos $fail && test -n "$TEST_ID" && { 100bb5046e5Schristos TEST_FAILURES="${TEST_FAILURES}${TEST_FAILURES:+ 101bb5046e5Schristos}${TEST_ID}[$TEST_NUM]: test of '$1' failed"; 102bb5046e5Schristos TEST_FAIL_COUNT=$(( $TEST_FAIL_COUNT + 1 )) 1031843eb8cSchristos return 0 10428604916Sjruoho } 105bb5046e5Schristos $fail && atf_fail "Test[$TEST_NUM] of '$1' failed" 106bb5046e5Schristos return 0 107bb5046e5Schristos} 108bb5046e5Schristos 109bb5046e5Schristosresults() 110bb5046e5Schristos{ 111bb5046e5Schristos test -z "${TEST_ID}" && return 0 112bb5046e5Schristos test -z "${TEST_FAILURES}" && return 0 113bb5046e5Schristos 114bb5046e5Schristos echo >&2 "==========================================" 115bb5046e5Schristos echo >&2 "While testing '${TEST_ID}'" 116bb5046e5Schristos echo >&2 " - - - - - - - - - - - - - - - - -" 117bb5046e5Schristos echo >&2 "${TEST_FAILURES}" 118bb5046e5Schristos atf_fail \ 119bb5046e5Schristos "Test ${TEST_ID}: $TEST_FAIL_COUNT subtests (of $TEST_NUM) failed - see stderr" 120bb5046e5Schristos} 12128604916Sjruoho 1221843eb8cSchristosatf_test_case do_simple 1231843eb8cSchristosdo_simple_head() { 12428604916Sjruoho atf_set "descr" "Basic tests for here documents" 12528604916Sjruoho} 1261843eb8cSchristosdo_simple_body() { 12728604916Sjruoho y=x 12828604916Sjruoho 129bb5046e5Schristos reset 'simple' 130bb5046e5Schristos IFS=' ' 1311843eb8cSchristos check 'x=`cat <<EOF'$nl'text'${nl}EOF$nl'`; echo $x' 'text' 0 1321843eb8cSchristos check 'x=`cat <<\EOF'$nl'text'${nl}EOF$nl'`; echo $x' 'text' 0 13328604916Sjruoho 1341843eb8cSchristos check "y=${y};"'x=`cat <<EOF'$nl'te${y}t'${nl}EOF$nl'`; echo $x' \ 1351843eb8cSchristos 'text' 0 1361843eb8cSchristos check "y=${y};"'x=`cat <<\EOF'$nl'te${y}t'${nl}EOF$nl'`; echo $x' \ 1371843eb8cSchristos 'te${y}t' 0 1381843eb8cSchristos check "y=${y};"'x=`cat <<"EOF"'$nl'te${y}t'${nl}EOF$nl'`; echo $x' \ 1391843eb8cSchristos 'te${y}t' 0 1401843eb8cSchristos check "y=${y};"'x=`cat <<'"'EOF'"$nl'te${y}t'${nl}EOF$nl'`; echo $x' \ 1411843eb8cSchristos 'te${y}t' 0 14228604916Sjruoho 1431843eb8cSchristos # check that quotes in the here doc survive and cause no problems 1441843eb8cSchristos check "cat <<EOF${nl}te'xt${nl}EOF$nl" "te'xt" 0 1451843eb8cSchristos check "cat <<\EOF${nl}te'xt${nl}EOF$nl" "te'xt" 0 1461843eb8cSchristos check "cat <<'EOF'${nl}te'xt${nl}EOF$nl" "te'xt" 0 1471843eb8cSchristos check "cat <<EOF${nl}te\"xt${nl}EOF$nl" 'te"xt' 0 1481843eb8cSchristos check "cat <<\EOF${nl}te\"xt${nl}EOF$nl" 'te"xt' 0 1491843eb8cSchristos check "cat <<'EOF'${nl}te\"xt${nl}EOF$nl" 'te"xt' 0 1501843eb8cSchristos check "cat <<'EO'F${nl}te\"xt${nl}EOF$nl" 'te"xt' 0 15128604916Sjruoho 1521843eb8cSchristos check "y=${y};"'x=`cat <<EOF'$nl'te'"'"'${y}t'${nl}EOF$nl'`; echo $x' \ 1531843eb8cSchristos 'te'"'"'xt' 0 1541843eb8cSchristos check "y=${y};"'x=`cat <<EOF'$nl'te'"''"'${y}t'${nl}EOF$nl'`; echo $x' \ 1551843eb8cSchristos 'te'"''"'xt' 0 1561843eb8cSchristos 1571843eb8cSchristos # note that the blocks of empty space in the following must 1581843eb8cSchristos # be entirely tab characters, no spaces. 1591843eb8cSchristos 1601843eb8cSchristos check 'x=`cat <<EOF'"$nl text${nl}EOF$nl"'`; echo "$x"' \ 1611843eb8cSchristos ' text' 0 1621843eb8cSchristos check 'x=`cat <<-EOF'"$nl text${nl}EOF$nl"'`; echo $x' \ 1631843eb8cSchristos 'text' 0 1641843eb8cSchristos check 'x=`cat <<-EOF'"${nl}text${nl} EOF$nl"'`; echo $x' \ 1651843eb8cSchristos 'text' 0 1661843eb8cSchristos check 'x=`cat <<-\EOF'"$nl text${nl} EOF$nl"'`; echo $x' \ 1671843eb8cSchristos 'text' 0 1681843eb8cSchristos check 'x=`cat <<- "EOF"'"$nl text${nl}EOF$nl"'`; echo $x' \ 1691843eb8cSchristos 'text' 0 1701843eb8cSchristos check 'x=`cat <<- '"'EOF'${nl}text${nl} EOF$nl"'`; echo $x' \ 1711843eb8cSchristos 'text' 0 172bb5046e5Schristos results 173bb5046e5Schristos} 174bb5046e5Schristos 175bb5046e5Schristosatf_test_case end_markers 176bb5046e5Schristosend_markers_head() { 177bb5046e5Schristos atf_set "descr" "Tests for various end markers of here documents" 178bb5046e5Schristos} 179bb5046e5Schristosend_markers_body() { 180bb5046e5Schristos 181bb5046e5Schristos reset 'end_markers' 182de3efde9Schristos for end in EOF 1 \! '$$$' "string " a\\\ a\\\ \ '&' '' ' ' ' ' \ 183de3efde9Schristos --STRING-- . '~~~' ')' '(' '#' '()' '(\)' '(\/)' '--' '\' '{' '}' \ 184bb5046e5SchristosVERYVERYVERYVERYLONGLONGLONGin_fact_absurdly_LONG_LONG_HERE_DOCUMENT_TERMINATING_MARKER_THAT_goes_On_forever_and_ever_and_ever... 185bb5046e5Schristos do 186bb5046e5Schristos # check unquoted end markers 187bb5046e5Schristos case "${end}" in 188de3efde9Schristos ('' | *[' ()\$&#*~']* ) ;; # skip unquoted endmark test for these 189bb5046e5Schristos (*) check \ 190de3efde9Schristos 'x=$(cat << '"${end}${nl}text${nl}${end}${nl}"'); printf %s "$x"' 'text' 0 191bb5046e5Schristos ;; 192bb5046e5Schristos esac 193bb5046e5Schristos 194bb5046e5Schristos # and quoted end markers 195bb5046e5Schristos check \ 196de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end}${nl}"'); printf %s "$x"' 'text' 0 197bb5046e5Schristos 198bb5046e5Schristos # and see what happens if we encounter "almost" an end marker 199bb5046e5Schristos case "${#end}" in 200bb5046e5Schristos (0|1) ;; # too short to try truncation tests 201bb5046e5Schristos (*) check \ 202de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end%?}${nl}${end}${nl}"'); printf %s "$x"' \ 203bb5046e5Schristos "text ${end%?}" 0 204bb5046e5Schristos check \ 205de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end#?}${nl}${end}${nl}"'); printf %s "$x"' \ 206bb5046e5Schristos "text ${end#?}" 0 207bb5046e5Schristos check \ 208de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end%?}+${nl}${end}${nl}"');printf %s "$x"' \ 209bb5046e5Schristos "text ${end%?}+" 0 210bb5046e5Schristos ;; 211bb5046e5Schristos esac 212bb5046e5Schristos 213bb5046e5Schristos # or something that is a little longer 214bb5046e5Schristos check \ 215de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end}x${nl}${end}${nl}"'); printf %s "$x"' \ 216bb5046e5Schristos "text ${end}x" 0 217bb5046e5Schristos check \ 218de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}!${end}${nl}${end}${nl}"'); printf %s "$x"' \ 219bb5046e5Schristos "text !${end}" 0 220bb5046e5Schristos 221bb5046e5Schristos # or which does not begin at start of line 222bb5046e5Schristos check \ 223de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl} ${end}${nl}${end}${nl}"'); printf %s "$x"' \ 224bb5046e5Schristos "text ${end}" 0 225bb5046e5Schristos check \ 226de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl} ${end}${nl}${end}${nl}"'); printf %s "$x"' \ 227bb5046e5Schristos "text ${end}" 0 228bb5046e5Schristos 229bb5046e5Schristos # or end at end of line 230bb5046e5Schristos check \ 231de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end} ${nl}${end}${nl}"'); printf %s "$x"' \ 232bb5046e5Schristos "text ${end} " 0 233bb5046e5Schristos 234bb5046e5Schristos # or something that is correct much of the way, but then... 235bb5046e5Schristos 236bb5046e5Schristos case "${#end}" in 237bb5046e5Schristos (0) ;; # cannot test this one 238bb5046e5Schristos (1) check \ 239de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end}${end}${nl}${end}${nl}"'); printf %s "$x"' \ 240bb5046e5Schristos "text ${end}${end}" 0 241bb5046e5Schristos ;; 242bb5046e5Schristos (2-7) pfx="${end%?}" 243bb5046e5Schristos check \ 244de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end}${pfx}${nl}${end}${nl}"'); printf %s "$x"' \ 245bb5046e5Schristos "text ${end}${pfx}" 0 246bb5046e5Schristos check \ 247de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${pfx}${end}${nl}${end}${nl}"'); printf %s "$x"' \ 248bb5046e5Schristos "text ${pfx}${end}" 0 249bb5046e5Schristos ;; 250bb5046e5Schristos (*) pfx=${end%??????}; sfx=${end#??????} 251bb5046e5Schristos check \ 252de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${end}${sfx}${nl}${end}${nl}"'); printf %s "$x"' \ 253bb5046e5Schristos "text ${end}${sfx}" 0 254bb5046e5Schristos check \ 255de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${pfx}${end}${nl}${end}${nl}"'); printf %s "$x"' \ 256bb5046e5Schristos "text ${pfx}${end}" 0 257bb5046e5Schristos check \ 258de3efde9Schristos 'x=$(cat <<'"'${end}'${nl}text${nl}${pfx}${sfx}${nl}${end}${nl}"'); printf %s "$x"' \ 259bb5046e5Schristos "text ${pfx}${sfx}" 0 260bb5046e5Schristos ;; 261bb5046e5Schristos esac 262bb5046e5Schristos done 263bb5046e5Schristos 264bb5046e5Schristos # Add striptabs tests (in similar way) here one day... 265bb5046e5Schristos 266bb5046e5Schristos results 2671843eb8cSchristos} 2681843eb8cSchristos 2691843eb8cSchristosatf_test_case incomplete 2701843eb8cSchristosincomplete_head() { 2711843eb8cSchristos atf_set "descr" "Basic tests for incomplete here documents" 2721843eb8cSchristos} 2731843eb8cSchristosincomplete_body() { 274bb5046e5Schristos reset incomplete 275bb5046e5Schristos 2761843eb8cSchristos check 'cat <<EOF' '' 2 2771843eb8cSchristos check 'cat <<- EOF' '' 2 2781843eb8cSchristos check 'cat <<\EOF' '' 2 2791843eb8cSchristos check 'cat <<- \EOF' '' 2 2801843eb8cSchristos 2811843eb8cSchristos check 'cat <<EOF'"${nl}" '' 2 2821843eb8cSchristos check 'cat <<- EOF'"${nl}" '' 2 2831843eb8cSchristos check 'cat <<'"'EOF'${nl}" '' 2 2841843eb8cSchristos check 'cat <<- "EOF"'"${nl}" '' 2 2851843eb8cSchristos 2861843eb8cSchristos check 'cat << EOF'"${nl}${nl}" '' 2 2871843eb8cSchristos check 'cat <<-EOF'"${nl}${nl}" '' 2 2881843eb8cSchristos check 'cat << '"'EOF'${nl}${nl}" '' 2 2891843eb8cSchristos check 'cat <<-"EOF"'"${nl}${nl}" '' 2 2901843eb8cSchristos 2911843eb8cSchristos check 'cat << EOF'"${nl}"'line 1'"${nl}" '' 2 2921843eb8cSchristos check 'cat <<-EOF'"${nl}"' line 1'"${nl}" '' 2 2931843eb8cSchristos check 'cat << EOF'"${nl}"'line 1'"${nl}"' line 2'"${nl}" '' 2 2941843eb8cSchristos check 'cat <<-EOF'"${nl}"' line 1'"${nl}"'line 2'"${nl}" '' 2 2951843eb8cSchristos 2961843eb8cSchristos check 'cat << EOF'"${nl}line 1${nl}${nl}line3${nl}${nl}5!${nl}" '' 2 297bb5046e5Schristos 298bb5046e5Schristos results 299bb5046e5Schristos} 300bb5046e5Schristos 301bb5046e5Schristosatf_test_case lineends 302bb5046e5Schristoslineends_head() { 303bb5046e5Schristos atf_set "descr" "Tests for line endings in here documents" 304bb5046e5Schristos} 305bb5046e5Schristoslineends_body() { 306bb5046e5Schristos reset lineends 307bb5046e5Schristos 308bb5046e5Schristos # note that "check" removes newlines from stdout before comparing. 309bb5046e5Schristos # (they become blanks, provided there is something before & after) 310bb5046e5Schristos 311bb5046e5Schristos check 'cat << \echo'"${nl}"'\'"${nl}echo${nl}echo${nl}" '\' 0 312bb5046e5Schristos check 'cat << echo'"${nl}"'\'"${nl}echo${nl}echo${nl}" 'echo' 0 313bb5046e5Schristos check 'cat << echo'"${nl}"'\\'"${nl}echo${nl}echo${nl}" '\' 0 314bb5046e5Schristos 315bb5046e5Schristos check 'X=3; cat << ec\ho'"${nl}"'$X\'"${nl}echo${nl}echo${nl}" \ 316bb5046e5Schristos '$X\' 0 317bb5046e5Schristos check 'X=3; cat << echo'"${nl}"'$X'"${nl}echo${nl}echo${nl}" \ 318bb5046e5Schristos '3' 0 319bb5046e5Schristos check 'X=3; cat << echo'"${nl}"'$X\'"${nl}echo${nl}echo${nl}" \ 320bb5046e5Schristos '' 0 321bb5046e5Schristos check 'X=3; cat << echo'"${nl}"'${X}\'"${nl}echo${nl}echo${nl}" \ 322bb5046e5Schristos '3echo' 0 323bb5046e5Schristos check 'X=3; cat << echo'"${nl}"'\$X\'"${nl}echo${nl}echo${nl}" \ 324bb5046e5Schristos '$Xecho' 0 325bb5046e5Schristos check 'X=3; cat << echo'"${nl}"'\\$X \'"${nl}echo${nl}echo${nl}" \ 326bb5046e5Schristos '\3 echo' 0 327bb5046e5Schristos 328bb5046e5Schristos check \ 329bb5046e5Schristos 'cat << "echo"'"${nl}"'line1\'"${nl}"'line2\'"${nl}echo${nl}echo${nl}" \ 330bb5046e5Schristos 'line1\ line2\' 0 331bb5046e5Schristos check \ 332bb5046e5Schristos 'cat << echo'"${nl}"'line1\'"${nl}"'line2\'"${nl}echo${nl}echo${nl}" \ 333bb5046e5Schristos 'line1line2echo' 0 334bb5046e5Schristos 335bb5046e5Schristos results 3361843eb8cSchristos} 3371843eb8cSchristos 3381843eb8cSchristosatf_test_case multiple 3391843eb8cSchristosmultiple_head() { 340bb5046e5Schristos atf_set "descr" "Tests for multiple here documents on one cmd line" 3411843eb8cSchristos} 3421843eb8cSchristosmultiple_body() { 343bb5046e5Schristos reset multiple 344bb5046e5Schristos 3451843eb8cSchristos check \ 3461843eb8cSchristos "(cat ; cat <&3) <<EOF0 3<<EOF3${nl}STDIN${nl}EOF0${nl}-3-${nl}EOF3${nl}" \ 3471843eb8cSchristos 'STDIN -3-' 0 3481843eb8cSchristos 3491843eb8cSchristos check "(read line; echo \"\$line\"; cat <<EOF1; echo \"\$line\") <<EOF2 3501843eb8cSchristosThe File 3511843eb8cSchristosEOF1 3521843eb8cSchristosThe Line 3531843eb8cSchristosEOF2 3541843eb8cSchristos" 'The Line The File The Line' 0 3551843eb8cSchristos 3561843eb8cSchristos check "(read line; echo \"\$line\"; cat <<EOF; echo \"\$line\") <<EOF 3571843eb8cSchristosThe File 3581843eb8cSchristosEOF 3591843eb8cSchristosThe Line 3601843eb8cSchristosEOF 3611843eb8cSchristos" 'The Line The File The Line' 0 3621843eb8cSchristos 363bb5046e5Schristos check "V=1; W=2; cat <<-1; cat <<2; cat <<- 3; cat <<'4';"' cat <<\5 364bb5046e5Schristos $V 365bb5046e5Schristos $W 366bb5046e5Schristos 3 367bb5046e5Schristos 4 368bb5046e5Schristos 5 369bb5046e5Schristos 1 370bb5046e5Schristos2 371bb5046e5Schristos 5 372bb5046e5Schristos 4*$W+\$V 373bb5046e5Schristos 3 374bb5046e5Schristos$W 375bb5046e5Schristos1 376bb5046e5Schristos2 377bb5046e5Schristos3 378bb5046e5Schristos4 379bb5046e5Schristos7+$V 380bb5046e5Schristos$W+6 381bb5046e5Schristos5 382bb5046e5Schristos' '1 2 3 4 5 5 4*2+$V $W 1 2 3 7+$V $W+6' 0 383bb5046e5Schristos 384bb5046e5Schristos results 385bb5046e5Schristos} 386bb5046e5Schristos 387bb5046e5Schristosatf_test_case nested 388bb5046e5Schristosnested_head() { 389bb5046e5Schristos atf_set "descr" "Tests for nested here documents for one cmd" 390bb5046e5Schristos} 391bb5046e5Schristosnested_body() { 392bb5046e5Schristos reset nested 393bb5046e5Schristos 394bb5046e5Schristos check \ 395bb5046e5Schristos'cat << EOF1'"${nl}"'$(cat << EOF2'"${nl}LINE${nl}EOF2${nl}"')'"${nl}EOF1${nl}"\ 396bb5046e5Schristos 'LINE' 0 397bb5046e5Schristos 398bb5046e5Schristos# This next one fails ... and correctly, so we will omit it (bad test) 399bb5046e5Schristos# Reasoning is that the correct data "$(cat << EOF2)\nLINE\nEOF2\n" is 400bb5046e5Schristos# collected for the outer (EOF1) heredoc, when that is parsed, it looks 401bb5046e5Schristos# like 402bb5046e5Schristos# $(cat <<EOF2) 403bb5046e5Schristos# LINE 404bb5046e5Schristos# EOF2 405bb5046e5Schristos# which looks like a good command - except it is being parsed in "heredoc" 406bb5046e5Schristos# syntax, which means it is enclosed in double quotes, which means that 407bb5046e5Schristos# the newline after the ')' in the first line is not a newline token, but 408bb5046e5Schristos# just a character. The EOF2 heredoc cannot start until after the next 409bb5046e5Schristos# newline token, of which there are none here... LINE and EOF2 are just 410bb5046e5Schristos# more data in the outer EOF1 heredoc for its "cat" command to read & write. 411bb5046e5Schristos# 412bb5046e5Schristos# The previous sub-test works because there the \n comes inside the 413bb5046e5Schristos# $( ), and in there, the outside quoting rules are suspended, and it 414bb5046e5Schristos# all starts again - so that \n is a newline token, and the EOF2 heredoc 415bb5046e5Schristos# is processed. 416bb5046e5Schristos# 417bb5046e5Schristos# check \ 418bb5046e5Schristos# 'cat << EOF1'"${nl}"'$(cat << EOF2 )'"${nl}LINE${nl}EOF2${nl}EOF1${nl}" \ 419bb5046e5Schristos# 'LINE' 0 420bb5046e5Schristos 421bb5046e5Schristos L='cat << EOF1'"${nl}"'LINE1$(cat << EOF2'"${nl}" 422bb5046e5Schristos L="${L}"'LINE2$(cat << EOF3'"${nl}" 423bb5046e5Schristos L="${L}"'LINE3$(cat << EOF4'"${nl}" 424bb5046e5Schristos L="${L}"'LINE4$(cat << EOF5'"${nl}" 425bb5046e5Schristos L="${L}LINE5${nl}EOF5${nl})4${nl}EOF4${nl})3${nl}" 426bb5046e5Schristos L="${L}EOF3${nl})2${nl}EOF2${nl})1${nl}EOF1${nl}" 427bb5046e5Schristos 428bb5046e5Schristos # That mess is ... 429bb5046e5Schristos # 430bb5046e5Schristos # cat <<EOF1 431bb5046e5Schristos # LINE1$(cat << EOF2 432bb5046e5Schristos # LINE2$(cat << EOF3 433bb5046e5Schristos # LINE3$(cat << EOF4 434bb5046e5Schristos # LINE4$(cat << EOF5 435bb5046e5Schristos # LINE5 436bb5046e5Schristos # EOF5 437bb5046e5Schristos # )4 438bb5046e5Schristos # EOF4 439bb5046e5Schristos # )3 440bb5046e5Schristos # EOF3 441bb5046e5Schristos # )2 442bb5046e5Schristos # EOF2 443bb5046e5Schristos # )1 444bb5046e5Schristos # EOF1 445bb5046e5Schristos 446bb5046e5Schristos check "${L}" 'LINE1LINE2LINE3LINE4LINE54321' 0 447bb5046e5Schristos 448bb5046e5Schristos results 449bb5046e5Schristos} 450bb5046e5Schristos 451bb5046e5Schristosatf_test_case quoting 452bb5046e5Schristosquoting_head() { 453bb5046e5Schristos atf_set "descr" "Tests for use of quotes inside here documents" 454bb5046e5Schristos} 455bb5046e5Schristosquoting_body() { 456bb5046e5Schristos reset quoting 457bb5046e5Schristos 458bb5046e5Schristos check 'X=!; cat <<- E\0F 459bb5046e5Schristos <'\''"'\'' \\$X\$X "'\''" \\> 460bb5046e5Schristos E0F 461bb5046e5Schristos ' '<'\''"'\'' \\$X\$X "'\''" \\>' 0 462bb5046e5Schristos 463bb5046e5Schristos check 'X=!; cat <<- E0F 464bb5046e5Schristos <'\''"'\'' \\$X\$X "'\''" \\> 465bb5046e5Schristos E0F 466bb5046e5Schristos ' '<'\''"'\'' \!$X "'\''" \>' 0 467bb5046e5Schristos 468bb5046e5Schristos check 'cat <<- END 469bb5046e5Schristos $( echo "'\''" ) $( echo '\''"'\'' ) $( echo \\ ) 470bb5046e5Schristos END 471bb5046e5Schristos ' "' \" \\" 0 472bb5046e5Schristos 473bb5046e5Schristos check 'X=12345; Y="string1 line1?-line2"; Z=; unset W; cat <<-EOF 474bb5046e5Schristos ${#X}${Z:-${Y}}${W+junk}${Y%%l*}${Y#*\?} 475bb5046e5Schristos "$Z"'\''$W'\'' ${Y%" "*} $(( X + 54321 )) 476bb5046e5Schristos EOF 477bb5046e5Schristos ' '5string1 line1?-line2string1 -line2 ""'\'\'' string1 66666' 0 478bb5046e5Schristos 4798d9df45bSkre # check that \ only quotes the magic chars, otherwise is retained 4808d9df45bSkre check 'p=A; cat <<-EOF 4818d9df45bSkre ${p+\%$p\%} 4828d9df45bSkre ${p+%$p%} 4838d9df45bSkre EOF 4848d9df45bSkre ' '\%A\% %A%' 0 4858d9df45bSkre 4868d9df45bSkre # and check that " is not magic, so \ does not quote it 4878d9df45bSkre check 'p=A; cat <<-EOF 4888d9df45bSkre ${p+\"$p\"} 4898d9df45bSkre ${p+"$p"} 4908d9df45bSkre EOF 4918d9df45bSkre ' '\"A\" "A"' 0 4928d9df45bSkre 4938d9df45bSkre # except in a ${var%<word>} word, base syntax reapplies, and 4948d9df45bSkre # there quotes are magic again 4958d9df45bSkre check 'p=ABCD; cat <<-EOF 4968d9df45bSkre ${p%B?D} 4978d9df45bSkre ${p%B\?D} 4988d9df45bSkre ${p%"BCD"} 4998d9df45bSkre "${p%??}" 5008d9df45bSkre ${p#"${p%??}"} 5018d9df45bSkre "${p#"${p%?"?"}"}" 5028d9df45bSkre EOF 5038d9df45bSkre ' 'A ABCD A "AB" CD ""' 0 5048d9df45bSkre 5058d9df45bSkre check 'p=AB??; cat <<-EOF 5068d9df45bSkre ${p%B?D} 5078d9df45bSkre ${p%B\??} 5088d9df45bSkre ${p%"B??"} 5098d9df45bSkre "${p%??}" 5108d9df45bSkre ${p#"${p%??}"} 5118d9df45bSkre "${p#"${p%?"?"}"}" 5128d9df45bSkre EOF 5138d9df45bSkre ' 'AB?? A A "AB" ?? "??"' 0 5148d9df45bSkre 515bb5046e5Schristos results 516bb5046e5Schristos} 517bb5046e5Schristos 518*ccfbc41cSkre# 519*ccfbc41cSkre# This next test is really just testing what our shell happens to do. 520*ccfbc41cSkre# There doesn't seem to be any spec on in which context expansions 521*ccfbc41cSkre# in redirects are processed. Most shells do them in the parent 522*ccfbc41cSkre# shell context, meaning that side effects of the expansion become 523*ccfbc41cSkre# visible to the shell - a couple process redirect expansions in 524*ccfbc41cSkre# a subshell, meaning that side effects are lost. 525*ccfbc41cSkre# 526*ccfbc41cSkre# Before PR bin/53550 was fixed, the NetBSD sh evaluated all redirect 527*ccfbc41cSkre# expansions, except here documents, in the context of the shell, and 528*ccfbc41cSkre# here document redirects in a subshell context. That distinction 529*ccfbc41cSkre# makes no real sense (and only an old, and maybe still current, FreeBSD 530*ccfbc41cSkre# shell shares that pecadillo.) Afer that fix, the NetBSD shell joins 531*ccfbc41cSkre# almost all others in expanding redirects (all of them) in the shell 532*ccfbc41cSkre# context, meaning that side effects of here documenty expansions become 533*ccfbc41cSkre# visible in the shell. 534*ccfbc41cSkre# 535*ccfbc41cSkre# Before the fix, we used to get "2\n1\n" as the output from this 536*ccfbc41cSkre# test, now the variable assignment in the here document persists 537*ccfbc41cSkre# and we get "2\n2\n" as do most other shells. (bash is a notable 538*ccfbc41cSkre# exception, but it does all redirect expansions in a subshell context) 539*ccfbc41cSkre# 540*ccfbc41cSkre 541bb5046e5Schristosatf_test_case side_effects 542bb5046e5Schristosside_effects_head() { 543bb5046e5Schristos atf_set "descr" "Tests how side effects in here documents are handled" 544bb5046e5Schristos} 545bb5046e5Schristosside_effects_body() { 546bb5046e5Schristos 547*ccfbc41cSkre atf_check -s exit:0 -o inline:'2\n2\n' -e empty ${TEST_SH} -c ' 548bb5046e5Schristos unset X 549bb5046e5Schristos cat <<-EOF 550bb5046e5Schristos ${X=2} 551bb5046e5Schristos EOF 552bb5046e5Schristos echo "${X-1}" 553bb5046e5Schristos ' 5541843eb8cSchristos} 5551843eb8cSchristos 556*ccfbc41cSkre# This is a test for the specific bug reported in PR bin/53550 557*ccfbc41cSkre# This should work in any shell. 558*ccfbc41cSkre 559*ccfbc41cSkreatf_test_case exit_status 560*ccfbc41cSkreexit_status_head() { 561*ccfbc41cSkre atf_set descr "Tests exit status of a command substitution in a heredoc" 562*ccfbc41cSkre} 563*ccfbc41cSkreexit_status_body() { 564*ccfbc41cSkre 565*ccfbc41cSkre # PR bin/53550 test 566*ccfbc41cSkre atf_check -s exit:7 -o empty -e empty ${TEST_SH} -c ' 567*ccfbc41cSkre <<-EOF 568*ccfbc41cSkre $(exit 7) 569*ccfbc41cSkre EOF 570*ccfbc41cSkre ' 571*ccfbc41cSkre} 572*ccfbc41cSkre 573f54a5526Skre# The following tests a problem reported on the austin-list 2021-09-08 574f54a5526Skre# by oguzismailuysal@gmail.com ... it affected all ash derived shells 575f54a5526Skreatf_test_case hard_cases 576f54a5526Skrehard_cases_head() { 577f54a5526Skre atf_set "descr" \ 578f54a5526Skre "Tests here docs in positions that have confised our parser" 579f54a5526Skre} 580f54a5526Skrehard_cases_body() { 581f54a5526Skre 582f54a5526Skre atf_check -s exit:0 -o inline:'xxx\n' -e empty ${TEST_SH} -c ' 583f54a5526Skre : <<- do | for x in xxx 584f54a5526Skre do 585f54a5526Skre do echo $x 586f54a5526Skre done' 587f54a5526Skre 588f54a5526Skre atf_check -s exit:0 -o inline:'xxx\n' -e empty ${TEST_SH} -c ' 589f54a5526Skre set -- xxx 590f54a5526Skre : <<- done | for x in xxx 591f54a5526Skre done 592f54a5526Skre do echo $x 593f54a5526Skre done' 594f54a5526Skre 595f54a5526Skre atf_check -s exit:0 -o inline:'xxx\n' -e empty ${TEST_SH} -c ' 596f54a5526Skre : <<- in | case xxx 597f54a5526Skre in 598f54a5526Skre in xxx) echo xxx;; 599f54a5526Skre esac' 600f54a5526Skre} 601f54a5526Skre 60206f9bef6Schristosatf_test_case vicious 60306f9bef6Schristosvicious_head() { 6041843eb8cSchristos atf_set "descr" "Tests for obscure and obnoxious uses of here docs" 6051843eb8cSchristos} 60606f9bef6Schristosvicious_body() { 607bb5046e5Schristos reset 6081843eb8cSchristos 6091843eb8cSchristos cat <<- \END_SCRIPT > script 6101843eb8cSchristos cat <<ONE && cat \ 6111843eb8cSchristos <<TWO 6121843eb8cSchristos a 6131843eb8cSchristos ONE 6141843eb8cSchristos b 6151843eb8cSchristos TWO 6161843eb8cSchristos END_SCRIPT 6171843eb8cSchristos 6181843eb8cSchristos atf_check -s exit:0 -o inline:'a\nb\n' -e empty ${TEST_SH} script 6191843eb8cSchristos 6201843eb8cSchristos # This next one is causing discussion currently (late Feb 2016) 6211843eb8cSchristos # amongst stds writers & implementors. Consequently we 6221843eb8cSchristos # will not check what it produces. The eventual result 6231843eb8cSchristos # seems unlikely to be what we currently output, which 6241843eb8cSchristos # is: 62506f9bef6Schristos # A:echo line 1 6261843eb8cSchristos # B:echo line 2)" && prefix DASH_CODE <<DASH_CODE 6271843eb8cSchristos # B:echo line 3 6281843eb8cSchristos # line 4 6291843eb8cSchristos # line 5 6301843eb8cSchristos # 6311843eb8cSchristos # The likely intended output is ... 6321843eb8cSchristos # 6331843eb8cSchristos # A:echo line 3 6341843eb8cSchristos # B:echo line 1 6351843eb8cSchristos # line 2 6361843eb8cSchristos # DASH_CODE:echo line 4)" 6371843eb8cSchristos # DASH_CODE:echo line 5 6381843eb8cSchristos # 639bb5046e5Schristos # The difference is explained by differing opinions on just 6401843eb8cSchristos # when processing of a here doc should start 6411843eb8cSchristos 6421843eb8cSchristos cat <<- \END_SCRIPT > script 6431843eb8cSchristos prefix() { sed -e "s/^/$1:/"; } 6441843eb8cSchristos DASH_CODE() { :; } 6451843eb8cSchristos 6461843eb8cSchristos prefix A <<XXX && echo "$(prefix B <<XXX 6471843eb8cSchristos echo line 1 6481843eb8cSchristos XXX 6491843eb8cSchristos echo line 2)" && prefix DASH_CODE <<DASH_CODE 6501843eb8cSchristos echo line 3 6511843eb8cSchristos XXX 6521843eb8cSchristos echo line 4)" 6531843eb8cSchristos echo line 5 6541843eb8cSchristos DASH_CODE 6551843eb8cSchristos END_SCRIPT 6561843eb8cSchristos 6571843eb8cSchristos # we will just verify that the shell can parse the 6581843eb8cSchristos # script somehow, and doesn't fall over completely... 6591843eb8cSchristos 660bb5046e5Schristos atf_check -s exit:0 -o ignore -e empty ${TEST_SH} script 66128604916Sjruoho} 66228604916Sjruoho 66328604916Sjruohoatf_init_test_cases() { 664bb5046e5Schristos atf_add_test_case do_simple # not worthy of a comment 665bb5046e5Schristos atf_add_test_case end_markers # the mundane, the weird, the bizarre 666*ccfbc41cSkre atf_add_test_case exit_status # PR bin/53550, cmdsub in heredoc 667bb5046e5Schristos atf_add_test_case incomplete # where the end marker isn't... 668bb5046e5Schristos atf_add_test_case lineends # test weird line endings in heredocs 6691843eb8cSchristos atf_add_test_case multiple # multiple << operators on one cmd 670bb5046e5Schristos atf_add_test_case nested # here docs inside here docs 671bb5046e5Schristos atf_add_test_case quoting # stuff quoted inside 672bb5046e5Schristos atf_add_test_case side_effects # here docs that modify environment 673f54a5526Skre atf_add_test_case hard_cases # here doc bodies appearing mid command 67406f9bef6Schristos atf_add_test_case vicious # evil test from the austin-l list... 67528604916Sjruoho} 676