#!/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 -- \ ge 1 grandchild \ ge 1 var \ eq 0 -L \ eq 0 -p \ eq 0 -e \ eq 0 -@ \ eq 0 - \ eq 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 $(quote_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 3 "$@" } test_chdir_noop() { set -- \ eq 0 '' callback() { shift test_description="chdir $(quote_args "$@")" chdir "$@" \ && test "$PWD" = "$OLDPWD" \ || { cd - >/dev/null; false; } } iterate_tests 3 "$@" } test_die() { set -- \ eq 1 0 \ eq 2 2 \ eq 126 126 \ eq 255 255 callback() { test_description="( exit $2 ); die" ( exit "$2" ) stderr=$(die "$2" 2>&1) retval=$? if [ "${stderr}" = "test-functions: $2" ]; then return "${retval}" else return 1 fi } iterate_tests 3 "$@" } test_ebegin() { _eprint() { shift _ends_with_newline "$*" } set -- "message" ebegin "$1" retval=$? if [ "${retval}" -ne 0 ]; then printf 'not ' fi printf 'ok %d - ebegin %s (expecting terminating newline)\n' "$((testnum + 1))" "$1" return "${retval}" } test_edo() { set -- \ eq 1 false \ eq 0 true callback() { shift test_description="edo $1" ( edo "$1" >/dev/null ) } iterate_tests 3 "$@" } test_is_older_than() { set -- \ ge 1 N/A N/A \ ge 1 newer N/A \ ge 1 newer-empty N/A \ ge 1 newer/file N/A \ ge 1 non-existent N/A \ eq 0 newer newer \ ge 1 newer newer-empty \ eq 0 newer newer/file \ ge 1 newer non-existent \ ge 1 newer older \ ge 1 newer older-empty \ ge 1 newer older/file \ eq 0 newer-empty newer \ ge 1 newer-empty newer-empty \ eq 0 newer-empty newer/file \ ge 1 newer-empty non-existent \ ge 1 newer-empty older \ ge 1 newer-empty older-empty \ ge 1 newer-empty older/file \ ge 1 newer/file newer \ ge 1 newer/file newer-empty \ ge 1 newer/file newer/file \ ge 1 newer/file non-existent \ ge 1 newer/file older \ ge 1 newer/file older-empty \ ge 1 newer/file older/file \ eq 0 non-existent newer \ eq 0 non-existent newer-empty \ eq 0 non-existent newer/file \ ge 1 non-existent non-existent \ eq 0 non-existent older \ eq 0 non-existent older-empty \ eq 0 non-existent older/file \ eq 0 older newer \ eq 0 older newer-empty \ eq 0 older newer/file \ ge 1 older non-existent \ eq 0 older older \ ge 1 older older-empty \ eq 0 older older/file \ eq 0 older-empty newer \ eq 0 older-empty newer-empty \ eq 0 older-empty newer/file \ ge 1 older-empty non-existent \ eq 0 older-empty older \ ge 1 older-empty older-empty \ eq 0 older-empty older/file \ eq 0 older/file newer \ eq 0 older/file newer-empty \ eq 0 older/file newer/file \ ge 1 older/file non-existent \ ge 1 older/file older \ ge 1 older/file older-empty \ ge 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 $(quote_args "$@")" is_older_than "$@" } iterate_tests 4 "$@" } test_get_bootparam() { cmdline="foo gentoo=bar,baz quux" set -- \ ge 1 "${cmdline}" N/A \ ge 1 "${cmdline}" '' \ ge 1 "gentoo=" '' \ ge 1 "${cmdline}" foo \ eq 0 "${cmdline}" bar \ eq 0 "foo gentoo=gentoo=1,bar baz" bar \ eq 0 "foo gentoo=bar,gentoo=1 baz" bar \ eq 0 "${cmdline}" baz \ ge 1 "${cmdline}" bar,baz \ eq 0 "foo gentoo=bar,gentoo=1 baz" gentoo=1 \ eq 0 "foo gentoo=gentoo=1,bar baz" gentoo=1 \ ge 1 "${cmdline}" quux callback() { cmdline=$2 shift 2 test_description="get_bootparam $(quote_args "$@")" printf '%s\n' "${cmdline}" | get_bootparam "$@" } iterate_tests 4 "$@" } test_esyslog() { set -- \ ge 1 0 N/A N/A N/A \ ge 1 0 debug N/A N/A \ eq 0 0 debug user N/A \ eq 0 0 debug user '' \ eq 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. printf '1\n' } callback() { should_log=$2 shift 2 test_description="esyslog $(quote_args "$@")" logged=$(EINFO_LOG=1 esyslog "$@") case $? in 0) test "${logged:-0}" -eq "${should_log}" ;; *) return "$?" esac } iterate_tests 6 "$@" } test_is_identifier() { set -- \ ge 1 '' \ ge 1 _ \ ge 1 0 \ ge 1 0a \ ge 1 0Z \ ge 1 9 \ ge 1 9a \ ge 1 9Z \ ge 1 /a \ ge 1 /Z \ ge 1 .a \ ge 1 .Z \ ge 1 '[a' \ ge 1 '[Z' \ ge 1 '`a' \ ge 1 '`Z' \ ge 1 '{a' \ ge 1 '{Z' \ ge 1 '|a' \ ge 1 '|Z' \ ge 1 a/ \ ge 1 Z/ \ ge 1 a. \ ge 1 Z. \ ge 1 'a[' \ ge 1 'Z[' \ ge 1 'a`' \ ge 1 'Z`' \ ge 1 'a{' \ ge 1 'Z{' \ ge 1 'a|' \ ge 1 'Z|' \ eq 0 a \ eq 0 Z \ eq 0 __ \ eq 0 _a \ eq 0 _Z \ eq 0 a_ \ eq 0 Z_ \ eq 0 a_a \ eq 0 a_Z \ eq 0 Z_a \ eq 0 Z_Z callback() { shift test_description="is_identifier $(quote_args "$@")" is_identifier "$@" } iterate_tests 3 "$@" } test_is_int() { set -- \ ge 1 N/A \ ge 1 ' ' \ ge 1 ' 1 ' \ ge 1 '' \ ge 1 +1 \ ge 1 +008 \ ge 1 -008 \ ge 1 008 \ ge 1 x \ eq 0 0 \ eq 0 1 \ eq 0 -1 \ eq 0 123456789 callback() { shift test_description="is_int $(quote_args "$@")" is_int "$@" } iterate_tests 3 "$@" } test_is_visible() { set -- \ ge 1 '' \ ge 1 ' ' \ ge 1 "$(printf '\t')" \ ge 1 "$(printf '\a')" \ eq 0 . \ eq 0 ' . ' \ eq 0 "$(printf '\t.\t')" \ eq 0 "$(printf '\a.\a')" callback() { shift test_description="_is_visible $(quote_args "$@")" _is_visible "$@" } iterate_tests 3 "$@" } test_yesno() { set -- \ eq 0 yes \ eq 0 YES \ eq 0 Yes \ eq 0 true \ eq 0 TRUE \ eq 0 true \ eq 0 on \ eq 0 ON \ eq 0 On \ eq 0 1 \ eq 0 truthful_nameref \ ge 1 no \ ge 1 NO \ ge 1 No \ ge 1 false \ ge 1 FALSE \ ge 1 False \ ge 1 off \ ge 1 OFF \ ge 1 Off \ ge 1 0 \ ge 1 not_a_nameref \ ge 1 not-a-valid-nameref \ ge 1 '_"; set -- yes # code injection' # shellcheck disable=2034 truthful_nameref=yes callback() { shift test_description="yesno $(quote_args "$@")" yesno "$@" } iterate_tests 3 "$@" } test_srandom() { set -- \ eq 0 \ eq 0 \ eq 0 \ eq 0 \ eq 0 row=0 callback() { number=$(srandom) test_description="srandom ($(( row += 1 ))/5: ${number:-blank})" is_int "${number}" \ && test "${number}" -ge 0 \ && test "${number}" -le 4294967295 } iterate_tests 2 "$@" } test_newest() { set -- \ ge 1 non-existent non-existent \ ge 1 N/A N/A \ \ eq 0 newer/file N/A \ eq 0 newer/file newer/file \ eq 0 newer/file non-existent \ eq 0 newer/file older/file \ eq 0 non-existent newer/file \ eq 0 older/file newer/file \ \ eq 0 older/file N/A \ eq 0 older/file older/file \ eq 0 older/file non-existent \ ge 1 newer/file older/file \ eq 0 non-existent older/file \ ge 1 older/file newer/file row=0 callback() { shift test_description="newest $(quote_args "$@")" row=$(( row + 1 )) true | if [ "${row}" -le 2 ]; then newest "$@" elif [ "${row}" -le 8 ]; then test "$(newest "$@")" = "newer/file" else test "$(newest "$@")" = "older/file" fi } iterate_tests 4 "$@" } test_trim() { set -- \ eq 0 '' '' \ eq 0 ' ' '' \ eq 0 ' ' '' \ eq 0 ' X' 'X' \ eq 0 ' X' 'X' \ eq 0 'X ' 'X' \ eq 0 ' X Y' 'X Y' \ eq 0 ' X Y' 'X Y' \ eq 0 'X Y ' 'X Y' \ eq 0 'X Y ' 'X Y' \ eq 0 "$(printf ' \tX')" 'X' \ eq 0 "$(printf ' \tX\t ')" 'X' \ eq 0 "$(printf 'X\t ')" 'X' \ eq 0 "$(printf ' \tX Y')" 'X Y' \ eq 0 "$(printf ' \tX Y\t ')" 'X Y' \ eq 0 "$(printf 'X Y\t ')" 'X Y' callback() { shift test_description="trim $(quote_args "$1") (expecting $(quote_args "$2"))" test "$(trim "$1")" = "$2" } iterate_tests 4 "$@" } test_hr() { # shellcheck disable=2183 set -- \ eq 0 "$(printf '%80s' | tr ' ' -)" N/A N/A \ eq 0 "$(printf '%80s' | tr ' ' -)" - N/A \ eq 0 '' - 0 \ eq 0 - - 1 \ eq 0 ----- - 5 \ eq 0 '' xyz 0 \ eq 0 x xyz 1 \ eq 0 xyzxy xyz 5 callback() { shift expected=$1 shift test_description="hr $(quote_args "$@")" test "$(hr "$@")" = "${expected}" } iterate_tests 5 "$@" } test_whenceforth() { set -- \ ge 1 PATH N/A N/A \ ge 1 PATH . N/A \ ge 1 PATH unlikely-to-exist N/A \ ge 1 PATH /var/empty N/A \ ge 1 PATH /var/empty/nofile N/A \ eq 0 PATH /bin/sh N/A \ eq 0 PATH sh N/A \ ge 1 PATH -x . \ ge 1 PATH -x unlikely-to-exist \ ge 1 PATH -x /var/empty \ ge 1 PATH -x /var/empty/nofile \ eq 0 PATH -x /bin/sh \ eq 0 PATH -x sh \ eq 0 '' -x newer/file \ eq 0 . -x newer/file \ eq 0 :/var/empty/x -x newer/file \ eq 0 /var/empty/x: -x newer/file \ eq 0 /var/empty/x::/var/empty/y -x newer/file \ eq 0 '' -x newer/file \ eq 0 . -x newer/file \ eq 0 :/var/empty/x -x newer/file \ eq 0 /var/empty/x: -x newer/file \ eq 0 /var/empty/x::/var/empty/y -x newer/file \ eq 0 '' older/file N/A \ eq 0 . older/file N/A \ eq 0 :/var/empty/x older/file N/A \ eq 0 /var/empty/x: older/file N/A \ eq 0 /var/empty/x::/var/empty/y older/file N/A \ ge 1 '' -x older/file \ ge 1 . -x older/file \ ge 1 :/var/empty/x -x older/file \ ge 1 /var/empty/x: -x older/file \ ge 1 /var/empty/x::/var/empty/y -x older/file chmod +x newer/file callback() { shift path=$1 shift if [ "${path}" = PATH ]; then test_description="whenceforth $(quote_args "$@")" whenceforth "$@" >/dev/null else test_description="PATH=${path} whenceforth $(quote_args "$@")" PATH=${path} whenceforth "$@" >/dev/null fi } iterate_tests 5 "$@" } test_get_nprocs() { set -- eq 0 callback() { shift test_description="get_nprocs" nproc=$(get_nprocs) && is_int "${nproc}" && test "${nproc}" -gt 0 } iterate_tests 2 "$@" } test_parallel_run() { set -- \ ge 1 N/A N/A \ eq 0 / N/A \ ge 1 /var/empty/nonexistent N/A \ eq 0 / / \ ge 1 / /var/empty/nonexistent \ ge 1 /var/empty/nonexistent /var/empty/nonexistent \ ge 1 /var/empty/nonexistent / callback() { shift test_description="parallel_run $(quote_args 0 ls "$@")" parallel_run 0 ls "$@" >/dev/null 2>&1 } iterate_tests 4 "$@" } test_is_anyof() { set -- \ ge 1 N/A N/A N/A \ ge 1 x N/A N/A \ ge 1 x y N/A \ ge 1 x y z \ eq 0 x x N/A \ eq 0 x x y \ eq 0 x y x callback() { shift test_description="is_anyof $(quote_args "$@")" is_anyof "$@" } iterate_tests 5 "$@" } test_is_subset() { set -- \ ge 1 N/A N/A N/A N/A N/A \ ge 1 -- N/A N/A N/A N/A \ ge 1 -- -- N/A N/A N/A \ ge 1 -- x N/A N/A N/A \ ge 1 x -- N/A N/A N/A \ ge 1 x y N/A N/A N/A \ ge 1 x y x N/A N/A \ eq 0 x -- x N/A N/A \ eq 0 x -- x y N/A \ eq 0 x -- y x N/A \ eq 0 x y -- x y \ eq 0 x y -- y x \ ge 1 x y -- x z \ ge 1 y x -- z x \ ge 1 x z -- x y \ ge 1 z x -- y x callback() { shift test_description="is_subset $(quote_args "$@")" is_subset "$@" } iterate_tests 7 "$@" } test_trueof_all() { set -- \ ge 1 N/A N/A N/A N/A N/A \ ge 1 test -d N/A N/A N/A \ ge 1 test -d -- N/A N/A \ ge 1 test -d -- /dev/null N/A \ ge 1 test -d -- /dev/null /dev/null \ eq 0 test -d -- / N/A \ eq 0 test -d -- / / \ ge 1 test -d -- / /dev/null \ ge 1 test -d -- /dev/null / callback() { shift test_description="trueof_all $(quote_args "$@")" trueof_all "$@" } iterate_tests 7 "$@" } test_trueof_any() { set -- \ ge 1 N/A N/A N/A N/A N/A \ ge 1 test -d N/A N/A N/A \ ge 1 test -d -- N/A N/A \ ge 1 test -d -- /dev/null N/A \ ge 1 test -d -- /dev/null /dev/null \ eq 0 test -d -- / N/A \ eq 0 test -d -- / / \ eq 0 test -d -- / /dev/null \ eq 0 test -d -- /dev/null / callback() { shift test_description="trueof_any $(quote_args "$@")" trueof_any "$@" } iterate_tests 7 "$@" } test_substr() { set -- \ ge 1 - foobar N/A N/A \ ge 1 - foobar '' N/A \ ge 1 - foobar x N/A \ ge 1 - foobar '' '' \ ge 1 - foobar x y \ eq 0 foobar foobar 1 N/A \ eq 0 foobar foobar -1 N/A \ eq 0 foobar foobar 1 7 \ eq 0 foobar foobar -1 7 \ eq 0 foo foobar 1 3 \ eq 0 foo foobar -1 3 \ eq 0 f foobar 1 1 \ eq 0 f foobar -1 1 \ eq 0 '' foobar 1 0 \ eq 0 '' foobar 1 -1 \ eq 0 '' foobar 0 0 \ eq 0 '' foobar 0 -1 \ eq 0 '' foobar -1 0 \ eq 0 '' foobar -1 -1 \ eq 0 bar foobar 4 N/A \ eq 0 bar foobar 4 4 \ eq 0 b foobar 4 1 \ eq 0 '' foobar 4 0 \ eq 0 '' foobar 4 -1 callback() { shift expected=$1 shift test_description="substr $(quote_args "$@")" str=$(substr "$@") && test "${str}" = "${expected}" } iterate_tests 6 "$@" } test_contains_all() { set -- \ ge 1 N/A N/A N/A N/A \ ge 1 'foo bar' '' N/A N/A \ ge 1 'foo bar' '' ' ' N/A \ ge 1 'foo bar' '' ' bar' N/A \ ge 1 'foo bar' '' ' bar' N/A \ ge 1 'foo bar' '' 'foo ' N/A \ ge 1 'foo bar' '' 'foo bar' N/A \ ge 1 'foo bar' ' ' '' N/A \ ge 1 'foo bar' ' ' ' ' N/A \ ge 1 'foo bar' ' ' N/A N/A \ ge 1 'foo bar' ' bar' '' N/A \ ge 1 'foo bar' ' bar' N/A N/A \ ge 1 'foo bar' 'foo ' '' N/A \ ge 1 'foo bar' 'foo ' ' bar' N/A \ ge 1 'foo bar' 'foo ' N/A N/A \ ge 1 'foo bar' 'foo bar' '' N/A \ ge 1 'foo bar' 'foo bar' N/A N/A \ ge 1 'foo bar' N/A N/A N/A \ ge 1 'foo bar' bar foo '' \ ge 1 'foo bar' bar foo ' ' \ ge 1 'foo bar' baz bar foo \ ge 1 'foo bar' fo ba N/A \ ge 1 'foo bar' foo bar '' \ ge 1 'foo bar' foo bar ' ' \ ge 1 'foo bar' foo bar baz \ ge 1 'foo bar' o a N/A \ ge 1 'foo bar' oo ar N/A \ eq 0 'foo bar' foo bar N/A \ eq 0 'foo bar' bar foo N/A callback() { shift test_description="contains_all $(quote_args "$@")" contains_all "$@" } iterate_tests 6 "$@" } test_contains_any() { set -- \ ge 1 N/A N/A N/A \ ge 1 'foo bar' N/A N/A \ ge 1 'foo bar' fo ba \ ge 1 'foo bar' oo ar \ ge 1 'foo bar' o a \ ge 1 'foo bar' 'foo bar' 'foo bar' \ ge 1 'foo bar' 'foo bar' _ \ ge 1 'foo bar' _ 'foo bar' \ ge 1 'foo bar' 'foo ' ' bar' \ ge 1 'foo bar' 'foo ' _ \ ge 1 'foo bar' _ ' bar' \ ge 1 'foo bar' ' bar' _ \ ge 1 'foo bar' _ 'foo ' \ ge 1 'foo bar' '' '' \ ge 1 'foo bar' '' _ \ ge 1 'foo bar' _ '' \ ge 1 'foo bar' ' ' ' ' \ ge 1 'foo bar' ' ' _ \ ge 1 'foo bar' _ ' ' \ eq 0 'foo bar' foo bar \ eq 0 'foo bar' bar foo \ eq 0 'foo bar' foo _ \ eq 0 'foo bar' _ bar \ eq 0 'foo bar' bar _ \ eq 0 'foo bar' _ foo callback() { shift test_description="contains_any $(quote_args "$@")" contains_any "$@" } iterate_tests 5 "$@" } iterate_tests() { slice_width=$1 shift total=$(( $# / slice_width )) passed=0 i=0 while [ "$((i += 1))" -le "${total}" ]; do code="callback" j=1 while [ "$((j += 1))" -le "${slice_width}" ]; do if eval "[ \"\$${j}\" = N/A ]"; then break else code="${code} \"\$${j}\"" fi done eval "${code}" retval=$? if test "${retval}" -"$1" "$2"; then passed=$((passed + 1)) else printf 'not ' fi printf 'ok %d - %s (test %d -%s %d)\n' \ "$((testnum += 1))" "${test_description}" "${retval}" "$1" "$2" shift "${slice_width}" done return "$(( passed < total ))" } printf 'TAP version 13\n' unset -v dir # PATH is redefined to prevent ebuild-helpers such as die from interfering. export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/opt/pkg/bin export TEST_GENFUNCS=1 export TZ=UTC testnum=0 rc=0 if [ "${PORTAGE_BIN_PATH}" ] && [ "${S}" ]; then genfun_basedir=${S} fi if ! GENFUN_MODULES="portage rc" . ./functions.sh; then bailout "Couldn't source ./functions.sh" fi assign_tmpdir test_chdir || rc=1 test_chdir_noop || rc=1 ( test_ebegin ) || rc=1; testnum=$((testnum + 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_yesno || rc=1 test_die || rc=1 test_edo || rc=1 test_srandom || rc=1 test_newest || rc=1 test_trim || rc=1 test_hr || rc=1 test_whenceforth || rc=1 test_parallel_run || rc=1 test_is_anyof || rc=1 test_is_subset || rc=1 test_trueof_all || rc=1 test_trueof_any || rc=1 #test_substr || rc=1 test_contains_all || rc=1 test_contains_any || rc=1 cleanup_tmpdir printf '1..%d\n' "${testnum}" exit "${rc}"