summaryrefslogtreecommitdiff
path: root/t/ax/test-lib.sh
blob: c0a077ceb271a1ad12b8a62c03b97fee66a251ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# -*- shell-script -*-
#
# Copyright (C) 1996-2023 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

########################################################
###  IMPORTANT NOTE: keep this file 'set -e' clean.  ###
########################################################

# Do not source several times.
test ${test_lib_sourced-no} = yes && return 0
test_lib_sourced=yes

# CDPATH is evil if used in non-interactive scripts (and even more
# evil if exported in the environment).
CDPATH=; unset CDPATH

# Be more Bourne compatible.
# (Snippet inspired to configure's initialization in Autoconf 2.64)
DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
  emulate sh
  NULLCMD=:
  setopt NO_GLOB_SUBST
  # If Zsh is not started directly in POSIX-compatibility mode, it has some
  # incompatibilities in the handling of $0 that conflict with our usage;
  # i.e., $0 inside a file sourced with the '.' builtin is temporarily set
  # to the name of the sourced file.  Work around that.
  # Note that a bug in some versions of Zsh prevents us from resetting $0
  # in a sourced script, so the use of $argv0.  For more info see:
  #   <http://www.zsh.org/mla/workers/2009/msg01140.html>
  # The apparently useless 'eval' here is needed by at least dash 0.5.2,
  # to prevent it from bailing out with an error like:
  #   "Syntax error: Bad substitution".
  eval 'argv0=${functrace[-1]%:*}' && test -f "$argv0" || {
    echo "Cannot determine the path of running test script." >&2
    echo "Your Zsh (version $ZSH_VERSION) is probably too old." >&2
    exit 99
  }
else
  argv0=$0
  # Ignore command substitution failure, for it might cause problems
  # with "set -e" on some shells.
  am_shell_opts=$(set -o) || :
  case $am_shell_opts in *posix*) set -o posix;; esac
  unset am_shell_opts
fi

# A single whitespace character.
sp=' '
# A tabulation character.
tab='	'
# A newline character.
nl='
'

# As autoconf-generated configure scripts do, ensure that IFS
# is defined initially, so that saving and restoring $IFS works.
IFS=$sp$tab$nl

# The name of the current test (without the '.sh' or '.tap' suffix).
me=${argv0##*/} # Strip all directory components.
case $me in     # Strip test suffix.
   *.tap) me=${me%.tap};;
    *.sh) me=${me%.sh} ;;
 esac

# Source extra package-specific configuration.
. test-defs.sh
# And fail hard if something went wrong.
test $? -eq 0 || exit 99

# We use a trap below for cleanup.  This requires us to go through
# hoops to get the right exit status transported through the signal.
# Turn off errexit here so that we don't trip the bug with OSF1/Tru64
# sh inside this function (FIXME: is this still relevant now that we
# require a POSIX shell?).
_am_exit ()
{
  set +e
  # See comments in the exit trap for the reason we do this.
  test 77 = $1 && am__test_skipped=yes
  # Extra escaping to ensure we do not call our 'exit' alias.
  (\exit $1); \exit $1
}
# Avoid interferences from the environment
am__test_skipped=no
# This alias must actually be placed before any use if 'exit' -- even
# just inside a function definition.  Weird, but real.
alias exit=_am_exit

# In some shells (e.g., Solaris 10 /bin/ksh, or NetBSD 5.1 /bin/sh),
# "unset VAR" returns a non-zero exit status in case the VAR variable
# is already unset.  This doesn't interact well with our usage of
# "set -e" in the testsuite.  This function and the alias below help
# to work around the issue.  But be sure to use them only if actually
# needed.  The repeated unset in the check below cater to the very
# unlikely case where the '_am_v' variable is set in the environment.
if unset _am_v && unset _am_v; then
  : Nothing needs to be done.
else
  _am_unset ()
  {
    for _am_v
    do
      # Extra escaping (here and below) to ensure we do not call our
      # 'unset' alias.
      eval ${_am_v}=dummy && \unset ${_am_v} || return 1
    done
    \unset _am_v
  }
  alias unset=_am_unset
fi

## ------------------------------------ ##
##  General testsuite shell functions.  ##
## ------------------------------------ ##

