1 1.6 kre # $NetBSD: t_builtins.sh,v 1.6 2021/05/18 21:37:56 kre Exp $ 2 1.1 kre # 3 1.2 kre # Copyright (c) 2018 The NetBSD Foundation, Inc. 4 1.1 kre # All rights reserved. 5 1.1 kre # 6 1.1 kre # Redistribution and use in source and binary forms, with or without 7 1.1 kre # modification, are permitted provided that the following conditions 8 1.1 kre # are met: 9 1.1 kre # 1. Redistributions of source code must retain the above copyright 10 1.1 kre # notice, this list of conditions and the following disclaimer. 11 1.1 kre # 2. Redistributions in binary form must reproduce the above copyright 12 1.1 kre # notice, this list of conditions and the following disclaimer in the 13 1.1 kre # documentation and/or other materials provided with the distribution. 14 1.1 kre # 15 1.1 kre # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 1.1 kre # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 1.1 kre # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 1.1 kre # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 1.1 kre # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 1.1 kre # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 1.1 kre # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 1.1 kre # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 1.1 kre # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 1.1 kre # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 kre # POSSIBILITY OF SUCH DAMAGE. 26 1.1 kre # 27 1.1 kre # the implementation of "sh" to test 28 1.1 kre : ${TEST_SH:="/bin/sh"} 29 1.1 kre 30 1.1 kre # 31 1.1 kre # This file tests the various sh builtin utilities. 32 1.1 kre # 33 1.1 kre # Those utilities that are really external programs, which are builtin in 34 1.1 kre # for (mostly) performance (printf, kill, test, ...), are tested elsewhere. 35 1.1 kre # We do test the builtin "echo" here as (in NetBSD) it is different than 36 1.1 kre # the external one. 37 1.1 kre # 38 1.1 kre # The (mostly special) builtins which appear to be more syntax than command 39 1.1 kre # are tested in other test programs, rather than here (break, continue...) 40 1.1 kre # 41 1.1 kre # And finally, those which are fundamental to the operation of the shell, 42 1.1 kre # like wait, set, shift, ... are also tested in other test programs where 43 1.1 kre # all their operations can be more thoroughly verified. 44 1.1 kre # 45 1.1 kre # This leaves those which need to be built in (cd, umask, ...) but whose 46 1.1 kre # purpose is mostly to alter the environment in which the shell operates 47 1.1 kre # of that of the commands it runs. These tests act in co-operation with 48 1.1 kre # other tests exist here (where thy do) by not duplicating tests run 49 1.1 kre # elsewhere (ulimit is one example) but just adding to those. 50 1.1 kre # One day these might be unified. 51 1.1 kre # 52 1.1 kre # We do test both standard use of the builtins (where they are standard) 53 1.1 kre # and NetBSD sh extensions (when run on a shell with no support, such tests 54 1.1 kre # should be skipped.) 55 1.1 kre # 56 1.1 kre 57 1.1 kre # Utility function able to test whether most of the builtins exist in 58 1.1 kre # the shell being tested. 59 1.1 kre have_builtin() 60 1.1 kre { 61 1.1 kre ${TEST_SH} -c "( $3 $1 $4 ) >/dev/null 2>&1" && 62 1.1 kre LC_ALL=C ${TEST_SH} -c \ 63 1.1 kre 'case "$( (type '"$1"') 2>&1)" in 64 1.1 kre (*built*) exit 0 ;; 65 1.3 kre (*reserved*) exit 0 ;; # zsh!! (reserved words are builtin) 66 1.1 kre esac 67 1.1 kre exit 1' || 68 1.1 kre { 69 1.1 kre test -z "$2" && atf_skip "${TEST_SH} has no '$1$5' built-in" 70 1.1 kre return 1; 71 1.1 kre } 72 1.1 kre 73 1.1 kre return 0 74 1.1 kre } 75 1.1 kre 76 1.5 kre # And another to test if the shell being tested is the NetBSD shell, 77 1.5 kre # as we use these tests both to test standards conformance (correctness) 78 1.5 kre # which should be possible for all shells, and to test NetBSD 79 1.5 kre # extensions (which we mostly do by testing if the extension exists) 80 1.5 kre # and NetBSD sh behaviour for what is unspecified by the standard 81 1.5 kre # (so we will be notified via test failure should that unspecified 82 1.5 kre # behaviour alter) for which we have to discover if that shell is the 83 1.5 kre # one being tested. 84 1.5 kre 85 1.5 kre is_netbsd_sh() 86 1.5 kre { 87 1.5 kre unset NETBSD_SHELL 2>/dev/null 88 1.5 kre test -n "$( ${TEST_SH} -c 'printf %s "${NETBSD_SHELL}"')" 89 1.5 kre } 90 1.5 kre 91 1.1 kre ### Helper functions 92 1.1 kre 93 1.1 kre nl=' 94 1.1 kre ' 95 1.1 kre reset() 96 1.1 kre { 97 1.1 kre TEST_NUM=0 98 1.1 kre TEST_FAILURES='' 99 1.1 kre TEST_FAIL_COUNT=0 100 1.1 kre TEST_ID="$1" 101 1.1 kre 102 1.1 kre # These are used in check() 103 1.1 kre atf_require_prog tr 104 1.1 kre atf_require_prog printf 105 1.1 kre atf_require_prog mktemp 106 1.1 kre } 107 1.1 kre 108 1.1 kre # Test run & validate. 109 1.1 kre # 110 1.1 kre # $1 is the command to run (via sh -c) 111 1.1 kre # $2 is the expected output 112 1.1 kre # $3 is the expected exit status from sh 113 1.1 kre # $4 is optional extra data for the error msg (if there is one) 114 1.1 kre # 115 1.1 kre # Stderr is exxpected to be empty, unless the expected exit code ($3) is != 0 116 1.1 kre # in which case some message there is expected (and nothing is a failure). 117 1.1 kre # When non-zero exit is expected, we note a different (non-zero) value 118 1.1 kre # observed, but do not fail the test because of that. 119 1.1 kre 120 1.1 kre check() 121 1.1 kre { 122 1.1 kre fail=false 123 1.1 kre TEMP_FILE=$( mktemp OUT.XXXXXX ) 124 1.1 kre TEST_NUM=$(( $TEST_NUM + 1 )) 125 1.1 kre MSG= 126 1.1 kre 127 1.1 kre # our local shell (ATF_SHELL) better do quoting correctly... 128 1.1 kre # some of the tests expect us to expand $nl internally... 129 1.1 kre CMD="$1" 130 1.1 kre 131 1.1 kre # determine what the test generates, preserving trailing \n's 132 1.1 kre result="$( ${TEST_SH} -c "${CMD}" 2>"${TEMP_FILE}" && printf X )" 133 1.1 kre STATUS=$? 134 1.1 kre result="${result%X}" 135 1.1 kre 136 1.1 kre 137 1.1 kre if [ "${STATUS}" -ne "$3" ]; then 138 1.1 kre MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 139 1.1 kre MSG="${MSG} expected exit code $3, got ${STATUS}" 140 1.1 kre 141 1.1 kre # don't actually fail just because of wrong exit code 142 1.1 kre # unless we either expected, or received "good" 143 1.1 kre # or something else is detected as incorrect as well. 144 1.1 kre case "$3/${STATUS}" in 145 1.1 kre (*/0|0/*) fail=true;; 146 1.1 kre esac 147 1.1 kre fi 148 1.1 kre 149 1.1 kre if [ "$3" -eq 0 ]; then 150 1.1 kre if [ -s "${TEMP_FILE}" ]; then 151 1.1 kre MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 152 1.1 kre MSG="${MSG} Messages produced on stderr unexpected..." 153 1.1 kre MSG="${MSG}${nl}$( cat "${TEMP_FILE}" )" 154 1.1 kre fail=true 155 1.1 kre fi 156 1.1 kre else 157 1.1 kre if ! [ -s "${TEMP_FILE}" ]; then 158 1.1 kre MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 159 1.1 kre MSG="${MSG} Expected messages on stderr," 160 1.1 kre MSG="${MSG} nothing produced" 161 1.1 kre fail=true 162 1.1 kre fi 163 1.1 kre fi 164 1.1 kre rm -f "${TEMP_FILE}" 165 1.1 kre 166 1.1 kre if [ "$2" != "${result}" ] 167 1.1 kre then 168 1.1 kre MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 169 1.1 kre MSG="${MSG} Expected: <<$2>>, received: <<$result>>" 170 1.1 kre fail=true 171 1.1 kre fi 172 1.1 kre 173 1.1 kre if $fail 174 1.1 kre then 175 1.1 kre if [ -n "$4" ]; then 176 1.1 kre MSG="${MSG}${MSG:+${nl}}[$TEST_NUM] Note: ${4}" 177 1.1 kre fi 178 1.1 kre MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]" 179 1.1 kre MSG="${MSG} Full command: <<${CMD}>>" 180 1.1 kre fi 181 1.1 kre 182 1.1 kre $fail && test -n "$TEST_ID" && { 183 1.1 kre TEST_FAILURES="${TEST_FAILURES}${TEST_FAILURES:+${nl}}" 184 1.1 kre TEST_FAILURES="${TEST_FAILURES}${TEST_ID}[$TEST_NUM]:" 185 1.1 kre TEST_FAILURES="${TEST_FAILURES} Test of <<$1>> failed."; 186 1.1 kre TEST_FAILURES="${TEST_FAILURES}${nl}${MSG}" 187 1.1 kre TEST_FAIL_COUNT=$(( $TEST_FAIL_COUNT + 1 )) 188 1.1 kre return 0 189 1.1 kre } 190 1.1 kre $fail && atf_fail "Test[$TEST_NUM] failed: $( 191 1.1 kre # ATF does not like newlines in messages, so change them... 192 1.1 kre printf '%s' "${MSG}" | tr '\n' ';' 193 1.1 kre )" 194 1.1 kre return 0 195 1.1 kre } 196 1.1 kre 197 1.1 kre results() 198 1.1 kre { 199 1.1 kre test -n "$1" && atf_expect_fail "$1" 200 1.1 kre 201 1.1 kre test -z "${TEST_ID}" && return 0 202 1.1 kre test -z "${TEST_FAILURES}" && return 0 203 1.1 kre 204 1.1 kre echo >&2 "==========================================" 205 1.1 kre echo >&2 "While testing '${TEST_ID}'" 206 1.1 kre echo >&2 " - - - - - - - - - - - - - - - - -" 207 1.1 kre echo >&2 "${TEST_FAILURES}" 208 1.1 kre 209 1.1 kre atf_fail \ 210 1.1 kre "Test ${TEST_ID}: $TEST_FAIL_COUNT (of $TEST_NUM) subtests failed - see stderr" 211 1.1 kre } 212 1.1 kre 213 1.1 kre ####### End helpers 214 1.1 kre 215 1.1 kre atf_test_case colon 216 1.1 kre colon_head() { 217 1.1 kre atf_set "descr" "Tests the shell special builtin ':' command" 218 1.1 kre } 219 1.1 kre colon_body() { 220 1.1 kre have_builtin : || return 0 221 1.1 kre 222 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c ":" 223 1.1 kre 224 1.1 kre # ':' is a special builtin, so we should exit on redirect error 225 1.1 kre # and variable assignments should persist (stupid, but it is the rule) 226 1.1 kre 227 1.1 kre atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \ 228 1.1 kre ": >/foo/bar; printf %s No-exit-BUG" 229 1.1 kre atf_check -s exit:0 -e empty -o inline:OK ${TEST_SH} -c \ 230 1.1 kre 'X=BUG; X=OK : ; printf %s "${X}"' 231 1.1 kre } 232 1.1 kre 233 1.1 kre atf_test_case echo 234 1.1 kre echo_head() { 235 1.1 kre atf_set "descr" "Tests the shell builtin version of echo" 236 1.1 kre } 237 1.1 kre echo_body() { 238 1.1 kre have_builtin echo || return 0 239 1.1 kre 240 1.5 kre if ! is_netbsd_sh; then 241 1.1 kre atf_skip \ 242 1.1 kre "${TEST_SH%% *} is not the NetBSD shell, this test is for it alone" 243 1.1 kre return 0 244 1.1 kre fi 245 1.1 kre 246 1.1 kre reset echo 247 1.1 kre 248 1.1 kre check 'echo "hello world"' "hello world${nl}" 0 249 1.1 kre check 'echo hello world' "hello world${nl}" 0 250 1.1 kre check 'echo -n "hello world"' "hello world" 0 251 1.1 kre check 'IFS=:; echo hello world' "hello world${nl}" 0 252 1.1 kre check 'IFS=; echo hello world' "hello world${nl}" 0 253 1.1 kre 254 1.1 kre check 'echo -e "hello world"' "hello world${nl}" 0 255 1.1 kre check 'echo -e hello world' "hello world${nl}" 0 256 1.1 kre check 'IFS=:; echo -e hello world' "hello world${nl}" 0 257 1.1 kre 258 1.1 kre # only one of the options is used 259 1.1 kre check 'echo -e -n "hello world"' "-n hello world${nl}" 0 260 1.1 kre check 'echo -n -e "hello world"' "-e hello world" 0 261 1.1 kre # and only when it is alone 262 1.1 kre check 'echo -en "hello world"' "-en hello world${nl}" 0 263 1.1 kre check 'echo -ne "hello world"' "-ne hello world${nl}" 0 264 1.1 kre 265 1.1 kre # echo is specifically required to *not* support -- 266 1.1 kre check 'echo -- "hello world"' "-- hello world${nl}" 0 267 1.1 kre 268 1.1 kre # similarly any other unknown option is simply part of the output 269 1.1 kre for OPT in a b c v E N Q V 0 1 2 @ , \? \[ \] \( \; . \* -help -version 270 1.1 kre do 271 1.1 kre check "echo '-${OPT}' foo" "-${OPT} foo${nl}" 0 272 1.1 kre done 273 1.1 kre 274 1.1 kre # Now test the \\ expansions, with and without -e 275 1.1 kre 276 1.1 kre # We rely upon printf %b (tested elsewhere, not only a sh test) 277 1.1 kre # to verify the output when the \\ is supposed to be expanded. 278 1.1 kre 279 1.1 kre for E in '' -e 280 1.1 kre do 281 1.1 kre for B in a b c e f n r t v \\ 04 010 012 0177 282 1.1 kre do 283 1.1 kre S="test string with \\${B} in it" 284 1.1 kre if [ -z "${E}" ]; then 285 1.1 kre R="${S}${nl}" 286 1.1 kre else 287 1.1 kre R="$(printf '%b\nX' "${S}")" 288 1.1 kre R=${R%X} 289 1.1 kre fi 290 1.1 kre check "echo $E '${S}'" "${R}" 0 291 1.1 kre done 292 1.1 kre done 293 1.1 kre 294 1.6 kre check 'echo foo >&-' "" 1 295 1.6 kre check 'echo foo >&- 2>&-; echo $?; echo $?' "1${nl}0${nl}" 0 296 1.6 kre 297 1.1 kre results 298 1.1 kre } 299 1.1 kre 300 1.1 kre atf_test_case eval 301 1.1 kre eval_head() { 302 1.1 kre atf_set "descr" "Tests the shell special builtin 'eval'" 303 1.1 kre } 304 1.1 kre eval_body() { 305 1.1 kre have_builtin eval || return 0 306 1.1 kre 307 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'eval "exit 0"' 308 1.1 kre atf_check -s exit:1 -e empty -o empty ${TEST_SH} -c 'eval "exit 1"' 309 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'eval exit 0' 310 1.5 kre atf_check -s exit:1 -e empty -o empty ${TEST_SH} -c 'eval exit 1' 311 1.5 kre 312 1.5 kre atf_check -s exit:0 -e empty -o inline:0 ${TEST_SH} -c \ 313 1.5 kre 'eval true; printf %d $?' 314 1.5 kre atf_check -s exit:0 -e empty -o inline:1 ${TEST_SH} -c \ 315 1.5 kre 'eval false; printf %d $?' 316 1.1 kre 317 1.1 kre atf_check -s exit:0 -e empty -o inline:abc ${TEST_SH} -c \ 318 1.1 kre 'X=a Y=b Z=c; for V in X Y Z; do eval "printf %s \$$V"; done' 319 1.1 kre atf_check -s exit:0 -e empty -o inline:abc ${TEST_SH} -c \ 320 1.1 kre 'X=a Y=b Z=c; for V in X Y Z; do eval printf %s \$$V; done' 321 1.1 kre atf_check -s exit:0 -e empty -o inline:XYZ ${TEST_SH} -c \ 322 1.1 kre 'for V in X Y Z; do eval "${V}=${V}"; done; printf %s "$X$Y$Z"' 323 1.5 kre 324 1.5 kre # make sure eval'd strings affect the shell environment 325 1.5 kre 326 1.5 kre atf_check -s exit:0 -e empty -o inline:/b/ ${TEST_SH} -c \ 327 1.5 kre 'X=a; eval "X=b"; printf /%s/ "${X-unset}"' 328 1.5 kre atf_check -s exit:0 -e empty -o inline:/b/ ${TEST_SH} -c \ 329 1.5 kre 'X=a; Y=X; Z=b; eval "$Y=$Z"; printf /%s/ "${X-unset}"' 330 1.5 kre atf_check -s exit:0 -e empty -o inline:/unset/ ${TEST_SH} -c \ 331 1.5 kre 'X=a; eval "unset X"; printf /%s/ "${X-unset}"' 332 1.5 kre atf_check -s exit:0 -e empty -o inline:// ${TEST_SH} -c \ 333 1.5 kre 'unset X; eval "X="; printf /%s/ "${X-unset}"' 334 1.5 kre atf_check -s exit:0 -e empty -o inline:'2 y Z ' ${TEST_SH} -c \ 335 1.5 kre 'set -- X y Z; eval shift; printf "%s " "$#" "$@"' 336 1.5 kre 337 1.5 kre # ensure an error in an eval'd string causes the shell to exit 338 1.5 kre # unless 'eval' is preceded by 'command' (in which case the 339 1.5 kre # string is not eval'd but execution continues) 340 1.5 kre 341 1.5 kre atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \ 342 1.5 kre 'eval "if done"; printf %s status=$?' 343 1.5 kre 344 1.5 kre atf_check -s exit:0 -e not-empty -o 'match:status=[1-9]' \ 345 1.5 kre ${TEST_SH} -c \ 346 1.5 kre 'command eval "if done"; printf %s status=$?' 347 1.5 kre 348 1.5 kre atf_check -s not-exit:0 -e not-empty \ 349 1.5 kre -o 'match:status=[1-9]' -o 'not-match:[XY]' ${TEST_SH} -c \ 350 1.5 kre 'command eval "printf X; if done; printf Y" 351 1.5 kre S=$?; printf %s status=$S; exit $S' 352 1.5 kre 353 1.5 kre # whether 'X' is output here is (or should be) unspecified. 354 1.5 kre atf_check -s not-exit:0 -e not-empty \ 355 1.5 kre -o 'match:status=[1-9]' -o 'not-match:Y' ${TEST_SH} -c \ 356 1.5 kre 'command eval "printf X 357 1.5 kre if done 358 1.5 kre printf Y" 359 1.5 kre S=$?; printf %s status=$S; exit $S' 360 1.5 kre 361 1.5 kre if is_netbsd_sh 362 1.5 kre then 363 1.5 kre # but on NetBSD we expect that X to appear... 364 1.5 kre atf_check -s not-exit:0 -e not-empty -o 'match:X' \ 365 1.5 kre -o 'match:status=[1-9]' -o 'not-match:Y' ${TEST_SH} -c \ 366 1.5 kre 'command eval "printf X 367 1.5 kre if done 368 1.5 kre printf Y" 369 1.5 kre S=$?; printf %s status=$S; exit $S' 370 1.5 kre fi 371 1.1 kre } 372 1.1 kre 373 1.1 kre atf_test_case exec 374 1.1 kre exec_head() { 375 1.1 kre atf_set "descr" "Tests the shell special builtin 'exec'" 376 1.1 kre } 377 1.1 kre exec_body() { 378 1.1 kre have_builtin exec || return 0 379 1.1 kre 380 1.1 kre atf_check -s exit:0 -e empty -o inline:OK ${TEST_SH} -c \ 381 1.1 kre 'exec printf OK; printf BROKEN; exit 3' 382 1.1 kre atf_check -s exit:3 -e empty -o inline:OKOK ${TEST_SH} -c \ 383 1.1 kre '(exec printf OK); printf OK; exit 3' 384 1.1 kre } 385 1.1 kre 386 1.1 kre atf_test_case export 387 1.1 kre export_head() { 388 1.1 kre atf_set "descr" "Tests the shell builtin 'export'" 389 1.1 kre } 390 1.1 kre export_body() { 391 1.1 kre have_builtin export || return 0 392 1.1 kre 393 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'export VAR' 394 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'export VAR=abc' 395 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'export V A R' 396 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \ 397 1.1 kre 'export V A=1 R=2' 398 1.1 kre 399 1.1 kre atf_require_prog printenv 400 1.1 kre 401 1.1 kre atf_check -s exit:1 -e empty -o empty ${TEST_SH} -c \ 402 1.1 kre 'unset VAR || exit 7; export VAR; printenv VAR' 403 1.1 kre atf_check -s exit:0 -e empty -o inline:\\n ${TEST_SH} -c \ 404 1.1 kre 'unset VAR || exit 7; export VAR=; printenv VAR' 405 1.1 kre atf_check -s exit:0 -e empty -o inline:\\n ${TEST_SH} -c \ 406 1.1 kre 'unset VAR || exit 7; VAR=; export VAR; printenv VAR' 407 1.1 kre atf_check -s exit:0 -e empty -o inline:\\n ${TEST_SH} -c \ 408 1.1 kre 'unset VAR || exit 7; export VAR; VAR=; printenv VAR' 409 1.1 kre atf_check -s exit:0 -e empty -o inline:XYZ\\n ${TEST_SH} -c \ 410 1.1 kre 'unset VAR || exit 7; export VAR=XYZ; printenv VAR' 411 1.1 kre atf_check -s exit:0 -e empty -o inline:ABC\\n ${TEST_SH} -c \ 412 1.1 kre 'VAR=ABC; export VAR; printenv VAR' 413 1.1 kre atf_check -s exit:0 -e empty -o inline:ABC\\n ${TEST_SH} -c \ 414 1.1 kre 'unset VAR || exit 7; export VAR; VAR=ABC; printenv VAR' 415 1.1 kre atf_check -s exit:0 -e empty -o inline:ABC\\nXYZ\\n ${TEST_SH} -c \ 416 1.1 kre 'VAR=ABC; export VAR; printenv VAR; VAR=XYZ; printenv VAR' 417 1.1 kre atf_check -s exit:0 -e empty -o inline:ABC\\nXYZ\\n ${TEST_SH} -c \ 418 1.1 kre 'unset VAR || exit 7; export VAR; 419 1.1 kre VAR=ABC; printenv VAR; VAR=XYZ; printenv VAR' 420 1.1 kre 421 1.3 kre # don't check VAR=value, some shells provide meaningless quoting... 422 1.3 kre atf_check -s exit:0 -e empty -o match:VAR= -o match:foobar \ 423 1.3 kre ${TEST_SH} -c \ 424 1.3 kre 'VAR=foobar ; export VAR ; export -p' 425 1.3 kre atf_check -s exit:0 -e empty -o match:VAR= -o match:foobar \ 426 1.3 kre ${TEST_SH} -c \ 427 1.3 kre 'export VAR=foobar ; export -p' 428 1.3 kre atf_check -s exit:0 -e empty -o match:VAR\$ ${TEST_SH} -c \ 429 1.3 kre 'unset VAR ; export VAR ; export -p' 430 1.3 kre atf_check -s exit:0 -e empty -o not-match:VAR ${TEST_SH} -c \ 431 1.3 kre 'export VAR ; unset VAR ; export -p' 432 1.3 kre atf_check -s exit:0 -e empty -o not-match:VAR -o not-match:foobar \ 433 1.3 kre ${TEST_SH} -c \ 434 1.3 kre 'VAR=foobar; export VAR ; unset VAR ; export -p' 435 1.3 kre 436 1.3 kre atf_check -s exit:0 -e empty -o match:VAR= -o match:FOUND=foobar \ 437 1.3 kre ${TEST_SH} -c \ 438 1.3 kre 'export VAR=foobar; V=$(export -p); 439 1.3 kre unset VAR; eval "$V"; export -p; 440 1.3 kre printf %s\\n FOUND=${VAR-unset}' 441 1.3 kre atf_check -s exit:0 -e empty -o match:VAR -o match:FOUND=unset \ 442 1.3 kre ${TEST_SH} -c \ 443 1.3 kre 'export VAR; V=$(export -p); 444 1.3 kre unset VAR; eval "$V"; export -p; 445 1.3 kre printf %s\\n FOUND=${VAR-unset}' 446 1.3 kre 447 1.1 kre atf_check -s exit:1 -e empty -o inline:ABC\\nXYZ\\n ${TEST_SH} -c \ 448 1.1 kre 'VAR=ABC; export VAR; printenv VAR; VAR=XYZ; printenv VAR; 449 1.1 kre unset VAR; printenv VAR; VAR=PQR; printenv VAR' 450 1.1 kre atf_check -s exit:0 -e empty -o inline:ABC\\nXYZ\\nVAR=unset\\nMNO\\n \ 451 1.1 kre ${TEST_SH} -c \ 452 1.1 kre 'VAR=ABC; export VAR; printenv VAR; VAR=XYZ; printenv VAR; 453 1.1 kre unset VAR; printf %s\\n "VAR=${VAR-unset}"; printenv VAR; 454 1.1 kre VAR=PQR; printenv VAR; VAR=MNO; export VAR; printenv VAR' 455 1.1 kre } 456 1.1 kre 457 1.1 kre atf_test_case export_nbsd 458 1.1 kre export_nbsd_head() { 459 1.1 kre atf_set "descr" "Tests NetBSD extensions to the shell builtin 'export'" 460 1.1 kre } 461 1.1 kre export_nbsd_body() { 462 1.1 kre have_builtin "export" "" "" "-n foo" ' -n' || return 0 463 1.1 kre 464 1.1 kre atf_require_prog printenv 465 1.1 kre 466 1.1 kre atf_check -s exit:1 -e empty -o inline:ABC\\nXYZ\\n ${TEST_SH} -c \ 467 1.1 kre 'VAR=ABC; export VAR; printenv VAR; VAR=XYZ; printenv VAR; 468 1.1 kre export -n VAR; printenv VAR; VAR=PQR; printenv VAR' 469 1.1 kre 470 1.1 kre atf_check -s exit:0 -e empty -o inline:ABC\\nXYZ\\nVAR=XYZ\\nMNO\\n \ 471 1.1 kre ${TEST_SH} -c \ 472 1.1 kre 'VAR=ABC; export VAR; printenv VAR; VAR=XYZ; printenv VAR; 473 1.1 kre export -n VAR; printf %s\\n "VAR=${VAR-unset}"; printenv VAR; 474 1.1 kre VAR=PQR; printenv VAR; VAR=MNO; export VAR; printenv VAR' 475 1.1 kre 476 1.1 kre have_builtin "export" "" "" -x ' -x' || return 0 477 1.1 kre 478 1.1 kre atf_check -s exit:1 -e empty -o empty ${TEST_SH} -c \ 479 1.1 kre 'export VAR=exported; export -x VAR; printenv VAR' 480 1.1 kre atf_check -s exit:1 -e empty -o empty ${TEST_SH} -c \ 481 1.1 kre 'export VAR=exported; export -x VAR; VAR=local; printenv VAR' 482 1.1 kre atf_check -s exit:0 -e empty -o inline:once\\nx\\n ${TEST_SH} -c \ 483 1.1 kre 'export VAR=exported 484 1.1 kre export -x VAR 485 1.1 kre VAR=once printenv VAR 486 1.1 kre printenv VAR || printf %s\\n x' 487 1.1 kre 488 1.1 kre atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \ 489 1.1 kre 'export VAR=exported; export -x VAR; export VAR=FOO' 490 1.4 kre 491 1.4 kre have_builtin export '' 'export VAR;' '-q VAR' ' -q' || return 0 492 1.4 kre 493 1.4 kre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 494 1.4 kre 'unset VAR; VAR=set; export -q VAR' 495 1.4 kre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 496 1.4 kre 'export VAR=set; export -q VAR' 497 1.4 kre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 498 1.4 kre 'VAR=set; RW=set; export -q VAR RW' 499 1.4 kre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 500 1.4 kre 'VAR=set; export RO=set; export -q VAR RO' 501 1.4 kre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 502 1.4 kre 'export VAR=set RO=set; export -q VAR RO' 503 1.4 kre 504 1.4 kre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 505 1.4 kre 'unset VAR; export -q VAR' 506 1.4 kre # next one is the same as the have_builtin test, so "cannot" fail... 507 1.4 kre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 508 1.4 kre 'unset VAR; export VAR; export -q VAR' 509 1.4 kre 510 1.4 kre # if we have -q we should also have -p var... 511 1.4 kre # What's more, we are testing NetBSD sh, so we know output format. 512 1.4 kre 513 1.4 kre atf_check -s exit:0 -e empty -o match:VAR=foobar \ 514 1.4 kre ${TEST_SH} -c \ 515 1.4 kre 'VAR=foobar ; export VAR ; export -p VAR' 516 1.4 kre atf_check -s exit:0 -e empty -o inline:1 \ 517 1.4 kre ${TEST_SH} -c \ 518 1.4 kre 'VAR=foobar ; export VAR ; 519 1.4 kre printf %d $(export -p VAR | wc -l)' 520 1.4 kre atf_check -s exit:0 -e empty \ 521 1.4 kre -o inline:'export VAR=foobar\nexport OTHER\n' \ 522 1.4 kre ${TEST_SH} -c \ 523 1.4 kre 'VAR=foobar; export VAR OTHER; export -p VAR OTHER' 524 1.4 kre atf_check -s exit:0 -e empty \ 525 1.4 kre -o inline:'export A=aaa\nexport B\nexport D='"''"'\n' \ 526 1.4 kre ${TEST_SH} -c \ 527 1.4 kre 'A=aaa D= C=foo; unset B; export A B D; 528 1.4 kre export -p A B C D' 529 1.1 kre } 530 1.1 kre 531 1.1 kre atf_test_case getopts 532 1.1 kre getopts_head() { 533 1.1 kre atf_set "descr" "Tests the shell builtin 'getopts'" 534 1.1 kre } 535 1.1 kre getopts_body() { 536 1.1 kre have_builtin getopts "" "f() {" "a x; }; f -a" || return 0 537 1.1 kre } 538 1.1 kre 539 1.1 kre atf_test_case jobs 540 1.1 kre jobs_head() { 541 1.1 kre atf_set "descr" "Tests the shell builting 'jobs' command" 542 1.1 kre } 543 1.1 kre jobs_body() { 544 1.1 kre have_builtin jobs || return 0 545 1.1 kre 546 1.1 kre atf_require_prog sleep 547 1.1 kre 548 1.1 kre # note that POSIX requires that we reference $! otherwise 549 1.1 kre # the shell is not required to remember the process... 550 1.1 kre 551 1.1 kre atf_check -s exit:0 -e empty -o match:sleep -o match:Running \ 552 1.1 kre ${TEST_SH} -c 'sleep 1 & P=$!; jobs; wait' 553 1.1 kre atf_check -s exit:0 -e empty -o match:sleep -o match:Done \ 554 1.1 kre ${TEST_SH} -c 'sleep 1 & P=$!; sleep 2; jobs; wait' 555 1.1 kre } 556 1.1 kre 557 1.1 kre atf_test_case read 558 1.1 kre read_head() { 559 1.1 kre atf_set "descr" "Tests the shell builtin read command" 560 1.1 kre } 561 1.1 kre read_body() { 562 1.1 kre have_builtin read "" "echo x|" "var" || return 0 563 1.1 kre } 564 1.1 kre 565 1.1 kre atf_test_case readonly 566 1.1 kre readonly_head() { 567 1.1 kre atf_set "descr" "Tests the shell builtin 'readonly'" 568 1.1 kre } 569 1.1 kre readonly_body() { 570 1.1 kre have_builtin readonly || return 0 571 1.1 kre 572 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'readonly VAR' 573 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'readonly VAR=abc' 574 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'readonly V A R' 575 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c 'readonly V A=1 R=2' 576 1.1 kre 577 1.1 kre atf_check -s exit:0 -e empty -o inline:unset ${TEST_SH} -c \ 578 1.1 kre 'unset VAR; readonly VAR; printf %s ${VAR-unset}' 579 1.1 kre atf_check -s exit:0 -e empty -o inline:set ${TEST_SH} -c \ 580 1.1 kre 'unset VAR; readonly VAR=set; printf %s ${VAR-unset}' 581 1.3 kre atf_check -s exit:0 -e empty -o inline:set ${TEST_SH} -c \ 582 1.3 kre 'VAR=initial; readonly VAR=set; printf %s ${VAR-unset}' 583 1.1 kre atf_check -s not-exit:0 -e not-empty -o empty ${TEST_SH} -c \ 584 1.1 kre 'readonly VAR=initial; VAR=new; printf %s "${VAR}"' 585 1.1 kre 586 1.3 kre # don't check VAR=value, some shells provide meaningless quoting... 587 1.3 kre atf_check -s exit:0 -e empty -o match:VAR= -o match:foobar \ 588 1.3 kre ${TEST_SH} -c \ 589 1.3 kre 'VAR=foobar ; readonly VAR ; readonly -p' 590 1.3 kre atf_check -s exit:0 -e empty -o match:VAR= -o match:foobar \ 591 1.3 kre ${TEST_SH} -c \ 592 1.3 kre 'readonly VAR=foobar ; readonly -p' 593 1.3 kre atf_check -s exit:0 -e empty -o match:VAR= -o match:foobar \ 594 1.3 kre -o not-match:badvalue ${TEST_SH} -c \ 595 1.3 kre 'VAR=badvalue; readonly VAR=foobar ; readonly -p' 596 1.3 kre atf_check -s exit:0 -e empty -o match:VAR\$ ${TEST_SH} -c \ 597 1.3 kre 'unset VAR ; readonly VAR ; readonly -p' 598 1.3 kre 599 1.3 kre # checking that readonly -p works (to reset stuff) is a pain... 600 1.3 kre # particularly since not all shells say "readonly..." by default 601 1.3 kre atf_check -s exit:0 -e empty -o match:MYVAR= -o match:FOUND=foobar \ 602 1.3 kre ${TEST_SH} -c \ 603 1.3 kre 'V=$(readonly MYVAR=foobar; readonly -p | grep " MYVAR") 604 1.3 kre unset MYVAR; eval "$V"; readonly -p; 605 1.3 kre printf %s\\n FOUND=${MYVAR-unset}' 606 1.3 kre atf_check -s exit:0 -e empty -o match:MYVAR\$ -o match:FOUND=unset \ 607 1.3 kre ${TEST_SH} -c \ 608 1.3 kre 'V=$(readonly MYVAR; readonly -p | grep " MYVAR") 609 1.3 kre unset MYVAR; eval "$V"; readonly -p; 610 1.3 kre printf %s\\n "FOUND=${MYVAR-unset}"' 611 1.3 kre atf_check -s exit:0 -e empty -o match:MYVAR= -o match:FOUND=empty \ 612 1.3 kre ${TEST_SH} -c \ 613 1.3 kre 'V=$(readonly MYVAR=; readonly -p | grep " MYVAR") 614 1.3 kre unset VAR; eval "$V"; readonly -p; 615 1.3 kre printf %s\\n "FOUND=${MYVAR-unset&}${MYVAR:-empty}"' 616 1.3 kre 617 1.1 kre # don't test stderr, some shells inist on generating a message for an 618 1.1 kre # unset of a readonly var (rather than simply having unset make $?=1) 619 1.1 kre 620 1.1 kre atf_check -s not-exit:0 -e empty -o empty ${TEST_SH} -c \ 621 1.1 kre 'unset VAR; readonly VAR=set; 622 1.1 kre unset VAR 2>/dev/null && printf %s ${VAR:-XX}' 623 1.1 kre atf_check -s not-exit:0 -e ignore -o empty ${TEST_SH} -c \ 624 1.1 kre 'unset VAR; readonly VAR=set; unset VAR && printf %s ${VAR:-XX}' 625 1.1 kre atf_check -s exit:0 -e ignore -o inline:set ${TEST_SH} -c \ 626 1.1 kre 'unset VAR; readonly VAR=set; unset VAR; printf %s ${VAR-unset}' 627 1.1 kre } 628 1.1 kre 629 1.4 kre atf_test_case readonly_nbsd 630 1.4 kre readonly_nbsd_head() { 631 1.4 kre atf_set "descr" "Tests NetBSD extensions to 'readonly'" 632 1.4 kre } 633 1.4 kre readonly_nbsd_body() { 634 1.4 kre have_builtin readonly '' 'readonly VAR;' '-q VAR' ' -q' || return 0 635 1.4 kre 636 1.4 kre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 637 1.4 kre 'VAR=set; readonly -q VAR' 638 1.4 kre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 639 1.4 kre 'readonly VAR=set; readonly -q VAR' 640 1.4 kre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 641 1.4 kre 'VAR=set; RW=set; readonly -q VAR RW' 642 1.4 kre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 643 1.4 kre 'VAR=set; readonly RO=set; readonly -q VAR RO' 644 1.4 kre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 645 1.4 kre 'readonly VAR=set RO=set; readonly -q VAR RO' 646 1.4 kre 647 1.4 kre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 648 1.4 kre 'unset VAR; readonly -q VAR' 649 1.4 kre # next one is the same as the have_builtin test, so "cannot" fail... 650 1.4 kre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 651 1.4 kre 'unset VAR; readonly VAR; readonly -q VAR' 652 1.4 kre 653 1.4 kre # if we have -q we should also have -p var... 654 1.4 kre # What's more, we are testing NetBSD sh, so we know output format. 655 1.4 kre 656 1.4 kre atf_check -s exit:0 -e empty -o match:VAR=foobar \ 657 1.4 kre ${TEST_SH} -c \ 658 1.4 kre 'VAR=foobar ; readonly VAR ; readonly -p VAR' 659 1.4 kre atf_check -s exit:0 -e empty -o inline:1 \ 660 1.4 kre ${TEST_SH} -c \ 661 1.4 kre 'VAR=foobar ; readonly VAR ; 662 1.4 kre printf %d $(readonly -p VAR | wc -l)' 663 1.4 kre atf_check -s exit:0 -e empty \ 664 1.4 kre -o inline:'readonly VAR=foobar\nreadonly OTHER\n' \ 665 1.4 kre ${TEST_SH} -c \ 666 1.4 kre 'VAR=foobar; readonly VAR OTHER; readonly -p VAR OTHER' 667 1.4 kre atf_check -s exit:0 -e empty \ 668 1.4 kre -o inline:'readonly A=aaa\nreadonly B\nreadonly D='"''"'\n' \ 669 1.4 kre ${TEST_SH} -c \ 670 1.4 kre 'A=aaa D= C=foo; unset B; readonly A B D; 671 1.4 kre readonly -p A B C D' 672 1.4 kre } 673 1.4 kre 674 1.1 kre atf_test_case cd_pwd 675 1.1 kre cd_pwd_head() { 676 1.1 kre atf_set "descr" "Tests the shell builtins 'cd' & 'pwd'" 677 1.1 kre } 678 1.1 kre cd_pwd_body() { 679 1.1 kre have_builtin cd "" "HOME=/;" || return 0 680 1.1 kre have_builtin pwd || return 0 681 1.1 kre } 682 1.1 kre 683 1.1 kre atf_test_case true_false 684 1.1 kre true_false_head() { 685 1.1 kre atf_set "descr" "Tests the 'true' and 'false' shell builtin commands" 686 1.1 kre } 687 1.1 kre true_false_body() { 688 1.1 kre have_builtin true || return 0 689 1.1 kre 690 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c true 691 1.1 kre 692 1.1 kre # true is not a special builtin, so errors do not cause exit 693 1.1 kre # but we should still get an error from the broken redirect 694 1.1 kre # and the exit status of true should be false... 695 1.1 kre 696 1.1 kre atf_check -s exit:0 -e not-empty -o inline:OK ${TEST_SH} -c \ 697 1.1 kre "true >/foo/bar && printf %s NOT-; printf %s OK" 698 1.1 kre 699 1.1 kre # and var-assigns should not affect the current sh env 700 1.1 kre 701 1.1 kre atf_check -s exit:0 -e empty -o inline:IS-OK ${TEST_SH} -c \ 702 1.1 kre 'X=OK; X=BROKEN true && printf %s IS-; printf %s "${X}"' 703 1.1 kre 704 1.1 kre have_builtin false "" ! || return 0 705 1.1 kre 706 1.1 kre atf_check -s exit:1 -e empty -o empty ${TEST_SH} -c false 707 1.1 kre } 708 1.1 kre 709 1.1 kre atf_test_case type 710 1.1 kre type_head() { 711 1.1 kre atf_set "descr" "Tests the sh builtin 'type' command" 712 1.1 kre } 713 1.1 kre type_body() { 714 1.1 kre have_builtin type "" "" type || return 0 715 1.1 kre } 716 1.1 kre 717 1.1 kre # This currently has its own t_ulimit - either merge that here, 718 1.1 kre # or delete this one and keep that... ulimit -n is also tested in 719 1.1 kre # the t_redir tests, as that affects the shell's use of file descriptors 720 1.1 kre atf_test_case ulimit 721 1.1 kre ulimit_head() { 722 1.1 kre atf_set "descr" "Tests the sh builtin 'ulimit'" 723 1.1 kre } 724 1.1 kre ulimit_body() { 725 1.1 kre have_builtin ulimit || return 0 726 1.1 kre } 727 1.1 kre 728 1.1 kre atf_test_case umask 729 1.1 kre umask_head() { 730 1.1 kre atf_set "descr" "Tests the sh builtin 'umask'" 731 1.1 kre } 732 1.1 kre umask_body() { 733 1.1 kre have_builtin umask || return 0 734 1.1 kre 735 1.1 kre atf_require_prog touch 736 1.1 kre atf_require_prog stat 737 1.1 kre atf_require_prog rm 738 1.1 kre atf_require_prog chmod 739 1.1 kre 740 1.1 kre reset umask 741 1.1 kre 742 1.1 kre # 8 octal digits 743 1.1 kre for M in 0 1 2 3 4 5 6 7 744 1.1 kre do 745 1.1 kre # Test numbers start: 1 25 49 73 97 121 145 169 746 1.1 kre 747 1.1 kre # 8 combinations of each to test (64 inner loops) 748 1.1 kre # 3 tests in each loop, hence 192 subtests in all 749 1.1 kre 750 1.1 kre # Test numbers from loop above, plus (below) and the next 2 751 1.1 kre #+ 1 4 7 10 13 752 1.1 kre for T in "0${M}" "00${M}" "0${M}0" "0${M}00" "0${M}${M}" \ 753 1.1 kre "0${M}${M}0" "0${M}${M}${M}" "0${M}0${M}" 754 1.1 kre #+ 16 19 22 755 1.1 kre do 756 1.1 kre # umask turns bits off, calculate which bits will be on... 757 1.1 kre 758 1.1 kre D=$(( 0777 & ~ T )) # for directories 759 1.1 kre F=$(( $D & ~ 0111 )) # and files with no 'x' bits 760 1.1 kre 761 1.1 kre # Note: $(( )) always produces decimal, so we test that format 762 1.1 kre # (see '%d' in printf of stat result) 763 1.1 kre 764 1.1 kre # need chmod or we might have no perm to rmdir TD 765 1.1 kre { chmod +rwx TF TFT TD; rm -fr TF TFT TD; } 2>/dev/null || : 766 1.1 kre 767 1.1 kre # check that the umask applies to files created by the shell 768 1.1 kre check \ 769 1.1 kre "umask $T; > TF; printf %d \$(stat -nf %#Lp TF)" \ 770 1.1 kre "$F" 0 "$F is $(printf %#o $F)" # 1 4 7 10 ... 771 1.1 kre 772 1.1 kre # and to files created by commands that the shell runs 773 1.1 kre check \ 774 1.1 kre "umask $T; touch TFT; printf %d \$(stat -nf %#Lp TFT)" \ 775 1.1 kre "$F" 0 "$F is $(printf %#o $F)" # 2 5 8 11 ... 776 1.1 kre 777 1.1 kre # and to directories created b ... (directories keep 'x') 778 1.1 kre check \ 779 1.1 kre "umask $T; mkdir TD; printf %d \$(stat -nf %#Lp TD)" \ 780 1.1 kre "$D" 0 "$D is $(printf %#o $D)" # 3 6 9 12 ... 781 1.1 kre done 782 1.1 kre done 783 1.1 kre 784 1.1 kre # Now add a few more tests with less regular u/g/m masks 785 1.1 kre # In here, include tests where umask value has no leading '0' 786 1.1 kre 787 1.1 kre # 10 loops, the same 3 tests in each loop, 30 more subtests 788 1.1 kre # from 193 .. 222 789 1.1 kre 790 1.1 kre # 193 196 199 202 205 208 211 214 217 220 791 1.1 kre for T in 013 047 722 0772 027 123 421 0124 0513 067 792 1.1 kre do 793 1.1 kre D=$(( 0777 & ~ 0$T )) 794 1.1 kre F=$(( $D & ~ 0111 )) 795 1.1 kre 796 1.1 kre { chmod +rwx TF TFT TD; rm -fr TF TFT TD; } 2>/dev/null || : 797 1.1 kre 798 1.1 kre check \ 799 1.1 kre "umask $T; > TF; printf %d \$(stat -nf %#Lp TF)" \ 800 1.1 kre "$F" 0 "$F is $(printf %#o $F)" # +0 801 1.1 kre 802 1.1 kre check \ 803 1.1 kre "umask $T; touch TFT; printf %d \$(stat -nf %#Lp TFT)" \ 804 1.1 kre "$F" 0 "$F is $(printf %#o $F)" # +1 805 1.1 kre 806 1.1 kre check \ 807 1.1 kre "umask $T; mkdir TD; printf %d \$(stat -nf %#Lp TD)" \ 808 1.1 kre "$D" 0 "$D is $(printf %#o $D)" # +2 809 1.1 kre done 810 1.1 kre 811 1.1 kre results 812 1.1 kre } 813 1.1 kre 814 1.1 kre atf_test_case unset 815 1.1 kre unset_head() { 816 1.1 kre atf_set "descr" "Tests the sh builtin 'unset'" 817 1.1 kre } 818 1.1 kre unset_body() { 819 1.1 kre have_builtin unset || return 0 820 1.1 kre } 821 1.1 kre 822 1.1 kre atf_test_case hash 823 1.1 kre hash_head() { 824 1.1 kre atf_set "descr" "Tests the sh builtin 'hash' (ash extension)" 825 1.1 kre } 826 1.1 kre hash_body() { 827 1.1 kre have_builtin hash || return 0 828 1.1 kre } 829 1.1 kre 830 1.1 kre atf_test_case jobid 831 1.1 kre jobid_head() { 832 1.1 kre atf_set "descr" "Tests sh builtin 'jobid' (NetBSD extension)" 833 1.1 kre } 834 1.1 kre jobid_body() { 835 1.1 kre 836 1.1 kre # have_builtin jobid || return 0 No simple jobid command test 837 1.1 kre $TEST_SH -c '(exit 0)& jobid $!' >/dev/null 2>&1 || { 838 1.1 kre atf_skip "${TEST_SH} has no 'jobid' built-in" 839 1.1 kre return 0 840 1.1 kre } 841 1.1 kre } 842 1.1 kre 843 1.1 kre atf_test_case let 844 1.1 kre let_head() { 845 1.1 kre atf_set "descr" "Tests the sh builtin 'let' (common extension from ksh)" 846 1.1 kre } 847 1.1 kre let_body() { 848 1.1 kre have_builtin let "" "" 1 || return 0 849 1.1 kre } 850 1.1 kre 851 1.1 kre atf_test_case local 852 1.1 kre local_head() { 853 1.1 kre atf_set "descr" "Tests the shell builtin 'local' (common extension)" 854 1.1 kre } 855 1.1 kre local_body() { 856 1.1 kre have_builtin local "" "f () {" "X; }; f" || return 0 857 1.1 kre } 858 1.1 kre 859 1.1 kre atf_test_case setvar 860 1.1 kre setvar_head() { 861 1.1 kre atf_set "descr" "Tests the shell builtin 'setvar' (BSD extension)" 862 1.1 kre } 863 1.1 kre setvar_body() { 864 1.1 kre have_builtin setvar || return 0 865 1.1 kre 866 1.1 kre atf_check -s exit:0 -e empty -o inline:foo ${TEST_SH} -c \ 867 1.1 kre 'unset PQ && setvar PQ foo; printf %s "${PQ-not set}"' 868 1.1 kre atf_check -s exit:0 -e empty -o inline:abcd ${TEST_SH} -c \ 869 1.1 kre 'for x in a b c d; do setvar "$x" "$x"; done; 870 1.1 kre printf %s "$a$b$c$d"' 871 1.1 kre atf_check -s exit:0 -e empty -o empty ${TEST_SH} -c \ 872 1.1 kre 'a=1; b=2; c=3; d=4 873 1.1 kre for x in a b c d; do setvar "$x" ""; done; 874 1.1 kre printf %s "$a$b$c$d"' 875 1.1 kre } 876 1.1 kre 877 1.1 kre atf_test_case fdflags 878 1.1 kre fdflags_head() { 879 1.1 kre atf_set "descr" \ 880 1.1 kre "Tests basic operation of sh builtin 'fdflags' (NetBSD extension)" 881 1.1 kre } 882 1.1 kre fdflags_body() { 883 1.1 kre have_builtin fdflags || return 0 884 1.1 kre } 885 1.1 kre 886 1.1 kre atf_test_case fdflags__s 887 1.1 kre fdflags__s_head() { 888 1.1 kre atf_set "descr" "Checks setting/clearing flags on file descriptors" 889 1.1 kre } 890 1.1 kre fdflags__s_body() { 891 1.1 kre have_builtin fdflags || return 0 892 1.1 kre } 893 1.1 kre 894 1.1 kre atf_test_case fdflags__v 895 1.1 kre fdflags__v_head() { 896 1.1 kre atf_set "descr" "Checks verbose operation of fdflags" 897 1.1 kre } 898 1.1 kre fdflags__v_body() { 899 1.1 kre have_builtin fdflags || return 0 900 1.1 kre } 901 1.1 kre 902 1.1 kre atf_test_case fdflags__v_s 903 1.1 kre fdflags__v_s_head() { 904 1.1 kre atf_set "descr" "tests verbose operation of fdflags -s" 905 1.1 kre } 906 1.1 kre fdflags__v_s_body() { 907 1.1 kre have_builtin fdflags || return 0 908 1.1 kre } 909 1.1 kre 910 1.1 kre atf_test_case fdflags_multiple_fd 911 1.1 kre fdflags_multiple_fd_head() { 912 1.1 kre atf_set "descr" "Checks operation of fdflags with more than one fd" 913 1.1 kre } 914 1.1 kre fdflags_multiple_fd_body() { 915 1.1 kre have_builtin fdflags || return 0 916 1.1 kre } 917 1.1 kre 918 1.1 kre atf_test_case fdflags_one_flag_at_a_time 919 1.1 kre fdflags_one_flag_at_a_time_head() { 920 1.1 kre atf_set "descr" "Tests all possible fdflags flags, and combinations" 921 1.1 kre } 922 1.1 kre fdflags_one_flag_at_a_time_body() { 923 1.1 kre have_builtin fdflags || return 0 924 1.1 kre } 925 1.1 kre 926 1.1 kre atf_test_case fdflags_save_restore 927 1.1 kre fdflags_save_restore_head() { 928 1.1 kre atf_set "descr" 'Verify that fd flags can be saved and restored' 929 1.1 kre } 930 1.1 kre fdflags_save_restore_body() { 931 1.1 kre have_builtin fdflags || return 0 932 1.1 kre } 933 1.1 kre 934 1.1 kre atf_test_case fdflags_names_abbreviated 935 1.1 kre fdflags_names_abbreviated_head() { 936 1.1 kre atf_set "descr" 'Tests using abbreviated names for fdflags' 937 1.1 kre } 938 1.1 kre fdflags_names_abbreviated_body() { 939 1.1 kre have_builtin fdflags || return 0 940 1.1 kre } 941 1.1 kre 942 1.1 kre atf_test_case fdflags_xx_errors 943 1.1 kre fdflags_xx_errors_head() { 944 1.1 kre atf_set "descr" 'Check various erroneous fdflags uses' 945 1.1 kre } 946 1.1 kre fdflags_xx_errors_body() { 947 1.1 kre have_builtin fdflags || return 0 948 1.1 kre } 949 1.1 kre 950 1.1 kre 951 1.1 kre atf_init_test_cases() { 952 1.1 kre 953 1.1 kre # "standard" builtin commands in sh 954 1.1 kre 955 1.1 kre # no tests of the "very special" (almost syntax) builtins 956 1.1 kre # (break/continue/return) - they're tested enough elsewhere 957 1.1 kre 958 1.1 kre atf_add_test_case cd_pwd 959 1.1 kre atf_add_test_case colon 960 1.1 kre atf_add_test_case echo 961 1.1 kre atf_add_test_case eval 962 1.1 kre atf_add_test_case exec 963 1.1 kre atf_add_test_case export 964 1.1 kre atf_add_test_case getopts 965 1.1 kre atf_add_test_case jobs 966 1.1 kre atf_add_test_case read 967 1.1 kre atf_add_test_case readonly 968 1.1 kre atf_add_test_case true_false 969 1.1 kre atf_add_test_case type 970 1.1 kre atf_add_test_case ulimit 971 1.1 kre atf_add_test_case umask 972 1.1 kre atf_add_test_case unset 973 1.1 kre 974 1.1 kre # exit/wait/set/shift/trap/alias/unalias/. should have their own tests 975 1.1 kre # fc/times/fg/bg/% are too messy to contemplate for now 976 1.1 kre # command ?? (probably should have some tests) 977 1.1 kre 978 1.1 kre # Note that builtin versions of, printf, kill, ... are tested separately 979 1.1 kre # (these are all "optional" builtins) 980 1.1 kre # (echo is tested here because NetBSD sh builtin echo and /bin/echo 981 1.1 kre # are different) 982 1.1 kre 983 1.1 kre atf_add_test_case export_nbsd 984 1.1 kre atf_add_test_case hash 985 1.1 kre atf_add_test_case jobid 986 1.1 kre atf_add_test_case let 987 1.1 kre atf_add_test_case local 988 1.4 kre atf_add_test_case readonly_nbsd 989 1.1 kre atf_add_test_case setvar 990 1.1 kre # inputrc should probably be tested in libedit tests (somehow) 991 1.1 kre 992 1.1 kre # fdflags has a bunch of test cases 993 1.1 kre 994 1.1 kre # Always run one test, so we get at least "skipped" result 995 1.1 kre atf_add_test_case fdflags 996 1.1 kre 997 1.1 kre # but no need to say "skipped" lots more times... 998 1.1 kre have_builtin fdflags available && { 999 1.1 kre atf_add_test_case fdflags__s 1000 1.1 kre atf_add_test_case fdflags__v 1001 1.1 kre atf_add_test_case fdflags__v_s 1002 1.1 kre atf_add_test_case fdflags_multiple_fd 1003 1.1 kre atf_add_test_case fdflags_names_abbreviated 1004 1.1 kre atf_add_test_case fdflags_one_flag_at_a_time 1005 1.1 kre atf_add_test_case fdflags_save_restore 1006 1.1 kre atf_add_test_case fdflags_xx_errors 1007 1.1 kre } 1008 1.1 kre return 0 1009 1.1 kre } 1010