1# $NetBSD: t_expand.sh,v 1.8 2016/04/29 18:29:17 christos Exp $ 2# 3# Copyright (c) 2007, 2009 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 the functions in expand.c. 32# 33 34delim_argv() { 35 str= 36 while [ $# -gt 0 ]; do 37 if [ -z "${str}" ]; then 38 str=">$1<" 39 else 40 str="${str} >$1<" 41 fi 42 shift 43 done 44 echo ${str} 45} 46 47atf_test_case dollar_at 48dollar_at_head() { 49 atf_set "descr" "Somewhere between 2.0.2 and 3.0 the expansion" \ 50 "of the \$@ variable had been broken. Check for" \ 51 "this behavior." 52} 53dollar_at_body() { 54 # This one should work everywhere. 55 atf_check -s exit:0 -o inline:' EOL\n' -e empty \ 56 ${TEST_SH} -c 'echo "" "" | '" sed 's,\$,EOL,'" 57 58 # This code triggered the bug. 59 atf_check -s exit:0 -o inline:' EOL\n' -e empty \ 60 ${TEST_SH} -c 'set -- "" ""; echo "$@" | '" sed 's,\$,EOL,'" 61 62 atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \ 63 'set -- -; shift; n_arg() { echo $#; }; n_arg "$@"' 64} 65 66atf_test_case dollar_at_with_text 67dollar_at_with_text_head() { 68 atf_set "descr" "Test \$@ expansion when it is surrounded by text" \ 69 "within the quotes. PR bin/33956." 70} 71dollar_at_with_text_body() { 72 73 cat <<'EOF' > h-f1 74 75delim_argv() { 76 str= 77 while [ $# -gt 0 ]; do 78 if [ -z "${str}" ]; then 79 str=">$1<" 80 else 81 str="${str} >$1<" 82 fi 83 shift 84 done 85 echo "${str}" 86} 87 88EOF 89 cat <<'EOF' > h-f2 90 91delim_argv() { 92 str= 93 while [ $# -gt 0 ]; do 94 95 str="${str}${str:+ }>$1<" 96 shift 97 98 done 99 echo "${str}" 100} 101 102EOF 103 104 chmod +x h-f1 h-f2 105 106 for f in 1 2 107 do 108 atf_check -s exit:0 -o inline:'\n' -e empty ${TEST_SH} -c \ 109 ". ./h-f${f}; "'set -- ; delim_argv "$@"' 110 atf_check -s exit:0 -o inline:'>foobar<\n' -e empty \ 111 ${TEST_SH} -c \ 112 ". ./h-f${f}; "'set -- ; delim_argv "foo$@bar"' 113 atf_check -s exit:0 -o inline:'>foo bar<\n' -e empty \ 114 ${TEST_SH} -c \ 115 ". ./h-f${f}; "'set -- ; delim_argv "foo $@ bar"' 116 117 atf_check -s exit:0 -o inline:'>a< >b< >c<\n' -e empty \ 118 ${TEST_SH} -c \ 119 ". ./h-f${f}; "'set -- a b c; delim_argv "$@"' 120 atf_check -s exit:0 -o inline:'>fooa< >b< >cbar<\n' -e empty \ 121 ${TEST_SH} -c \ 122 ". ./h-f${f}; "'set -- a b c; delim_argv "foo$@bar"' 123 atf_check -s exit:0 -o inline:'>foo a< >b< >c bar<\n' -e empty \ 124 ${TEST_SH} -c \ 125 ". ./h-f${f}; "'set -- a b c; delim_argv "foo $@ bar"' 126 done 127} 128 129atf_test_case strip 130strip_head() { 131 atf_set "descr" "Checks that the %% operator works and strips" \ 132 "the contents of a variable from the given point" \ 133 "to the end" 134} 135strip_body() { 136 line='#define bindir "/usr/bin" /* comment */' 137 stripped='#define bindir "/usr/bin" ' 138 139 # atf_expect_fail "PR bin/43469" -- now fixed 140 for exp in \ 141 '${line%%/\**}' \ 142 '${line%%"/*"*}' \ 143 '${line%%'"'"'/*'"'"'*}' \ 144 '"${line%%/\**}"' \ 145 '"${line%%"/*"*}"' \ 146 '"${line%%'"'"'/*'"'"'*}"' \ 147 '${line%/\**}' \ 148 '${line%"/*"*}' \ 149 '${line%'"'"'/*'"'"'*}' \ 150 '"${line%/\**}"' \ 151 '"${line%"/*"*}"' \ 152 '"${line%'"'"'/*'"'"'*}"' 153 do 154 atf_check -o inline:":$stripped:\n" -e empty ${TEST_SH} -c \ 155 "line='${line}'; echo :${exp}:" 156 done 157} 158 159atf_test_case varpattern_backslashes 160varpattern_backslashes_head() { 161 atf_set "descr" "Tests that protecting wildcards with backslashes" \ 162 "works in variable patterns." 163} 164varpattern_backslashes_body() { 165 line='/foo/bar/*/baz' 166 stripped='/foo/bar/' 167 atf_check -o inline:'/foo/bar/\n' -e empty ${TEST_SH} -c \ 168 'line="/foo/bar/*/baz"; echo ${line%%\**}' 169} 170 171atf_test_case arithmetic 172arithmetic_head() { 173 atf_set "descr" "POSIX requires shell arithmetic to use signed" \ 174 "long or a wider type. We use intmax_t, so at" \ 175 "least 64 bits should be available. Make sure" \ 176 "this is true." 177} 178arithmetic_body() { 179 180 atf_check -o inline:'3' -e empty ${TEST_SH} -c \ 181 'printf %s $((1 + 2))' 182 atf_check -o inline:'2147483647' -e empty ${TEST_SH} -c \ 183 'printf %s $((0x7fffffff))' 184 atf_check -o inline:'9223372036854775807' -e empty ${TEST_SH} -c \ 185 'printf %s $(((1 << 63) - 1))' 186} 187 188atf_test_case iteration_on_null_parameter 189iteration_on_null_parameter_head() { 190 atf_set "descr" "Check iteration of \$@ in for loop when set to null;" \ 191 "the error \"sh: @: parameter not set\" is incorrect." \ 192 "PR bin/48202." 193} 194iteration_on_null_parameter_body() { 195 atf_check -o empty -e empty ${TEST_SH} -c \ 196 'N=; set -- ${N}; for X; do echo "[$X]"; done' 197} 198 199atf_test_case iteration_on_quoted_null_parameter 200iteration_on_quoted_null_parameter_head() { 201 atf_set "descr" \ 202 'Check iteration of "$@" in for loop when set to null;' 203} 204iteration_on_quoted_null_parameter_body() { 205 atf_check -o inline:'[]\n' -e empty ${TEST_SH} -c \ 206 'N=; set -- "${N}"; for X; do echo "[$X]"; done' 207} 208 209atf_test_case iteration_on_null_or_null_parameter 210iteration_on_null_or_null_parameter_head() { 211 atf_set "descr" \ 212 'Check expansion of null parameter as default for another null' 213} 214iteration_on_null_or_null_parameter_body() { 215 atf_check -o empty -e empty ${TEST_SH} -c \ 216 'N=; E=; set -- ${N:-${E}}; for X; do echo "[$X]"; done' 217} 218 219atf_test_case iteration_on_null_or_missing_parameter 220iteration_on_null_or_missing_parameter_head() { 221 atf_set "descr" \ 222 'Check expansion of missing parameter as default for another null' 223} 224iteration_on_null_or_missing_parameter_body() { 225 # atf_expect_fail 'PR bin/50834' 226 atf_check -o empty -e empty ${TEST_SH} -c \ 227 'N=; set -- ${N:-}; for X; do echo "[$X]"; done' 228} 229 230nl=' 231' 232reset() 233{ 234 TEST_NUM=0 235 TEST_FAILURES='' 236 TEST_FAIL_COUNT=0 237 TEST_ID="$1" 238} 239 240check() 241{ 242 fail=false 243 TEMP_FILE=$( mktemp OUT.XXXXXX ) 244 TEST_NUM=$(( $TEST_NUM + 1 )) 245 MSG= 246 247 # our local shell (ATF_SHELL) better do quoting correctly... 248 # some of the tests expect us to expand $nl internally... 249 CMD="$1" 250 251 result="$( ${TEST_SH} -c "${CMD}" 2>"${TEMP_FILE}" )" 252 STATUS=$? 253 254 if [ "${STATUS}" -ne "$3" ]; then 255 MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 256 MSG="${MSG} expected exit code $3, got ${STATUS}" 257 258 # don't actually fail just because of wrong exit code 259 # unless we either expected, or received "good" 260 case "$3/${STATUS}" in 261 (*/0|0/*) fail=true;; 262 esac 263 fi 264 265 if [ "$3" -eq 0 ]; then 266 if [ -s "${TEMP_FILE}" ]; then 267 MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 268 MSG="${MSG} Messages produced on stderr unexpected..." 269 MSG="${MSG}${nl}$( cat "${TEMP_FILE}" )" 270 fail=true 271 fi 272 else 273 if ! [ -s "${TEMP_FILE}" ]; then 274 MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 275 MSG="${MSG} Expected messages on stderr," 276 MSG="${MSG} nothing produced" 277 fail=true 278 fi 279 fi 280 rm -f "${TEMP_FILE}" 281 282 # Remove newlines (use local shell for this) 283 oifs="$IFS" 284 IFS="$nl" 285 result="$(echo $result)" 286 IFS="$oifs" 287 if [ "$2" != "$result" ] 288 then 289 MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 290 MSG="${MSG} Expected output '$2', received '$result'" 291 fail=true 292 fi 293 294 if $fail 295 then 296 MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 297 MSG="${MSG} Full command: <<${CMD}>>" 298 fi 299 300 $fail && test -n "$TEST_ID" && { 301 TEST_FAILURES="${TEST_FAILURES}${TEST_FAILURES:+${nl}}" 302 TEST_FAILURES="${TEST_FAILURES}${TEST_ID}[$TEST_NUM]:" 303 TEST_FAILURES="${TEST_FAILURES} Test of '$1' failed."; 304 TEST_FAILURES="${TEST_FAILURES}${nl}${MSG}" 305 TEST_FAIL_COUNT=$(( $TEST_FAIL_COUNT + 1 )) 306 return 0 307 } 308 $fail && atf_fail "Test[$TEST_NUM] of '$1' failed${nl}${MSG}" 309 return 0 310} 311 312results() 313{ 314 test -z "${TEST_ID}" && return 0 315 test -z "${TEST_FAILURES}" && return 0 316 317 echo >&2 "==========================================" 318 echo >&2 "While testing '${TEST_ID}'" 319 echo >&2 " - - - - - - - - - - - - - - - - -" 320 echo >&2 "${TEST_FAILURES}" 321 atf_fail \ 322 "Test ${TEST_ID}: $TEST_FAIL_COUNT subtests (of $TEST_NUM) failed - see stderr" 323} 324 325atf_test_case shell_params 326shell_params_head() { 327 atf_set "descr" "Test correct operation of the numeric parameters" 328} 329shell_params_body() { 330 atf_require_prog mktemp 331 332 reset shell_params 333 334 check 'set -- a b c; echo "$#: $1 $2 $3"' '3: a b c' 0 335 check 'set -- a b c d e f g h i j k l m; echo "$#: ${1}0 ${10} $10"' \ 336 '13: a0 j a0' 0 337 check 'x="$0"; set -- a b; y="$0"; 338 [ "x${x}y" = "x${y}y" ] && echo OK || echo x="$x" y="$y"' \ 339 'OK' 0 340 check "${TEST_SH} -c 'echo 0=\$0 1=\$1 2=\$2' a b c" '0=a 1=b 2=c' 0 341 342 echo 'echo 0="$0" 1="$1" 2="$2"' > helper.sh 343 check "${TEST_SH} helper.sh a b c" '0=helper.sh 1=a 2=b' 0 344 345 check 'set -- a bb ccc dddd eeeee ffffff ggggggg hhhhhhhh \ 346 iiiiiiiii jjjjjjjjjj kkkkkkkkkkk 347 echo "${#}: ${#1} ${#2} ${#3} ${#4} ... ${#9} ${#10} ${#11}"' \ 348 '11: 1 2 3 4 ... 9 10 11' 0 349 350 check 'set -- a b c; echo "$#: ${1-A} ${2-B} ${3-C} ${4-D} ${5-E}"' \ 351 '3: a b c D E' 0 352 check 'set -- a "" c "" e 353 echo "$#: ${1:-A} ${2:-B} ${3:-C} ${4:-D} ${5:-E}"' \ 354 '5: a B c D e' 0 355 check 'set -- a "" c "" e 356 echo "$#: ${1:+A} ${2:+B} ${3:+C} ${4:+D} ${5:+E}"' \ 357 '5: A C E' 0 358 check 'set -- "abab*cbb" 359 echo "${1} ${1#a} ${1%b} ${1##ab} ${1%%b} ${1#*\*} ${1%\**}"' \ 360 'abab*cbb bab*cbb abab*cb ab*cbb abab*cb cbb abab' 0 361 check 'set -- "abab?cbb" 362 echo "${1}:${1#*a}+${1%b*}-${1##*a}_${1%%b*}%${1#[ab]}=${1%?*}/${1%\?*}"' \ 363 'abab?cbb:bab?cbb+abab?cb-b?cbb_a%bab?cbb=abab?cb/abab' 0 364 check 'set -- a "" c "" e; echo "${2:=b}"' '' 1 365 366 results 367} 368 369atf_init_test_cases() { 370 atf_add_test_case dollar_at 371 atf_add_test_case dollar_at_with_text 372 atf_add_test_case strip 373 atf_add_test_case varpattern_backslashes 374 atf_add_test_case arithmetic 375 atf_add_test_case iteration_on_null_parameter 376 atf_add_test_case iteration_on_quoted_null_parameter 377 atf_add_test_case iteration_on_null_or_null_parameter 378 atf_add_test_case iteration_on_null_or_missing_parameter 379 atf_add_test_case shell_params 380} 381