#!/bin/sh # shellcheck disable=2015,2154,2164,2181,2317 # Requires mktemp(1), which is not a standard utility, but is commonly # available. The implementations provided by GNU coreutils, busybox and toybox # are known to be compatible. bailout() { printf 'Bail out! %s.\n' "$1" cleanup_tmpdir exit 1 } assign_tmpdir() { # shellcheck disable=1007 dir=$(mktemp -d) \ && chdir "${dir}" \ || bailout "Couldn't create or change to the temp dir" } cleanup_tmpdir() { if [ -n "${dir}" ]; then rm -rf -- "${dir}" fi } test_chdir() { set -- \ 1 grandchild \ 1 var \ 0 -L \ 0 -p \ 0 -e \ 0 -@ \ 0 - \ 0 child if ! mkdir -p -- -L -p -e -@ - child child/grandchild; then bailout "Couldn't set up all test directories" fi callback() { shift test_description="chdir $(print_args "$@")" if [ "$BASH" ]; then # shellcheck disable=3044 shopt -s cdable_vars fi CDPATH=child var=child chdir "$@" \ && test "$PWD" != "$OLDPWD" \ && cd - >/dev/null } iterate_tests 2 "$@" } test_chdir_noop() { set -- 0 '' callback() { shift test_description="chdir $(print_args "$@")" chdir "$@" \ && test "$PWD" = "$OLDPWD" \ || { cd - >/dev/null; false; } } iterate_tests 2 "$@" } test_is_older_than() { set -- \ 1 N/A N/A \ 1 newer N/A \ 1 newer-empty N/A \ 1 newer/file N/A \ 1 non-existent N/A \ 0 newer newer \ 1 newer newer-empty \ 0 newer newer/file \ 1 newer non-existent \ 1 newer older \ 1 newer older-empty \ 1 newer older/file \ 0 newer-empty newer \ 1 newer-empty newer-empty \ 0 newer-empty newer/file \ 1 newer-empty non-existent \ 1 newer-empty older \ 1 newer-empty older-empty \ 1 newer-empty older/file \ 1 newer/file newer \ 1 newer/file newer-empty \ 1 newer/file newer/file \ 1 newer/file non-existent \ 1 newer/file older \ 1 newer/file older-empty \ 1 newer/file older/file \ 0 non-existent newer \ 0 non-existent newer-empty \ 0 non-existent newer/file \ 1 non-existent non-existent \ 0 non-existent older \ 0 non-existent older-empty \ 0 non-existent older/file \ 0 older newer \ 0 older newer-empty \ 0 older newer/file \ 1 older non-existent \ 0 older older \ 1 older older-empty \ 0 older older/file \ 0 older-empty newer \ 0 older-empty newer-empty \ 0 older-empty newer/file \ 1 older-empty non-existent \ 0 older-empty older \ 1 older-empty older-empty \ 0 older-empty older/file \ 0 older/file newer \ 0 older/file newer-empty \ 0 older/file newer/file \ 1 older/file non-existent \ 1 older/file older \ 1 older/file older-empty \ 1 older/file older/file # The mtimes need to be explicitly assigned. Empirical evidence has # shown that executing mkdir(1) sequentially, with a single operand # each time, does not guarantee the order of the resulting mtimes. tstamp=197001010000 for age in older newer; do mkdir "${age}" "${age}-empty" \ && touch -m -t "${tstamp%0}1" "${age}"/file \ && touch -m -t "${tstamp}" "${age}" "${age}-empty" \ || bailout "Couldn't create or adjust the mtimes of the sample files" tstamp=197001010100 # add an hour done callback() { shift test_description="is_older_than $(print_args "$@")" is_older_than "$@" } iterate_tests 3 "$@" } test_get_bootparam() { cmdline="foo gentoo=bar,baz quux" set -- \ 1 "${cmdline}" N/A \ 1 "${cmdline}" '' \ 1 "gentoo=" '' \ 1 "${cmdline}" foo \ 0 "${cmdline}" bar \ 0 "foo gentoo=gentoo=1,bar baz" bar \ 0 "foo gentoo=bar,gentoo=1 baz" bar \ 0 "${cmdline}" baz \ 1 "${cmdline}" bar,baz \ 0 "foo gentoo=bar,gentoo=1 baz" gentoo=1 \ 0 "foo gentoo=gentoo=1,bar baz" gentoo=1 \ 1 "${cmdline}" quux callback() { cmdline=$2 shift 2 test_description="get_bootparam $(print_args "$@")" printf '%s\n' "${cmdline}" | get_bootparam "$@" } iterate_tests 3 "$@" } test_esyslog() { set -- \ 1 0 N/A N/A N/A \ 1 0 debug N/A N/A \ 0 0 debug user N/A \ 0 0 debug user '' \ 0 1 debug user message logger() { # esyslog() ignores empty messages. By overriding logger(1), it # can be determined whether a message would have been logged. logged=$((logged + 1)) } callback() { should_log=$2 shift 2 logged=0 test_description="esyslog $(print_args "$@")" EINFO_LOG=1 esyslog "$@" 2>/dev/null case $? in 0) test "${logged}" -eq "${should_log}" ;; *) return "$?" esac } iterate_tests 5 "$@" } test_is_identifier() { set -- \ 1 '' \ 1 _ \ 1 0 \ 1 0a \ 1 0Z \ 1 9 \ 1 9a \ 1 9Z \ 1 /a \ 1 /Z \ 1 .a \ 1 .Z \ 1 [a \ 1 [Z \ 1 '`a' \ 1 '`Z' \ 1 '{a' \ 1 '{Z' \ 1 '|a' \ 1 '|Z' \ 1 a/ \ 1 Z/ \ 1 a. \ 1 Z. \ 1 a[ \ 1 Z[ \ 1 'a`' \ 1 'Z`' \ 1 'a{' \ 1 'Z{' \ 1 'a|' \ 1 'Z|' \ 0 a \ 0 Z \ 0 __ \ 0 _a \ 0 _Z \ 0 a_ \ 0 Z_ \ 0 a_a \ 0 a_Z \ 0 Z_a \ 0 Z_Z callback() { shift test_description="is_identifier $(print_args "$@")" is_identifier "$@" } iterate_tests 2 "$@" } test_is_int() { set -- \ 1 N/A \ 1 ' ' \ 1 ' 1 ' \ 1 '' \ 1 +1 \ 1 +008 \ 1 -008 \ 1 008 \ 1 x \ 0 0 \ 0 1 \ 0 -1 \ 0 123456789 callback() { shift test_description="is_int $(print_args "$@")" is_int "$@" } iterate_tests 2 "$@" } test_is_visible() { set -- \ 1 '' \ 1 ' ' \ 1 "$(printf '\t')" \ 1 "$(printf '\a')" \ 0 . \ 0 ' . ' \ 0 "$(printf '\t.\t')" \ 0 "$(printf '\a.\a')" callback() { shift test_description="_is_visible $(print_args "$@")" _is_visible "$@" } iterate_tests 2 "$@" } test_update_cursor_coords() { printf '%d..%d\n' "${tap_i}" "${tap_i}" skip() { print 'ok %d # SKIP\n' "${tap_i}" } if _has_dumb_terminal; then skip elif ! ctty=$(ps -p "$$" -otty= 2>/dev/null) || [ -z "${ctty}" ]; then # The ps(1) implementation is defective or non-compliant skip elif [ "${ctty}" = "?" ]; then # No controlling terminal is available skip elif [ ! -e /dev/tty ]; then skip elif ! _update_winsize /dev/tty; then printf 'not ok %d - _update_cursor_coords\n' "${tap_i}" false else printf 'ok %d - _update_cursor_coords (x = %d, y = %d)\n' "${tap_i}" "${genfun_x}" "${genfun_y}" fi } test_yesno() { set -- \ 0 yes \ 0 YES \ 0 Yes \ 0 true \ 0 TRUE \ 0 true \ 0 on \ 0 ON \ 0 On \ 0 1 \ 1 no \ 1 NO \ 1 No \ 1 false \ 1 FALSE \ 1 False \ 1 off \ 1 OFF \ 1 Off \ 1 0 \ 1 not_a_nameref \ 1 not-a-valid-nameref \ 1 '_"; set -- yes # code injection' \ 0 truthful_nameref # shellcheck disable=2034 truthful_nameref=yes callback() { shift test_description="yesno $(print_args "$@")" yesno "$@" } iterate_tests 2 "$@" } iterate_tests() { slice_width=$1 shift total=$(( $# / slice_width )) printf '%d..%d\n' "${tap_i}" "$((tap_i + total - 1))" passed=0 i=0 while [ "$((i += 1))" -le "${total}" ]; do code="callback" j=0 while [ "$((j += 1))" -le "${slice_width}" ]; do if eval "[ \"\$${j}\" = N/A ]"; then break else code="${code} \"\$${j}\"" fi done eval "${code}" case $? in 0) test "$?" -eq "$1" ;; *) test "$?" -ge "$1" esac if [ "$?" -eq 0 ]; then passed=$((passed + 1)) else printf 'not ' fi if [ "$1" -eq 0 ]; then expected=$1 else expected=">=$1" fi printf 'ok %d - %s (expecting %s)\n' "${tap_i}" "${test_description}" "${expected}" shift "${slice_width}" tap_i=$((tap_i + 1)) done return "$(( passed < total ))" } print_args() { i=0 for arg; do if [ "$((i += 1))" -eq 1 ]; then set -- fi case ${arg} in ''|*[[:space:]]*) set -- "$@" "'${arg}'" ;; *) set -- "$@" "${arg}" esac done printf '%s\n' "$*" } printf 'TAP version 14\n' unset -v dir if ! . ./functions.sh; then bailout "Couldn't source ./functions.sh" fi # Since the test suite is normally executed during the src_test phase, the # ecma48-cpr utility will not yet have been installed. Account for that by # redeclaring its shim function. if [ "${EBUILD_PHASE}" = test ]; then export BUILD_DIR="${PWD}" _ecma48_cpr() { "${BUILD_DIR}"/ecma48-cpr; } fi assign_tmpdir export TEST_GENFUNCS=1 export TZ=UTC tap_i=1 rc=0 test_chdir || rc=1 test_chdir_noop || rc=1 test_is_older_than || rc=1 test_get_bootparam || rc=1 test_esyslog || rc=1 test_is_identifier || rc=1 test_is_int || rc=1 test_is_visible || rc=1 test_update_cursor_coords || rc=1 test_yesno || rc=1 cleanup_tmpdir exit "${rc}"