Imported Upstream version 1.3.14
[debian/gzip] / tests / test-lib.sh
1 # source this file; set up for tests
2
3 # Copyright (C) 2009 Free Software Foundation, Inc.
4
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 # Skip this test if the shell lacks support for functions.
19 unset function_test
20 eval 'function_test() { return 11; }; function_test'
21 if test $? != 11; then
22   echo "$0: /bin/sh lacks support for functions; skipping this test." 1>&2
23   Exit 77
24 fi
25
26 skip_test_()
27 {
28   echo "$0: skipping test: $@" | head -1 1>&9
29   echo "$0: skipping test: $@" 1>&2
30   Exit 77
31 }
32
33 getlimits_()
34 {
35     eval $(getlimits)
36     test "$INT_MAX" ||
37     error_ "Error running getlimits"
38 }
39
40 require_acl_()
41 {
42   getfacl --version < /dev/null > /dev/null 2>&1 \
43     && setfacl --version < /dev/null > /dev/null 2>&1 \
44       || skip_test_ "This test requires getfacl and setfacl."
45
46   id -u bin > /dev/null 2>&1 \
47     || skip_test_ "This test requires a local user named bin."
48 }
49
50 # Skip this test if we're not in SELinux "enforcing" mode.
51 require_selinux_enforcing_()
52 {
53   test "$(getenforce)" = Enforcing \
54     || skip_test_ "This test is useful only with SELinux in Enforcing mode."
55 }
56
57
58 require_openat_support_()
59 {
60   # Skip this test if your system has neither the openat-style functions
61   # nor /proc/self/fd support with which to emulate them.
62   test -z "$CONFIG_HEADER" \
63     && skip_test_ 'internal error: CONFIG_HEADER not defined'
64
65   _skip=yes
66   grep '^#define HAVE_OPENAT' "$CONFIG_HEADER" > /dev/null && _skip=no
67   test -d /proc/self/fd && _skip=no
68   if test $_skip = yes; then
69     skip_test_ 'this system lacks openat support'
70   fi
71 }
72
73 require_ulimit_()
74 {
75   ulimit_works=yes
76   # Expect to be able to exec a program in 10MB of virtual memory,
77   # but not in 20KB.  I chose "date".  It must not be a shell built-in
78   # function, so you can't use echo, printf, true, etc.
79   # Of course, in coreutils, I could use $top_builddir/src/true,
80   # but this should be able to work for other projects, too.
81   ( ulimit -v 10000; date ) > /dev/null 2>&1 || ulimit_works=no
82   ( ulimit -v 20;    date ) > /dev/null 2>&1 && ulimit_works=no
83
84   test $ulimit_works = no \
85     && skip_test_ "this shell lacks ulimit support"
86 }
87
88 require_readable_root_()
89 {
90   test -r / || skip_test_ "/ is not readable"
91 }
92
93 # Skip the current test if strace is not available or doesn't work
94 # with the named syscall.  Usage: require_strace_ unlink
95 require_strace_()
96 {
97   test $# = 1 || framework_failure
98
99   strace -V < /dev/null > /dev/null 2>&1 ||
100     skip_test_ 'no strace program'
101
102   strace -qe "$1" echo > /dev/null 2>&1 ||
103     skip_test_ 'strace -qe "'"$1"'" does not work'
104 }
105
106 # Require a controlling input `terminal'.
107 require_controlling_input_terminal_()
108 {
109   tty -s || have_input_tty=no
110   test -t 0 || have_input_tty=no
111   if test "$have_input_tty" = no; then
112     skip_test_ 'requires controlling input terminal
113 This test must have a controlling input "terminal", so it may not be
114 run via "batch", "at", or "ssh".  On some systems, it may not even be
115 run in the background.'
116   fi
117 }
118
119 require_built_()
120 {
121   skip_=no
122   for i in "$@"; do
123     case " $built_programs " in
124       *" $i "*) ;;
125       *) echo "$i: not built" 1>&2; skip_=yes ;;
126     esac
127   done
128
129   test $skip_ = yes && skip_test_ "required program(s) not built"
130 }
131
132 uid_is_privileged_()
133 {
134   # Make sure id -u succeeds.
135   my_uid=$(id -u) \
136     || { echo "$0: cannot run \`id -u'" 1>&2; return 1; }
137
138   # Make sure it gives valid output.
139   case $my_uid in
140     0) ;;
141     *[!0-9]*)
142       echo "$0: invalid output (\`$my_uid') from \`id -u'" 1>&2
143       return 1 ;;
144     *) return 1 ;;
145   esac
146 }
147
148 get_process_status_()
149 {
150   sed -n '/^State:[      ]*\([[:alpha:]]\).*/s//\1/p' /proc/$1/status
151 }
152
153 # Convert an ls-style permission string, like drwxr----x and -rw-r-x-wx
154 # to the equivalent chmod --mode (-m) argument, (=,u=rwx,g=r,o=x and
155 # =,u=rw,g=rx,o=wx).  Ignore ACLs.
156 rwx_to_mode_()
157 {
158   case $# in
159     1) rwx=$1;;
160     *) echo "$0: wrong number of arguments" 1>&2
161       echo "Usage: $0 ls-style-mode-string" 1>&2
162       return;;
163   esac
164
165   case $rwx in
166     [ld-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxtT-]) ;;
167     [ld-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxtT-][+.]) ;;
168     *) echo "$0: invalid mode string: $rwx" 1>&2; return;;
169   esac
170
171   # Perform these conversions:
172   # S  s
173   # s  xs
174   # T  t
175   # t  xt
176   # The `T' and `t' ones are only valid for `other'.
177   s='s/S/@/;s/s/x@/;s/@/s/'
178   t='s/T/@/;s/t/x@/;s/@/t/'
179
180   u=`echo $rwx|sed 's/^.\(...\).*/,u=\1/;s/-//g;s/^,u=$//;'$s`
181   g=`echo $rwx|sed 's/^....\(...\).*/,g=\1/;s/-//g;s/^,g=$//;'$s`
182   o=`echo $rwx|sed 's/^.......\(...\).*/,o=\1/;s/-//g;s/^,o=$//;'$s';'$t`
183   echo "=$u$g$o"
184 }
185
186 skip_if_()
187 {
188   case $1 in
189     root) skip_test_ must be run as root ;;
190     non-root) skip_test_ must be run as non-root ;;
191     *) ;;  # FIXME?
192   esac
193 }
194
195 require_selinux_()
196 {
197   case `ls -Zd .` in
198     '? .'|'unlabeled .')
199       skip_test_ "this system (or maybe just" \
200         "the current file system) lacks SELinux support"
201     ;;
202   esac
203 }
204
205 very_expensive_()
206 {
207   if test "$RUN_VERY_EXPENSIVE_TESTS" != yes; then
208     skip_test_ 'very expensive: disabled by default
209 This test is very expensive, so it is disabled by default.
210 To run it anyway, rerun make check with the RUN_VERY_EXPENSIVE_TESTS
211 environment variable set to yes.  E.g.,
212
213   env RUN_VERY_EXPENSIVE_TESTS=yes make check
214 '
215   fi
216 }
217
218 expensive_()
219 {
220   if test "$RUN_EXPENSIVE_TESTS" != yes; then
221     skip_test_ 'expensive: disabled by default
222 This test is relatively expensive, so it is disabled by default.
223 To run it anyway, rerun make check with the RUN_EXPENSIVE_TESTS
224 environment variable set to yes.  E.g.,
225
226   env RUN_EXPENSIVE_TESTS=yes make check
227 '
228   fi
229 }
230
231 require_root_()
232 {
233   uid_is_privileged_ || skip_test_ "must be run as root"
234   NON_ROOT_USERNAME=${NON_ROOT_USERNAME=nobody}
235   NON_ROOT_GROUP=${NON_ROOT_GROUP=$(id -g $NON_ROOT_USERNAME)}
236 }
237
238 skip_if_root_() { uid_is_privileged_ && skip_test_ "must be run as non-root"; }
239 error_() { echo "$0: $@" 1>&2; Exit 1; }
240 framework_failure() { error_ 'failure in testing framework'; }
241
242 # Set `groups' to a space-separated list of at least two groups
243 # of which the user is a member.
244 require_membership_in_two_groups_()
245 {
246   test $# = 0 || framework_failure
247
248   groups=${COREUTILS_GROUPS-`(id -G || /usr/xpg4/bin/id -G) 2>/dev/null`}
249   case "$groups" in
250     *' '*) ;;
251     *) skip_test_ 'requires membership in two groups
252 this test requires that you be a member of more than one group,
253 but running `id -G'\'' either failed or found just one.  If you really
254 are a member of at least two groups, then rerun this test with
255 COREUTILS_GROUPS set in your environment to the space-separated list
256 of group names or numbers.  E.g.,
257
258   env COREUTILS_GROUPS='users cdrom' make check
259
260 '
261      ;;
262   esac
263 }
264
265 # Is /proc/$PID/status supported?
266 require_proc_pid_status_()
267 {
268     sleep 2 &
269     local pid=$!
270     sleep .5
271     grep '^State:[       ]*[S]' /proc/$pid/status > /dev/null 2>&1 ||
272     skip_test_ "/proc/$pid/status: missing or 'different'"
273     kill $pid
274 }
275
276 # Does the current (working-dir) file system support sparse files?
277 require_sparse_support_()
278 {
279   test $# = 0 || framework_failure
280   # Test whether we can create a sparse file.
281   # For example, on Darwin6.5 with a file system of type hfs, it's not possible.
282   # NTFS requires 128K before a hole appears in a sparse file.
283   t=sparse.$$
284   dd bs=1 seek=128K of=$t < /dev/null 2> /dev/null
285   set x `du -sk $t`
286   kb_size=$2
287   rm -f $t
288   if test $kb_size -ge 128; then
289     skip_test_ 'this file system does not support sparse files'
290   fi
291 }
292
293 mkfifo_or_skip_()
294 {
295   test $# = 1 || framework_failure
296   if ! mkfifo "$1"; then
297     # Make an exception of this case -- usually we interpret framework-creation
298     # failure as a test failure.  However, in this case, when running on a SunOS
299     # system using a disk NFS mounted from OpenBSD, the above fails like this:
300     # mkfifo: cannot make fifo `fifo-10558': Not owner
301     skip_test_ 'NOTICE: unable to create test prerequisites'
302   fi
303 }
304
305 # Disable the current test if the working directory seems to have
306 # the setgid bit set.
307 skip_if_setgid_()
308 {
309   setgid_tmpdir=setgid-$$
310   (umask 77; mkdir $setgid_tmpdir)
311   perms=$(stat --printf %A $setgid_tmpdir)
312   rmdir $setgid_tmpdir
313   case $perms in
314     drwx------);;
315     drwxr-xr-x);;  # Windows98 + DJGPP 2.03
316     *) skip_test_ 'this directory has the setgid bit set';;
317   esac
318 }
319
320 skip_if_mcstransd_is_running_()
321 {
322   test $# = 0 || framework_failure
323
324   # When mcstransd is running, you'll see only the 3-component
325   # version of file-system context strings.  Detect that,
326   # and if it's running, skip this test.
327   __ctx=$(stat --printf='%C\n' .) || framework_failure
328   case $__ctx in
329     *:*:*:*) ;; # four components is ok
330     *) # anything else probably means mcstransd is running
331         skip_test_ "unexpected context '$__ctx'; turn off mcstransd" ;;
332   esac
333 }
334
335 # Skip the current test if umask doesn't work as usual.
336 # This test should be run in the temporary directory that ends
337 # up being removed via the trap commands.
338 working_umask_or_skip_()
339 {
340   umask 022
341   touch file1 file2
342   chmod 644 file2
343   perms=`ls -l file1 file2 | sed 's/ .*//' | uniq`
344   rm -f file1 file2
345
346   case $perms in
347   *'
348   '*) skip_test_ 'your build directory has unusual umask semantics'
349   esac
350 }
351
352 # We use a trap below for cleanup.  This requires us to go through
353 # hoops to get the right exit status transported through the signal.
354 # So use `Exit STATUS' instead of `exit STATUS' inside of the tests.
355 # Turn off errexit here so that we don't trip the bug with OSF1/Tru64
356 # sh inside this function.
357 Exit ()
358 {
359   set +e
360   (exit $1)
361   exit $1
362 }
363
364 test_dir_=$(pwd)
365
366 this_test_() { echo "./$0" | sed 's,.*/,,'; }
367 this_test=$(this_test_)
368
369 # This is a stub function that is run upon trap (upon regular exit and
370 # interrupt).  Override it with a per-test function, e.g., to unmount
371 # a partition, or to undo any other global state changes.
372 cleanup_() { :; }
373
374 t_=$(mktemp -d --tmp="$test_dir_" gz-$this_test.XXXXXXXXXX)\
375     || error_ "failed to create temporary directory in $test_dir_"
376
377 remove_tmp_()
378 {
379   __st=$?
380   cleanup_
381   cd "$test_dir_" && chmod -R u+rwx "$t_" && rm -rf "$t_" && exit $__st
382 }
383
384 # Run each test from within a temporary sub-directory named after the
385 # test itself, and arrange to remove it upon exception or normal exit.
386 trap remove_tmp_ 0
387 trap 'Exit $?' 1 2 13 15
388
389 cd "$t_" || error_ "failed to cd to $t_"
390
391 if ( diff --version < /dev/null 2>&1 | grep GNU ) 2>&1 > /dev/null; then
392   compare() { diff -u "$@"; }
393 elif ( cmp --version < /dev/null 2>&1 | grep GNU ) 2>&1 > /dev/null; then
394   compare() { cmp -s "$@"; }
395 else
396   compare() { cmp "$@"; }
397 fi