1#
2# CDDL HEADER START
3#
4# The contents of this file are subject to the terms of the
5# Common Development and Distribution License (the "License").
6# You may not use this file except in compliance with the License.
7#
8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9# or http://www.opensolaris.org/os/licensing.
10# See the License for the specific language governing permissions
11# and limitations under the License.
12#
13# When distributing Covered Code, include this CDDL HEADER in each
14# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15# If applicable, add the following below this CDDL HEADER, with the
16# fields enclosed by brackets "[]" replaced with your own identifying
17# information: Portions Copyright [yyyy] [name of copyright owner]
18#
19# CDDL HEADER END
20#
21
22#
23# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24#
25
26# test setup
27function err_exit
28{
29	print -u2 -n "\t"
30	print -u2 -r ${Command}[$1]: "${@:2}"
31	(( Errors < 127 && Errors++ ))
32}
33alias err_exit='err_exit $LINENO'
34
35# "nounset" disabled for now
36#set -o nounset
37Command=${0##*/}
38integer Errors=0
39
40compound bracketstat=(
41	integer bopen=0
42	integer bclose=0
43)
44
45function count_brackets
46{
47	typeset x="$1"
48	typeset c
49
50	integer i
51	(( bracketstat.bopen=0 , bracketstat.bclose=0 ))
52
53	for (( i=0 ; i < ${#x} ; i++ )) ; do
54	        c="${x:i:1}"
55		[[ "$c" == "(" ]] && (( bracketstat.bopen++ ))
56		[[ "$c" == ")" ]] && (( bracketstat.bclose++ ))
57	done
58
59	(( bracketstat.bopen != bracketstat.bclose )) && return 1
60
61	return 0
62}
63
64# compound variable "cat" nr.1, using $ print "%B\n" ... #
65function cpvcat1
66{
67	set -o errexit
68	compound tmp
69
70	while read -C tmp ; do printf "%B\n" tmp ; done
71	return 0
72}
73
74# compound variable "cat" nr.2, using $ print "%#B\n" ... #
75function cpvcat2
76{
77	set -o errexit
78	compound tmp
79
80	while read -C tmp ; do printf "%#B\n" tmp ; done
81	return 0
82}
83
84# compound variable "cat" nr.3, using $ print -C ... #
85function cpvcat3
86{
87	set -o errexit
88	compound tmp
89
90	while read -C tmp ; do print -C tmp ; done
91	return 0
92}
93
94# compound variable "cat" nr.4, using $ print -v ... #
95function cpvcat4
96{
97	set -o errexit
98	compound tmp
99
100	while read -C tmp ; do print -v tmp ; done
101	return 0
102}
103
104typeset s
105
106# Test 1:
107# Check whether "read -C" leaves the file pointer at the next line
108# (and does not read beyond that point).
109# Data layout is:
110# -- snip --
111# <compound var>
112# hello
113# -- snip --
114# (additionally we test some extra stuff like bracket count)
115s=${
116	compound x=(
117		a=1 b=2
118		typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 )
119		typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 )
120		typeset -A myarray3=(
121			[a]=(
122				float m1=0.5
123				float m2=0.6
124				foo="hello"
125			)
126			[b]=(
127				foo="bar"
128			)
129			["c d"]=(
130				integer at=90
131			)
132			[e]=(
133				compound nested_cpv=(
134					typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 )
135					typeset str=$'a \'string'
136				)
137			)
138			[f]=(
139				typeset g="f"
140			)
141			[a_nan]=(
142				float my_nan=-nan
143			)
144			[a_hexfloat]=(
145			       typeset -X my_hexfloat=1.1
146			)
147		)
148	)
149
150	{
151		printf "%B\n" x
152		print "hello"
153	} | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | {
154		read -C y
155		read s
156	}
157	print "x${s}x"
158} || err_exit "test returned exit code $?"
159
160[[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}"
161count_brackets "$y" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
162count_brackets "$(print -v y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
163count_brackets "$(print -C y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
164
165# cleanup
166unset x y || err_exit "unset failed"
167[[ "$x" == "" ]] || err_exit "cleanup failed for x"
168[[ "$y" == "" ]] || err_exit "cleanup failed for y"
169
170
171# Test 2:
172# Same as test 1 except one more compound var following the "hello"
173# line.
174# Data layout is:
175# -- snip --
176# <compound var>
177# hello
178# <compound var>
179# -- snip --
180s=${
181	compound x=(
182		a=1 b=2
183		typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 )
184		typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 )
185		compound -A myarray3=(
186			[a]=(
187				float m1=0.5
188				float m2=0.6
189				foo="hello"
190			)
191			[b]=(
192				foo="bar"
193			)
194			["c d"]=(
195				integer at=90
196			)
197			[e]=(
198				compound nested_cpv=(
199					typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 )
200					typeset str=$'a \'string'
201				)
202			)
203			[f]=(
204				typeset g="f"
205			)
206			[a_nan]=(
207				float my_nan=-nan
208			)
209			[a_hexfloat]=(
210			       typeset -X my_hexfloat=1.1
211			)
212		)
213	)
214
215	{
216		printf "%B\n" x
217		print "hello"
218		printf "%B\n" x
219	} | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | {
220		read -C y1
221		read s
222		read -C y2
223	}
224
225	print "x${s}x"
226} || err_exit "test returned exit code $?"
227
228[[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}."
229[[ "${y1.myarray3[b].foo}" == "bar" ]] || err_exit "y1.myarray3[b].foo != bar"
230[[ "${y2.myarray3[b].foo}" == "bar" ]] || err_exit "y2.myarray3[b].foo != bar"
231[[ "$y1" != "" ]] || err_exit "y1 is empty"
232[[ "$y2" != "" ]] || err_exit "y2 is empty"
233(( ${#y1.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y1.myarray3[e].nested_cpv, got ${#y1.myarray3[e].nested_cpv[@]}"
234(( ${#y2.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y2.myarray3[e].nested_cpv, got ${#y2.myarray3[e].nested_cpv[@]}"
235(( isnan(y1.myarray3[a_nan].my_nan) ))   || err_exit "y1.myarray3[a_nan].my_nan not a NaN"
236(( isnan(y2.myarray3[a_nan].my_nan) ))   || err_exit "y2.myarray3[a_nan].my_nan not a NaN"
237(( signbit(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not negative"
238(( signbit(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not negative"
239count_brackets "$y1" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
240count_brackets "$(print -v y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
241count_brackets "$(print -C y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
242count_brackets "$y2" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
243count_brackets "$(print -v y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
244count_brackets "$(print -C y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
245[[ "$y1" == "$y2" ]] || err_exit "Expected $(printf "%q\n" "${y1}") == $(printf "%q\n" "${y2}")."
246[[ "$x"  == "$y1" ]] || err_exit "Expected $(printf "%q\n" "${x}") == $(printf "%q\n" "${y}")."
247
248# cleanup
249unset x y1 y2 || err_exit "unset failed"
250[[ "$x" == "" ]]  || err_exit "cleanup failed for x"
251[[ "$y1" == "" ]] || err_exit "cleanup failed for y1"
252[[ "$y2" == "" ]] || err_exit "cleanup failed for y2"
253
254
255# Test 3: Test compound variable copy operator vs. "read -C"
256compound x=(
257	a=1 b=2
258	typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 )
259	typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 )
260	compound -A myarray3=(
261		[a]=(
262			float m1=0.5
263			float m2=0.6
264			foo="hello"
265		)
266		[b]=(
267			foo="bar"
268		)
269		["c d"]=(
270			integer at=90
271		)
272		[e]=(
273			compound nested_cpv=(
274				typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 )
275				typeset str=$'a \'string'
276			)
277		)
278		[f]=(
279			typeset g="f"
280		)
281		[a_nan]=(
282			float my_nan=-nan
283		)
284		[a_hexfloat]=(
285		       typeset -X my_hexfloat=1.1
286		)
287	)
288)
289
290compound x_copy=x || err_exit "x_copy copy failed"
291[[ "${x_copy}" != "" ]] || err_exit "x_copy should not be empty"
292count_brackets "${x_copy}" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
293count_brackets "$(print -v x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
294count_brackets "$(print -C x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
295
296compound nested_cpv_copy
297
298nested_cpv_copy=x.myarray3[e].nested_cpv || err_exit "x.myarray3[e].nested_cpv copy failed"
299(( ${#nested_cpv_copy.myarray[@]} == 10 )) || err_exit "Expected 10 elements in nested_cpv_copy.myarray, got ${#nested_cpv_copy.myarray[@]}"
300
301# unset branch "x.myarray3[e].nested_cpv" of the variable tree "x" ...
302unset x.myarray3[e].nested_cpv || err_exit "unset x.myarray3[e].nested_cpv failed"
303[[ "${x.myarray3[e].nested_cpv}" == "" ]] || err_exit "x.myarray3[e].nested_cpv still has a value"
304
305# ... and restore it from the saved copy
306printf "%B\n" nested_cpv_copy | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | read -C x.myarray3[e].nested_cpv || err_exit "read failed"
307
308# compare copy of the original tree and the modified one
309[[ "${x}" == "${x_copy}" ]] || err_exit "x != x_copy"
310count_brackets "${x}" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
311count_brackets "$(print -v x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
312count_brackets "$(print -C x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}"
313(( ${#x.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in x.myarray3[e].nested_cpv, got ${#x.myarray3[e].nested_cpv[@]}"
314(( isnan(x.myarray3[a_nan].my_nan) ))   || err_exit "x.myarray3[a_nan].my_nan not a NaN"
315(( signbit(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not negative"
316
317# cleanup
318unset x x_copy nested_cpv_copy || err_exit "unset failed"
319
320
321# Test 4: Test "read -C" failure for missing bracket at the end
322typeset s
323s=$($SHELL -c 'compound myvar ; print "( unfinished=1" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed"
324[[ "$s" == "error 3" ]] || err_exit "compound_read: expected error 3, got ${s}"
325
326
327# Test 5: Test "read -C" failure for missing bracket at the beginning
328typeset s
329s=$($SHELL -c 'compound myvar ; print "  unfinished=1 )" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed"
330[[ "$s" == "error 3" ]] || err_exit "compound_read: expected error 3, got ${s}"
331
332
333# tests done
334exit $((Errors))
335