1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#          Copyright (c) 1982-2011 AT&T Intellectual Property          #
5#                      and is licensed under the                       #
6#                 Eclipse Public License, Version 1.0                  #
7#                    by AT&T Intellectual Property                     #
8#                                                                      #
9#                A copy of the License is available at                 #
10#          http://www.eclipse.org/org/documents/epl-v10.html           #
11#         (with md5 checksum b35adb5213ca9657e911e9befb180842)         #
12#                                                                      #
13#              Information and Software Systems Research               #
14#                            AT&T Research                             #
15#                           Florham Park NJ                            #
16#                                                                      #
17#                  David Korn <dgk@research.att.com>                   #
18#                                                                      #
19########################################################################
20#
21# Written by Roland Mainz <roland.mainz@nrubsig.org>
22#
23
24function err_exit
25{
26	print -u2 -n "\t"
27	print -u2 -r ${Command}[$1]: "${@:2}"
28	(( Errors < 127 && Errors++ ))
29}
30
31alias err_exit='err_exit $LINENO'
32
33set -o nounset
34Command=${0##*/}
35integer Errors=0
36
37
38
39typeset -T test_t=(
40	typeset name
41	typeset cmd
42	typeset expected_output
43)
44
45function testfunc
46{
47	integer line_number=$1
48	typeset cmd="$2"
49	typeset expected_output="$3"
50	typeset output
51
52	output="$($SHELL -c "${cmd}" 2>&1 )"
53
54	[[ "${output}" == "${expected_output}" ]] || err_exit ${line_number} "${output} != ${expected_output}"
55}
56
57# test1: basic tests
58function test1
59{
60	# string
61	testfunc ${LINENO} '(function l { typeset -S x ;     x+="#" ; $1 && print "$x" ; } ; l false ; l false   ; l true)'  "###"
62	testfunc ${LINENO} 'function  l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; l false   ; l true'   ">###"
63	testfunc ${LINENO} 'function  l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; (l false) ; l true'   ">##"
64	testfunc ${LINENO} 'function  l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false; ( ulimit -c 0 ; l false) ; l true' ">##"
65
66	# integer
67	# (normal)
68	testfunc ${LINENO} '(function l { integer -S x ;        x+=1 ;   $1 && print "$x" ; } ; l false ; l false   ; l true )' "3"
69	testfunc ${LINENO} '(function l { integer -S x ;        x+=1 ;   $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2"
70	# (int)
71	testfunc ${LINENO} '(function l { typeset -S -i x ;     x+=1 ;   $1 && print "$x" ; } ; l false ; l false   ; l true )' "3"
72	testfunc ${LINENO} '(function l { typeset -S -i x ;     x+=1 ;   $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2"
73	# (short)
74	testfunc ${LINENO} '(function l { typeset -S -s -i x ;  x+=1 ;   $1 && print "$x" ; } ; l false ; l false   ; l true )' "3"
75	testfunc ${LINENO} '(function l { typeset -S -s -i x ;  x+=1 ;   $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2"
76
77	# float
78	testfunc ${LINENO} '(function l { float -S x=0.5 ;  (( x+=.5 )) ;   $1 && print "$x" ; } ; l false ; l false   ; l true )' "2"
79	testfunc ${LINENO} '(function l { float -S x=0.5 ;  (( x+=.5 )) ;   $1 && print "$x" ; } ; l false ; (l false) ; l true )' "1.5"
80
81	return 0
82}
83
84# test2: test the more complex datatypes
85function test2
86{
87        compound out=( typeset stdout stderr ; integer res )
88	integer i
89
90	test_t -r -a tests=(
91		(
92			name='compound'
93			cmd=$'
94				function l
95				{
96					compound -S s=(
97						integer a=1
98						integer b=2
99					)
100
101					(( s.a++, s.b++ ))
102
103					$1 && printf "a=%d, b=%d\n" s.a s.b
104				}
105				(l false ; l false ; l true ; printf ";")
106				(l false ; l false ; l true ; printf ";")
107			'
108			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
109		)
110		(
111			name='compound_nameref'
112			cmd=$'
113				function l_n
114				{
115					nameref sn=$2
116					(( sn.a++, sn.b++ ))
117
118					$1 && printf "a=%d, b=%d\n" sn.a sn.b
119				}
120				function l
121				{
122					compound -S s=( a=1 b=2 )
123					l_n $1 s
124				}
125				(l false ; l false ; l true ; printf ";")
126				(l false ; l false ; l true ; printf ";")
127			'
128			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
129		)
130
131		(
132			name='type'
133			cmd=$'
134				typeset -T ab_t=(
135					integer a=1
136					integer b=2
137
138					function increment
139					{
140						(( _.a++, _.b++ ))
141					}
142				)
143				function l
144				{
145					ab_t -S s
146
147					s.increment
148
149					$1 && printf "a=%d, b=%d\n" s.a s.b
150				}
151				(l false ; l false ; l true ; printf ";")
152				(l false ; l false ; l true ; printf ";")
153			'
154			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
155		)
156
157		(
158			name='type_nameref'
159			cmd=$'
160				typeset -T ab_t=(
161					integer a=1
162					integer b=2
163
164					function increment
165					{
166						(( _.a++, _.b++ ))
167					}
168				)
169				function l_n
170				{
171					nameref sn=$2
172
173					sn.increment
174
175					$1 && printf "a=%d, b=%d\n" sn.a sn.b
176				}
177				function l
178				{
179					ab_t -S s
180					l_n $1 s
181				}
182				(l false ; l false ; l true ; printf ";")
183				(l false ; l false ; l true ; printf ";")
184			'
185			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
186		)
187
188		(
189			name='indexed_string_array_appendelement'
190			cmd=$'
191				function ar
192				{
193					typeset -a -S s=( "hello" )
194
195					s+=( "an element" )
196
197					$1 && { printf "%s" "${s[@]}" ; printf "\n" ; }
198				}
199				(ar false ; ar false ; ar true ; printf ";")
200				(ar false ; ar false ; ar true ; printf ";")
201			'
202			expected_output=$'helloan elementan elementan element\n;helloan elementan elementan element\n;'
203		)
204
205		(
206			name='indexed_string_array_nameref_appendelement'
207			cmd=$'
208				function ar_n
209				{
210					nameref sn=$2
211					sn+=( "an element" )
212
213					$1 && { printf "%s" "${sn[@]}" ; printf "\n" ; }
214				}
215				function ar
216				{
217					typeset -a -S s=( "hello" )
218					ar_n $1 s
219				}
220				(ar false ; ar false ; ar true ; printf ";")
221				(ar false ; ar false ; ar true ; printf ";")
222			'
223			expected_output=$'helloan elementan elementan element\n;helloan elementan elementan element\n;'
224		)
225
226		(
227			name='associative_string_array_appendelement'
228			cmd=$'
229				function ar
230				{
231					typeset -A -S s=( [0]="hello" )
232
233					s[$(( ${#s[@]} + 1))]="an element"
234
235					$1 && { printf "%s" "${s[@]}" ; printf "\n" ; }
236				}
237				(ar false ; ar false ; ar true ; printf ";")
238				(ar false ; ar false ; ar true ; printf ";")
239			'
240			expected_output=$'helloan elementan elementan element\n;helloan elementan elementan element\n;'
241		)
242
243		(
244			name='associative_string_array_nameref_appendelement'
245			cmd=$'
246				function ar_n
247				{
248					nameref sn=$2
249
250					sn[$(( ${#sn[@]} + 1))]="an element"
251
252					$1 && { printf "%s" "${sn[@]}" ; printf "\n" ; }
253				}
254				function ar
255				{
256					typeset -A -S s=( [0]="hello" )
257					ar_n $1 s
258				}
259				(ar false ; ar false ; ar true ; printf ";")
260				(ar false ; ar false ; ar true ; printf ";")
261			'
262			expected_output=$'helloan elementan elementan element\n;helloan elementan elementan element\n;'
263		)
264
265		(
266			name='indexed_compound_array_editelement'
267			cmd=$'
268				function ar
269				{
270					compound -S -a s=(
271						[5]=(
272							integer a=1
273							integer b=2
274						)
275					)
276
277					(( s[5].a++, s[5].b++ ))
278					$1 && printf "a=%d, b=%d\n" s[5].a s[5].b
279				}
280				(ar false ; ar false ; ar true ; printf ";")
281				(ar false ; ar false ; ar true ; printf ";")
282			'
283			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
284		)
285
286		(
287			name='indexed_compound_array_nameref_editelement'
288			cmd=$'
289				function ar_n
290				{
291					nameref sn=$2
292
293					(( sn.a++, sn.b++ ))
294					$1 && printf "a=%d, b=%d\n" sn.a sn.b
295				}
296				function ar
297				{
298					compound -S -a s=(
299						[5]=(
300							integer a=1
301							integer b=2
302						)
303					)
304
305					ar_n $1 s[5]
306				}
307				(ar false ; ar false ; ar true ; printf ";")
308				(ar false ; ar false ; ar true ; printf ";")
309			'
310			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
311		)
312
313		(
314			name='2d_indexed_compound_array_editelement'
315			cmd=$'
316				function ar
317				{
318					compound -S -a s=(
319						[8][5]=(
320							integer a=1
321							integer b=2
322						)
323					)
324
325					(( s[8][5].a++, s[8][5].b++ ))
326					$1 && printf "a=%d, b=%d\n" s[8][5].a s[8][5].b
327				}
328				(ar false ; ar false ; ar true ; printf ";")
329				(ar false ; ar false ; ar true ; printf ";")
330			'
331			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
332		)
333
334		(
335			name='2d_indexed_compound_array_nameref_editelement'
336			cmd=$'
337				function ar_n
338				{
339					nameref sn=$2
340
341					(( sn.a++, sn.b++ ))
342					$1 && printf "a=%d, b=%d\n" sn.a sn.b
343				}
344				function ar
345				{
346					compound -S -a s=(
347						[8][5]=(
348							integer a=1
349							integer b=2
350						)
351					)
352
353					ar_n $1 s[8][5]
354				}
355				(ar false ; ar false ; ar true ; printf ";")
356				(ar false ; ar false ; ar true ; printf ";")
357			'
358			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
359		)
360		(
361			name='4d_indexed_compound_array_editelement'
362			cmd=$'
363				function ar
364				{
365					compound -S -a s=(
366						[8][5][0][9]=(
367							integer a=1
368							integer b=2
369						)
370					)
371
372					(( s[8][5][0][9].a++, s[8][5][0][9].b++ ))
373					$1 && printf "a=%d, b=%d\n" s[8][5][0][9].a s[8][5][0][9].b
374				}
375				(ar false ; ar false ; ar true ; printf ";")
376				(ar false ; ar false ; ar true ; printf ";")
377			'
378			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
379		)
380
381		(
382			name='4d_indexed_compound_array_nameref_editelement'
383			cmd=$'
384				function ar_n
385				{
386					nameref sn=$2
387
388					(( sn.a++, sn.b++ ))
389					$1 && printf "a=%d, b=%d\n" sn.a sn.b
390				}
391				function ar
392				{
393					compound -S -a s=(
394						[8][5][0][9]=(
395							integer a=1
396							integer b=2
397						)
398					)
399
400					ar_n $1 s[8][5][0][9]
401				}
402				(ar false ; ar false ; ar true ; printf ";")
403				(ar false ; ar false ; ar true ; printf ";")
404			'
405			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
406		)
407
408		(
409			name='associative_compound_array_editelement'
410			cmd=$'
411				function ar
412				{
413					compound -S -A s=(
414						[5]=(
415							integer a=1
416							integer b=2
417						)
418					)
419
420					(( s[5].a++, s[5].b++ ))
421					$1 && printf "a=%d, b=%d\n" s[5].a s[5].b
422				}
423				(ar false ; ar false ; ar true ; printf ";")
424				(ar false ; ar false ; ar true ; printf ";")
425			'
426			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
427		)
428
429		(
430			name='associative_compound_array_nameref_editelement'
431			cmd=$'
432				function ar_n
433				{
434					nameref sn=$2
435
436					(( sn.a++, sn.b++ ))
437					$1 && printf "a=%d, b=%d\n" sn.a sn.b
438				}
439				function ar
440				{
441					compound -S -A s=(
442						[5]=(
443							integer a=1
444							integer b=2
445						)
446					)
447
448					ar_n $1 s[5]
449				}
450				(ar false ; ar false ; ar true ; printf ";")
451				(ar false ; ar false ; ar true ; printf ";")
452			'
453			expected_output=$'a=4, b=5\n;a=4, b=5\n;'
454		)
455
456			(
457				name='indexed_type_array_editelement'
458				cmd=$'
459					typeset -T ab_t=(
460						integer a=1
461						integer b=2
462
463						function increment
464						{
465							(( _.a++, _.b++ ))
466						}
467					)
468
469					function ar
470					{
471						ab_t -S -a s
472						[[ -v s[5] ]] || s[5]=( ) # how do I init an array of types ?
473
474						s[5].increment
475						$1 && printf "a=%d, b=%d\n" s[5].a s[5].b
476					}
477					(ar false ; ar false ; ar true ; printf ";")
478					(ar false ; ar false ; ar true ; printf ";")
479				'
480				expected_output=$'a=4, b=5\n;a=4, b=5\n;'
481			)
482
483			(
484				name='indexed_type_array_nameref_editelement'
485				cmd=$'
486					typeset -T ab_t=(
487						integer a=1
488						integer b=2
489
490						function increment
491						{
492							(( _.a++, _.b++ ))
493						}
494					)
495
496					function ar_n
497					{
498						nameref sn=$2
499
500						sn.increment
501						$1 && printf "a=%d, b=%d\n" sn.a sn.b
502					}
503					function ar
504					{
505						ab_t -S -a s
506						[[ -v s[5] ]] || s[5]=( ) # how do I init an array of types ?
507
508						ar_n $1 s[5]
509					}
510					(ar false ; ar false ; ar true ; printf ";")
511					(ar false ; ar false ; ar true ; printf ";")
512				'
513				expected_output=$'a=4, b=5\n;a=4, b=5\n;'
514			)
515
516			(
517				name='2d_indexed_type_array_editelement'
518				cmd=$'
519					typeset -T ab_t=(
520						integer a=1
521						integer b=2
522
523						function increment
524						{
525							(( _.a++, _.b++ ))
526						}
527					)
528
529					function ar
530					{
531						ab_t -S -a s
532						[[ -v s[9][5] ]] || s[9][5]=( ) # how do I init an array of types ?
533
534						s[9][5].increment
535						$1 && printf "a=%d, b=%d\n" s[9][5].a s[9][5].b
536					}
537					(ar false ; ar false ; ar true ; printf ";")
538					(ar false ; ar false ; ar true ; printf ";")
539				'
540				expected_output=$'a=4, b=5\n;a=4, b=5\n;'
541			)
542
543			(
544				name='2d_indexed_type_array_nameref_editelement'
545				cmd=$'
546					typeset -T ab_t=(
547						integer a=1
548						integer b=2
549
550						function increment
551						{
552							(( _.a++, _.b++ ))
553						}
554					)
555
556					function ar_n
557					{
558						nameref sn=$2
559
560						sn.increment
561						$1 && printf "a=%d, b=%d\n" sn.a sn.b
562					}
563					function ar
564					{
565						ab_t -S -a s
566						[[ -v s[9][5] ]] || s[9][5]=( ) # how do I init an array of types ?
567
568						ar_n $1 s[9][5]
569					}
570					(ar false ; ar false ; ar true ; printf ";")
571					(ar false ; ar false ; ar true ; printf ";")
572				'
573				expected_output=$'a=4, b=5\n;a=4, b=5\n;'
574			)
575
576			(
577				name='associative_type_array_editelement'
578				cmd=$'
579					typeset -T ab_t=(
580						integer a=1
581						integer b=2
582
583						function increment
584						{
585							(( _.a++, _.b++ ))
586						}
587					)
588
589					function ar
590					{
591						ab_t -S -A s
592						[[ -v s[5] ]] || s[5]=( ) # how do I init an array of types ?
593
594						s[5].increment
595						$1 && printf "a=%d, b=%d\n" s[5].a s[5].b
596					}
597					(ar false ; ar false ; ar true ; printf ";")
598					(ar false ; ar false ; ar true ; printf ";")
599				'
600				expected_output=$'a=4, b=5\n;a=4, b=5\n;'
601			)
602
603			(
604				name='associative_type_array_nameref_editelement'
605				cmd=$'
606					typeset -T ab_t=(
607						integer a=1
608						integer b=2
609
610						function increment
611						{
612							(( _.a++, _.b++ ))
613						}
614					)
615
616					function ar_n
617					{
618						nameref sn=$2
619
620						sn.increment
621						$1 && printf "a=%d, b=%d\n" sn.a sn.b
622					}
623					function ar
624					{
625						ab_t -S -A s
626						[[ -v s[5] ]] || s[5]=( ) # how do I init an array of types ?
627
628						ar_n $1 s[5]
629					}
630					(ar false ; ar false ; ar true ; printf ";")
631					(ar false ; ar false ; ar true ; printf ";")
632				'
633				expected_output=$'a=4, b=5\n;a=4, b=5\n;'
634			)
635
636	)
637
638	for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do
639		nameref currtest=tests[i]
640
641#print -u2 -- "${currtest.cmd}"
642		out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${currtest.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
643
644		(( out.res == 0 )) || err_exit "${currtest.name}: Test shell returned with exit code ${out.res}"
645		[[ "${out.stdout}" == "${currtest.expected_output}" ]] || err_exit "${currtest.name}: Expected stdout == $(printf "%q\n" "${currtest.expected_output}"), got $(printf "%q\n" "${out.stdout}")"
646		[[ "${out.stderr}" == '' ]] || err_exit "${currtest.name}: Expected empty stderr, got $(printf "%q\n" "${out.stderr}")"
647   	done
648
649	return 0
650}
651
652# run tests
653test1
654test2
655
656
657# Test visibilty of "global" vs. "static" variables. if we have a "static" variable in a
658# function and "unset" it we should see a global variable with the same
659# name, right ?
660integer hx=5
661function test_hx_scope
662{
663	integer -S hx=9
664	$2 && unset hx
665	$1 && printf 'hx=%d\n' hx
666}
667test_hx_scope false false
668test_hx_scope false false
669# first test the "unset" call in a $(...) subshell...
670[[ "$( test_hx_scope true true   )" == 'hx=5' ]] || err_exit "can't see global variable hx after unsetting static variable hx"
671# ... end then test whether the value has changed.
672[[ "${ test_hx_scope true false ;}" == 'hx=9' ]] || err_exit "hx variable somehow changed"
673
674out=$(function fun2
675{
676        nameref sn=$1
677        (( sn.a++, sn.b++ ))
678        $2 && printf "a=%d, b=%d\n" sn.a sn.b
679}
680function fun1
681{
682        compound -S s=( a=0 b=0 )
683        fun2 s $1
684}
685(fun1 false ; fun1 false ; fun1 true)
686(fun1 false ; fun1 false ; fun1 true)
687)
688[[ $out == $'a=3, b=3\na=3, b=3' ]] || err_exit 'static variables in functions with initializers not working'
689
690exit $((Errors<125?Errors:125))
691