#!/bin/bash # Test suite helper functions, uses ideas and code from git's test-lib.sh, # Copyright (c) 2005 Junio C Hamano. Licensed under the GPL v2, see file # COPYING. RED='\33[31m' GREEN='\33[32m' YELLOW='\33[33m' MAGENTA='\33[35m' CYAN='\033[36m' BOLD='\033[1m' RESET='\033[m' declare -A severity_colors=( [error]="$BOLD$RED" [skip]="$MAGENTA" [ok]="$GREEN" [pass]="$BOLD$GREEN" [info]="$YELLOW" [run]="$CYAN" ) get_audio_file_paths() { local suffix=$1 if (($# == 0)); then result=$(find "$test_audio_file_dir" -type f) else result=$(find "$test_audio_file_dir" -type f -name "*.$suffix") fi } say_color() { local severity=$1 local -i outfd local pfx= sfx= shift [[ "$severity" == 'error' ]] && outfd=2 || outfd=1 if [[ "$o_nocolor" != 'true' ]]; then pfx=${severity_colors[$severity]} sfx=$RESET fi printf 1>&$outfd '%b%s%b\n' "$pfx" "$*" "$sfx" } die() { local code=$? [[ "$exit_ok" == 'true' ]] && exit $code say_color error "FATAL: Unexpected exit with code $code" exit 1 } error() { say_color error "error: $*" exit_ok='true' exit 1 } say() { say_color info "$*" } retval_ok() { local rv=$1 expectation=$2 if [[ "$expectation" == 'success' ]]; then ((rv == 0)) && return 0 || return 1 fi if ((rv > 129 && rv <= 192)); then printf >&2 'died by signal\n' return 1 fi if ((rv == 127)); then printf >&2 'command not found\n' return 1 fi if ((rv == 0)); then printf >&2 'command was supposed to fail but succeeded\n' return 1 fi return 0 } _test_run() { local f expectation=$3 ret let test_count++ eval >&3 2>&4 "$2" ret=$? if retval_ok "$ret" "$expectation"; then let test_success++ say_color ok "ok $test_count - $1" return fi let test_failure++ say_color error "not ok - $test_count $1" f="$o_results_dir/${0##*/}-$$.out" if [[ -s "$f" ]]; then sed -e 's/^/# /' < "$f" else sed -e 's/^/# /' <<< "$2" fi } test_skip() { (($# != 2)) && error 'bug: not 2 parameters to test_skip()' let test_count++ let test_skipped++ say_color skip >&3 "skipping test $this_test.$test_count ($1): $2" say_color skip "ok $test_count - $1 # skipped ($2)" } test_require_objects() { local o1 o2 found result= # if no objects were given, we assume this test is run manually # rather than via "make test". We won't check anything in this case [[ -z "$o_objects" ]] && return for o1 in $1; do found= for o2 in $o_objects; do [[ "$o1" != "$o2" ]] && continue found='true' break done [[ "$found" == 'true' ]] && continue [[ -n "$result" ]] && result+=' ' result+=$o1 done [[ -z "$result" ]] } test_require_executables() { local i result= for i in "$@"; do [[ -n "$(builtin type -t "$i")" ]] && continue [[ -n "$result" ]] && result+=' ' result+=$i done [[ -z "$result" ]] } test_duration() { local t=$(exec 2>&1 1>/dev/null; time -p "$@") result=$(awk '{print $2 * 1000; exit 0}' <<< "$t") } test_expect_success() { (($# != 2)) && error 'bug: not 2 parameters to test_expect_success()' printf >&3 'expecting success: %s\n' "$2" _test_run "$1" "$2" 'success' printf >&3 '\n' } test_expect_failure() { (($# != 2)) && error 'bug: not 2 parameters to test_expect_failure()' printf >&3 'expecting failure: %s\n' "$2" _test_run "$1" "$2" 'failure' printf >&3 '\n' } test_done() { test_results_path="$o_results_dir/${0##*/}-$$.counts" { printf 'total %d\n' "$test_count" printf 'success %d\n' "$test_success" printf 'failed %d\n' "$test_failure" printf 'skipped %d\n' "$test_skipped" printf '\n' } > $test_results_path exit_ok='true' msg="$test_count test(s) ($test_skipped test(s) skipped)" if ((test_failure == 0)); then say_color pass "# ${0##*/}: passed all $msg" exit 0 else say_color error "# ${0##*/}: failed $test_failure among $msg" exit 1 fi } sanitize_environment() { export LANG=C export LC_ALL=C export PAGER=cat export TZ=UTC export TERM=dumb export EDITOR=: export HOME=$(pwd) unset VISUAL unset EMAIL unset CDPATH unset GREP_OPTIONS } parse_options() { while (($# > 0)); do case "$1" in -h|--help) o_help='true'; shift;; -v=0|--verbose=0) o_verbose='0'; shift;; -v=1|--verbose=1) o_verbose='1'; shift;; -v|--verbose|-v=2|--verbose=2) o_verbose='2'; shift;; --no-color) o_nocolor='true'; shift;; --man-dir) export o_man_dir=$2; shift; shift;; --results-dir) o_results_dir=$2; shift; shift;; --trash-dir) o_trash_dir=$2; shift; shift;; --executables-dir) export o_executables_dir=$2; shift; shift;; --executables) export o_executables=$2; shift; shift;; --objects) export o_objects=$2; shift; shift;; *) printf 'error: unknown test option: %s\n' "$1" >&2; exit 1;; esac done [[ -z "$o_verbose" ]] && o_verbose=1 } create_trash_dir_and_cd() { local trash="$o_trash_dir/trash-dir.${0##*/}" rm -rf "$trash" || error "could not remove trash dir" mkdir -p "$trash" || error "could not make trash dir" cd "$trash" || error "could not change to trash dir" } fixup_dirs() { local wd=$(pwd) test_dir=$(realpath $wd/${0%/*}) test_audio_file_dir="$test_dir/audio_files" [[ -z "$o_results_dir" ]] && o_results_dir="$test_dir/test-results" [[ -z "$o_executables_dir" ]] && o_executables_dir="$test_dir/.." [[ -z "$o_trash_dir" ]] && o_trash_dir="$test_dir/trashes" [[ -z "$o_man_dir" ]] && o_man_dir="$test_dir/../build/man/man1" # we want absolute paths because relative paths become invalid # after changing to the trash dir [[ -n "${o_results_dir##/*}" ]] && o_results_dir="$wd/$o_results_dir" [[ -n "${o_executables_dir##/*}" ]] && o_executables_dir="$wd/$o_results_dir" [[ -n "${o_man_dir##/*}" ]] && o_man_dir="$wd/$o_man_dir" [[ -n "${o_trash_dir##/*}" ]] && o_trash_dir="$wd/$o_trash_dir" mkdir -p "$o_results_dir" } parse_options "$@" [[ -t 1 ]] || o_nocolor='true' # Each test must set test_description [[ -z "${test_description}" ]] && error "${0##*/} did not set test_description" if [[ "$o_help" == 'true' ]]; then printf "${0##*/}: " sed -e '1!d' <<< "$test_description" if ((o_verbose >= 2)); then printf '\n' sed -e '1,2d' -e 's/^/ /g' <<< "$test_description" printf '\n' fi exit 0 fi fixup_dirs [[ -z "$o_executables" ]] && o_executables='para_afh para_audioc para_audiod para_client para_mixer para_filter para_gui para_recv para_server para_write' for exe in $o_executables; do eval ${exe^^}="$o_executables_dir/$exe" done test_failure=0 test_count=0 test_success=0 test_skipped=0 ORIGINAL_TERM=$TERM sanitize_environment create_trash_dir_and_cd if ((o_verbose >= 2)); then exec 4>&2 3>&1 else exec 4>$o_results_dir/${0##*/}-$$.out 3>&4 fi exit_ok= trap 'die' EXIT say_color run "# running ${0##*/}"