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