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
338
339
340
341
|
#! /bin/sh
# Copyright (C) 2010-2017 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 <http://www.gnu.org/licenses/>.
# Check that building from, or installing to, directories with shell
# metacharacters succeed.
# Original report from James Amundson about file names with spaces.
# Other characters added by Paul Eggert.
. test-init.sh
# Usage: is_in_list ITEM [LIST...]
is_in_list ()
{
item=$1; shift;
case " $* " in
*[\ \ ]"$item"[\ \ ]*) return 0;;
*) return 1;;
esac
}
# Helper subroutine for test data definition.
# Usage: define_problematic_string NAME STRING
define_problematic_string ()
{
tst=$1; shift
eval "instspc__$tst=\$1" \
|| fatal_ "define_problematic_string: bad argument: '$tst'"
shift
all_test_names_list="$all_test_names_list $tst"
# Some of the "problematic" characters cannot be used in the name of
# a build or install directory on a POSIX host. These lists should
# be empty, but are not due to limitations in Autoconf, Automake, Make,
# M4, or the shell.
if is_in_list fail-builddir "$@"; then
builddir_xfails="$builddir_xfails $tst"
fi
if is_in_list fail-destdir "$@"; then
destdir_xfails="$destdir_xfails $tst"
fi
}
# Be sure to avoid interferences from the environment.
all_test_names_list=''
builddir_xfails=''
destdir_xfails=''
expected_to_fail ()
{
case $1 in
build) is_in_list "$2" $builddir_xfails;;
dest) is_in_list "$2" $destdir_xfails;;
*) fatal_ "incorrect 'expected_to_fail' usage";;
esac
}
# Helper subroutines for creation of input data files.
create_input_data ()
{
mkdir sub
unindent >> configure.ac << 'EOF'
AC_PROG_CC
AM_PROG_AR
AC_PROG_RANLIB
AC_OUTPUT
EOF
: > sub/base.h
: > sub/nobase.h
: > sub/base.dat
: > sub/nobase.dat
: > sub/base.sh
: > sub/nobase.sh
unindent > source.c << 'EOF'
int
main (int argc, char **argv)
{
return 0;
}
EOF
unindent > Makefile.am << 'EOF'
foodir = $(prefix)/foo
fooexecdir = $(prefix)/foo
foo_HEADERS = sub/base.h
nobase_foo_HEADERS = sub/nobase.h
dist_foo_DATA = sub/base.dat
nobase_dist_foo_DATA = sub/nobase.dat
dist_fooexec_SCRIPTS = sub/base.sh
nobase_dist_fooexec_SCRIPTS = sub/nobase.sh
fooexec_PROGRAMS = sub/base
nobase_fooexec_PROGRAMS = sub/nobase
sub_base_SOURCES = source.c
sub_nobase_SOURCES = source.c
fooexec_LIBRARIES = sub/libbase.a
nobase_fooexec_LIBRARIES = sub/libnobase.a
sub_libbase_a_SOURCES = source.c
sub_libnobase_a_SOURCES = source.c
.PHONY: test-inst
test-inst: install
test -f '$(DESTDIR)/$(file)-prefix/foo/sub/nobase.h'
test ! -f '$(DESTDIR)/$(file)-prefix/foo/nobase.h'
test -f '$(DESTDIR)/$(file)-prefix/foo/base.h'
test -f '$(DESTDIR)/$(file)-prefix/foo/sub/nobase.dat'
test ! -f '$(DESTDIR)/$(file)-prefix/foo/nobase.dat'
test -f '$(DESTDIR)/$(file)-prefix/foo/base.dat'
test -f '$(DESTDIR)/$(file)-prefix/foo/sub/nobase.sh'
test ! -f '$(DESTDIR)/$(file)-prefix/foo/nobase.sh'
test -f '$(DESTDIR)/$(file)-prefix/foo/base.sh'
test -f '$(DESTDIR)/$(file)-prefix/foo/sub/nobase$(EXEEXT)'
test ! -f '$(DESTDIR)/$(file)-prefix/foo/nobase$(EXEEXT)'
test -f '$(DESTDIR)/$(file)-prefix/foo/base$(EXEEXT)'
test -f '$(DESTDIR)/$(file)-prefix/foo/sub/libnobase.a'
test ! -f '$(DESTDIR)/$(file)-prefix/foo/libnobase.a'
test -f '$(DESTDIR)/$(file)-prefix/foo/libbase.a'
EOF
$ACLOCAL || framework_failure_ "aclocal failed"
$AUTOCONF || framework_failure_ "autoconf failed"
$AUTOMAKE -a || framework_failure_ "automake failed"
}
# ================= #
# Test data begin #
# ----------------- #
# Some control characters that are white space.
bs='' # back space
cr='
' # carriage return
ff='' # form feed
ht=' ' # horizontal tab
lf='
' # line feed (aka newline)
# Hack to save typing and make code visually clearer.
def=define_problematic_string
$def squote \' fail-builddir fail-destdir
$def dquote '"' fail-builddir fail-destdir
$def bquote '`' fail-builddir fail-destdir
$def sharp '#' fail-builddir fail-destdir
$def dollar '$' fail-builddir fail-destdir
$def bang '!'
$def bslash '\' fail-builddir
$def ampersand '&' fail-builddir
$def percent '%'
$def leftpar '('
$def rightpar ')'
$def pipe '|'
$def caret '^'
$def tilde '~'
$def qmark '?'
$def star '*'
$def plus '+'
$def minus '-'
$def comma ','
$def colon ':'
$def semicol ';'
$def equal '='
$def less '<'
$def more '>'
$def at '@'
$def lqbrack '['
$def rqbrack ']'
$def lcbrack '{'
$def rcbrack '}'
$def space ' '
$def tab "$ht"
$def linefeed "$lf" fail-builddir fail-destdir
$def backspace "$bs"
$def formfeed "$ff"
$def carriageret "$cr"
$def quadrigraph0 '@&t@' fail-builddir
$def quadrigraph1 '@<:@'
$def quadrigraph2 '@:>@'
$def quadrigraph3 '@S|@'
$def quadrigraph4 '@%:@'
$def a_b 'a b'
$def a__b 'a b'
$def a_lf_b "a${lf}b" fail-builddir fail-destdir
$def dotdotdot '...'
$def dosdrive 'a:'
$def miscglob1 '?[a-z]*'
$def miscglob2 '.*?[0-9]'
unset def
# --------------- #
# Test data end #
# =============== #
# Allow the user to select a subset of the tests.
if test $# -gt 0; then
test_names_list=$*
for test_name in $test_names_list; do
case " $all_test_names_list " in
*" $test_name "*);;
*) fatal_ "invalid user-specified test_name '$test_name'"
esac
done
# We need to determine the TAP plan adaptively.
n=$(for t in $test_names_list; do echo $t; done | wc -l)
plan_ $(($n * 2)) # Two tests per "problematic string".
unset n
else
test_names_list=$all_test_names_list
# Prefer static TAP plan if possible, it minimizes the chance of errors.
plan_ 94
fi
ocwd=$(pwd) || fatal_ "getting current working directory"
create_input_data
for test_name in $test_names_list; do
eval "test_string=\${instspc__$test_name}" \
|| fatal_ "invalid test name: '$test_name'"
if test x"$test_string" = x; then
if test x"$test_name" != xcarriageret; then
fatal_ "invalid test name: '$test_name'"
else
# MSYS version 1.0.17 still mishandles carriage returns; see
# automake bug#7849.
skip_ -r "carriage-return treated as null char" "$test_name in builddir"
skip_ -r "carriage-return treated as null char" "$test_name in destdir"
continue
fi
fi
# Skip the next checks if this system doesn't support the required
# characters in file names.
mkdir "./$test_string" || {
skip_ -r "mkdir failed" "$test_name in builddir"
skip_ -r "mkdir failed" "$test_name in destdir"
continue
}
case $test_string in
*:*)
# On MSYS 1.0.17, "mkdir ./a:" creates ./a, and "cd ./a:" takes you
# to a strange directory with pwd equal to "a". But only for
# interactive shells. Or something? In this script, "cd ./a:" fails
# on MSYS. Marvelous.
( cd "./$test_string" ) || {
rmdir "./$test_string" || fatal_ "removing directory"
skip_ -r "cd failed" "$test_name in builddir"
skip_ -r "cd failed" "$test_name in destdir"
continue
}
;;
esac
# Where are the "weird" characters going to be used, in $(builddir)
# or in $(DESTDIR)? They are always going to be used in $(prefix)
# though; should we maybe separate this into a dedicated check?
for where in build dest; do
case $where in
build)
build=./$test_string
dest=$ocwd/dest-$test_name
;;
dest)
build=build-$test_name
# Also use $test_name in the definition of $dest, to avoid
# interferences among different tests in case $test_string
# is strangely munged (which is not unexpected, considering
# how tricky its characters are). With some shells, this
# has already happened (at least on OpenIndiana 11 and on
# Solaris 10).
dest=$ocwd/dest-$test_name/$test_string
mkdir "$build" || fatal_ "cannot create '$build'"
;;
*)
fatal_ "invalid where '$where'"
;;
esac
cd "$build" || fatal_ "cannot chdir into '$build'"
# Some make implementations eliminate leading and trailing whitespace
# from macros passed on the command line, and some eliminate leading
# whitespace from macros set from environment variables, so prepend
# './' and use the latter here.
r=ok
../configure --prefix "/$test_string-prefix" \
&& $MAKE all \
&& DESTDIR="$dest" file="./$test_string" $MAKE test-inst \
|| r='not ok'
description="$test_name in ${where}dir"
if expected_to_fail "$where" "$test_name"; then
directive=TODO
reason="long-standing limitation"
else
directive=
reason=
fi
# Test case outcome is here.
result_ "$r" -D "$directive" -r "$reason" -- "$description"
cd "$ocwd" || fatal_ "cannot chdir back to test directory"
# Remove subdirectories for tests that have passed, to avoid ending up
# with a too big test directory. This is especially important since
# some tests in this tests are expected to fail, and this will cause
# the test directory not to be removed when the script terminates.
if not am_keeping_testdirs && test "$r" = ok; then
rm_rf_ "$build" "$dest" || fatal_ "removing temporary subdirectory"
fi
: For shells with busted 'set -e'.
done # $instspc_action
done # $test_name
:
|