1# $NetBSD: t_fsplit.sh,v 1.4 2016/03/27 14:50:01 christos Exp $ 2# 3# Copyright (c) 2007-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 28# The standard 29# http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html 30# explains (section 2.6) that Field splitting should be performed on the 31# result of variable expansions. 32# In particular this means that in ${x-word}, 'word' must be expanded as if 33# the "${x-" and "}" were absent from the input line. 34# 35# So: sh -c 'set ${x-a b c}; echo $#' should give 3. 36# and: sh -c 'set -- ${x-}' echo $#' shold give 0 37# 38 39# the implementation of "sh" to test 40: ${TEST_SH:="/bin/sh"} 41 42nl=' 43' 44 45check() 46{ 47 TEST=$((${TEST} + 1)) 48 49 case "$#" in 50 (2) ;; 51 (*) atf_fail "Internal test error, $# args to check test ${TEST}";; 52 esac 53 54 result=$( ${TEST_SH} -c "unset x; $1" ) 55 STATUS="$?" 56 57 # Remove newlines 58 oifs="$IFS" 59 IFS="$nl" 60 result="$(echo $result)" 61 IFS="$oifs" 62 63 # trim the test text in case we use it in a message below 64 case "$1" in 65 ????????????????*) 66 set -- "$(expr "$1" : '\(............\).*')..." "$2" ;; 67 esac 68 69 if [ "$2" != "$result" ] 70 then 71 if [ "${STATUS}" = "0" ] 72 then 73 atf_fail "Test ${TEST} '$1': expected [$2], found [$result]" 74 else 75 atf_fail \ 76 "TEST ${TEST} '$1' failed ($STATUS): expected [$2], found [$result]" 77 fi 78 elif [ "${STATUS}" != 0 ] 79 then 80 atf_fail "TEST ${TEST} '$1' failed ($STATUS)" 81 fi 82} 83 84atf_test_case for 85for_head() { 86 atf_set "descr" "Checks field splitting in for loops" 87} 88for_body() { 89 unset x 90 91 TEST=0 92 # Since I managed to break this, leave the test in 93 check 'for f in $x; do echo x${f}y; done' '' 94} 95 96atf_test_case default_val 97default_val_head() { 98 atf_set "descr" "Checks field splitting in variable default values" 99} 100default_val_body() { 101 TEST=0 102 # Check that IFS is applied to text from ${x-...} unless it is inside 103 # any set of "..." 104 check 'set -- ${x-a b c}; echo $#' 3 105 106 check 'set -- ${x-"a b" c}; echo $#' 2 107 check 'set -- ${x-a "b c"}; echo $#' 2 108 check 'set -- ${x-"a b c"}; echo $#' 1 109 110 check "set -- \${x-'a b' c}; echo \$#" 2 111 check "set -- \${x-a 'b c'}; echo \$#" 2 112 check "set -- \${x-'a b c'}; echo \$#" 1 113 114 check 'set -- ${x-a\ b c}; echo $#' 2 115 check 'set -- ${x-a b\ c}; echo $#' 2 116 check 'set -- ${x-a\ b\ c}; echo $#' 1 117 118 check 'set -- ${x}; echo $#' 0 119 check 'set -- ${x-}; echo $#' 0 120 check 'set -- ${x-""}; echo $#' 1 121 check 'set -- ""${x}; echo $#' 1 122 check 'set -- ""${x-}; echo $#' 1 123 check 'set -- ""${x-""}; echo $#' 1 124 check 'set -- ${x}""; echo $#' 1 125 check 'set -- ${x-}""; echo $#' 1 126 check 'set -- ${x-""}""; echo $#' 1 127 check 'set -- ""${x}""; echo $#' 1 128 check 'set -- ""${x-}""; echo $#' 1 129 check 'set -- ""${x-""}""; echo $#' 1 130 131 check 'for i in ${x-a b c}; do echo "z${i}z"; done' \ 132 'zaz zbz zcz' 133 check 'for i in ${x-"a b" c}; do echo "z${i}z"; done' \ 134 'za bz zcz' 135 check 'for i in ${x-"a ${x-b c}" d}; do echo "z${i}z"; done' \ 136 'za b cz zdz' 137 check 'for i in ${x-a ${x-b c} d}; do echo "z${i}z"; done' \ 138 'zaz zbz zcz zdz' 139 140 # I am not sure these two are correct, the rules on quoting word 141 # in ${var-word} are peculiar, and hard to fathom... 142 # They are what the NetBSD shell does, and bash, not the freebsd shell 143 # (as of Mar 1, 2016) 144 145 check 'for i in ${x-"a ${x-"b c"}" d}; do echo "z${i}z"; done' \ 146 'za b cz zdz' 147 check 'for i in ${x-a ${x-"b c"} d}; do echo "z${i}z"; done' \ 148 'zaz zb cz zdz' 149} 150 151atf_test_case replacement_val 152replacement_val_head() { 153 atf_set "descr" "Checks field splitting in variable replacement values" 154} 155replacement_val_body() { 156 TEST=0 157 158 # Check that IFS is applied to text from ${x+...} unless it is inside 159 # any set of "...", or whole expansion is quoted, or both... 160 161 check 'x=BOGUS; set -- ${x+a b c}; echo $#' 3 162 163 check 'x=BOGUS; set -- ${x+"a b" c}; echo $#' 2 164 check 'x=BOGUS; set -- ${x+a "b c"}; echo $#' 2 165 check 'x=BOGUS; set -- ${x+"a b c"}; echo $#' 1 166 167 check "x=BOGUS; set -- \${x+'a b' c}; echo \$#" 2 168 check "x=BOGUS; set -- \${x+a 'b c'}; echo \$#" 2 169 check "x=BOGUS; set -- \${x+'a b c'}; echo \$#" 1 170 171 check 'x=BOGUS; set -- ${x+a\ b c}; echo $#' 2 172 check 'x=BOGUS; set -- ${x+a b\ c}; echo $#' 2 173 check 'x=BOGUS; set -- ${x+a\ b\ c}; echo $#' 1 174 175 check 'x=BOGUS; set -- ${x+}; echo $#' 0 176 check 'x=BOGUS; set -- ${x+""}; echo $#' 1 177 check 'x=BOGUS; set -- ""${x+}; echo $#' 1 178 check 'x=BOGUS; set -- ""${x+""}; echo $#' 1 179 check 'x=BOGUS; set -- ${x+}""; echo $#' 1 180 check 'x=BOGUS; set -- ${x+""}""; echo $#' 1 181 check 'x=BOGUS; set -- ""${x+}""; echo $#' 1 182 check 'x=BOGUS; set -- ""${x+""}""; echo $#' 1 183 184 # verify that the value of $x does not affecty the value of ${x+...} 185 check 'x=BOGUS; set -- ${x+}; echo X$1' X 186 check 'x=BOGUS; set -- ${x+""}; echo X$1' X 187 check 'x=BOGUS; set -- ""${x+}; echo X$1' X 188 check 'x=BOGUS; set -- ""${x+""}; echo X$1' X 189 check 'x=BOGUS; set -- ${x+}""; echo X$1' X 190 check 'x=BOGUS; set -- ${x+""}""; echo X$1' X 191 check 'x=BOGUS; set -- ""${x+}""; echo X$1' X 192 check 'x=BOGUS; set -- ""${x+""}""; echo X$1' X 193 194 check 'x=BOGUS; set -- ${x+}; echo X${1-:}X' X:X 195 check 'x=BOGUS; set -- ${x+""}; echo X${1-:}X' XX 196 check 'x=BOGUS; set -- ""${x+}; echo X${1-:}X' XX 197 check 'x=BOGUS; set -- ""${x+""}; echo X${1-:}X' XX 198 check 'x=BOGUS; set -- ${x+}""; echo X${1-:}X' XX 199 check 'x=BOGUS; set -- ${x+""}""; echo X${1-:}X' XX 200 check 'x=BOGUS; set -- ""${x+}""; echo X${1-:}X' XX 201 check 'x=BOGUS; set -- ""${x+""}""; echo X${1-:}X' XX 202 203 # and validate that the replacement can be used as expected 204 check 'x=BOGUS; for i in ${x+a b c}; do echo "z${i}z"; done'\ 205 'zaz zbz zcz' 206 check 'x=BOGUS; for i in ${x+"a b" c}; do echo "z${i}z"; done'\ 207 'za bz zcz' 208 check 'x=BOGUS; for i in ${x+"a ${x+b c}" d}; do echo "z${i}z"; done'\ 209 'za b cz zdz' 210 check 'x=BOGUS; for i in ${x+"a ${x+"b c"}" d}; do echo "z${i}z"; done'\ 211 'za b cz zdz' 212 check 'x=BOGUS; for i in ${x+a ${x+"b c"} d}; do echo "z${i}z"; done'\ 213 'zaz zb cz zdz' 214 check 'x=BOGUS; for i in ${x+a ${x+b c} d}; do echo "z${i}z"; done'\ 215 'zaz zbz zcz zdz' 216} 217 218atf_test_case ifs_alpha 219ifs_alpha_head() { 220 atf_set "descr" "Checks that field splitting works with alphabetic" \ 221 "characters" 222} 223ifs_alpha_body() { 224 unset x 225 226 TEST=0 227 # repeat with an alphabetic in IFS 228 check 'IFS=q; set ${x-aqbqc}; echo $#' 3 229 check 'IFS=q; for i in ${x-aqbqc}; do echo "z${i}z"; done' \ 230 'zaz zbz zcz' 231 check 'IFS=q; for i in ${x-"aqb"qc}; do echo "z${i}z"; done' \ 232 'zaqbz zcz' 233 check 'IFS=q; for i in ${x-"aq${x-bqc}"qd}; do echo "z${i}z"; done' \ 234 'zaqbqcz zdz' 235 check 'IFS=q; for i in ${x-"aq${x-"bqc"}"qd}; do echo "z${i}z"; done' \ 236 'zaqbqcz zdz' 237 check 'IFS=q; for i in ${x-aq${x-"bqc"}qd}; do echo "z${i}z"; done' \ 238 'zaz zbqcz zdz' 239} 240 241atf_test_case quote 242quote_head() { 243 atf_set "descr" "Checks that field splitting works with multi-word" \ 244 "fields" 245} 246quote_body() { 247 unset x 248 249 TEST=0 250 # Some quote propagation checks 251 check 'set "${x-a b c}"; echo $#' 1 252 check 'set "${x-"a b" c}"; echo $1' 'a b c' 253 check 'for i in "${x-a b c}"; do echo "z${i}z"; done' 'za b cz' 254} 255 256atf_test_case dollar_at 257dollar_at_head() { 258 atf_set "descr" "Checks that field splitting works when expanding" \ 259 "\$@" 260} 261dollar_at_body() { 262 unset x 263 264 TEST=0 265 # Check we get "$@" right 266 267 check 'set --; for i in x"$@"x; do echo "z${i}z"; done' 'zxxz' 268 check 'set a; for i in x"$@"x; do echo "z${i}z"; done' 'zxaxz' 269 check 'set a b; for i in x"$@"x; do echo "z${i}z"; done' 'zxaz zbxz' 270 271 check 'set --; for i; do echo "z${i}z"; done' '' 272 check 'set --; for i in $@; do echo "z${i}z"; done' '' 273 check 'set --; for i in "$@"; do echo "z${i}z"; done' '' 274 # atf_expect_fail "PR bin/50834" 275 check 'set --; for i in ""$@; do echo "z${i}z"; done' 'zz' 276 # atf_expect_pass 277 check 'set --; for i in $@""; do echo "z${i}z"; done' 'zz' 278 check 'set --; for i in ""$@""; do echo "z${i}z"; done' 'zz' 279 check 'set --; for i in """$@"; do echo "z${i}z"; done' 'zz' 280 check 'set --; for i in "$@"""; do echo "z${i}z"; done' 'zz' 281 check 'set --; for i in """$@""";do echo "z${i}z"; done' 'zz' 282 283 check 'set ""; for i; do echo "z${i}z"; done' 'zz' 284 check 'set ""; for i in "$@"; do echo "z${i}z"; done' 'zz' 285 check 'set "" ""; for i; do echo "z${i}z"; done' 'zz zz' 286 check 'set "" ""; for i in "$@"; do echo "z${i}z"; done' 'zz zz' 287 check 'set "" ""; for i in $@; do echo "z${i}z"; done' '' 288 289 check 'set "a b" c; for i; do echo "z${i}z"; done' \ 290 'za bz zcz' 291 check 'set "a b" c; for i in "$@"; do echo "z${i}z"; done' \ 292 'za bz zcz' 293 check 'set "a b" c; for i in $@; do echo "z${i}z"; done' \ 294 'zaz zbz zcz' 295 check 'set " a b " c; for i in "$@"; do echo "z${i}z"; done' \ 296 'z a b z zcz' 297 298 check 'set a b c; for i in "$@$@"; do echo "z${i}z"; done' \ 299 'zaz zbz zcaz zbz zcz' 300 check 'set a b c; for i in "$@""$@";do echo "z${i}z"; done' \ 301 'zaz zbz zcaz zbz zcz' 302} 303 304atf_test_case ifs 305ifs_head() { 306 atf_set "descr" "Checks that IFS correctly configures field" \ 307 "splitting behavior" 308} 309ifs_body() { 310 unset x 311 312 TEST=0 313 # Some IFS tests 314 check 't="-- "; IFS=" "; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '0' 315 check 't=" x"; IFS=" x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '1' 316 check 't=" x "; IFS=" x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '1' 317 check 't=axb; IFS="x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '2 a:b' 318 check 't="a x b"; IFS="x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '2 a : b' 319 check 't="a xx b"; IFS="x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '3 a :: b' 320 check 't="a xx b"; IFS="x "; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '3 a::b' 321 # A recent 'clarification' means that a single trailing IFS non-whitespace 322 # doesn't generate an empty parameter 323 check 't="xax"; IFS="x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '2 :a' 324 check 't="xax "; IFS="x "; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '2 :a' 325 # Verify that IFS isn't being applied where it shouldn't be. 326 check 'IFS="x"; set axb; IFS=":"; r="$*"; IFS=; echo $# $r' '1 axb' 327} 328 329atf_test_case var_length 330var_length_head() { 331 atf_set "descr" "Checks that field splitting works when expanding" \ 332 "a variable's length" 333} 334var_length_body() { 335 TEST=0 336 337 long=12345678123456781234567812345678 338 long=$long$long$long$long 339 export long 340 341 # first test that the test method works... 342 check 'set -u; : ${long}; echo ${#long}' '128' 343 344 # Check that we apply IFS to ${#var} 345 check 'echo ${#long}; IFS=2; echo ${#long}; set 1 ${#long};echo $#' \ 346 '128 1 8 3' 347 check 'IFS=2; set ${x-${#long}}; IFS=" "; echo $* $#' '1 8 2' 348 check 'IFS=2; set ${x-"${#long}"}; IFS=" "; echo $* $#' '128 1' 349} 350 351atf_init_test_cases() { 352 atf_add_test_case for 353 atf_add_test_case default_val 354 atf_add_test_case replacement_val 355 atf_add_test_case ifs_alpha 356 atf_add_test_case quote 357 atf_add_test_case dollar_at 358 atf_add_test_case ifs 359 atf_add_test_case var_length 360} 361