afs: Shutdown signals on exit.
[paraslash.git] / t / test-lib.sh
1 #!/bin/bash
2
3 # Test suite helper functions, uses ideas and code from git's test-lib.sh,
4 # Copyright (c) 2005 Junio C Hamano. Licensed under the GPL v2, see file
5 # COPYING.
6
7 get_audio_file_paths()
8 {
9         local suffix="$1"
10
11         if (($# == 0)); then
12                 result=$(find "$test_audio_file_dir" -type f)
13         else
14                 result=$(find "$test_audio_file_dir" -type f -name "*.$suffix")
15         fi
16 }
17
18 say_color()
19 {
20         if [[ "$o_nocolor" != "true" && -n "$1" ]]; then
21                 export TERM=$ORIGINAL_TERM
22                 case "$1" in
23                         error) tput $C_BOLD; tput $C_SETAF 1;;
24                         skip)  tput $C_SETAF 5;;
25                         ok)
26                                 (($o_verbose == 0)) && return
27                                 tput $C_SETAF 2;;
28                         pass)  tput $C_BOLD; tput $C_SETAF 2;;
29                         info)  tput $C_SETAF 3;;
30                         run)
31                                 (($o_verbose == 0)) && return
32                                 tput $C_SETAF 6;;
33                 esac
34         fi
35         shift
36         printf "%s\n" "$*"
37         if [[ "$o_nocolor" != "true" && -n "$1" ]]; then
38                 tput $C_SGR0
39                 export TERM=dumb
40         fi
41 }
42
43 die()
44 {
45         local code=$?
46         [[ "$exit_ok" == "true" ]] && exit $code
47         say_color error "FATAL: Unexpected exit with code $code"
48         exit 1
49 }
50
51 error()
52 {
53         say_color error "error: $*"
54         exit_ok="true"
55         exit 1
56 }
57
58 say()
59 {
60         say_color info "$*"
61 }
62
63 retval_ok()
64 {
65         local rv="$1" expectation="$2"
66
67         if [[ "$expectation" == "success" ]]; then
68                 (($rv == 0)) && return 0 || return 1
69         fi
70         if (($rv > 129 && $rv <= 192)); then
71                 echo >&2 "died by signal"
72                 return 1
73         fi
74         if (($rv == 127)); then
75                 echo >&2 "command not found"
76                 return 1
77         fi
78         if (($rv == 0)); then
79                 echo >&2 "command was supposed to fail but succeeded"
80                 return 1
81         fi
82         return 0
83 }
84
85 _test_run()
86 {
87         local f expectation="$3" ret
88
89         let test_count++
90         eval >&3 2>&4 "$2"
91         ret=$?
92         if retval_ok "$ret" "$expectation"; then
93                 let test_success++
94                 say_color ok "ok $test_count - $1"
95                 return
96         fi
97         let test_failure++
98         say_color error "not ok - $test_count $1"
99         f="$o_results_dir/${0##*/}-$$.out"
100         if [[ -s "$f" ]]; then
101                 sed -e 's/^/#   /' < "$f"
102         else
103                 sed -e 's/^/#   /' <<< "$2"
104         fi
105         [[ "$o_immediate" != "true" ]] && return
106         exit_ok="true"
107         exit 1
108 }
109
110 test_skip()
111 {
112         (($# != 2)) && error "bug: not 2 parameters to test_skip()"
113         let test_count++
114         let test_skipped++
115         say_color skip >&3 "skipping test $this_test.$test_count ($1): $2"
116         say_color skip "ok $test_count - $1 # skipped ($2)"
117 }
118
119 test_require_objects()
120 {
121         local o1 o2 found
122
123         result=
124         # if no objects were given, we assume this test is run manually
125         # rather than via "make test". We won't check anything in this case
126         [[ -z "$o_objects" ]] && return
127
128         for o1 in $1; do
129                 found=
130                 for o2 in $o_objects; do
131                         [[ "$o1" != "$o2" ]] && continue
132                         found="true"
133                         break
134                 done
135                 [[ "$found" == "true" ]] && continue
136                 [[ -n "$result" ]] && result+=" "
137                 result+="$o1"
138         done
139         [[ -z "$result" ]]
140 }
141
142 test_require_executables()
143 {
144         local i
145
146         result=
147         for i in "$@"; do
148                 [[ -n "$(builtin type -t "$i")" ]] && continue
149                 [[ -n "$result" ]] && result+=" "
150                 result+="$i"
151         done
152         [[ -z "$result" ]]
153 }
154
155 test_duration()
156 {
157         local t=$(exec 2>&1 1>/dev/null; time -p "$@")
158         result=$(awk '{print $2 * 1000; exit 0}' <<< "$t")
159 }
160
161 test_expect_success()
162 {
163         (($# != 2)) && error "bug: not 2 parameters to test_expect_success()"
164         echo >&3 "expecting success: $2"
165         _test_run "$1" "$2" "success"
166         echo >&3 ""
167 }
168
169 test_expect_failure()
170 {
171         (($# != 2)) && error "bug: not 2 parameters to test_expect_failure()"
172         echo >&3 "expecting failure: $2"
173         _test_run "$1" "$2" "failure"
174         echo >&3 ""
175 }
176
177 test_done()
178 {
179         test_results_path="$o_results_dir/${0##*/}-$$.counts"
180         {
181                 echo "total $test_count"
182                 echo "success $test_success"
183                 echo "failed $test_failure"
184                 echo "skipped $test_skipped"
185                 echo
186         } > $test_results_path
187
188         exit_ok="true"
189         msg="$test_count test(s) ($test_skipped test(s) skipped)"
190         if (($test_failure == 0)); then
191                 say_color pass "# ${0##*/}: passed all $msg"
192                 exit 0
193         else
194                 say_color error "# ${0##*/}: failed $test_failure among $msg"
195                 exit 1
196         fi
197 }
198
199 sanitize_environment()
200 {
201         export LANG=C
202         export LC_ALL=C
203         export PAGER=cat
204         export TZ=UTC
205         export TERM=dumb
206         export EDITOR=:
207         export HOME=$(pwd)
208
209         unset VISUAL
210         unset EMAIL
211         unset CDPATH
212         unset GREP_OPTIONS
213 }
214
215 can_use_colors()
216 {
217         result="false"
218         [[ "$TERM" == "dumb" ]] && return
219         [[ -t 1 ]] || return
220         C_BOLD='bold'
221         tput $C_BOLD &>/dev/null || {
222                 C_BOLD='md'
223                 tput $C_BOLD &>/dev/null
224         } || return
225         C_SETAF='setaf'
226         tput $C_SETAF 1 &>/dev/null || {
227                 C_SETAF='AF'
228                 tput $C_SETAF 1 &>/dev/null
229         } || return
230         C_SGR0='sgr0'
231         tput $C_SGR0 >/dev/null 2>&1 || {
232                 C_SGR0='me'
233                 tput $C_SGR0 &>/dev/null
234         } || return
235         result="true"
236 }
237
238 parse_options()
239 {
240         while (($# > 0)); do
241                 case "$1" in
242                 -i|--immediate) o_immediate="true"; shift;;
243                 -l|--long) export o_long="true"; shift;;
244                 -h|--help) o_help="true"; shift;;
245                 -v=0|--verbose=0) o_verbose="0"; shift;;
246                 -v=1|--verbose=1) o_verbose="1"; shift;;
247                 -v|--verbose|-v=2|--verbose=2) o_verbose="2"; shift;;
248                 --no-color) o_nocolor="true"; shift;;
249                 --man-dir) export o_man_dir="$2"; shift; shift;;
250                 --results-dir) o_results_dir="$2"; shift; shift;;
251                 --trash-dir) o_trash_dir="$2"; shift; shift;;
252                 --executables-dir) export o_executables_dir="$2"; shift; shift;;
253                 --executables) export o_executables="$2"; shift; shift;;
254                 --objects) export o_objects="$2"; shift; shift;;
255                 *) echo "error: unknown test option '$1'" >&2; exit 1;;
256                 esac
257         done
258         [[ -z "$o_verbose" ]] && o_verbose=1
259 }
260
261 create_trash_dir_and_cd()
262 {
263         local trash="$o_trash_dir/trash-dir.${0##*/}"
264
265         rm -rf "$trash" || error "could not remove trash dir"
266         mkdir -p "$trash" || error "could not make trash dir"
267         cd "$trash" || error "could not change to trash dir"
268 }
269
270 fixup_dirs()
271 {
272         local wd=$(pwd)
273
274         test_dir="$(realpath $wd/${0%/*})"
275         test_audio_file_dir="$test_dir/audio_files"
276
277         [[ -z "$o_results_dir" ]] && o_results_dir="$test_dir/test-results"
278         [[ -z "$o_executables_dir" ]] && o_executables_dir="$test_dir/.."
279         [[ -z "$o_trash_dir" ]] && o_trash_dir="$test_dir/trashes"
280         [[ -z "$o_man_dir" ]] && o_man_dir="$test_dir/../build/man/man1"
281
282         # we want alsolute paths because relative paths become invalid
283         # after changing to the trash dir
284         [[ -n "${o_results_dir##/*}" ]] && o_results_dir="$wd/$o_results_dir"
285         [[ -n "${o_executables_dir##/*}" ]] && o_executables_dir="$wd/$o_results_dir"
286         [[ -n "${o_man_dir##/*}" ]] && o_man_dir="$wd/$o_man_dir"
287         [[ -n "${o_trash_dir##/*}" ]] && o_trash_dir="$wd/$o_trash_dir"
288
289         mkdir -p "$o_results_dir"
290 }
291
292 parse_options "$@"
293 if [[ "$o_nocolor" != "true" ]]; then
294         can_use_colors
295         [[ "$result" != "true" ]] && o_nocolor="true"
296 fi
297
298 # Each test must set test_description
299 [[ -z "${test_description}" ]] && error "${0##*/} did not set test_description"
300 if [[ "$o_help" == "true" ]]; then
301         printf "${0##*/}: "
302         sed -e '1!d' <<< "$test_description"
303         if (($o_verbose >= 2)); then
304                 echo
305                 sed -e '1,2d' -e 's/^/  /g' <<<"$test_description"
306                 echo
307         fi
308         exit 0
309 fi
310 fixup_dirs
311
312 [[ -z "$o_executables" ]] && o_executables="para_afh para_audioc para_audiod
313         para_client para_mixer para_filter para_gui para_recv para_server
314         para_write"
315 for exe in $o_executables; do
316         export $(tr 'a-z' 'A-Z' <<< $exe)="$o_executables_dir/$exe"
317 done
318
319 test_failure=0
320 test_count=0
321 test_success=0
322 test_skipped=0
323
324 ORIGINAL_TERM=$TERM
325 sanitize_environment
326 create_trash_dir_and_cd
327
328 if (($o_verbose >= 2)); then
329         exec 4>&2 3>&1
330 else
331         exec 4>$o_results_dir/${0##*/}-$$.out 3>&4
332 fi
333
334 exit_ok=
335 trap 'die' EXIT
336
337 say_color run "# running ${0##*/}"