t_here.sh revision 1.2
1# $NetBSD: t_here.sh,v 1.2 2016/02/29 23:52:53 christos Exp $
2#
3# Copyright (c) 2007 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
30nl='
31'
32
33check()
34{
35	fail=false
36	TEMP_FILE=$( mktemp OUT.XXXXXX )
37
38	# our local shell (ATF_SHELL) better do quoting correctly...
39	# some of the tests expect us to expand $nl internally...
40	CMD="nl='${nl}'; $1"
41
42echo "${CMD}" >/tmp/CMD
43	rm -f trace.*
44	result="$( ${TEST_SH} -c "${CMD}" 2>"${TEMP_FILE}" )"
45	STATUS=$?
46
47	if [ -s "${O_FILE}" ]; then
48		echo >&2 "unexpected shell output noise on stdout"
49		cat "${O_FILE}" >&2
50		fail=true
51	fi
52
53	if [ "${STATUS}" -ne "$3" ]; then
54		echo >&2 "expected exit code $3, got ${STATUS}"
55
56		# don't actually fail just because of wrong exit code
57		# unless we either expected, or received "good"
58		case "$3/${STATUS}" in
59		(*/0|0/*) fail=true;;
60		esac
61	fi
62
63	if [ "$3" -eq 0 ]; then
64		if [ -s "${TEMP_FILE}" ]; then
65			echo >&2 "Messages produced on stderr unexpected..."
66			cat "${TEMP_FILE}" >&2
67			fail=true
68		fi
69	else
70		if ! [ -s "${TEMP_FILE}" ]; then
71			echo >&2 "Expected messages on stderr, nothing produced"
72			fail=true
73		fi
74	fi
75	rm -f "${TEMP_FILE}"
76
77	# Remove newlines (use local shell for this)
78	oifs="$IFS"
79	IFS="$nl"
80	result="$(echo $result)"
81	IFS="$oifs"
82	if [ "$2" != "$result" ]
83	then
84		echo >&2 "Expected output '$2', received '$result'"
85		fail=true
86	fi
87
88	$fail && atf_fail "test of '$1' failed"
89	return 0
90}
91
92atf_test_case do_simple
93do_simple_head() {
94	atf_set "descr" "Basic tests for here documents"
95}
96do_simple_body() {
97	y=x
98
99	IFS=
100	check 'x=`cat <<EOF'$nl'text'${nl}EOF$nl'`; echo $x' 'text' 0
101	check 'x=`cat <<\EOF'$nl'text'${nl}EOF$nl'`; echo $x' 'text' 0
102
103	check "y=${y};"'x=`cat <<EOF'$nl'te${y}t'${nl}EOF$nl'`; echo $x' \
104			'text' 0
105	check "y=${y};"'x=`cat <<\EOF'$nl'te${y}t'${nl}EOF$nl'`; echo $x'  \
106			'te${y}t' 0
107	check "y=${y};"'x=`cat <<"EOF"'$nl'te${y}t'${nl}EOF$nl'`; echo $x'  \
108			'te${y}t' 0
109	check "y=${y};"'x=`cat <<'"'EOF'"$nl'te${y}t'${nl}EOF$nl'`; echo $x'  \
110			'te${y}t' 0
111
112	# check that quotes in the here doc survive and cause no problems
113	check "cat <<EOF${nl}te'xt${nl}EOF$nl" "te'xt" 0
114	check "cat <<\EOF${nl}te'xt${nl}EOF$nl" "te'xt" 0
115	check "cat <<'EOF'${nl}te'xt${nl}EOF$nl" "te'xt" 0
116	check "cat <<EOF${nl}te\"xt${nl}EOF$nl" 'te"xt' 0
117	check "cat <<\EOF${nl}te\"xt${nl}EOF$nl" 'te"xt' 0
118	check "cat <<'EOF'${nl}te\"xt${nl}EOF$nl" 'te"xt' 0
119	check "cat <<'EO'F${nl}te\"xt${nl}EOF$nl" 'te"xt' 0
120
121	check "y=${y};"'x=`cat <<EOF'$nl'te'"'"'${y}t'${nl}EOF$nl'`; echo $x' \
122			'te'"'"'xt' 0
123	check "y=${y};"'x=`cat <<EOF'$nl'te'"''"'${y}t'${nl}EOF$nl'`; echo $x' \
124			'te'"''"'xt' 0
125
126	# note that the blocks of empty space in the following must
127	# be entirely tab characters, no spaces.
128
129	check 'x=`cat <<EOF'"$nl	text${nl}EOF$nl"'`; echo "$x"' \
130			'	text' 0
131	check 'x=`cat <<-EOF'"$nl	text${nl}EOF$nl"'`; echo $x' \
132			'text' 0
133	check 'x=`cat <<-EOF'"${nl}text${nl}	EOF$nl"'`; echo $x' \
134			'text' 0
135	check 'x=`cat <<-\EOF'"$nl	text${nl}	EOF$nl"'`; echo $x' \
136			'text' 0
137	check 'x=`cat <<- "EOF"'"$nl	text${nl}EOF$nl"'`; echo $x' \
138			'text' 0
139	check 'x=`cat <<- '"'EOF'${nl}text${nl}	EOF$nl"'`; echo $x' \
140			'text' 0
141}
142
143atf_test_case incomplete
144incomplete_head() {
145	atf_set "descr" "Basic tests for incomplete here documents"
146}
147incomplete_body() {
148	check 'cat <<EOF' '' 2
149	check 'cat <<- EOF' '' 2
150	check 'cat <<\EOF' '' 2
151	check 'cat <<- \EOF' '' 2
152
153	check 'cat <<EOF'"${nl}" '' 2
154	check 'cat <<- EOF'"${nl}" '' 2
155	check 'cat <<'"'EOF'${nl}" '' 2
156	check 'cat <<- "EOF"'"${nl}" '' 2
157
158	check 'cat << EOF'"${nl}${nl}" '' 2
159	check 'cat <<-EOF'"${nl}${nl}" '' 2
160	check 'cat << '"'EOF'${nl}${nl}" '' 2
161	check 'cat <<-"EOF"'"${nl}${nl}" '' 2
162
163	check 'cat << EOF'"${nl}"'line 1'"${nl}" '' 2
164	check 'cat <<-EOF'"${nl}"'	line 1'"${nl}" '' 2
165	check 'cat << EOF'"${nl}"'line 1'"${nl}"'	line 2'"${nl}" '' 2
166	check 'cat <<-EOF'"${nl}"'	line 1'"${nl}"'line 2'"${nl}" '' 2
167
168	check 'cat << EOF'"${nl}line 1${nl}${nl}line3${nl}${nl}5!${nl}" '' 2
169}
170
171atf_test_case multiple
172multiple_head() {
173	atf_set "descr" "Tests for multiple here documents for one cmd"
174}
175multiple_body() {
176	check \
177    "(cat ; cat <&3) <<EOF0 3<<EOF3${nl}STDIN${nl}EOF0${nl}-3-${nl}EOF3${nl}" \
178		'STDIN -3-' 0
179
180	check "(read line; echo \"\$line\"; cat <<EOF1; echo \"\$line\") <<EOF2
181The File
182EOF1
183The Line
184EOF2
185"			'The Line The File The Line' 0
186
187	check "(read line; echo \"\$line\"; cat <<EOF; echo \"\$line\") <<EOF
188The File
189EOF
190The Line
191EOF
192"			'The Line The File The Line' 0
193
194}
195
196atf_test_case viscious
197viscious_head() {
198	atf_set "descr" "Tests for obscure and obnoxious uses of here docs"
199}
200viscious_body() {
201
202	cat <<- \END_SCRIPT > script
203		cat <<ONE && cat \
204		<<TWO
205		a
206		ONE
207		b
208		TWO
209	END_SCRIPT
210
211	atf_check -s exit:0 -o inline:'a\nb\n' -e empty ${TEST_SH} script
212
213	# This next one is causing discussion currently (late Feb 2016)
214	# amongst stds writers & implementors.   Consequently we
215	# will not check what it produces.   The eventual result
216	# seems unlikely to be what we currently output, which
217	# is:
218	#	:echo line 1
219	#	B:echo line 2)" && prefix DASH_CODE <<DASH_CODE
220	#	B:echo line 3
221	#	line 4
222	#	line 5
223	#
224	# The likely intended output is ...
225	#
226	#	A:echo line 3
227	#	B:echo line 1
228	#	line 2
229	#	DASH_CODE:echo line 4)"
230	#	DASH_CODE:echo line 5
231	#
232	# The difference is explained by differeng opinions on just
233	# when processing of a here doc should start
234
235	cat <<- \END_SCRIPT > script
236		prefix() { sed -e "s/^/$1:/"; }
237		DASH_CODE() { :; }
238
239		prefix A <<XXX && echo "$(prefix B <<XXX
240		echo line 1
241		XXX
242		echo line 2)" && prefix DASH_CODE <<DASH_CODE
243		echo line 3
244		XXX
245		echo line 4)"
246		echo line 5
247		DASH_CODE
248	END_SCRIPT
249
250	# we will just verify that the shell can parse the
251	# script somehow, and doesn't fall over completely...
252
253	atf_check -s exit:0 -o ignore -e empty ${TEST+SH} script
254}
255
256atf_init_test_cases() {
257	atf_add_test_case do_simple
258	atf_add_test_case incomplete
259	atf_add_test_case multiple	# multiple << operators on one cmd
260	atf_add_test_case viscious	# evil test from the austin-l list...
261}
262