t_option.sh revision 1.1 1 1.1 christos # $NetBSD: t_option.sh,v 1.1 2016/02/23 16:20:42 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 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.1 christos "${TEST_SH}" -enc 'ERR; FAIL; ABANDON HOPE'
276 1.1 christos
277 1.1 christos # but if there is a syntax error, it should be detected
278 1.1 christos atf_check -s not-exit:0 -o empty -e not-empty \
279 1.1 christos "${TEST_SH}" -enc 'echo JUMP; for frogs swim; echo in puddles'
280 1.1 christos
281 1.1 christos # eventually add tests that enable -n during the script
282 1.1 christos # but the standard NetBSD sh doesn't handle that properly yet, so ...
283 1.1 christos }
284 1.1 christos
285 1.1 christos atf_test_case set_u
286 1.1 christos set_u_head() {
287 1.1 christos atf_set "descr" "Tests that 'set -u' turns on unset var detection " \
288 1.1 christos "and that it behaves as defined by the standard"
289 1.1 christos }
290 1.1 christos set_u_body() {
291 1.1 christos test_option_on_off u
292 1.1 christos
293 1.1 christos # first make sure it is OK to unset an unset variable
294 1.1 christos atf_check -s exit:0 -o match:OK -e empty "${TEST_SH}" -ce \
295 1.1 christos 'unset _UNSET_VARIABLE_; echo OK'
296 1.1 christos # even if -u is set
297 1.1 christos atf_check -s exit:0 -o match:OK -e empty "${TEST_SH}" -cue \
298 1.1 christos 'unset _UNSET_VARIABLE_; echo OK'
299 1.1 christos
300 1.1 christos # and that without -u accessing an unset variable is harmless
301 1.1 christos atf_check -s exit:0 -o match:OK -e empty "${TEST_SH}" -ce \
302 1.1 christos 'unset X; echo ${X}; echo OK'
303 1.1 christos # and that the unset variable test expansion works properly
304 1.1 christos atf_check -s exit:0 -o match:OKOK -e empty "${TEST_SH}" -ce \
305 1.1 christos 'unset X; printf "%s" ${X-OK}; echo OK'
306 1.1 christos
307 1.1 christos # Next test that with -u set, the shell aborts on access to unset var
308 1.1 christos # do not use -e, want to make sure it is -u that causes abort
309 1.1 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty "${TEST_SH}" -c \
310 1.1 christos 'unset X; set -u; echo ${X}; echo ERR'
311 1.1 christos # quoting should make no difference...
312 1.1 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty "${TEST_SH}" -c \
313 1.1 christos 'unset X; set -u; echo "${X}"; echo ERR'
314 1.1 christos
315 1.1 christos # Now a bunch of accesses to unset vars, with -u, in ways that are OK
316 1.1 christos atf_check -s exit:0 -o match:OK -e empty "${TEST_SH}" -ce \
317 1.1 christos 'unset X; set -u; echo ${X-GOOD}; echo OK'
318 1.1 christos atf_check -s exit:0 -o match:OK -e empty "${TEST_SH}" -ce \
319 1.1 christos 'unset X; set -u; echo ${X-OK}'
320 1.1 christos atf_check -s exit:0 -o not-match:ERR -o match:OK -e empty \
321 1.1 christos "${TEST_SH}" -ce 'unset X; set -u; echo ${X+ERR}; echo OK'
322 1.1 christos
323 1.1 christos # and some more ways that are not OK
324 1.1 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty "${TEST_SH}" -c \
325 1.1 christos 'unset X; set -u; echo ${X#foo}; echo ERR'
326 1.1 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty "${TEST_SH}" -c \
327 1.1 christos 'unset X; set -u; echo ${X%%bar}; echo ERR'
328 1.1 christos
329 1.1 christos # lastly, just while we are checking unset vars, test aborts w/o -u
330 1.1 christos atf_check -s not-exit:0 -o not-match:ERR -e not-empty "${TEST_SH}" -c \
331 1.1 christos 'unset X; echo ${X?}; echo ERR'
332 1.1 christos atf_check -s not-exit:0 -o not-match:ERR -e match:X_NOT_SET \
333 1.1 christos "${TEST_SH}" -c 'unset X; echo ${X?X_NOT_SET}; echo ERR'
334 1.1 christos }
335 1.1 christos
336 1.1 christos atf_test_case set_v
337 1.1 christos set_v_head() {
338 1.1 christos atf_set "descr" "Tests that 'set -v' turns on input read echoing " \
339 1.1 christos "and that it behaves as defined by the standard"
340 1.1 christos }
341 1.1 christos set_v_body() {
342 1.1 christos test_option_on_off v
343 1.1 christos
344 1.1 christos # check that -v does nothing if no later input line is read
345 1.1 christos atf_check -s exit:0 \
346 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
347 1.1 christos -e empty \
348 1.1 christos "${TEST_SH}" -ec 'printf "%s" OK; set -v; echo OK; exit 0'
349 1.1 christos
350 1.1 christos # but that it does when there are multiple lines
351 1.1 christos atf_check -s exit:0 \
352 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
353 1.1 christos -e match:printf -e match:OK -e match:echo \
354 1.1 christos "${TEST_SH}" -ec '{
355 1.1 christos echo "set -v"
356 1.1 christos echo "printf %s OK"
357 1.1 christos echo "echo OK"
358 1.1 christos echo "exit 0"
359 1.1 christos } | '"'${TEST_SH}'"' -e'
360 1.1 christos
361 1.1 christos # and that it can be disabled again
362 1.1 christos atf_check -s exit:0 \
363 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
364 1.1 christos -e match:printf -e match:OK -e not-match:echo \
365 1.1 christos "${TEST_SH}" -ec '{
366 1.1 christos echo "set -v"
367 1.1 christos echo "printf %s OK"
368 1.1 christos echo "set +v"
369 1.1 christos echo "echo OK"
370 1.1 christos echo "exit 0"
371 1.1 christos } | '"'${TEST_SH}'"' -e'
372 1.1 christos
373 1.1 christos # and lastly, that shell keywords do get output when "read"
374 1.1 christos atf_check -s exit:0 \
375 1.1 christos -o match:111222333 -o not-match:printf \
376 1.1 christos -o not-match:for -o not-match:do -o not-match:done \
377 1.1 christos -e match:printf -e match:111 -e not-match:111222 \
378 1.1 christos -e match:for -e match:do -e match:done \
379 1.1 christos "${TEST_SH}" -ec '{
380 1.1 christos echo "set -v"
381 1.1 christos echo "for i in 111 222 333"
382 1.1 christos echo "do"
383 1.1 christos echo "printf %s \$i"
384 1.1 christos echo "done"
385 1.1 christos echo "exit 0"
386 1.1 christos } | '"'${TEST_SH}'"' -e'
387 1.1 christos }
388 1.1 christos
389 1.1 christos atf_test_case set_x
390 1.1 christos set_x_head() {
391 1.1 christos atf_set "descr" "Tests that 'set -x' turns on command exec logging " \
392 1.1 christos "and that it behaves as defined by the standard"
393 1.1 christos }
394 1.1 christos set_x_body() {
395 1.1 christos test_option_on_off x
396 1.1 christos
397 1.1 christos # check that cmd output appears after -x is enabled
398 1.1 christos atf_check -s exit:0 \
399 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
400 1.1 christos -e not-match:printf -e match:OK -e match:echo \
401 1.1 christos "${TEST_SH}" -ec 'printf "%s" OK; set -x; echo OK; exit 0'
402 1.1 christos
403 1.1 christos # and that it stops again afer -x is disabled
404 1.1 christos atf_check -s exit:0 \
405 1.1 christos -o match:OKOK -o not-match:echo -o not-match:printf \
406 1.1 christos -e match:printf -e match:OK -e not-match:echo \
407 1.1 christos "${TEST_SH}" -ec 'set -x; printf "%s" OK; set +x; echo OK; exit 0'
408 1.1 christos
409 1.1 christos # also check that PS4 is output correctly
410 1.1 christos atf_check -s exit:0 \
411 1.1 christos -o match:OK -o not-match:echo \
412 1.1 christos -e match:OK -e match:Run:echo \
413 1.1 christos "${TEST_SH}" -ec 'PS4=Run:; set -x; echo OK; exit 0'
414 1.1 christos
415 1.1 christos return 0
416 1.1 christos
417 1.1 christos # This one seems controversial... I suspect it is NetBSD's sh
418 1.1 christos # that is wrong to not output "for" "while" "if" ... etc
419 1.1 christos
420 1.1 christos # and lastly, that shell keywords do not get output when "executed"
421 1.1 christos atf_check -s exit:0 \
422 1.1 christos -o match:111222333 -o not-match:printf \
423 1.1 christos -o not-match:for \
424 1.1 christos -e match:printf -e match:111 -e not-match:111222 \
425 1.1 christos -e not-match:for -e not-match:do -e not-match:done \
426 1.1 christos "${TEST_SH}" -ec \
427 1.1 christos 'set -x; for i in 111 222 333; do printf "%s" $i; done; echo; exit 0'
428 1.1 christos }
429 1.1 christos
430 1.1 christos opt_test_setup()
431 1.1 christos {
432 1.1 christos test -n "$1" || { echo >&2 "Internal error"; exit 1; }
433 1.1 christos
434 1.1 christos cat > "$1" << 'END_OF_FUNCTIONS'
435 1.1 christos local_opt_check()
436 1.1 christos {
437 1.1 christos local -
438 1.1 christos }
439 1.1 christos
440 1.1 christos instr()
441 1.1 christos {
442 1.1 christos expr "$2" : "\(.*$1\)" >/dev/null
443 1.1 christos }
444 1.1 christos
445 1.1 christos save_opts()
446 1.1 christos {
447 1.1 christos local -
448 1.1 christos
449 1.1 christos set -e
450 1.1 christos set -u
451 1.1 christos
452 1.1 christos instr e "$-" && instr u "$-" && return 0
453 1.1 christos echo ERR
454 1.1 christos }
455 1.1 christos
456 1.1 christos fiddle_opts()
457 1.1 christos {
458 1.1 christos set -e
459 1.1 christos set -u
460 1.1 christos
461 1.1 christos instr e "$-" && instr u "$-" && return 0
462 1.1 christos echo ERR
463 1.1 christos }
464 1.1 christos
465 1.1 christos local_test()
466 1.1 christos {
467 1.1 christos set +eu
468 1.1 christos
469 1.1 christos save_opts
470 1.1 christos instr '[eu]' "$-" || printf %s "OK"
471 1.1 christos
472 1.1 christos fiddle_opts
473 1.1 christos instr e "$-" && instr u "$-" && printf %s "OK"
474 1.1 christos
475 1.1 christos set +eu
476 1.1 christos }
477 1.1 christos END_OF_FUNCTIONS
478 1.1 christos }
479 1.1 christos
480 1.1 christos atf_test_case restore_local_opts
481 1.1 christos restore_local_opts_head() {
482 1.1 christos atf_set "descr" "Tests that 'local -' saves and restores options. " \
483 1.1 christos "Note that "local" is a local shell addition"
484 1.1 christos }
485 1.1 christos restore_local_opts_body() {
486 1.1 christos atf_require_prog cat
487 1.1 christos atf_require_prog expr
488 1.1 christos
489 1.1 christos FN="test-funcs.$$"
490 1.1 christos opt_test_setup "${FN}" || atf_skip "Cannot setup test environment"
491 1.1 christos
492 1.1 christos "${TEST_SH}" -ec ". './${FN}'; local_opt_check" 2>/dev/null ||
493 1.1 christos atf_skip "sh extension 'local -' not supported by ${TEST_SH}"
494 1.1 christos
495 1.1 christos atf_check -s exit:0 -o match:OKOK -o not-match:ERR -e empty \
496 1.1 christos "${TEST_SH}" -ec ". './${FN}'; local_test"
497 1.1 christos }
498 1.1 christos
499 1.1 christos atf_test_case vi_emacs_VE_toggle
500 1.1 christos vi_emacs_VE_toggle_head() {
501 1.1 christos atf_set "descr" "Tests enabling vi disables emacs (and v.v - but why?)"\
502 1.1 christos " Note that -V and -E are local shell additions"
503 1.1 christos }
504 1.1 christos vi_emacs_VE_toggle_body() {
505 1.1 christos
506 1.1 christos test_optional_on_off V E ||
507 1.1 christos atf_skip "One or both V & E opts unsupported by ${TEST_SH}"
508 1.1 christos
509 1.1 christos atf_check -s exit:0 -o empty -e empty "${TEST_SH}" -c '
510 1.1 christos q() {
511 1.1 christos eval "case \"$-\" in
512 1.1 christos (*${2}*) return 1;;
513 1.1 christos (*${1}*) return 0;;
514 1.1 christos esac"
515 1.1 christos return 1
516 1.1 christos }
517 1.1 christos x() {
518 1.1 christos echo >&2 "Option set or toggle failure:" \
519 1.1 christos " on=$1 off=$2 set=$-"
520 1.1 christos exit 1
521 1.1 christos }
522 1.1 christos set -V; q V E || x V E
523 1.1 christos set -E; q E V || x E V
524 1.1 christos set -V; q V E || x V E
525 1.1 christos set +EV; q "" "[VE]" || x "" VE
526 1.1 christos exit 0
527 1.1 christos '
528 1.1 christos }
529 1.1 christos
530 1.1 christos atf_test_case xx_bogus
531 1.1 christos xx_bogus_head() {
532 1.1 christos atf_set "descr" "Tests that attempting to set a nonsense option fails."
533 1.1 christos }
534 1.1 christos xx_bogus_body() {
535 1.1 christos # Biggest problem here is picking a "nonsense option" that is
536 1.1 christos # not implemented by any shell, anywhere. Hopefully this will do.
537 1.1 christos atf_check -s not-exit:0 -o empty -e not-empty \
538 1.1 christos "${TEST_SH}" -c 'set -% ; echo ERR'
539 1.1 christos }
540 1.1 christos
541 1.1 christos atf_test_case Option_switching
542 1.1 christos Option_switching_head() {
543 1.1 christos atf_set "descr" "options can be enabled and disabled"
544 1.1 christos }
545 1.1 christos Option_switching_body() {
546 1.1 christos
547 1.1 christos # Cannot test -m, setting it causes test shell to fail...
548 1.1 christos # (test shell gets SIGKILL!) Wonder why ... something related to atf
549 1.1 christos # That is, it works if just run as "sh -c 'echo $-; set -m; echo $-'"
550 1.1 christos
551 1.1 christos # Don't bother testing toggling -n, once on, it stays on...
552 1.1 christos # (and because the test fn refuses to allow us to try)
553 1.1 christos
554 1.1 christos # Cannot test -o or -c here, or the extension -s
555 1.1 christos # they can only be used, not switched
556 1.1 christos
557 1.1 christos # these are the posix options, that all shells should implement
558 1.1 christos test_option_on_off a b C e f h u v x # m
559 1.1 christos
560 1.1 christos # and these are extensions that might not exist (non-fatal to test)
561 1.1 christos # -i and -s (and -c) are posix options, but are not required to
562 1.1 christos # be accessable via the "set" command, just the command line.
563 1.1 christos # We allow for -i to work with set, as that makes some sense,
564 1.1 christos # -c and -s do not.
565 1.1 christos test_optional_on_off E i I p q V || true
566 1.1 christos
567 1.1 christos # Also test (some) option combinations ...
568 1.1 christos # only testing posix options here, because it is easier...
569 1.1 christos test_option_on_off aeu vx Ca aCefux
570 1.1 christos }
571 1.1 christos
572 1.1 christos atf_init_test_cases() {
573 1.1 christos # tests are run in order sort of names produces, so choose names wisely
574 1.1 christos
575 1.1 christos # this one tests turning on/off all the mandatory. and extra flags
576 1.1 christos atf_add_test_case Option_switching
577 1.1 christos # and this tests the NetBSD "local -" functionality in functions.
578 1.1 christos atf_add_test_case restore_local_opts
579 1.1 christos
580 1.1 christos # no tests for -m (no idea how to do that one)
581 1.1 christos # -I (no easy way to generate the EOF it ignores)
582 1.1 christos # -i (not sure how to test that one at the minute)
583 1.1 christos # -p (because we aren't going to run tests setiud)
584 1.1 christos # -V/-E (too much effort, and a real test would be huge)
585 1.1 christos # -c (because almost all the other tests test it anyway)
586 1.1 christos # -q (because, for now, I am lazy)
587 1.1 christos # -s (coming soon, hopefully)
588 1.1 christos # -o (really +o: again, hopefully soon)
589 1.1 christos # -o longname (again, just laziness, don't wait...)
590 1.1 christos # -h/-b (because NetBSD doesn't implement them)
591 1.1 christos atf_add_test_case set_a
592 1.1 christos atf_add_test_case set_C
593 1.1 christos atf_add_test_case set_e
594 1.1 christos atf_add_test_case set_f
595 1.1 christos atf_add_test_case set_n
596 1.1 christos atf_add_test_case set_u
597 1.1 christos atf_add_test_case set_v
598 1.1 christos atf_add_test_case set_x
599 1.1 christos
600 1.1 christos atf_add_test_case vi_emacs_VE_toggle
601 1.1 christos atf_add_test_case xx_bogus
602 1.1 christos }
603