1313498Sngie# $NetBSD: t_expand.sh,v 1.8 2016/04/29 18:29:17 christos Exp $ 2272343Sngie# 3272343Sngie# Copyright (c) 2007, 2009 The NetBSD Foundation, Inc. 4272343Sngie# All rights reserved. 5272343Sngie# 6272343Sngie# Redistribution and use in source and binary forms, with or without 7272343Sngie# modification, are permitted provided that the following conditions 8272343Sngie# are met: 9272343Sngie# 1. Redistributions of source code must retain the above copyright 10272343Sngie# notice, this list of conditions and the following disclaimer. 11272343Sngie# 2. Redistributions in binary form must reproduce the above copyright 12272343Sngie# notice, this list of conditions and the following disclaimer in the 13272343Sngie# documentation and/or other materials provided with the distribution. 14272343Sngie# 15272343Sngie# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16272343Sngie# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17272343Sngie# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18272343Sngie# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19272343Sngie# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20272343Sngie# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21272343Sngie# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22272343Sngie# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23272343Sngie# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24272343Sngie# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25272343Sngie# POSSIBILITY OF SUCH DAMAGE. 26272343Sngie# 27313498Sngie# the implementation of "sh" to test 28313498Sngie: ${TEST_SH:="/bin/sh"} 29272343Sngie 30272343Sngie# 31272343Sngie# This file tests the functions in expand.c. 32272343Sngie# 33272343Sngie 34272343Sngiedelim_argv() { 35272343Sngie str= 36272343Sngie while [ $# -gt 0 ]; do 37272343Sngie if [ -z "${str}" ]; then 38272343Sngie str=">$1<" 39272343Sngie else 40272343Sngie str="${str} >$1<" 41272343Sngie fi 42272343Sngie shift 43272343Sngie done 44272343Sngie echo ${str} 45272343Sngie} 46272343Sngie 47272343Sngieatf_test_case dollar_at 48272343Sngiedollar_at_head() { 49272343Sngie atf_set "descr" "Somewhere between 2.0.2 and 3.0 the expansion" \ 50272343Sngie "of the \$@ variable had been broken. Check for" \ 51272343Sngie "this behavior." 52272343Sngie} 53272343Sngiedollar_at_body() { 54272343Sngie # This one should work everywhere. 55313498Sngie atf_check -s exit:0 -o inline:' EOL\n' -e empty \ 56313498Sngie ${TEST_SH} -c 'echo "" "" | '" sed 's,\$,EOL,'" 57272343Sngie 58272343Sngie # This code triggered the bug. 59313498Sngie atf_check -s exit:0 -o inline:' EOL\n' -e empty \ 60313498Sngie ${TEST_SH} -c 'set -- "" ""; echo "$@" | '" sed 's,\$,EOL,'" 61272343Sngie 62313498Sngie atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \ 63313498Sngie 'set -- -; shift; n_arg() { echo $#; }; n_arg "$@"' 64272343Sngie} 65272343Sngie 66272343Sngieatf_test_case dollar_at_with_text 67272343Sngiedollar_at_with_text_head() { 68272343Sngie atf_set "descr" "Test \$@ expansion when it is surrounded by text" \ 69272343Sngie "within the quotes. PR bin/33956." 70272343Sngie} 71272343Sngiedollar_at_with_text_body() { 72272343Sngie 73313498Sngie cat <<'EOF' > h-f1 74313498Sngie 75313498Sngiedelim_argv() { 76313498Sngie str= 77313498Sngie while [ $# -gt 0 ]; do 78313498Sngie if [ -z "${str}" ]; then 79313498Sngie str=">$1<" 80313498Sngie else 81313498Sngie str="${str} >$1<" 82313498Sngie fi 83313498Sngie shift 84313498Sngie done 85313498Sngie echo "${str}" 86272343Sngie} 87272343Sngie 88313498SngieEOF 89313498Sngie cat <<'EOF' > h-f2 90313498Sngie 91313498Sngiedelim_argv() { 92313498Sngie str= 93313498Sngie while [ $# -gt 0 ]; do 94313498Sngie 95313498Sngie str="${str}${str:+ }>$1<" 96313498Sngie shift 97313498Sngie 98313498Sngie done 99313498Sngie echo "${str}" 100313498Sngie} 101313498Sngie 102313498SngieEOF 103313498Sngie 104313498Sngie chmod +x h-f1 h-f2 105313498Sngie 106313498Sngie for f in 1 2 107313498Sngie do 108313498Sngie atf_check -s exit:0 -o inline:'\n' -e empty ${TEST_SH} -c \ 109313498Sngie ". ./h-f${f}; "'set -- ; delim_argv "$@"' 110313498Sngie atf_check -s exit:0 -o inline:'>foobar<\n' -e empty \ 111313498Sngie ${TEST_SH} -c \ 112313498Sngie ". ./h-f${f}; "'set -- ; delim_argv "foo$@bar"' 113313498Sngie atf_check -s exit:0 -o inline:'>foo bar<\n' -e empty \ 114313498Sngie ${TEST_SH} -c \ 115313498Sngie ". ./h-f${f}; "'set -- ; delim_argv "foo $@ bar"' 116313498Sngie 117313498Sngie atf_check -s exit:0 -o inline:'>a< >b< >c<\n' -e empty \ 118313498Sngie ${TEST_SH} -c \ 119313498Sngie ". ./h-f${f}; "'set -- a b c; delim_argv "$@"' 120313498Sngie atf_check -s exit:0 -o inline:'>fooa< >b< >cbar<\n' -e empty \ 121313498Sngie ${TEST_SH} -c \ 122313498Sngie ". ./h-f${f}; "'set -- a b c; delim_argv "foo$@bar"' 123313498Sngie atf_check -s exit:0 -o inline:'>foo a< >b< >c bar<\n' -e empty \ 124313498Sngie ${TEST_SH} -c \ 125313498Sngie ". ./h-f${f}; "'set -- a b c; delim_argv "foo $@ bar"' 126313498Sngie done 127313498Sngie} 128313498Sngie 129272343Sngieatf_test_case strip 130272343Sngiestrip_head() { 131272343Sngie atf_set "descr" "Checks that the %% operator works and strips" \ 132272343Sngie "the contents of a variable from the given point" \ 133272343Sngie "to the end" 134272343Sngie} 135272343Sngiestrip_body() { 136272343Sngie line='#define bindir "/usr/bin" /* comment */' 137272343Sngie stripped='#define bindir "/usr/bin" ' 138313498Sngie 139313498Sngie # atf_expect_fail "PR bin/43469" -- now fixed 140313498Sngie for exp in \ 141313498Sngie '${line%%/\**}' \ 142313498Sngie '${line%%"/*"*}' \ 143313498Sngie '${line%%'"'"'/*'"'"'*}' \ 144313498Sngie '"${line%%/\**}"' \ 145313498Sngie '"${line%%"/*"*}"' \ 146313498Sngie '"${line%%'"'"'/*'"'"'*}"' \ 147313498Sngie '${line%/\**}' \ 148313498Sngie '${line%"/*"*}' \ 149313498Sngie '${line%'"'"'/*'"'"'*}' \ 150313498Sngie '"${line%/\**}"' \ 151313498Sngie '"${line%"/*"*}"' \ 152313498Sngie '"${line%'"'"'/*'"'"'*}"' 153313498Sngie do 154313498Sngie atf_check -o inline:":$stripped:\n" -e empty ${TEST_SH} -c \ 155313498Sngie "line='${line}'; echo :${exp}:" 156313498Sngie done 157272343Sngie} 158272343Sngie 159272343Sngieatf_test_case varpattern_backslashes 160272343Sngievarpattern_backslashes_head() { 161272343Sngie atf_set "descr" "Tests that protecting wildcards with backslashes" \ 162272343Sngie "works in variable patterns." 163272343Sngie} 164272343Sngievarpattern_backslashes_body() { 165272343Sngie line='/foo/bar/*/baz' 166272343Sngie stripped='/foo/bar/' 167313498Sngie atf_check -o inline:'/foo/bar/\n' -e empty ${TEST_SH} -c \ 168313498Sngie 'line="/foo/bar/*/baz"; echo ${line%%\**}' 169272343Sngie} 170272343Sngie 171272343Sngieatf_test_case arithmetic 172272343Sngiearithmetic_head() { 173272343Sngie atf_set "descr" "POSIX requires shell arithmetic to use signed" \ 174272343Sngie "long or a wider type. We use intmax_t, so at" \ 175272343Sngie "least 64 bits should be available. Make sure" \ 176272343Sngie "this is true." 177272343Sngie} 178272343Sngiearithmetic_body() { 179313498Sngie 180313498Sngie atf_check -o inline:'3' -e empty ${TEST_SH} -c \ 181313498Sngie 'printf %s $((1 + 2))' 182313498Sngie atf_check -o inline:'2147483647' -e empty ${TEST_SH} -c \ 183313498Sngie 'printf %s $((0x7fffffff))' 184313498Sngie atf_check -o inline:'9223372036854775807' -e empty ${TEST_SH} -c \ 185313498Sngie 'printf %s $(((1 << 63) - 1))' 186272343Sngie} 187272343Sngie 188272343Sngieatf_test_case iteration_on_null_parameter 189272343Sngieiteration_on_null_parameter_head() { 190272343Sngie atf_set "descr" "Check iteration of \$@ in for loop when set to null;" \ 191272343Sngie "the error \"sh: @: parameter not set\" is incorrect." \ 192272343Sngie "PR bin/48202." 193272343Sngie} 194272343Sngieiteration_on_null_parameter_body() { 195313498Sngie atf_check -o empty -e empty ${TEST_SH} -c \ 196313498Sngie 'N=; set -- ${N}; for X; do echo "[$X]"; done' 197272343Sngie} 198272343Sngie 199313498Sngieatf_test_case iteration_on_quoted_null_parameter 200313498Sngieiteration_on_quoted_null_parameter_head() { 201313498Sngie atf_set "descr" \ 202313498Sngie 'Check iteration of "$@" in for loop when set to null;' 203313498Sngie} 204313498Sngieiteration_on_quoted_null_parameter_body() { 205313498Sngie atf_check -o inline:'[]\n' -e empty ${TEST_SH} -c \ 206313498Sngie 'N=; set -- "${N}"; for X; do echo "[$X]"; done' 207313498Sngie} 208313498Sngie 209313498Sngieatf_test_case iteration_on_null_or_null_parameter 210313498Sngieiteration_on_null_or_null_parameter_head() { 211313498Sngie atf_set "descr" \ 212313498Sngie 'Check expansion of null parameter as default for another null' 213313498Sngie} 214313498Sngieiteration_on_null_or_null_parameter_body() { 215313498Sngie atf_check -o empty -e empty ${TEST_SH} -c \ 216313498Sngie 'N=; E=; set -- ${N:-${E}}; for X; do echo "[$X]"; done' 217313498Sngie} 218313498Sngie 219313498Sngieatf_test_case iteration_on_null_or_missing_parameter 220313498Sngieiteration_on_null_or_missing_parameter_head() { 221313498Sngie atf_set "descr" \ 222313498Sngie 'Check expansion of missing parameter as default for another null' 223313498Sngie} 224313498Sngieiteration_on_null_or_missing_parameter_body() { 225313498Sngie # atf_expect_fail 'PR bin/50834' 226313498Sngie atf_check -o empty -e empty ${TEST_SH} -c \ 227313498Sngie 'N=; set -- ${N:-}; for X; do echo "[$X]"; done' 228313498Sngie} 229313498Sngie 230313498Sngienl=' 231313498Sngie' 232313498Sngiereset() 233313498Sngie{ 234313498Sngie TEST_NUM=0 235313498Sngie TEST_FAILURES='' 236313498Sngie TEST_FAIL_COUNT=0 237313498Sngie TEST_ID="$1" 238313498Sngie} 239313498Sngie 240313498Sngiecheck() 241313498Sngie{ 242313498Sngie fail=false 243313498Sngie TEMP_FILE=$( mktemp OUT.XXXXXX ) 244313498Sngie TEST_NUM=$(( $TEST_NUM + 1 )) 245313498Sngie MSG= 246313498Sngie 247313498Sngie # our local shell (ATF_SHELL) better do quoting correctly... 248313498Sngie # some of the tests expect us to expand $nl internally... 249313498Sngie CMD="$1" 250313498Sngie 251313498Sngie result="$( ${TEST_SH} -c "${CMD}" 2>"${TEMP_FILE}" )" 252313498Sngie STATUS=$? 253313498Sngie 254313498Sngie if [ "${STATUS}" -ne "$3" ]; then 255313498Sngie MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 256313498Sngie MSG="${MSG} expected exit code $3, got ${STATUS}" 257313498Sngie 258313498Sngie # don't actually fail just because of wrong exit code 259313498Sngie # unless we either expected, or received "good" 260313498Sngie case "$3/${STATUS}" in 261313498Sngie (*/0|0/*) fail=true;; 262313498Sngie esac 263313498Sngie fi 264313498Sngie 265313498Sngie if [ "$3" -eq 0 ]; then 266313498Sngie if [ -s "${TEMP_FILE}" ]; then 267313498Sngie MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 268313498Sngie MSG="${MSG} Messages produced on stderr unexpected..." 269313498Sngie MSG="${MSG}${nl}$( cat "${TEMP_FILE}" )" 270313498Sngie fail=true 271313498Sngie fi 272313498Sngie else 273313498Sngie if ! [ -s "${TEMP_FILE}" ]; then 274313498Sngie MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 275313498Sngie MSG="${MSG} Expected messages on stderr," 276313498Sngie MSG="${MSG} nothing produced" 277313498Sngie fail=true 278313498Sngie fi 279313498Sngie fi 280313498Sngie rm -f "${TEMP_FILE}" 281313498Sngie 282313498Sngie # Remove newlines (use local shell for this) 283313498Sngie oifs="$IFS" 284313498Sngie IFS="$nl" 285313498Sngie result="$(echo $result)" 286313498Sngie IFS="$oifs" 287313498Sngie if [ "$2" != "$result" ] 288313498Sngie then 289313498Sngie MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 290313498Sngie MSG="${MSG} Expected output '$2', received '$result'" 291313498Sngie fail=true 292313498Sngie fi 293313498Sngie 294313498Sngie if $fail 295313498Sngie then 296313498Sngie MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 297313498Sngie MSG="${MSG} Full command: <<${CMD}>>" 298313498Sngie fi 299313498Sngie 300313498Sngie $fail && test -n "$TEST_ID" && { 301313498Sngie TEST_FAILURES="${TEST_FAILURES}${TEST_FAILURES:+${nl}}" 302313498Sngie TEST_FAILURES="${TEST_FAILURES}${TEST_ID}[$TEST_NUM]:" 303313498Sngie TEST_FAILURES="${TEST_FAILURES} Test of '$1' failed."; 304313498Sngie TEST_FAILURES="${TEST_FAILURES}${nl}${MSG}" 305313498Sngie TEST_FAIL_COUNT=$(( $TEST_FAIL_COUNT + 1 )) 306313498Sngie return 0 307313498Sngie } 308313498Sngie $fail && atf_fail "Test[$TEST_NUM] of '$1' failed${nl}${MSG}" 309313498Sngie return 0 310313498Sngie} 311313498Sngie 312313498Sngieresults() 313313498Sngie{ 314313498Sngie test -z "${TEST_ID}" && return 0 315313498Sngie test -z "${TEST_FAILURES}" && return 0 316313498Sngie 317313498Sngie echo >&2 "==========================================" 318313498Sngie echo >&2 "While testing '${TEST_ID}'" 319313498Sngie echo >&2 " - - - - - - - - - - - - - - - - -" 320313498Sngie echo >&2 "${TEST_FAILURES}" 321313498Sngie atf_fail \ 322313498Sngie "Test ${TEST_ID}: $TEST_FAIL_COUNT subtests (of $TEST_NUM) failed - see stderr" 323313498Sngie} 324313498Sngie 325313498Sngieatf_test_case shell_params 326313498Sngieshell_params_head() { 327313498Sngie atf_set "descr" "Test correct operation of the numeric parameters" 328313498Sngie} 329313498Sngieshell_params_body() { 330313498Sngie atf_require_prog mktemp 331313498Sngie 332313498Sngie reset shell_params 333313498Sngie 334313498Sngie check 'set -- a b c; echo "$#: $1 $2 $3"' '3: a b c' 0 335313498Sngie check 'set -- a b c d e f g h i j k l m; echo "$#: ${1}0 ${10} $10"' \ 336313498Sngie '13: a0 j a0' 0 337313498Sngie check 'x="$0"; set -- a b; y="$0"; 338313498Sngie [ "x${x}y" = "x${y}y" ] && echo OK || echo x="$x" y="$y"' \ 339313498Sngie 'OK' 0 340313498Sngie check "${TEST_SH} -c 'echo 0=\$0 1=\$1 2=\$2' a b c" '0=a 1=b 2=c' 0 341313498Sngie 342313498Sngie echo 'echo 0="$0" 1="$1" 2="$2"' > helper.sh 343313498Sngie check "${TEST_SH} helper.sh a b c" '0=helper.sh 1=a 2=b' 0 344313498Sngie 345313498Sngie check 'set -- a bb ccc dddd eeeee ffffff ggggggg hhhhhhhh \ 346313498Sngie iiiiiiiii jjjjjjjjjj kkkkkkkkkkk 347313498Sngie echo "${#}: ${#1} ${#2} ${#3} ${#4} ... ${#9} ${#10} ${#11}"' \ 348313498Sngie '11: 1 2 3 4 ... 9 10 11' 0 349313498Sngie 350313498Sngie check 'set -- a b c; echo "$#: ${1-A} ${2-B} ${3-C} ${4-D} ${5-E}"' \ 351313498Sngie '3: a b c D E' 0 352313498Sngie check 'set -- a "" c "" e 353313498Sngie echo "$#: ${1:-A} ${2:-B} ${3:-C} ${4:-D} ${5:-E}"' \ 354313498Sngie '5: a B c D e' 0 355313498Sngie check 'set -- a "" c "" e 356313498Sngie echo "$#: ${1:+A} ${2:+B} ${3:+C} ${4:+D} ${5:+E}"' \ 357313498Sngie '5: A C E' 0 358313498Sngie check 'set -- "abab*cbb" 359313498Sngie echo "${1} ${1#a} ${1%b} ${1##ab} ${1%%b} ${1#*\*} ${1%\**}"' \ 360313498Sngie 'abab*cbb bab*cbb abab*cb ab*cbb abab*cb cbb abab' 0 361313498Sngie check 'set -- "abab?cbb" 362313498Sngie echo "${1}:${1#*a}+${1%b*}-${1##*a}_${1%%b*}%${1#[ab]}=${1%?*}/${1%\?*}"' \ 363313498Sngie 'abab?cbb:bab?cbb+abab?cb-b?cbb_a%bab?cbb=abab?cb/abab' 0 364313498Sngie check 'set -- a "" c "" e; echo "${2:=b}"' '' 1 365313498Sngie 366313498Sngie results 367313498Sngie} 368313498Sngie 369272343Sngieatf_init_test_cases() { 370272343Sngie atf_add_test_case dollar_at 371272343Sngie atf_add_test_case dollar_at_with_text 372272343Sngie atf_add_test_case strip 373272343Sngie atf_add_test_case varpattern_backslashes 374272343Sngie atf_add_test_case arithmetic 375272343Sngie atf_add_test_case iteration_on_null_parameter 376313498Sngie atf_add_test_case iteration_on_quoted_null_parameter 377313498Sngie atf_add_test_case iteration_on_null_or_null_parameter 378313498Sngie atf_add_test_case iteration_on_null_or_missing_parameter 379313498Sngie atf_add_test_case shell_params 380272343Sngie} 381