vscode: Add configurations to run the executables under the debugger
[lttng-tools.git] / tests / utils / tap / tap.sh
1 #!/bin/bash
2 #
3 # Copyright 2010 Patrick LeBoutillier <patrick.leboutillier@gmail.com>
4 #
5 # SPDX-License-Identifier: GPL-3.0-or-later
6 #
7
8 _version='1.01'
9
10 _plan_set=0
11 _no_plan=0
12 _skip_all=0
13 _test_died=0
14 _expected_tests=0
15 _executed_tests=0
16 _failed_tests=0
17 _auto_timing="${LTTNG_TESTS_TAP_AUTOTIME:-1}"
18 _last_time=''
19 TODO=
20 TIME_SCRIPT="$(realpath -e -- "$(dirname "${BASH_SOURCE[0]}")")/clock"
21
22 usage(){
23 cat <<'USAGE'
24 tap-functions: A TAP-producing BASH library
25
26 PLAN:
27 plan_no_plan
28 plan_skip_all [REASON]
29 plan_tests NB_TESTS
30
31 TEST:
32 ok RESULT [NAME]
33 okx COMMAND
34 is RESULT EXPECTED [NAME]
35 isnt RESULT EXPECTED [NAME]
36 like RESULT PATTERN [NAME]
37 unlike RESULT PATTERN [NAME]
38 pass [NAME]
39 fail [NAME]
40
41 SKIP:
42 skip [CONDITION] [REASON] [NB_TESTS=1]
43
44 skip $feature_not_present "feature not present" 2 || {
45 is $a "a"
46 is $b "b"
47 }
48
49 TODO:
50 Specify TODO mode by setting $TODO:
51 TODO="not implemented yet"
52 ok $result "some not implemented test"
53 unset TODO
54
55 OTHER:
56 diag MSG
57 autotime 0|1
58
59 EXAMPLE:
60 #!/bin/bash
61
62 . tap-functions
63
64 plan_tests 7
65
66 me=$USER
67 is $USER $me "I am myself"
68 like $HOME $me "My home is mine"
69 like "`id`" $me "My id matches myself"
70
71 /bin/ls $HOME 1>&2
72 ok $? "/bin/ls $HOME"
73 # Same thing using okx shortcut
74 okx /bin/ls $HOME
75
76 [[ "`id -u`" != "0" ]]
77 i_am_not_root=$?
78 skip $i_am_not_root "Must be root" || {
79 okx ls /root
80 }
81
82 TODO="figure out how to become root..."
83 okx [ "$HOME" == "/root" ]
84 unset TODO
85 USAGE
86 exit
87 }
88
89 opt=
90 set_u=
91 while getopts ":sx" opt ; do
92 case $_opt in
93 u) set_u=1 ;;
94 *) usage ;;
95 esac
96 done
97 shift $(( OPTIND - 1 ))
98 # Don't allow uninitialized variables if requested
99 [[ -n "$set_u" ]] && set -u
100 unset opt set_u
101
102 # Used to call _cleanup on shell exit
103 trap _exit EXIT
104
105
106 plan_no_plan(){
107 (( _plan_set != 0 )) && "You tried to plan twice!"
108
109 _plan_set=1
110 _no_plan=1
111 _last_time=$("${TIME_SCRIPT}")
112
113 return 0
114 }
115
116
117 plan_skip_all(){
118 local reason=${1:-''}
119
120 (( _plan_set != 0 )) && _die "You tried to plan twice!"
121
122 _print_plan 0 "Skip $reason"
123
124 _skip_all=1
125 _plan_set=1
126 _last_time=$("${TIME_SCRIPT}")
127 _exit 0
128
129 return 0
130 }
131
132 plan_tests(){
133 local tests=${1:?}
134
135 (( _plan_set != 0 )) && _die "You tried to plan twice!"
136 (( tests == 0 )) && _die "You said to run 0 tests! You've got to run something."
137
138 _print_plan $tests
139 _expected_tests=$tests
140 _plan_set=1
141 _last_time=$("${TIME_SCRIPT}")
142
143 return $tests
144 }
145
146
147 _print_plan(){
148 local tests=${1:?}
149 local directive=${2:-''}
150
151 echo -n "1..$tests"
152 [[ -n "$directive" ]] && echo -n " # $directive"
153 echo
154 }
155
156
157 pass(){
158 local name=$1
159 ok 0 "$name"
160 }
161
162
163 fail(){
164 local name=$1
165 ok 1 "$name"
166 }
167
168 # This is the workhorse method that actually
169 # prints the tests result.
170 ok(){
171 local result=${1:?}
172 local name=${2:-''}
173
174 (( _plan_set == 0 )) && _die "You tried to run a test without a plan! Gotta have a plan."
175
176 _executed_tests=$(( $_executed_tests + 1 ))
177
178 if [[ -n "$name" ]] ; then
179 if _matches "$name" "^[0-9]+$" ; then
180 diag " You named your test '$name'. You shouldn't use numbers for your test names."
181 diag " Very confusing."
182 fi
183 fi
184
185 if (( result != 0 )) ; then
186 echo -n "not "
187 _failed_tests=$(( _failed_tests + 1 ))
188 fi
189 echo -n "ok $_executed_tests"
190
191 if [[ -n "$name" ]] ; then
192 local ename=${name//\#/\\#}
193 echo -n " - $ename"
194 fi
195
196 if [[ -n "$TODO" ]] ; then
197 echo -n " # TODO $TODO" ;
198 if (( result != 0 )) ; then
199 _failed_tests=$(( _failed_tests - 1 ))
200 fi
201 fi
202
203 echo
204 _autotime
205 if (( result != 0 )) ; then
206 local file='tap-functions'
207 local func=
208 local line=
209
210 local i=0
211 local bt=$(caller $i)
212 while _matches "$bt" "tap-functions$" ; do
213 i=$(( $i + 1 ))
214 bt=$(caller $i)
215 done
216 local backtrace=
217 eval $(caller $i | (read line func file ; echo "backtrace=\"$file:$func() at line $line.\""))
218
219 local t=
220 [[ -n "$TODO" ]] && t="(TODO) "
221
222 if [[ -n "$name" ]] ; then
223 diag " Failed ${t}test '$name'"
224 diag " in $backtrace"
225 else
226 diag " Failed ${t}test in $backtrace"
227 fi
228 fi
229
230 return $result
231 }
232
233
234 okx(){
235 local command="$@"
236
237 local line=
238 diag "Output of '$command':"
239 "$@" | while read line ; do
240 diag "$line"
241 done
242 ok ${PIPESTATUS[0]} "$command"
243 _autotime
244 }
245
246
247 _equals(){
248 local result=${1:?}
249 local expected=${2:?}
250
251 if [[ "$result" == "$expected" ]] ; then
252 return 0
253 else
254 return 1
255 fi
256 }
257
258
259 # Thanks to Aaron Kangas for the patch to allow regexp matching
260 # under bash < 3.
261 _bash_major_version=${BASH_VERSION%%.*}
262 _matches(){
263 local result=${1:?}
264 local pattern=${2:?}
265
266 if [[ -z "$result" || -z "$pattern" ]] ; then
267 return 1
268 else
269 if (( _bash_major_version >= 3 )) ; then
270 [[ "$result" =~ "$pattern" ]]
271 else
272 echo "$result" | egrep -q "$pattern"
273 fi
274 fi
275 }
276
277
278 _is_diag(){
279 local result=${1:?}
280 local expected=${2:?}
281
282 diag " got: '$result'"
283 diag " expected: '$expected'"
284 }
285
286
287 is(){
288 local result=${1:?}
289 local expected=${2:?}
290 local name=${3:-''}
291
292 _equals "$result" "$expected"
293 (( $? == 0 ))
294 ok $? "$name"
295 local r=$?
296 (( r != 0 )) && _is_diag "$result" "$expected"
297 return $r
298 }
299
300
301 isnt(){
302 local result=${1:?}
303 local expected=${2:?}
304 local name=${3:-''}
305
306 _equals "$result" "$expected"
307 (( $? != 0 ))
308 ok $? "$name"
309 local r=$?
310 (( r != 0 )) && _is_diag "$result" "$expected"
311 return $r
312 }
313
314
315 like(){
316 local result=${1:?}
317 local pattern=${2:?}
318 local name=${3:-''}
319
320 _matches "$result" "$pattern"
321 (( $? == 0 ))
322 ok $? "$name"
323 local r=$?
324 (( r != 0 )) && diag " '$result' doesn't match '$pattern'"
325 return $r
326 }
327
328
329 unlike(){
330 local result=${1:?}
331 local pattern=${2:?}
332 local name=${3:-''}
333
334 _matches "$result" "$pattern"
335 (( $? != 0 ))
336 ok $? "$name"
337 local r=$?
338 (( r != 0 )) && diag " '$result' matches '$pattern'"
339 return $r
340 }
341
342
343 skip(){
344 local condition=${1:?}
345 local reason=${2:-''}
346 local n=${3:-1}
347
348 if (( condition == 0 )) ; then
349 local i=
350 for (( i=0 ; i<$n ; i++ )) ; do
351 _executed_tests=$(( _executed_tests + 1 ))
352 echo "ok $_executed_tests # skip: $reason"
353 _autotime
354 done
355 return 0
356 else
357 return
358 fi
359 }
360
361 _autotime(){
362 local new_time
363 local duration
364
365 if [ "${_auto_timing}" -eq "1" ] ; then
366 new_time=$("${TIME_SCRIPT}")
367 duration=$(awk "BEGIN { printf(\"%f\n\", ($new_time - $_last_time)*1000) }")
368 echo " ---"
369 echo " duration_ms: ${duration}"
370 echo " ..."
371 fi
372 _last_time=$("${TIME_SCRIPT}")
373 return 0
374 }
375
376
377 autotime(){
378 local val=${1:?}
379
380 if [[ "${val}" != "0" ]] ; then
381 _auto_timing=1
382 else
383 _auto_timing=0;
384 fi
385 return 0
386 }
387
388 diag(){
389 local msg=${1:?}
390
391 if [[ -n "$msg" ]] ; then
392 echo "# $msg"
393 fi
394
395 return 1
396 }
397
398
399 _die(){
400 local reason=${1:-'<unspecified error>'}
401
402 echo "$reason" >&2
403 _test_died=1
404 _exit 255
405 }
406
407
408 BAIL_OUT(){
409 local reason=${1:-''}
410
411 echo "Bail out! $reason" >&2
412 _exit 255
413 }
414
415
416 _cleanup(){
417 local rc=0
418
419 if (( _plan_set == 0 )) ; then
420 diag "Looks like your test died before it could output anything."
421 return $rc
422 fi
423
424 if (( _test_died != 0 )) ; then
425 diag "Looks like your test died just after $_executed_tests."
426 return $rc
427 fi
428
429 if (( _skip_all == 0 && _no_plan != 0 )) ; then
430 _print_plan $_executed_tests
431 fi
432
433 local s=
434 if (( _no_plan == 0 && _expected_tests < _executed_tests )) ; then
435 s= ; (( _expected_tests > 1 )) && s=s
436 local extra=$(( _executed_tests - _expected_tests ))
437 diag "Looks like you planned $_expected_tests test$s but ran $extra extra."
438 rc=1 ;
439 fi
440
441 if (( _no_plan == 0 && _expected_tests > _executed_tests )) ; then
442 s= ; (( _expected_tests > 1 )) && s=s
443 diag "Looks like you planned $_expected_tests test$s but only ran $_executed_tests."
444 fi
445
446 if (( _failed_tests > 0 )) ; then
447 s= ; (( _failed_tests > 1 )) && s=s
448 diag "Looks like you failed $_failed_tests test$s of $_executed_tests."
449 fi
450
451 return $rc
452 }
453
454
455 _exit_status(){
456 if (( _no_plan != 0 || _plan_set == 0 )) ; then
457 return $_failed_tests
458 fi
459
460 if (( _expected_tests < _executed_tests )) ; then
461 return $(( _executed_tests - _expected_tests ))
462 fi
463
464 return $(( _failed_tests + ( _expected_tests - _executed_tests )))
465 }
466
467
468 _exit(){
469 local rc=${1:-''}
470 if [[ -z "$rc" ]] ; then
471 _exit_status
472 rc=$?
473 fi
474
475 _cleanup
476 local alt_rc=$?
477 (( alt_rc != 0 )) && rc=$alt_rc
478 trap - EXIT
479 exit $rc
480 }
This page took 0.037664 seconds and 5 git commands to generate.