# Print warnings (e.g., about skipped and failed tests) to this file
# number.  Override by putting, say:
#   AM_TESTS_ENVIRONMENT = stderr_fileno_=9; export stderr_fileno_;
#   AM_TESTS_FD_REDIRECT = 9>&2
# in your Makefile.am.
# This is useful when using automake's parallel tests mode, to print the
# reason for skip/failure to console, rather than to the *.log files.
: ${stderr_fileno_=2}

# Helper functions used by "plain" tests of the Automake testsuite
# (i.e., tests that don't use any test protocol).
# TAP tests will override these functions with their TAP-enhanced
# equivalents later  (see sourcing of 'tap-functions.sh' below).
# These are copied from Gnulib's 'tests/init.sh'.
warn_ () { echo "$@" 1>&$stderr_fileno_; }
fail_ () { warn_ "$me: failed test: $@"; exit 1; }
skip_ () { warn_ "$me: skipped test: $@"; exit 77; }
fatal_ () { warn_ "$me: hard error: $@"; exit 99; }
framework_failure_ () { warn_ "$me: set-up failure: $@"; exit 99; }
# For compatibility with TAP functions.
skip_all_ () { skip_ "$@"; }

if test $am_test_protocol = tap; then
  . tap-functions.sh
fi

## ---------------------------- ##
##  Auxiliary shell functions.  ##
## ---------------------------- ##

# Tell whether we should keep the test directories around, even in
# case of success.  By default, we don't.
am_keeping_testdirs ()
{
  case $keep_testdirs in
     ""|n|no|NO) return 1;;
              *) return 0;;
  esac
}

# seq_ - print a sequence of numbers
# ----------------------------------
# This function simulates GNU seq(1) portably.  Valid usages:
#  - seq LAST
#  - seq FIRST LAST
#  - seq FIRST INCREMENT LAST
seq_ ()
{
  case $# in
    0) fatal_ "seq_: missing argument";;
    1) seq_first=1  seq_incr=1  seq_last=$1;;
    2) seq_first=$1 seq_incr=1  seq_last=$2;;
    3) seq_first=$1 seq_incr=$2 seq_last=$3;;
    *) fatal_ "seq_: too many arguments";;
  esac
  i=$seq_first
  while test $i -le $seq_last; do
    echo $i
    i=$(($i + $seq_incr))
  done
}

# rm_rf_ [FILES OR DIRECTORIES ...]
# ---------------------------------
# Recursively remove the given files or directory, also handling the case
# of non-writable subdirectories.
rm_rf_ ()
{
  test $# -gt 0 || return 0
  chmod -R u+rwx "$@" || :
  rm -rf "$@" # if it fails, ok, we fail
  _am_rmrf_status=$?
  #
  # In the past, we ran this Perl script instead of the above
  # chmod && rm.  See the ChangeLog for details.
  #$PERL "$am_testaux_srcdir"/deltree.pl "$@"
  #
  # Let's fail up front if anything remains after the supposed removal.
  for _am_rmrf_v
  do
    if test -e "$_am_rmrf_v"; then
      echo "$me (test-lib.sh:rm_rf_): tree not removed: $_am_rmrf_v" >&2
      echo "$me (test-lib.sh:rm_rf_): ls -alR follows:" >&2
      ls -alR $_am_rmrf_v >&2 # should always be there
      echo "$me (test-lib.sh:rm_rf_): " \
           "end ls of tree not removed ($_am_rmrf_v)." >&2
      _am_rmrf_status=2
    fi
  done
  return $_am_rmrf_status
}

commented_sed_unindent_prog='
  /^$/b                    # Nothing to do for empty lines.
  x                        # Get x<indent> into pattern space.
  /^$/{                    # No prior x<indent>, go prepare it.
    g                      # Copy this 1st non-blank line into pattern space.
    s/^\(['"$tab"' ]*\).*/x\1/   # Prepare x<indent> in pattern space.
  }                        # Now: x<indent> in pattern and <line> in hold.
  G                        # Build x<indent>\n<line> in pattern space, and
  h                        # duplicate it into hold space.
  s/\n.*$//                # Restore x<indent> in pattern space, and
  x                        # exchange with the above duplicate in hold space.
  s/^x\(.*\)\n\1//         # Remove leading <indent> from <line>.
  s/^x.*\n//               # Restore <line> when there is no leading <indent>.
