t_option.sh revision 1.3 1 1.3 christos # $NetBSD: t_option.sh,v 1.3 2016/03/08 14:19:28 christos Exp $
2 1.1 christos #
3 1.1 christos # Copyright (c) 2016 The NetBSD Foundation, Inc.
4 1.1 christos # All rights reserved.
5 1.1 christos #
6 1.1 christos # Redistribution and use in source and binary forms, with or without
7 1.1 christos # modification, are permitted provided that the following conditions
8 1.1 christos # are met:
9 1.1 christos # 1. Redistributions of source code must retain the above copyright
10 1.1 christos # notice, this list of conditions and the following disclaimer.
11 1.1 christos # 2. Redistributions in binary form must reproduce the above copyright
12 1.1 christos # notice, this list of conditions and the following disclaimer in the
13 1.1 christos # documentation and/or other materials provided with the distribution.
14 1.1 christos #
15 1.1 christos # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 1.1 christos # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 1.1 christos # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 1.1 christos # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 1.1 christos # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 1.1 christos # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 1.1 christos # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 1.1 christos # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 1.1 christos # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 1.1 christos # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 1.1 christos # POSSIBILITY OF SUCH DAMAGE.
26 1.1 christos #
27 1.1 christos # the implementation of "sh" to test
28 1.1 christos : ${TEST_SH:="/bin/sh"}
29 1.1 christos
30 1.1 christos # The standard
31 1.1 christos # http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
32 1.1 christos # says:
33 1.1 christos # ...[lots]
34 1.1 christos
35 1.1 christos test_option_on_off()
36 1.1 christos {
37 1.1 christos atf_require_prog tr
38 1.1 christos
39 1.1 christos for opt
40 1.1 christos do
41 1.1 christos # t is needed, as inside $()` $- appears to lose
42 1.1 christos # the 'e' option if it happened to already be
43 1.1 christos # set. Must check if that is what should
44 1.1 christos # happen, but that is a different issue.
45 1.1 christos
46 1.1 christos test -z "${opt}" && continue
47 1.1 christos
48 1.1 christos # if we are playing with more that one option at a
49 1.1 christos # time, the code below requires that we start with no
50 1.1 christos # options set, or it will mis-diagnose the situation
51 1.1 christos CLEAR=''
52 1.1 christos test "${#opt}" -gt 1 &&
53 1.1 christos CLEAR='xx="$-" && xx=$(echo "$xx" | tr -d cs) && test -n "$xx" && set +"$xx";'
54 1.1 christos
55 1.2 christos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
56 1.1 christos "opt=${opt}"'
57 1.1 christos x() {
58 1.1 christos echo "ERROR: Unable to $1 option $2" >&2
59 1.1 christos exit 1
60 1.1 christos }
61 1.1 christos s() {
62 1.1 christos set -"$1"
63 1.1 christos t="$-"
64 1.1 christos x=$(echo "$t" | tr -d "$1")
65 1.1 christos test "$t" = "$x" && x set "$1"
66 1.1 christos return 0
67 1.1 christos }
68 1.1 christos c() {
69 1.1 christos set +"$1"
70 1.1 christos t="$-"
71 1.1 christos x=$(echo "$t" | tr -d "$1")
72 1.1 christos test "$t" != "$x" && x clear "$1"
73 1.1 christos return 0
74 1.1 christos }
75 1.1 christos '"${CLEAR}"'
76 1.1 christos
77 1.1 christos # if we do not do this, -x tracing splatters stderr
78 1.1 christos # for some shells, -v does as well (is that correct?)
79 1.1 christos case "${opt}" in
80 1.1 christos (*[xv]*) exec 2>/dev/null;;
81 1.1 christos esac
82 1.1 christos
83 1.1 christos o="$-"
84 1.1 christos x=$(echo "$o" | tr -d "$opt")
85 1.1 christos
86 1.1 christos if [ "$o" = "$x" ]; then # option was off
87 1.1 christos s "${opt}"
88 1.1 christos c "${opt}"
89 1.1 christos else
90 1.1 christos c "${opt}"
91 1.1 christos s "${opt}"
92 1.1 christos fi
93 1.1 christos '
94 1.1 christos done
95 1.1 christos }
96 1.1 christos
97 1.1 christos test_optional_on_off()
98 1.1 christos {
99 1.1 christos RET=0
100 1.1 christos OPTS=
101 1.1 christos for opt
102 1.1 christos do
103 1.1 christos test "${opt}" = n && continue
104 1.2 christos ${TEST_SH} -c "set -${opt}" 2>/dev/null &&
105 1.1 christos OPTS="${OPTS} ${opt}" || RET=1
106 1.1 christos done
107 1.1 christos
108 1.1 christos test -n "${OPTS}" && test_option_on_off ${OPTS}
109 1.1 christos
110 1.1 christos return "${RET}"
111 1.1 christos }
112 1.1 christos
113 1.1 christos atf_test_case set_a
114 1.1 christos set_a_head() {
115 1.1 christos atf_set "descr" "Tests that 'set -a' turns on all var export " \
116 1.1 christos "and that it behaves as defined by the standard"
117 1.1 christos }
118 1.1 christos set_a_body() {
119 1.1 christos atf_require_prog env
120 1.1 christos atf_require_prog grep
121 1.1 christos
122 1.1 christos test_option_on_off a
123 1.1 christos
124 1.1 christos # without -a, new variables should not be exported (so grep "fails")
125 1.2 christos atf_check -s exit:1 -o empty -e empty ${TEST_SH} -ce \
126 1.1 christos 'unset VAR; set +a; VAR=value; env | grep "^VAR="'
127 1.1 christos
128 1.1 christos # with -a, they should be
129 1.2 christos atf_check -s exit:0 -o match:VAR=value -e empty ${TEST_SH} -ce \
130 1.1 christos 'unset VAR; set -a; VAR=value; env | grep "^VAR="'
131 1.1 christos }
132 1.1 christos
133 1.1 christos atf_test_case set_C
134 1.1 christos set_C_head() {
135 1.1 christos atf_set "descr" "Tests that 'set -C' turns on no clobber mode " \
136 1.1 christos "and that it behaves as defined by the standard"
137 1.1 christos }
138 1.1 christos set_C_body() {
139 1.1 christos atf_require_prog ls
140 1.1 christos
141 1.1 christos test_option_on_off C
142 1.1 christos
143 1.1 christos # Check that the environment to use for the tests is sane ...
144 1.1 christos # we assume current dir is a new tempory directory & is empty
145 1.1 christos
146 1.1 christos test -z "$(ls)" || atf_skip "Test execution directory not clean"
147 1.1 christos test -c "/dev/null" || atf_skip "Problem with /dev/null"
148 1.1 christos
149 1.1 christos echo Dummy_Content > Junk_File
150 1.1 christos echo Precious_Content > Important_File
151 1.1 christos
152 1.1 christos # Check that we can redirect onto file when -C is not set
153 1.2 christos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
154 1.1 christos '
155 1.1 christos D=$(ls -l Junk_File) || exit 1
156 1.1 christos set +C
157 1.1 christos echo "Overwrite it now" > Junk_File
158 1.1 christos A=$(ls -l Junk_File) || exit 1
159 1.1 christos test "${A}" != "${D}"
160 1.1 christos '
161 1.1 christos
162 1.1 christos # Check that we cannot redirect onto file when -C is set
163 1.2 christos atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} -c \
164 1.1 christos '
165 1.1 christos D=$(ls -l Important_File) || exit 1
166 1.1 christos set -C
167 1.1 christos echo "Fail to Overwrite it now" > Important_File
168 1.1 christos A=$(ls -l Important_File) || exit 1
169 1.1 christos test "${A}" = "${D}"
170 1.1 christos '
171 1.1 christos
172 1.1 christos # Check that we can append to file, even when -C is set
173 1.2 christos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
174 1.1 christos '
175 1.1 christos D=$(ls -l Junk_File) || exit 1
176 1.1 christos set -C
177 1.1 christos echo "Append to it now" >> Junk_File
178 1.1 christos A=$(ls -l Junk_File) || exit 1
179 1.1 christos test "${A}" != "${D}"
180 1.1 christos '
181 1.1 christos
182 1.1 christos # Check that we abort on attempt to redirect onto file when -Ce is set
183 1.2 christos atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
184 1.1 christos '
185 1.1 christos set -Ce
186 1.1 christos echo "Fail to Overwrite it now" > Important_File
187 1.1 christos echo "Should not reach this point"
188 1.1 christos '
189 1.1 christos
190 1.1 christos # Last check that we can override -C for when we really need to
191 1.2 christos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
192 1.1 christos '
193 1.1 christos D=$(ls -l Junk_File) || exit 1
194 1.1 christos set -C
195 1.1 christos echo "Change the poor bugger again" >| Junk_File
196 1.1 christos A=$(ls -l Junk_File) || exit 1
197 1.1 christos test "${A}" != "${D}"
198 1.1 christos '
199 1.1 christos }
200 1.1 christos
201 1.1 christos atf_test_case set_e
202 1.1 christos set_e_head() {
203 1.1 christos atf_set "descr" "Tests that 'set -e' turns on error detection " \
204 1.1 christos "and that a simple case behaves as defined by the standard"
205 1.1 christos }
206 1.1 christos set_e_body() {
207 1.1 christos test_option_on_off e
208 1.1 christos
209 1.1 christos # Check that -e does nothing if no commands fail
210 1.1 christos atf_check -s exit:0 -o match:I_am_OK -e empty \
211 1.2 christos ${TEST_SH} -c \
212 1.1 christos 'false; printf "%s" I_am; set -e; true; printf "%s\n" _OK'
213 1.1 christos
214 1.1 christos # and that it (silently, but with exit status) aborts if cmd fails
215 1.1 christos atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \
216 1.2 christos ${TEST_SH} -c \
217 1.1 christos 'false; printf "%s" I_am; set -e; false; printf "%s\n" _Broken'
218 1.1 christos
219 1.1 christos # same, except -e this time is on from the beginning
220 1.1 christos atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \
221 1.2 christos ${TEST_SH} -ec 'printf "%s" I_am; false; printf "%s\n" _Broken'
222 1.1 christos
223 1.1 christos # More checking of -e in other places, there is lots to deal with.
224 1.1 christos }
225 1.1 christos
226 1.1 christos atf_test_case set_f
227 1.1 christos set_f_head() {
228 1.1 christos atf_set "descr" "Tests that 'set -f' turns off pathname expansion " \
229 1.1 christos "and that it behaves as defined by the standard"
230 1.1 christos }
231 1.1 christos set_f_body() {
232 1.1 christos atf_require_prog ls
233 1.1 christos
234 1.1 christos test_option_on_off f
235 1.1 christos
236 1.1 christos # Check that the environment to use for the tests is sane ...
237 1.1 christos # we assume current dir is a new tempory directory & is empty
238 1.1 christos
239 1.1 christos test -z "$(ls)" || atf_skip "Test execution directory not clean"
240 1.1 christos
241 1.1 christos # we will assume that atf will clean up this junk directory
242 1.1 christos # when we are done. But for testing pathname expansion
243 1.1 christos # we need files
244 1.1 christos
245 1.1 christos for f in a b c d e f aa ab ac ad ae aaa aab aac aad aba abc bbb ccc
246 1.1 christos do
247 1.1 christos echo "$f" > "$f"
248 1.1 christos done
249 1.1 christos
250 1.2 christos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \
251 1.1 christos 'X=$(echo b*); Y=$(echo b*); test "${X}" != "a*";
252 1.1 christos test "${X}" = "${Y}"'
253 1.1 christos
254 1.1 christos # now test expansion is different when -f is set
255 1.2 christos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \
256 1.1 christos 'X=$(echo b*); Y=$(set -f; echo b*); test "${X}" != "${Y}"'
257 1.1 christos }
258 1.1 christos
259 1.1 christos atf_test_case set_n
260 1.1 christos set_n_head() {
261 1.1 christos atf_set "descr" "Tests that 'set -n' supresses command execution " \
262 1.1 christos "and that it behaves as defined by the standard"
263 1.1 christos }
264 1.1 christos set_n_body() {
265 1.1 christos # pointless to test this, if it turns on, it stays on...
266 1.1 christos # test_option_on_off n
267 1.1 christos # so just allow the tests below to verify it can be turned on
268 1.1 christos
269 1.1 christos # nothing should be executed, hence no output...
270 1.1 christos atf_check -s exit:0 -o empty -e empty \
271 1.2 christos ${TEST_SH} -enc 'echo ABANDON HOPE; echo ALL YE; echo ...'
272 1.1 christos
273 1.1 christos # this is true even when the "commands" do not exist
274 1.1 christos atf_check -s exit:0 -o empty -e empty \
275 1.2 christos ${TEST_SH} -enc 'ERR; FAIL; ABANDON HOPE'
276 1.1 christos
277 1.2 christos # but if there is a syntax error, it should be detected (w or w/o -e)
278 1.1 christos atf_check -s not-exit:0 -o empty -e not-empty \
279 1.2 christos ${TEST_SH} -enc 'echo JUMP; for frogs swim; echo in puddles'
280 1.2 christos atf_check -s not-exit:0 -o empty -e not-empty \
281 1.2 christos ${TEST_SH} -nc 'echo ABANDON HOPE; echo "ALL YE; echo ...'
282 1.2 christos atf_check -s not-exit:0 -o empty -e not-empty \
283 1.2 christos ${TEST_SH} -enc 'echo ABANDON HOPE;; echo ALL YE; echo ...'
284 1.2 christos atf_check -s not-exit:0 -o empty -e not-empty \
285 1.2 christos ${TEST_SH} -nc 'do YOU ABANDON HOPE; for all eternity?'
286 1.1 christos
287 1.2 christos # now test enabling -n in the middle of a script
288 1.2 christos # note that once turned on, it cannot be turned off again.
289 1.2 christos #
290 1.2 christos # omit more complex cases, as those can send some shells
291 1.2 christos # into infinite loops, and believe it or not, that might be OK!
292 1.2 christos
293 1.2 christos atf_check -s exit:0 -o match:first -o not-match:second -e empty \
294 1.2 christos ${TEST_SH} -c 'echo first; set -n; echo second'
295 1.2 christos atf_check -s exit:0 -o match:first -o not-match:third -e empty \
296 1.2 christos ${TEST_SH} -c 'echo first; set -n; echo second; set +n; echo third'
297 1.2 christos atf_check -s exit:0 -o inline:'a\nb\n' -e empty \
298 1.2 christos ${TEST_SH} -c 'for x in a b c d
299 1.2 christos do
300 1.2 christos case "$x" in
301 1.2 christos a);; b);; c) set -n;; d);;
302 1.2 christos esac
303 1.2 christos printf "%s\n" "$x"
304 1.2 christos done'
305 1.2 christos
306 1.2 christos # This last one is a bit more complex to explain, so I will not try
307 1.2 christos
308 1.2 christos # First, we need to know what signal number is used for SIGUSR1 on
309 1.2 christos # the local (testing) system (signal number is $(( $XIT - 128 )) )
310 1.2 christos
311 1.2 christos # this will take slightly over 1 second elapsed time (the sleep 1)
312 1.2 christos # The "10" for the first sleep just needs to be something big enough
313 1.2 christos # that the rest of the commands have time to complete, even on
314 1.2 christos # very slow testing systems. 10 should be enough. Otherwise irrelevant
315 1.2 christos
316 1.2 christos # The shell will usually blather to stderr about the sleep 10 being
317 1.2 christos # killed, but it affects nothing, so just allow it to cry.
318 1.2 christos
319 1.2 christos (sleep 10 & sleep 1; kill -USR1 $!; wait $!)
320 1.2 christos XIT="$?"
321 1.2 christos
322 1.2 christos # The exit value should be an integer > 128 and < 256 (often 158)
323 1.2 christos # If it is not just skip the test
324 1.2 christos
325 1.2 christos # If we do run the test, it should take (slightly over) either 1 or 2
326 1.2 christos # seconds to complete, depending upon the shell being tested.
327 1.2 christos
328 1.2 christos case "${XIT}" in
329 1.2 christos ( 129 | 1[3-9][0-9] | 2[0-4][0-9] | 25[0-5] )
330 1.2 christos
331 1.2 christos # The script below should exit with the same code - no output
332 1.2 christos
333 1.2 christos # Or that is the result that seems best explanable.
334 1.2 christos # "set -n" in uses like this is not exactly well defined...
335 1.2 christos
336 1.2 christos # This script comes from a member of the austin group
337 1.2 christos # (they author changes to the posix shell spec - and more.)
338 1.2 christos # The author is also an (occasional?) NetBSD user.
339 1.2 christos atf_check -s exit:${XIT} -o empty -e empty ${TEST_SH} -c '
340 1.2 christos trap "set -n" USR1
341 1.2 christos { sleep 1; kill -USR1 $$; sleep 1; } &
342 1.2 christos false
343 1.2 christos wait && echo t || echo f
344 1.2 christos wait
345 1.2 christos echo foo
346 1.2 christos '
347 1.2 christos ;;
348 1.2 christos esac
349 1.1 christos }
350 1.1 christos
351 1.1 christos atf_test_case set_u
352 1.1 christos set_u_head() {
353 1.1 christos atf_set "descr" "Tests that 'set -u' turns on unset var detection " \
354 1.1 christos "and that it behaves as defined by the standard"
355 1.1 christos }
356 1.1 christos set_u_body() {
357 1.1 christos test_option_on_off u
358 1.1 christos
359 1.1 christos # first make sure it is OK to unset an unset variable
360 1.2 christos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
361 1.1 christos 'unset _UNSET_VARIABLE_; echo OK'
362 1.1 christos # even if -u is set
363 1.2 christos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -cue \
364 1.1 christos 'unset _UNSET_VARIABLE_; echo OK'
365 1.1 christos
366 1.1 christos # and that without -u accessing an unset variable is harmless
367 1.2 christos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
368 1.1 christos 'unset X; echo ${X}; echo OK'
369 1.1 christos # and that the unset variable test expansion works properly
370 1.2 christos atf_check -s exit:0 -o match:OKOK -e empty ${TEST_SH} -ce \
371 1.1 christos 'unset X; printf "%s" ${X-OK}; echo OK'
372 1.1 christos
373 1.1 christos # Next test that with -u set, the shell aborts on access to unset var
374 1.1 christos # do not use -e, want to make sure it is -u that causes abort
375 1.2 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
376 1.1 christos 'unset X; set -u; echo ${X}; echo ERR'
377 1.1 christos # quoting should make no difference...
378 1.2 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
379 1.1 christos 'unset X; set -u; echo "${X}"; echo ERR'
380 1.1 christos
381 1.1 christos # Now a bunch of accesses to unset vars, with -u, in ways that are OK
382 1.2 christos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
383 1.1 christos 'unset X; set -u; echo ${X-GOOD}; echo OK'
384 1.2 christos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
385 1.1 christos 'unset X; set -u; echo ${X-OK}'
386 1.1 christos atf_check -s exit:0 -o not-match:ERR -o match:OK -e empty \
387 1.2 christos ${TEST_SH} -ce 'unset X; set -u; echo ${X+ERR}; echo OK'
388 1.1 christos
389 1.1 christos # and some more ways that are not OK
390 1.2 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
391 1.1 christos 'unset X; set -u; echo ${X#foo}; echo ERR'
392 1.2 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
393 1.1 christos 'unset X; set -u; echo ${X%%bar}; echo ERR'
394 1.1 christos
395 1.1 christos # lastly, just while we are checking unset vars, test aborts w/o -u
396 1.2 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
397 1.1 christos 'unset X; echo ${X?}; echo ERR'
398 1.1 christos atf_check -s not-exit:0 -o not-match:ERR -e match:X_NOT_SET \
399 1.2 christos ${TEST_SH} -c 'unset X; echo ${X?X_NOT_SET}; echo ERR'
400 1.1 christos }
401 1.1 christos
402 1.1 christos atf_test_case set_v
403 1.1 christos set_v_head() {
404 1.1 christos atf_set "descr" "Tests that 'set -v' turns on input read echoing " \
405 1.1 christos "and that it behaves as defined by the standard"
406 1.1 christos }
407 1.1 christos set_v_body() {
408 1.1 christos test_option_on_off v
409 1.1 christos
410 1.1 christos # check that -v does nothing if no later input line is read
411 1.1 christos atf_check -s exit:0 \
412 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
413 1.1 christos -e empty \
414 1.2 christos ${TEST_SH} -ec 'printf "%s" OK; set -v; echo OK; exit 0'
415 1.1 christos
416 1.1 christos # but that it does when there are multiple lines
417 1.3 christos cat <<- 'EOF' |
418 1.3 christos set -v
419 1.3 christos printf %s OK
420 1.3 christos echo OK
421 1.3 christos exit 0
422 1.3 christos EOF
423 1.1 christos atf_check -s exit:0 \
424 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
425 1.1 christos -e match:printf -e match:OK -e match:echo \
426 1.3 christos -e not-match:set ${TEST_SH}
427 1.1 christos
428 1.1 christos # and that it can be disabled again
429 1.3 christos cat <<- 'EOF' |
430 1.3 christos set -v
431 1.3 christos printf %s OK
432 1.3 christos set +v
433 1.3 christos echo OK
434 1.3 christos exit 0
435 1.3 christos EOF
436 1.1 christos atf_check -s exit:0 \
437 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
438 1.1 christos -e match:printf -e match:OK -e not-match:echo \
439 1.3 christos ${TEST_SH}
440 1.1 christos
441 1.1 christos # and lastly, that shell keywords do get output when "read"
442 1.3 christos cat <<- 'EOF' |
443 1.3 christos set -v
444 1.3 christos for i in 111 222 333
445 1.3 christos do
446 1.3 christos printf %s $i
447 1.3 christos done
448 1.3 christos exit 0
449 1.3 christos EOF
450 1.1 christos atf_check -s exit:0 \
451 1.1 christos -o match:111222333 -o not-match:printf \
452 1.1 christos -o not-match:for -o not-match:do -o not-match:done \
453 1.1 christos -e match:printf -e match:111 -e not-match:111222 \
454 1.1 christos -e match:for -e match:do -e match:done \
455 1.3 christos ${TEST_SH}
456 1.1 christos }
457 1.1 christos
458 1.1 christos atf_test_case set_x
459 1.1 christos set_x_head() {
460 1.1 christos atf_set "descr" "Tests that 'set -x' turns on command exec logging " \
461 1.1 christos "and that it behaves as defined by the standard"
462 1.1 christos }
463 1.1 christos set_x_body() {
464 1.1 christos test_option_on_off x
465 1.1 christos
466 1.1 christos # check that cmd output appears after -x is enabled
467 1.1 christos atf_check -s exit:0 \
468 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
469 1.1 christos -e not-match:printf -e match:OK -e match:echo \
470 1.2 christos ${TEST_SH} -ec 'printf "%s" OK; set -x; echo OK; exit 0'
471 1.1 christos
472 1.1 christos # and that it stops again afer -x is disabled
473 1.1 christos atf_check -s exit:0 \
474 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
475 1.1 christos -e match:printf -e match:OK -e not-match:echo \
476 1.2 christos ${TEST_SH} -ec 'set -x; printf "%s" OK; set +x; echo OK; exit 0'
477 1.1 christos
478 1.1 christos # also check that PS4 is output correctly
479 1.1 christos atf_check -s exit:0 \
480 1.1 christos -o match:OK -o not-match:echo \
481 1.1 christos -e match:OK -e match:Run:echo \
482 1.2 christos ${TEST_SH} -ec 'PS4=Run:; set -x; echo OK; exit 0'
483 1.1 christos
484 1.1 christos return 0
485 1.1 christos
486 1.1 christos # This one seems controversial... I suspect it is NetBSD's sh
487 1.1 christos # that is wrong to not output "for" "while" "if" ... etc
488 1.1 christos
489 1.1 christos # and lastly, that shell keywords do not get output when "executed"
490 1.1 christos atf_check -s exit:0 \
491 1.1 christos -o match:111222333 -o not-match:printf \
492 1.1 christos -o not-match:for \
493 1.1 christos -e match:printf -e match:111 -e not-match:111222 \
494 1.1 christos -e not-match:for -e not-match:do -e not-match:done \
495 1.2 christos ${TEST_SH} -ec \
496 1.1 christos 'set -x; for i in 111 222 333; do printf "%s" $i; done; echo; exit 0'
497 1.1 christos }
498 1.1 christos
499 1.1 christos opt_test_setup()
500 1.1 christos {
501 1.1 christos test -n "$1" || { echo >&2 "Internal error"; exit 1; }
502 1.1 christos
503 1.1 christos cat > "$1" << 'END_OF_FUNCTIONS'
504 1.1 christos local_opt_check()
505 1.1 christos {
506 1.1 christos local -
507 1.1 christos }
508 1.1 christos
509 1.1 christos instr()
510 1.1 christos {
511 1.1 christos expr "$2" : "\(.*$1\)" >/dev/null
512 1.1 christos }
513 1.1 christos
514 1.1 christos save_opts()
515 1.1 christos {
516 1.1 christos local -
517 1.1 christos
518 1.1 christos set -e
519 1.1 christos set -u
520 1.1 christos
521 1.1 christos instr e "$-" && instr u "$-" && return 0
522 1.1 christos echo ERR
523 1.1 christos }
524 1.1 christos
525 1.1 christos fiddle_opts()
526 1.1 christos {
527 1.1 christos set -e
528 1.1 christos set -u
529 1.1 christos
530 1.1 christos instr e "$-" && instr u "$-" && return 0
531 1.1 christos echo ERR
532 1.1 christos }
533 1.1 christos
534 1.1 christos local_test()
535 1.1 christos {
536 1.1 christos set +eu
537 1.1 christos
538 1.1 christos save_opts
539 1.1 christos instr '[eu]' "$-" || printf %s "OK"
540 1.1 christos
541 1.1 christos fiddle_opts
542 1.1 christos instr e "$-" && instr u "$-" && printf %s "OK"
543 1.1 christos
544 1.1 christos set +eu
545 1.1 christos }
546 1.1 christos END_OF_FUNCTIONS
547 1.1 christos }
548 1.1 christos
549 1.1 christos atf_test_case restore_local_opts
550 1.1 christos restore_local_opts_head() {
551 1.1 christos atf_set "descr" "Tests that 'local -' saves and restores options. " \
552 1.1 christos "Note that "local" is a local shell addition"
553 1.1 christos }
554 1.1 christos restore_local_opts_body() {
555 1.1 christos atf_require_prog cat
556 1.1 christos atf_require_prog expr
557 1.1 christos
558 1.1 christos FN="test-funcs.$$"
559 1.1 christos opt_test_setup "${FN}" || atf_skip "Cannot setup test environment"
560 1.1 christos
561 1.2 christos ${TEST_SH} -ec ". './${FN}'; local_opt_check" 2>/dev/null ||
562 1.1 christos atf_skip "sh extension 'local -' not supported by ${TEST_SH}"
563 1.1 christos
564 1.1 christos atf_check -s exit:0 -o match:OKOK -o not-match:ERR -e empty \
565 1.2 christos ${TEST_SH} -ec ". './${FN}'; local_test"
566 1.1 christos }
567 1.1 christos
568 1.1 christos atf_test_case vi_emacs_VE_toggle
569 1.1 christos vi_emacs_VE_toggle_head() {
570 1.1 christos atf_set "descr" "Tests enabling vi disables emacs (and v.v - but why?)"\
571 1.1 christos " Note that -V and -E are local shell additions"
572 1.1 christos }
573 1.1 christos vi_emacs_VE_toggle_body() {
574 1.1 christos
575 1.1 christos test_optional_on_off V E ||
576 1.1 christos atf_skip "One or both V & E opts unsupported by ${TEST_SH}"
577 1.1 christos
578 1.2 christos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '
579 1.1 christos q() {
580 1.1 christos eval "case \"$-\" in
581 1.1 christos (*${2}*) return 1;;
582 1.1 christos (*${1}*) return 0;;
583 1.1 christos esac"
584 1.1 christos return 1
585 1.1 christos }
586 1.1 christos x() {
587 1.1 christos echo >&2 "Option set or toggle failure:" \
588 1.1 christos " on=$1 off=$2 set=$-"
589 1.1 christos exit 1
590 1.1 christos }
591 1.1 christos set -V; q V E || x V E
592 1.1 christos set -E; q E V || x E V
593 1.1 christos set -V; q V E || x V E
594 1.1 christos set +EV; q "" "[VE]" || x "" VE
595 1.1 christos exit 0
596 1.1 christos '
597 1.1 christos }
598 1.1 christos
599 1.1 christos atf_test_case xx_bogus
600 1.1 christos xx_bogus_head() {
601 1.1 christos atf_set "descr" "Tests that attempting to set a nonsense option fails."
602 1.1 christos }
603 1.1 christos xx_bogus_body() {
604 1.1 christos # Biggest problem here is picking a "nonsense option" that is
605 1.1 christos # not implemented by any shell, anywhere. Hopefully this will do.
606 1.3 christos
607 1.3 christos # 'set' is a special builtin, so a conforming shell should exit
608 1.3 christos # on an arg error, and the ERR should not be printed.
609 1.1 christos atf_check -s not-exit:0 -o empty -e not-empty \
610 1.2 christos ${TEST_SH} -c 'set -% ; echo ERR'
611 1.1 christos }
612 1.1 christos
613 1.1 christos atf_test_case Option_switching
614 1.1 christos Option_switching_head() {
615 1.1 christos atf_set "descr" "options can be enabled and disabled"
616 1.1 christos }
617 1.1 christos Option_switching_body() {
618 1.1 christos
619 1.1 christos # Cannot test -m, setting it causes test shell to fail...
620 1.1 christos # (test shell gets SIGKILL!) Wonder why ... something related to atf
621 1.1 christos # That is, it works if just run as "sh -c 'echo $-; set -m; echo $-'"
622 1.1 christos
623 1.1 christos # Don't bother testing toggling -n, once on, it stays on...
624 1.1 christos # (and because the test fn refuses to allow us to try)
625 1.1 christos
626 1.1 christos # Cannot test -o or -c here, or the extension -s
627 1.1 christos # they can only be used, not switched
628 1.1 christos
629 1.1 christos # these are the posix options, that all shells should implement
630 1.1 christos test_option_on_off a b C e f h u v x # m
631 1.1 christos
632 1.1 christos # and these are extensions that might not exist (non-fatal to test)
633 1.1 christos # -i and -s (and -c) are posix options, but are not required to
634 1.1 christos # be accessable via the "set" command, just the command line.
635 1.1 christos # We allow for -i to work with set, as that makes some sense,
636 1.1 christos # -c and -s do not.
637 1.1 christos test_optional_on_off E i I p q V || true
638 1.1 christos
639 1.1 christos # Also test (some) option combinations ...
640 1.1 christos # only testing posix options here, because it is easier...
641 1.1 christos test_option_on_off aeu vx Ca aCefux
642 1.1 christos }
643 1.1 christos
644 1.1 christos atf_init_test_cases() {
645 1.1 christos # tests are run in order sort of names produces, so choose names wisely
646 1.1 christos
647 1.1 christos # this one tests turning on/off all the mandatory. and extra flags
648 1.1 christos atf_add_test_case Option_switching
649 1.1 christos # and this tests the NetBSD "local -" functionality in functions.
650 1.1 christos atf_add_test_case restore_local_opts
651 1.1 christos
652 1.1 christos # no tests for -m (no idea how to do that one)
653 1.1 christos # -I (no easy way to generate the EOF it ignores)
654 1.1 christos # -i (not sure how to test that one at the minute)
655 1.2 christos # -p (because we aren't going to run tests setuid)
656 1.1 christos # -V/-E (too much effort, and a real test would be huge)
657 1.1 christos # -c (because almost all the other tests test it anyway)
658 1.1 christos # -q (because, for now, I am lazy)
659 1.1 christos # -s (coming soon, hopefully)
660 1.1 christos # -o (really +o: again, hopefully soon)
661 1.1 christos # -o longname (again, just laziness, don't wait...)
662 1.1 christos # -h/-b (because NetBSD doesn't implement them)
663 1.1 christos atf_add_test_case set_a
664 1.1 christos atf_add_test_case set_C
665 1.1 christos atf_add_test_case set_e
666 1.1 christos atf_add_test_case set_f
667 1.1 christos atf_add_test_case set_n
668 1.1 christos atf_add_test_case set_u
669 1.1 christos atf_add_test_case set_v
670 1.1 christos atf_add_test_case set_x
671 1.1 christos
672 1.1 christos atf_add_test_case vi_emacs_VE_toggle
673 1.1 christos atf_add_test_case xx_bogus
674 1.1 christos }
675