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