t_cmdsub.sh revision 313498
1# $NetBSD: t_cmdsub.sh,v 1.4 2016/04/04 12:40:13 christos Exp $
2#
3# Copyright (c) 2016 The NetBSD Foundation, Inc.
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25# POSSIBILITY OF SUCH DAMAGE.
26#
27# the implementation of "sh" to test
28: ${TEST_SH:="/bin/sh"}
29
30#
31# This file tests command substitutions ( `...` and $( ... ) )
32#
33# CAUTION:
34#	Be careful attempting running these tests outside the ATF environment
35#	Some of the tests run "rm *" in the current directory to clean up
36#	An ATF test directory should be empty already, outside ATF, anything
37
38atf_test_case a_basic_cmdsub
39a_basic_cmdsub_head() {
40	atf_set "descr" 'Test operation of simple $( ) substitutions'
41}
42a_basic_cmdsub_body() {
43	atf_check -s exit:0 -o match:'Result is true today' -e empty \
44	    ${TEST_SH} -c \
45		'echo Result is $( true && echo true || echo false ) today'
46
47	atf_check -s exit:0 -o match:'Result is false today' -e empty \
48	    ${TEST_SH} -c \
49		'echo Result is $( false && echo true || echo false ) today'
50
51	atf_check -s exit:0 -o match:'aaabbbccc' -e empty \
52	    ${TEST_SH} -c 'echo aaa$( echo bbb )ccc'
53	atf_check -s exit:0 -o match:'aaabbb cccddd' -e empty \
54	    ${TEST_SH} -c 'echo aaa$( echo bbb ccc )ddd'
55	atf_check -s exit:0 -o inline:'aaabbb cccddd\n' -e empty \
56	    ${TEST_SH} -c 'echo aaa$( echo bbb; echo ccc )ddd'
57	atf_check -s exit:0 -o inline:'aaabbb\ncccddd\n' -e empty \
58	    ${TEST_SH} -c 'echo "aaa$( echo bbb; echo ccc )ddd"'
59
60	atf_check -s exit:0 -o inline:'some string\n' -e empty \
61	    ${TEST_SH} -c 'X=$( echo some string ); echo "$X"'
62	atf_check -s exit:0 -o inline:'weird; string *\n' -e empty \
63	    ${TEST_SH} -c 'X=$( echo "weird; string *" ); echo "$X"'
64
65	rm -f * 2>/dev/null || :
66	for f in file-1 file-2
67	do
68		cp /dev/null "$f"
69	done
70
71	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
72	    ${TEST_SH} -c 'echo Found $( echo * )'
73	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
74	    ${TEST_SH} -c 'echo Found "$( echo * )"'
75	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
76	    ${TEST_SH} -c 'echo Found $('" echo '*' )"
77	atf_check -s exit:0 -o match:'Found \*' -e empty \
78	    ${TEST_SH} -c 'echo Found "$('" echo '*' "')"'
79	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
80	    ${TEST_SH} -c 'echo Found $('" echo \\* )"
81	atf_check -s exit:0 -o match:'Found \*' -e empty \
82	    ${TEST_SH} -c 'echo Found "$('" echo \\* )"\"
83}
84
85atf_test_case b_basic_backticks
86b_basic_backticks_head() {
87	atf_set "descr" 'Test operation of old style ` ` substitutions'
88}
89b_basic_backticks_body() {
90	atf_check -s exit:0 -o match:'Result is true today' -e empty \
91	    ${TEST_SH} -c \
92		'echo Result is `true && echo true || echo false` today'
93
94	atf_check -s exit:0 -o match:'Result is false today' -e empty \
95	    ${TEST_SH} -c \
96		'echo Result is `false && echo true || echo false` today'
97
98	atf_check -s exit:0 -o match:'aaabbbccc' -e empty \
99	    ${TEST_SH} -c 'echo aaa` echo bbb `ccc'
100	atf_check -s exit:0 -o match:'aaabbb cccddd' -e empty \
101	    ${TEST_SH} -c 'echo aaa` echo bbb ccc `ddd'
102	atf_check -s exit:0 -o inline:'aaabbb cccddd\n' -e empty \
103	    ${TEST_SH} -c 'echo aaa` echo bbb; echo ccc `ddd'
104	atf_check -s exit:0 -o inline:'aaabbb\ncccddd\n' -e empty \
105	    ${TEST_SH} -c 'echo "aaa` echo bbb; echo ccc `ddd"'
106
107	atf_check -s exit:0 -o inline:'some string\n' -e empty \
108	    ${TEST_SH} -c 'X=` echo some string `; echo "$X"'
109	atf_check -s exit:0 -o inline:'weird; string *\n' -e empty \
110	    ${TEST_SH} -c 'X=` echo "weird; string *" `; echo "$X"'
111
112	rm -f * 2>/dev/null || :
113	for f in file-1 file-2
114	do
115		cp /dev/null "$f"
116	done
117
118	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
119	    ${TEST_SH} -c 'echo Found ` echo * `'
120	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
121	    ${TEST_SH} -c 'echo Found "` echo * `"'
122	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
123	    ${TEST_SH} -c 'echo Found `'" echo '*' "'`'
124	atf_check -s exit:0 -o match:'Found \*' -e empty \
125	    ${TEST_SH} -c 'echo Found "`'" echo '*' "'`"'
126	atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
127	    ${TEST_SH} -c 'echo Found `'" echo \\* "'`'
128	atf_check -s exit:0 -o match:'Found \*' -e empty \
129	    ${TEST_SH} -c 'echo Found "`'" echo \\* "'`"'
130}
131
132atf_test_case c_nested_cmdsub
133c_nested_cmdsub_head() {
134	atf_set "descr" "Test that cmd substitutions can be nested"
135}
136c_nested_cmdsub_body() {
137	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
138	    ${TEST_SH} -c 'echo __$( echo foo$(echo bar)bletch )__'
139	atf_check -s exit:0 -o match:'_abcde_' -e empty \
140	    ${TEST_SH} -c 'echo _$(echo a$(echo $(echo b)c$(echo d))e )_'
141	atf_check -s exit:0 -o match:'123454321' -e empty \
142	    ${TEST_SH} -c 'echo 1$(echo 2$(echo 3$(echo 4$(echo 5)4)3)2)1'
143}
144
145atf_test_case d_nested_backticks
146d_nested_backticks_head() {
147	atf_set "descr" "Tests that old style backtick cmd subs can be nested"
148}
149d_nested_backticks_body() {
150	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
151	    ${TEST_SH} -c 'echo __` echo foo\`echo bar\`bletch `__'
152	atf_check -s exit:0 -o match:'_abcde_' -e empty \
153	    ${TEST_SH} -c \
154		'echo _`echo a\`echo \\\`echo b\\\`c\\\`echo d\\\`\`e `_'
155	atf_check -s exit:0 -o match:'123454321' -e empty \
156	    ${TEST_SH} -c \
157	    'echo 1`echo 2\`echo 3\\\`echo 4\\\\\\\`echo 5\\\\\\\`4\\\`3\`2`1'
158}
159
160atf_test_case e_perverse_mixing
161e_perverse_mixing_head() {
162	atf_set "descr" \
163		"Checks various mixed new and old style cmd substitutions"
164}
165e_perverse_mixing_body() {
166	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
167	    ${TEST_SH} -c 'echo __$( echo foo`echo bar`bletch )__'
168	atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
169	    ${TEST_SH} -c 'echo __` echo foo$(echo bar)bletch `__'
170	atf_check -s exit:0 -o match:'_abcde_' -e empty \
171	    ${TEST_SH} -c 'echo _$(echo a`echo $(echo b)c$(echo d)`e )_'
172	atf_check -s exit:0 -o match:'_abcde_' -e empty \
173	    ${TEST_SH} -c 'echo _`echo a$(echo \`echo b\`c\`echo d\`)e `_'
174	atf_check -s exit:0 -o match:'12345654321' -e empty \
175	    ${TEST_SH} -c \
176		'echo 1`echo 2$(echo 3\`echo 4\\\`echo 5$(echo 6)5\\\`4\`3)2`1'
177}
178
179atf_test_case f_redirect_in_cmdsub
180f_redirect_in_cmdsub_head() {
181	atf_set "descr" "Checks that redirects work in command substitutions"
182}
183f_redirect_in_cmdsub_body() {
184	atf_require_prog cat
185	atf_require_prog rm
186
187	rm -f file 2>/dev/null || :
188	atf_check -s exit:0 -o match:'_aa_' -e empty \
189	    ${TEST_SH} -c 'echo _$( echo a$( echo b > file )a)_'
190	atf_check -s exit:0 -o match:b -e empty ${TEST_SH} -c 'cat file'
191	atf_check -s exit:0 -o match:'_aba_' -e empty \
192	    ${TEST_SH} -c 'echo _$( echo a$( cat < file )a)_'
193	atf_check -s exit:0 -o match:'_aa_' -e empty \
194	    ${TEST_SH} -c 'echo _$( echo a$( echo d >> file )a)_'
195	atf_check -s exit:0 -o inline:'b\nd\n' -e empty ${TEST_SH} -c 'cat file'
196	atf_check -s exit:0 -o match:'_aa_' -e match:'not error' \
197	    ${TEST_SH} -c 'echo _$( echo a$( echo not error >&2 )a)_'
198}
199
200atf_test_case g_redirect_in_backticks
201g_redirect_in_backticks_head() {
202	atf_set "descr" "Checks that redirects work in old style cmd sub"
203}
204g_redirect_in_backticks_body() {
205	atf_require_prog cat
206	atf_require_prog rm
207
208	rm -f file 2>/dev/null || :
209	atf_check -s exit:0 -o match:'_aa_' -e empty \
210	    ${TEST_SH} -c 'echo _` echo a\` echo b > file \`a`_'
211	atf_check -s exit:0 -o match:b -e empty ${TEST_SH} -c 'cat file'
212	atf_check -s exit:0 -o match:'_aba_' -e empty \
213	    ${TEST_SH} -c 'echo _` echo a\` cat < file \`a`_'
214	atf_check -s exit:0 -o match:'_aa_' -e empty \
215	    ${TEST_SH} -c 'echo _` echo a\` echo d >> file \`a`_'
216	atf_check -s exit:0 -o inline:'b\nd\n' -e empty ${TEST_SH} -c 'cat file'
217	atf_check -s exit:0 -o match:'_aa_' -e match:'not error' \
218	    ${TEST_SH} -c 'echo _` echo a\` echo not error >&2 \`a`_'
219}
220
221atf_test_case h_vars_in_cmdsub
222h_vars_in_cmdsub_head() {
223	atf_set "descr" "Check that variables work in command substitutions"
224}
225h_vars_in_cmdsub_body() {
226	atf_check -s exit:0 -o match:'__abc__' -e empty \
227	    ${TEST_SH} -c 'X=abc; echo __$( echo ${X} )__'
228	atf_check -s exit:0 -o match:'__abc__' -e empty \
229	    ${TEST_SH} -c 'X=abc; echo __$( echo "${X}" )__'
230	atf_check -s exit:0 -o match:'__abc__' -e empty \
231	    ${TEST_SH} -c 'X=abc; echo "__$( echo ${X} )__"'
232	atf_check -s exit:0 -o match:'__abc__' -e empty \
233	    ${TEST_SH} -c 'X=abc; echo "__$( echo "${X}" )__"'
234
235	atf_check -s exit:0 -o inline:'a\n\nb\n\nc\n' -e empty \
236	    ${TEST_SH} -c "for X in a '' b '' c"'; do echo $( echo "$X" ); done'
237
238	atf_check -s exit:0 -o match:'__acd__' -e empty \
239	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X-b}${Y-c}d)__"'
240	atf_check -s exit:0 -o match:'__abcd__' -e empty \
241	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X:-b}${Y:-c}d)__"'
242	atf_check -s exit:0 -o match:'__XYX__' -e empty \
243	    ${TEST_SH} -c 'X=X; echo "__${X}$( X=Y; echo ${X} )${X}__"'
244	atf_check -s exit:0 -o match:'__def__' -e empty \
245	    ${TEST_SH} -c 'X=abc; echo "__$(X=def; echo "${X}" )__"'
246	atf_check -s exit:0 -o inline:'abcdef\nabc\n' -e empty \
247	    ${TEST_SH} -c 'X=abc; echo "$X$(X=def; echo ${X} )"; echo $X'
248}
249
250atf_test_case i_vars_in_backticks
251i_vars_in_backticks_head() {
252	atf_set "descr" "Checks that variables work in old style cmd sub"
253}
254i_vars_in_backticks_body() {
255	atf_check -s exit:0 -o match:'__abc__' -e empty \
256	    ${TEST_SH} -c 'X=abc; echo __` echo ${X} `__'
257	atf_check -s exit:0 -o match:'__abc__' -e empty \
258	    ${TEST_SH} -c 'X=abc; echo __` echo "${X}" `__'
259	atf_check -s exit:0 -o match:'__abc__' -e empty \
260	    ${TEST_SH} -c 'X=abc; echo "__` echo ${X} `__"'
261	atf_check -s exit:0 -o match:'__abc__' -e empty \
262	    ${TEST_SH} -c 'X=abc; echo "__` echo \"${X}\" `__"'
263
264	atf_check -s exit:0 -o inline:'a\n\nb\n\nc\n' -e empty \
265	    ${TEST_SH} -c "for X in a '' b '' c"'; do echo $( echo "$X" ); done'
266
267	atf_check -s exit:0 -o match:'__acd__' -e empty \
268	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X-b}${Y-c}d)__"'
269	atf_check -s exit:0 -o match:'__abcd__' -e empty \
270	    ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X:-b}${Y:-c}d)__"'
271	atf_check -s exit:0 -o match:'__XYX__' -e empty \
272	    ${TEST_SH} -c 'X=X; echo "__${X}$( X=Y; echo ${X} )${X}__"'
273	atf_check -s exit:0 -o inline:'abcdef\nabc\n' -e empty \
274	    ${TEST_SH} -c 'X=abc; echo "$X`X=def; echo \"${X}\" `";echo $X'
275
276	# The following is nonsense, so is not included ...
277	# atf_check -s exit:0 -o match:'__abc__' -e empty \
278	#                              oV             cV   oV   cV
279	#    ${TEST_SH} -c 'X=abc; echo "__`X=def echo "${X}" `__"'
280	#				   `start in " ^ " ends, ` not yet
281}
282
283atf_test_case j_cmdsub_in_varexpand
284j_cmdsub_in_varexpand_head() {
285	atf_set "descr" "Checks that command sub can be used in var expansion"
286}
287j_cmdsub_in_varexpand_body() {
288	atf_check -s exit:0 -o match:'foo' -e empty \
289	    ${TEST_SH} -c 'X=set; echo ${X+$(echo foo)}'
290	atf_check -s exit:0 -o match:'set' -e empty \
291	    ${TEST_SH} -c 'X=set; echo ${X-$(echo foo)}'
292	rm -f bar 2>/dev/null || :
293	atf_check -s exit:0 -o match:'set' -e empty \
294	    ${TEST_SH} -c 'X=set; echo ${X-$(echo foo > bar)}'
295	test -f bar && atf_fail "bar should not exist, but does"
296	atf_check -s exit:0 -o inline:'\n' -e empty \
297	    ${TEST_SH} -c 'X=set; echo ${X+$(echo foo > bar)}'
298	test -f bar || atf_fail "bar should exist, but does not"
299}
300
301atf_test_case k_backticks_in_varexpand
302k_backticks_in_varexpand_head() {
303	atf_set "descr" "Checks that old style cmd sub works in var expansion"
304}
305k_backticks_in_varexpand_body() {
306	atf_check -s exit:0 -o match:'foo' -e empty \
307	    ${TEST_SH} -c 'X=set; echo ${X+`echo foo`}'
308	atf_check -s exit:0 -o match:'set' -e empty \
309	    ${TEST_SH} -c 'X=set; echo ${X-`echo foo`}'
310	rm -f bar 2>/dev/null || :
311	atf_check -s exit:0 -o match:'set' -e empty \
312	    ${TEST_SH} -c 'X=set; echo ${X-`echo foo > bar`}'
313	test -f bar && atf_fail "bar should not exist, but does"
314	atf_check -s exit:0 -o inline:'\n' -e empty \
315	    ${TEST_SH} -c 'X=set; echo ${X+`echo foo > bar`}'
316	test -f bar || atf_fail "bar should exist, but does not"
317}
318
319atf_test_case l_arithmetic_in_cmdsub
320l_arithmetic_in_cmdsub_head() {
321	atf_set "descr" "Checks that arithmetic works in cmd substitutions"
322}
323l_arithmetic_in_cmdsub_body() {
324	atf_check -s exit:0 -o inline:'1 + 1 = 2\n' -e empty \
325	    ${TEST_SH} -c 'echo 1 + 1 = $( echo $(( 1 + 1 )) )'
326	atf_check -s exit:0 -o inline:'X * Y = 6\n' -e empty \
327	    ${TEST_SH} -c 'X=2; Y=3; echo X \* Y = $( echo $(( X * Y )) )'
328	atf_check -s exit:0 -o inline:'Y % X = 1\n' -e empty \
329	    ${TEST_SH} -c 'X=2; Y=3; echo Y % X = $( echo $(( $Y % $X )) )'
330}
331
332atf_test_case m_arithmetic_in_backticks
333m_arithmetic_in_backticks_head() {
334	atf_set "descr" "Checks that arithmetic works in old style cmd sub"
335}
336m_arithmetic_in_backticks_body() {
337	atf_check -s exit:0 -o inline:'2 + 3 = 5\n' -e empty \
338	    ${TEST_SH} -c 'echo 2 + 3 = ` echo $(( 2 + 3 )) `'
339	atf_check -s exit:0 -o inline:'X * Y = 6\n' -e empty \
340	    ${TEST_SH} -c 'X=2; Y=3; echo X \* Y = ` echo $(( X * Y )) `'
341	atf_check -s exit:0 -o inline:'Y % X = 1\n' -e empty \
342	    ${TEST_SH} -c 'X=2; Y=3; echo Y % X = ` echo $(( $Y % $X )) `'
343}
344
345atf_test_case n_cmdsub_in_arithmetic
346n_cmdsub_in_arithmetic_head() {
347	atf_set "descr" "Tests uses of command substitutions in arithmetic"
348}
349n_cmdsub_in_arithmetic_body() {
350	atf_check -s exit:0 -o inline:'7\n' -e empty \
351	    ${TEST_SH} -c 'echo $(( $( echo 3 ) $( echo + ) $( echo 4 ) ))'
352	atf_check -s exit:0 -o inline:'11\n7\n18\n4\n1\n' -e empty \
353	    ${TEST_SH} -c \
354		 'for op in + - \* / %
355		  do
356		      echo $(( $( echo 9 ) $( echo "${op}" ) $( echo 2 ) ))
357		  done'
358}
359
360atf_test_case o_backticks_in_arithmetic
361o_backticks_in_arithmetic_head() {
362	atf_set "descr" "Tests old style cmd sub used in arithmetic"
363}
364o_backticks_in_arithmetic_body() {
365	atf_check -s exit:0 -o inline:'33\n' -e empty \
366	    ${TEST_SH} -c 'echo $(( `echo 77` `echo -` `echo 44`))'
367	atf_check -s exit:0 -o inline:'14\n8\n33\n3\n2\n' -e empty \
368	    ${TEST_SH} -c \
369		 'for op in + - \* / %
370		  do
371		      echo $((`echo 11``echo "${op}"``echo 3`))
372		  done'
373}
374
375atf_test_case p_cmdsub_in_heredoc
376p_cmdsub_in_heredoc_head() {
377	atf_set "descr" "Checks that cmdsubs work inside a here document"
378}
379p_cmdsub_in_heredoc_body() {
380	atf_require_prog cat
381
382	atf_check -s exit:0 -o inline:'line 1+1\nline 2\nline 3\n' -e empty \
383	    ${TEST_SH} -c \
384		'cat <<- EOF
385			$( echo line 1 )$( echo +1 )
386			$( echo line 2;echo line 3 )
387		EOF'
388}
389
390atf_test_case q_backticks_in_heredoc
391q_backticks_in_heredoc_head() {
392	atf_set "descr" "Checks that old style cmdsubs work in here docs"
393}
394q_backticks_in_heredoc_body() {
395	atf_require_prog cat
396
397	atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
398	    ${TEST_SH} -c \
399		'cat <<- EOF
400			`echo Mary ` `echo had a `
401			` echo little; echo lamb `
402		EOF'
403}
404
405atf_test_case r_heredoc_in_cmdsub
406r_heredoc_in_cmdsub_head() {
407	atf_set "descr" "Checks that here docs work inside cmd subs"
408}
409r_heredoc_in_cmdsub_body() {
410	atf_require_prog cat
411
412	atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
413	    ${TEST_SH} -c 'echo "$( cat <<- \EOF
414				Mary had a
415				little
416				lamb
417			EOF
418			)"'
419
420	atf_check -s exit:0 -e empty \
421	    -o inline:'Mary had 1\nlittle\nlamb\nMary had 4\nlittle\nlambs\n' \
422	    ${TEST_SH} -c 'for N in 1 4; do echo "$( cat <<- EOF
423				Mary had ${N}
424				little
425				lamb$( [ $N -gt 1 ] && echo s )
426			EOF
427			)"; done'
428
429
430	atf_check -s exit:0 -o inline:'A Calculation:\n2 * 7 = 14\n' -e empty \
431	    ${TEST_SH} -c 'echo "$( cat <<- EOF
432				A Calculation:
433					2 * 7 = $(( 2 * 7 ))
434			EOF
435			)"'
436}
437
438atf_test_case s_heredoc_in_backticks
439s_heredoc_in_backticks_head() {
440	atf_set "descr" "Checks that here docs work inside old style cmd subs"
441}
442s_heredoc_in_backticks_body() {
443	atf_require_prog cat
444
445	atf_check -s exit:0 -o inline:'Mary had a little lamb\n' -e empty \
446	    ${TEST_SH} -c 'echo ` cat <<- \EOF
447				Mary had a
448				little
449				lamb
450			EOF
451			`'
452
453	atf_check -s exit:0 -o inline:'A Calculation:\n17 / 3 = 5\n' -e empty \
454	    ${TEST_SH} -c 'echo "` cat <<- EOF
455				A Calculation:
456					17 / 3 = $(( 17 / 3 ))
457			EOF
458			`"'
459}
460
461atf_test_case t_nested_cmdsubs_in_heredoc
462t_nested_cmdsubs_in_heredoc_head() {
463	atf_set "descr" "Checks nested command substitutions in here docs"
464}
465t_nested_cmdsubs_in_heredoc_body() {
466	atf_require_prog cat
467	atf_require_prog rm
468
469	rm -f * 2>/dev/null || :
470	echo "Hello" > File
471
472	atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
473	    ${TEST_SH} -c 'cat <<- EOF
474		$(cat File) U
475		$( V=$(cat File); echo "${V%lo}p" ) me!
476		EOF'
477
478	rm -f * 2>/dev/null || :
479	echo V>V ; echo A>A; echo R>R
480	echo Value>VAR
481
482	atf_check -s exit:0 -o inline:'$2.50\n' -e empty \
483	    ${TEST_SH} -c 'cat <<- EOF
484	$(Value='\''$2.50'\'';eval echo $(eval $(cat V)$(cat A)$(cat R)=\'\''\$$(cat $(cat V)$(cat A)$(cat R))\'\''; eval echo \$$(set -- *;echo ${3}${1}${2})))
485		EOF'
486}
487
488atf_test_case u_nested_backticks_in_heredoc
489u_nested_backticks_in_heredoc_head() {
490	atf_set "descr" "Checks nested old style cmd subs in here docs"
491}
492u_nested_backticks_in_heredoc_body() {
493	atf_require_prog cat
494	atf_require_prog rm
495
496	rm -f * 2>/dev/null || :
497	echo "Hello" > File
498
499	atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
500	    ${TEST_SH} -c 'cat <<- EOF
501		`cat File` U
502		`V=\`cat File\`; echo "${V%lo}p" ` me!
503		EOF'
504
505	rm -f * 2>/dev/null || :
506	echo V>V ; echo A>A; echo R>R
507	echo Value>VAR
508
509	atf_check -s exit:0 -o inline:'$5.20\n' -e empty \
510	    ${TEST_SH} -c 'cat <<- EOF
511	`Value='\''$5.20'\'';eval echo \`eval \\\`cat V\\\`\\\`cat A\\\`\\\`cat R\\\`=\\\'\''\\\$\\\`cat \\\\\\\`cat V\\\\\\\`\\\\\\\`cat A\\\\\\\`\\\\\\\`cat R\\\\\\\`\\\`\\\'\''; eval echo \\\$\\\`set -- *;echo \\\\\${3}\\\\\${1}\\\\\${2}\\\`\``
512		EOF'
513}
514
515atf_test_case v_cmdsub_paren_tests
516v_cmdsub__paren_tests_head() {
517	atf_set "descr" "tests with cmdsubs containing embedded ')'"
518}
519v_cmdsub_paren_tests_body() {
520
521	# Tests from:
522	#	http://www.in-ulm.de/~mascheck/various/cmd-subst/
523	# (slightly modified.)
524
525	atf_check -s exit:0 -o inline:'A.1\n' -e empty ${TEST_SH} -c \
526		'echo $(
527			case x in  x) echo A.1;; esac
528		)'
529
530	atf_check -s exit:0 -o inline:'A.2\n' -e empty ${TEST_SH} -c \
531		'echo $(
532			case x in  x) echo A.2;; esac # comment
533		)'
534
535	atf_check -s exit:0 -o inline:'A.3\n' -e empty ${TEST_SH} -c \
536		'echo $(
537			case x in (x) echo A.3;; esac
538		)'
539
540	atf_check -s exit:0 -o inline:'A.4\n' -e empty ${TEST_SH} -c \
541		'echo $(
542			case x in (x) echo A.4;; esac # comment
543		)'
544
545	atf_check -s exit:0 -o inline:'A.5\n' -e empty ${TEST_SH} -c \
546		'echo $(
547			case x in (x) echo A.5
548			esac
549		)'
550
551	atf_check -s exit:0 -o inline:'B: quoted )\n' -e empty ${TEST_SH} -c \
552		'echo $(
553			echo '\''B: quoted )'\''
554		)'
555
556	atf_check -s exit:0 -o inline:'C: comment then closing paren\n' \
557		-e empty ${TEST_SH} -c \
558			'echo $(
559				echo C: comment then closing paren # )
560			)'
561
562	atf_check -s exit:0 -o inline:'D.1: here-doc with )\n' \
563		-e empty ${TEST_SH} -c \
564			'echo $(
565				cat <<-\eof
566				D.1: here-doc with )
567				eof
568			)'
569
570	# D.2 is a bogus test.
571
572	atf_check -s exit:0 -o inline:'D.3: here-doc with \()\n' \
573		-e empty ${TEST_SH} -c \
574			'echo $(
575				cat <<-\eof
576				D.3: here-doc with \()
577				eof
578			)'
579
580	atf_check -s exit:0 -e empty \
581	  -o inline:'E: here-doc terminated with a parenthesis ("academic")\n' \
582		${TEST_SH} -c \
583		'echo $(
584			cat <<-\)
585			E: here-doc terminated with a parenthesis ("academic")
586			)
587		)'
588
589	atf_check -s exit:0 -e empty \
590-o inline:'F.1: here-doc embed with unbal single, back- or doublequote '\''\n' \
591		${TEST_SH} -c \
592		'echo $(
593			cat <<-"eof"
594		F.1: here-doc embed with unbal single, back- or doublequote '\''
595			eof
596		)'
597	atf_check -s exit:0 -e empty \
598 -o inline:'F.2: here-doc embed with unbal single, back- or doublequote "\n' \
599		${TEST_SH} -c \
600		'echo $(
601			cat <<-"eof"
602		F.2: here-doc embed with unbal single, back- or doublequote "
603			eof
604		)'
605	atf_check -s exit:0 -e empty \
606 -o inline:'F.3: here-doc embed with unbal single, back- or doublequote `\n' \
607		${TEST_SH} -c \
608		'echo $(
609			cat <<-"eof"
610		F.3: here-doc embed with unbal single, back- or doublequote `
611			eof
612		)'
613
614	atf_check -s exit:0 -e empty -o inline:'G: backslash at end of line\n' \
615		${TEST_SH} -c \
616			'echo $(
617				echo G: backslash at end of line # \
618			)'
619
620	atf_check -s exit:0 -e empty \
621		-o inline:'H: empty command-substitution\n' \
622		${TEST_SH} -c 'echo H: empty command-substitution $( )'
623}
624
625atf_test_case w_heredoc_outside_cmdsub
626w_heredoc_outside_cmdsub_head() {
627	atf_set "descr" "Checks that here docs work inside cmd subs"
628}
629w_heredoc_outside_cmdsub_body() {
630	atf_require_prog cat
631
632	atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
633	    ${TEST_SH} -c 'echo "$( cat <<- \EOF )"
634				Mary had a
635				little
636				lamb
637			EOF
638			'
639
640	atf_check -s exit:0 -e empty \
641	    -o inline:'Mary had 1\nlittle\nlamb\nMary had 4\nlittle\nlambs\n' \
642	    ${TEST_SH} -c 'for N in 1 4; do echo "$( cat <<- EOF )"
643				Mary had ${N}
644				little
645				lamb$( [ $N -gt 1 ] && echo s )
646			EOF
647			done'
648
649
650	atf_check -s exit:0 -o inline:'A Calculation:\n2 * 7 = 14\n' -e empty \
651	    ${TEST_SH} -c 'echo "$( cat <<- EOF)"
652				A Calculation:
653					2 * 7 = $(( 2 * 7 ))
654			EOF
655			'
656}
657
658atf_test_case x_heredoc_outside_backticks
659x_heredoc_outside_backticks_head() {
660	atf_set "descr" "Checks that here docs work inside old style cmd subs"
661}
662x_heredoc_outside_backticks_body() {
663	atf_require_prog cat
664
665	atf_check -s exit:0 -o inline:'Mary had a little lamb\n' -e empty \
666	    ${TEST_SH} -c 'echo ` cat <<- \EOF `
667				Mary had a
668				little
669				lamb
670			EOF
671			'
672
673	atf_check -s exit:0 -o inline:'A Calculation:\n17 / 3 = 5\n' -e empty \
674	    ${TEST_SH} -c 'echo "` cat <<- EOF `"
675				A Calculation:
676					17 / 3 = $(( 17 / 3 ))
677			EOF
678			'
679}
680
681atf_test_case t_nested_cmdsubs_in_heredoc
682t_nested_cmdsubs_in_heredoc_head() {
683	atf_set "descr" "Checks nested command substitutions in here docs"
684}
685t_nested_cmdsubs_in_heredoc_body() {
686	atf_require_prog cat
687	atf_require_prog rm
688
689	rm -f * 2>/dev/null || :
690	echo "Hello" > File
691
692	atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
693	    ${TEST_SH} -c 'cat <<- EOF
694		$(cat File) U
695		$( V=$(cat File); echo "${V%lo}p" ) me!
696		EOF'
697
698	rm -f * 2>/dev/null || :
699	echo V>V ; echo A>A; echo R>R
700	echo Value>VAR
701
702	atf_check -s exit:0 -o inline:'$2.50\n' -e empty \
703	    ${TEST_SH} -c 'cat <<- EOF
704	$(Value='\''$2.50'\'';eval echo $(eval $(cat V)$(cat A)$(cat R)=\'\''\$$(cat $(cat V)$(cat A)$(cat R))\'\''; eval echo \$$(set -- *;echo ${3}${1}${2})))
705		EOF'
706}
707
708atf_test_case z_absurd_heredoc_cmdsub_combos
709z_absurd_heredoc_cmdsub_combos_head() {
710	atf_set "descr" "perverse and unusual cmd substitutions & more"
711}
712z_absurd_heredoc_cmdsub_combos_body() {
713
714	echo "Help!" > help
715
716	# This version works in NetBSD (& FreeBSD)'s sh (and most others)
717	atf_check -s exit:0 -o inline:'Help!\nMe 2\n' -e empty ${TEST_SH} -c '
718			cat <<- EOF
719				$(
720					cat <<- STOP
721						$(
722							cat `echo help`
723						)
724					STOP
725				)
726				$(
727					cat <<- END 4<<-TRASH
728						Me $(( 1 + 1 ))
729					END
730					This is unused noise!
731					TRASH
732				)
733			EOF
734		'
735
736	# atf_expect_fail "PR bin/50993 - heredoc parsing done incorrectly"
737	atf_check -s exit:0 -o inline:'Help!\nMe 2\n' -e empty ${TEST_SH} -c '
738			cat <<- EOF
739				$(
740					cat << STOP
741						$(
742							cat `echo help`
743						)
744					STOP
745				)
746				$(
747					cat <<- END 4<<TRASH
748						Me $(( 1 + 1 ))
749					END
750					This is unused noise!
751					TRASH
752				)
753			EOF
754		'
755}
756
757atf_init_test_cases() {
758	atf_add_test_case a_basic_cmdsub
759	atf_add_test_case b_basic_backticks
760	atf_add_test_case c_nested_cmdsub
761	atf_add_test_case d_nested_backticks
762	atf_add_test_case e_perverse_mixing
763	atf_add_test_case f_redirect_in_cmdsub
764	atf_add_test_case g_redirect_in_backticks
765	atf_add_test_case h_vars_in_cmdsub
766	atf_add_test_case i_vars_in_backticks
767	atf_add_test_case j_cmdsub_in_varexpand
768	atf_add_test_case k_backticks_in_varexpand
769	atf_add_test_case l_arithmetic_in_cmdsub
770	atf_add_test_case m_arithmetic_in_backticks
771	atf_add_test_case n_cmdsub_in_arithmetic
772	atf_add_test_case o_backticks_in_arithmetic
773	atf_add_test_case p_cmdsub_in_heredoc
774	atf_add_test_case q_backticks_in_heredoc
775	atf_add_test_case r_heredoc_in_cmdsub
776	atf_add_test_case s_heredoc_in_backticks
777	atf_add_test_case t_nested_cmdsubs_in_heredoc
778	atf_add_test_case u_nested_backticks_in_heredoc
779	atf_add_test_case v_cmdsub_paren_tests
780	atf_add_test_case w_heredoc_outside_cmdsub
781	atf_add_test_case x_heredoc_outside_backticks
782	atf_add_test_case z_absurd_heredoc_cmdsub_combos
783}
784