f9347d80b6cf41bfa951dce738694c668439725d
[openafs.git] / src / external / c-tap-harness / tests / tap / libtap.sh
1 # Shell function library for test cases.
2 #
3 # Note that while many of the functions in this library could benefit from
4 # using "local" to avoid possibly hammering global variables, Solaris /bin/sh
5 # doesn't support local and this library aspires to be portable to Solaris
6 # Bourne shell.  Instead, all private variables are prefixed with "tap_".
7 #
8 # This file provides a TAP-compatible shell function library useful for
9 # writing test cases.  It is part of C TAP Harness, which can be found at
10 # <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
11 #
12 # Written by Russ Allbery <rra@stanford.edu>
13 # Copyright 2009, 2010, 2011, 2012 Russ Allbery <rra@stanford.edu>
14 # Copyright 2006, 2007, 2008
15 #     The Board of Trustees of the Leland Stanford Junior University
16 #
17 # Permission is hereby granted, free of charge, to any person obtaining a copy
18 # of this software and associated documentation files (the "Software"), to
19 # deal in the Software without restriction, including without limitation the
20 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
21 # sell copies of the Software, and to permit persons to whom the Software is
22 # furnished to do so, subject to the following conditions:
23 #
24 # The above copyright notice and this permission notice shall be included in
25 # all copies or substantial portions of the Software.
26 #
27 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
30 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
33 # IN THE SOFTWARE.
34
35 # Print out the number of test cases we expect to run.
36 plan () {
37     count=1
38     planned="$1"
39     failed=0
40     echo "1..$1"
41     trap finish 0
42 }
43
44 # Prepare for lazy planning.
45 plan_lazy () {
46     count=1
47     planned=0
48     failed=0
49     trap finish 0
50 }
51
52 # Report the test status on exit.
53 finish () {
54     tap_highest=`expr "$count" - 1`
55     if [ "$planned" = 0 ] ; then
56         echo "1..$tap_highest"
57         planned="$tap_highest"
58     fi
59     tap_looks='# Looks like you'
60     if [ "$planned" -gt 0 ] ; then
61         if [ "$planned" -gt "$tap_highest" ] ; then
62             if [ "$planned" -gt 1 ] ; then
63                 echo "$tap_looks planned $planned tests but only ran" \
64                     "$tap_highest"
65             else
66                 echo "$tap_looks planned $planned test but only ran" \
67                     "$tap_highest"
68             fi
69         elif [ "$planned" -lt "$tap_highest" ] ; then
70             tap_extra=`expr "$tap_highest" - "$planned"`
71             if [ "$planned" -gt 1 ] ; then
72                 echo "$tap_looks planned $planned tests but ran" \
73                     "$tap_extra extra"
74             else
75                 echo "$tap_looks planned $planned test but ran" \
76                     "$tap_extra extra"
77             fi
78         elif [ "$failed" -gt 0 ] ; then
79             if [ "$failed" -gt 1 ] ; then
80                 echo "$tap_looks failed $failed tests of $planned"
81             else
82                 echo "$tap_looks failed $failed test of $planned"
83             fi
84         elif [ "$planned" -gt 1 ] ; then
85             echo "# All $planned tests successful or skipped"
86         else
87             echo "# $planned test successful or skipped"
88         fi
89     fi
90 }
91
92 # Skip the entire test suite.  Should be run instead of plan.
93 skip_all () {
94     tap_desc="$1"
95     if [ -n "$tap_desc" ] ; then
96         echo "1..0 # skip $tap_desc"
97     else
98         echo "1..0 # skip"
99     fi
100     exit 0
101 }
102
103 # ok takes a test description and a command to run and prints success if that
104 # command is successful, false otherwise.  The count starts at 1 and is
105 # updated each time ok is printed.
106 ok () {
107     tap_desc="$1"
108     if [ -n "$tap_desc" ] ; then
109         tap_desc=" - $tap_desc"
110     fi
111     shift
112     if "$@" ; then
113         echo ok "$count$tap_desc"
114     else
115         echo not ok "$count$tap_desc"
116         failed=`expr $failed + 1`
117     fi
118     count=`expr $count + 1`
119 }
120
121 # Skip the next test.  Takes the reason why the test is skipped.
122 skip () {
123     echo "ok $count # skip $*"
124     count=`expr $count + 1`
125 }
126
127 # Report the same status on a whole set of tests.  Takes the count of tests,
128 # the description, and then the command to run to determine the status.
129 ok_block () {
130     tap_i=$count
131     tap_end=`expr $count + $1`
132     shift
133     while [ "$tap_i" -lt "$tap_end" ] ; do
134         ok "$@"
135         tap_i=`expr $tap_i + 1`
136     done
137 }
138
139 # Skip a whole set of tests.  Takes the count and then the reason for skipping
140 # the test.
141 skip_block () {
142     tap_i=$count
143     tap_end=`expr $count + $1`
144     shift
145     while [ "$tap_i" -lt "$tap_end" ] ; do
146         skip "$@"
147         tap_i=`expr $tap_i + 1`
148     done
149 }
150
151 # Portable variant of printf '%s\n' "$*".  In the majority of cases, this
152 # function is slower than printf, because the latter is often implemented
153 # as a builtin command.  The value of the variable IFS is ignored.
154 #
155 # This macro must not be called via backticks inside double quotes, since this
156 # will result in bizarre escaping behavior and lots of extra backslashes on
157 # Solaris.
158 puts () {
159     cat << EOH
160 $@
161 EOH
162 }
163
164 # Run a program expected to succeed, and print ok if it does and produces the
165 # correct output.  Takes the description, expected exit status, the expected
166 # output, the command to run, and then any arguments for that command.
167 # Standard output and standard error are combined when analyzing the output of
168 # the command.
169 #
170 # If the command may contain system-specific error messages in its output,
171 # add strip_colon_error before the command to post-process its output.
172 ok_program () {
173     tap_desc="$1"
174     shift
175     tap_w_status="$1"
176     shift
177     tap_w_output="$1"
178     shift
179     tap_output=`"$@" 2>&1`
180     tap_status=$?
181     if [ $tap_status = $tap_w_status ] \
182         && [ x"$tap_output" = x"$tap_w_output" ] ; then
183         ok "$tap_desc" true
184     else
185         echo "#  saw: ($tap_status) $tap_output"
186         echo "#  not: ($tap_w_status) $tap_w_output"
187         ok "$tap_desc" false
188     fi
189 }
190
191 # Strip a colon and everything after it off the output of a command, as long
192 # as that colon comes after at least one whitespace character.  (This is done
193 # to avoid stripping the name of the program from the start of an error
194 # message.)  This is used to remove system-specific error messages (coming
195 # from strerror, for example).
196 strip_colon_error() {
197     tap_output=`"$@" 2>&1`
198     tap_status=$?
199     tap_output=`puts "$tap_output" | sed 's/^\([^ ]* [^:]*\):.*/\1/'`
200     puts "$tap_output"
201     return $tap_status
202 }
203
204 # Bail out with an error message.
205 bail () {
206     echo 'Bail out!' "$@"
207     exit 1
208 }
209
210 # Output a diagnostic on standard error, preceded by the required # mark.
211 diag () {
212     echo '#' "$@"
213 }
214
215 # Search for the given file first in $BUILD and then in $SOURCE and echo the
216 # path where the file was found, or the empty string if the file wasn't
217 # found.
218 #
219 # This macro uses puts, so don't run it using backticks inside double quotes
220 # or bizarre quoting behavior will happen with Solaris sh.
221 test_file_path () {
222     if [ -n "$BUILD" ] && [ -f "$BUILD/$1" ] ; then
223         puts "$BUILD/$1"
224     elif [ -n "$SOURCE" ] && [ -f "$SOURCE/$1" ] ; then
225         puts "$SOURCE/$1"
226     else
227         echo ''
228     fi
229 }
230
231 # Create $BUILD/tmp for use by tests for storing temporary files and return
232 # the path (via standard output).
233 #
234 # This macro uses puts, so don't run it using backticks inside double quotes
235 # or bizarre quoting behavior will happen with Solaris sh.
236 test_tmpdir () {
237     if [ -z "$BUILD" ] ; then
238         tap_tmpdir="./tmp"
239     else
240         tap_tmpdir="$BUILD"/tmp
241     fi
242     if [ ! -d "$tap_tmpdir" ] ; then
243         mkdir "$tap_tmpdir" || bail "Error creating $tap_tmpdir"
244     fi
245     puts "$tap_tmpdir"
246 }