'

# unindent [input files...]
# -------------------------
# Remove the "proper" amount of leading whitespace from the given files,
# and output the result on stdout.  That amount is determined by looking
# at the leading whitespace of the first non-blank line in the input
# files.  If no input file is specified, standard input is implied.
unindent ()
{
  if test x"$sed_unindent_prog" = x; then
    sed_unindent_prog=$(printf '%s\n' "$commented_sed_unindent_prog" \
                          | sed -e "s/  *# .*//")
  fi
  sed "$sed_unindent_prog" ${1+"$@"}
}
sed_unindent_prog="" # Avoid interferences from the environment.

## ---------------------------------------------------------------- ##
##  Create and set up of the temporary directory used by the test.  ##
##  Set up of the exit trap for cleanup of said directory.          ##
## ---------------------------------------------------------------- ##

# Set up the exit trap.
am_exit_trap ()
{
  exit_status=$1
  set +e
  cd "$am_top_builddir"
  if test $am_test_protocol = tap; then
    if test "$planned_" = later && test $exit_status -eq 0; then
      plan_ "now"
    fi
    test $exit_status -eq 0 && test $tap_pass_count_ -eq $tap_count_ \
      || keep_testdirs=yes
  else
    # This is to ensure that a test script does give a SKIP outcome just
    # because a command in it happens to exit with status 77.  This
    # behaviour, while from time to time useful to developers, is not
    # meant to be enabled by default, as it could cause spurious failures
    # in the wild.  Thus it will be enabled only when the variable
    # 'am_explicit_skips' is set to a "true" value.
    case $am_explicit_skips in
      [yY]|[yY]es|1)
        if test $exit_status -eq 77 && test $am__test_skipped != yes; then
          echo "$me: implicit skip turned into failure"
          exit_status=78
        fi;;
    esac
    test $exit_status -eq 0 || keep_testdirs=yes
  fi
  am_keeping_testdirs || rm_rf_ $am_test_subdir
  set +x
  # Spurious escaping to ensure we do not call our "exit" alias.
  \exit $exit_status
}

am_set_exit_traps ()
{
  trap 'am_exit_trap $?' 0
  trap "fatal_ 'caught signal SIGHUP'" 1
  trap "fatal_ 'caught signal SIGINT'" 2
  trap "fatal_ 'caught signal SIGTERM'" 15
  # Various shells seems to just ignore SIGQUIT under some circumstances,
  # even if the signal is not blocked; however, if the signal is trapped,
  # the trap gets correctly executed.  So we also trap SIGQUIT.
  # Here is a list of some shells that have been verified to exhibit the
  # problematic behavior with SIGQUIT:
  #  - zsh 4.3.12 on Debian GNU/Linux
  #  - /bin/ksh and /usr/xpg4/bin/sh on Solaris 10
  #  - Bash 3.2.51 on Solaris 10 and bash 4.1.5 on Debian GNU/Linux
  #  - AT&T ksh on Debian Gnu/Linux (deb package ksh, version 93u-1)
  # OTOH, at least these shells that do *not* exhibit that behaviour:
  #  - modern version of the Almquist Shell (at least 0.5.5.1), on
  #    both Solaris and GNU/Linux
  #  - public domain Korn Shell, version 5.2.14, on Debian GNU/Linux
  trap "fatal_ 'caught signal SIGQUIT'" 3
  # Ignore further SIGPIPE in the trap code.  This is required to avoid
  # a very weird issue with some shells, at least when the execution of
  # the automake testsuite is driven by the 'prove' utility: if prove
  # (or the make process that has spawned it) gets interrupted with
  # Ctrl-C, the shell might go in a loop, continually getting a SIGPIPE,
  # sometimes finally dumping core, other times hanging indefinitely.
  # See also Test::Harness bug [rt.cpan.org #70855], archived at
  # <https://rt.cpan.org/Ticket/Display.html?id=70855>
  trap "trap '' 13; fatal_ 'caught signal SIGPIPE'" 13
}

am_test_setup ()
{
  process_requirements $required
  am_set_exit_traps
  # Create and populate the temporary directory, if required.
  if test x"$am_create_testdir" = x"no"; then
    am_test_subdir=
  else
    am_setup_testdir
  fi
  am_extra_info
  set -x
  pwd
}