xref: /titanic_51/usr/src/lib/libshell/common/tests/variables.sh (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin########################################################################
2da2e3ebdSchin#                                                                      #
3da2e3ebdSchin#               This software is part of the ast package               #
4*3e14f97fSRoger A. Faulkner#          Copyright (c) 1982-2010 AT&T Intellectual Property          #
5da2e3ebdSchin#                      and is licensed under the                       #
6da2e3ebdSchin#                  Common Public License, Version 1.0                  #
77c2fbfb3SApril Chin#                    by AT&T Intellectual Property                     #
8da2e3ebdSchin#                                                                      #
9da2e3ebdSchin#                A copy of the License is available at                 #
10da2e3ebdSchin#            http://www.opensource.org/licenses/cpl1.0.txt             #
11da2e3ebdSchin#         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         #
12da2e3ebdSchin#                                                                      #
13da2e3ebdSchin#              Information and Software Systems Research               #
14da2e3ebdSchin#                            AT&T Research                             #
15da2e3ebdSchin#                           Florham Park NJ                            #
16da2e3ebdSchin#                                                                      #
17da2e3ebdSchin#                  David Korn <dgk@research.att.com>                   #
18da2e3ebdSchin#                                                                      #
19da2e3ebdSchin########################################################################
20da2e3ebdSchinfunction err_exit
21da2e3ebdSchin{
22da2e3ebdSchin	print -u2 -n "\t"
23da2e3ebdSchin	print -u2 -r ${Command}[$1]: "${@:2}"
24da2e3ebdSchin	let Errors+=1
25da2e3ebdSchin}
26da2e3ebdSchinalias err_exit='err_exit $LINENO'
27da2e3ebdSchin
28da2e3ebdSchinCommand=${0##*/}
29da2e3ebdSchininteger Errors=0
307c2fbfb3SApril Chin
3134f9b3eeSRoland Mainztmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
3234f9b3eeSRoland Mainztrap "cd /; rm -rf $tmp" EXIT
3334f9b3eeSRoland Mainz
347c2fbfb3SApril Chin[[ ${.sh.version} == "$KSH_VERSION" ]] || err_exit '.sh.version != KSH_VERSION'
357c2fbfb3SApril Chinunset ss
367c2fbfb3SApril Chin[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset'
377c2fbfb3SApril Chin[[ ${!ss} == ss ]] ||  err_exit '${!ss} should be ss when ss is unset'
387c2fbfb3SApril Chin[[ ${#ss} == 0 ]] ||  err_exit '${#ss} should be 0 when ss is unset'
39da2e3ebdSchin# RANDOM
40da2e3ebdSchinif	(( RANDOM==RANDOM || $RANDOM==$RANDOM ))
41da2e3ebdSchinthen	err_exit RANDOM variable not working
42da2e3ebdSchinfi
43da2e3ebdSchin# SECONDS
44da2e3ebdSchinsleep 3
45da2e3ebdSchinif	(( SECONDS < 2 ))
46da2e3ebdSchinthen	err_exit SECONDS variable not working
47da2e3ebdSchinfi
48da2e3ebdSchin# _
49da2e3ebdSchinset abc def
50da2e3ebdSchinif	[[ $_ != def ]]
51da2e3ebdSchinthen	err_exit _ variable not working
52da2e3ebdSchinfi
53da2e3ebdSchin# ERRNO
54da2e3ebdSchin#set abc def
55da2e3ebdSchin#rm -f foobar#
56da2e3ebdSchin#ERRNO=
57da2e3ebdSchin#2> /dev/null < foobar#
58da2e3ebdSchin#if	(( ERRNO == 0 ))
59da2e3ebdSchin#then	err_exit ERRNO variable not working
60da2e3ebdSchin#fi
61da2e3ebdSchin# PWD
62da2e3ebdSchinif	[[ !  $PWD -ef . ]]
6334f9b3eeSRoland Mainzthen	err_exit PWD variable failed, not equivalent to .
64da2e3ebdSchinfi
65da2e3ebdSchin# PPID
6634f9b3eeSRoland Mainzexp=$$
6734f9b3eeSRoland Mainzgot=${ $SHELL -c 'print $PPID'; }
6834f9b3eeSRoland Mainzif	[[ ${ $SHELL -c 'print $PPID'; } != $$ ]]
6934f9b3eeSRoland Mainzthen	err_exit "PPID variable failed -- expected '$exp', got '$got'"
70da2e3ebdSchinfi
71da2e3ebdSchin# OLDPWD
72da2e3ebdSchinold=$PWD
73da2e3ebdSchincd /
74da2e3ebdSchinif	[[ $OLDPWD != $old ]]
7534f9b3eeSRoland Mainzthen	err_exit "OLDPWD variable failed -- expected '$old', got '$OLDPWD'"
76da2e3ebdSchinfi
77da2e3ebdSchincd $old || err_exit cd failed
78da2e3ebdSchin# REPLY
79da2e3ebdSchinread <<-!
80da2e3ebdSchin	foobar
81da2e3ebdSchin	!
82da2e3ebdSchinif	[[ $REPLY != foobar ]]
83da2e3ebdSchinthen	err_exit REPLY variable not working
84da2e3ebdSchinfi
85da2e3ebdSchininteger save=$LINENO
86da2e3ebdSchin# LINENO
87da2e3ebdSchinLINENO=10
88da2e3ebdSchin#
89da2e3ebdSchin#  These lines intentionally left blank
90da2e3ebdSchin#
91da2e3ebdSchinif	(( LINENO != 13))
92da2e3ebdSchinthen	err_exit LINENO variable not working
93da2e3ebdSchinfi
94da2e3ebdSchinLINENO=save+10
95da2e3ebdSchinIFS=:
96da2e3ebdSchinx=a::b::c
97da2e3ebdSchinif	[[ $x != a::b::c ]]
9834f9b3eeSRoland Mainzthen	err_exit "word splitting on constants"
99da2e3ebdSchinfi
100da2e3ebdSchinset -- $x
101da2e3ebdSchinif	[[ $# != 5 ]]
102da2e3ebdSchinthen	err_exit ":: doesn't separate null arguments "
103da2e3ebdSchinfi
104da2e3ebdSchinset x
105da2e3ebdSchinif	x$1=0 2> /dev/null
106da2e3ebdSchinthen	err_exit "x\$1=value treated as an assignment"
107da2e3ebdSchinfi
108da2e3ebdSchin# check for attributes across subshells
109da2e3ebdSchintypeset -i x=3
110da2e3ebdSchiny=1/0
111da2e3ebdSchinif	( typeset x=y ) 2> /dev/null
1127c2fbfb3SApril Chinthen	err_exit "attributes not passed to subshells"
113da2e3ebdSchinfi
114da2e3ebdSchinunset x
115da2e3ebdSchinfunction x.set
116da2e3ebdSchin{
117da2e3ebdSchin	nameref foo=${.sh.name}.save
118da2e3ebdSchin	foo=${.sh.value}
119da2e3ebdSchin	.sh.value=$0
120da2e3ebdSchin}
121da2e3ebdSchinx=bar
122da2e3ebdSchinif	[[ $x != x.set ]]
123da2e3ebdSchinthen	err_exit 'x.set does not override assignment'
124da2e3ebdSchinfi
125da2e3ebdSchinx.get()
126da2e3ebdSchin{
127da2e3ebdSchin	nameref foo=${.sh.name}.save
128da2e3ebdSchin	.sh.value=$foo
129da2e3ebdSchin}
130da2e3ebdSchin
131da2e3ebdSchinif	[[ $x != bar ]]
132da2e3ebdSchinthen	err_exit 'x.get does not work correctly'
133da2e3ebdSchinfi
134da2e3ebdSchintypeset +n foo
135da2e3ebdSchinunset foo
136da2e3ebdSchinfoo=bar
137da2e3ebdSchin(
138da2e3ebdSchin	unset foo
139da2e3ebdSchin	set +u
140da2e3ebdSchin	if	[[ $foo != '' ]]
141da2e3ebdSchin	then	err_exit '$foo not null after unset in subsehll'
142da2e3ebdSchin	fi
143da2e3ebdSchin)
144da2e3ebdSchinif	[[ $foo != bar ]]
145da2e3ebdSchinthen	err_exit 'unset foo in subshell produces side effect '
146da2e3ebdSchinfi
147da2e3ebdSchinunset foo
148da2e3ebdSchinif	[[ $( { : ${foo?hi there} ; } 2>&1) != *'hi there' ]]
149da2e3ebdSchinthen	err_exit '${foo?hi there} with foo unset does not print hi there on 2'
150da2e3ebdSchinfi
151da2e3ebdSchinx=$0
152da2e3ebdSchinset foobar
153da2e3ebdSchinif	[[ ${@:0} != "$x foobar" ]]
154da2e3ebdSchinthen	err_exit '${@:0} not expanding correctly'
155da2e3ebdSchinfi
156da2e3ebdSchinset --
157da2e3ebdSchinif	[[ ${*:0:1} != "$0" ]]
158da2e3ebdSchinthen	err_exit '${@:0} not expanding correctly'
159da2e3ebdSchinfi
160da2e3ebdSchinACCESS=0
161da2e3ebdSchinfunction COUNT.set
162da2e3ebdSchin{
163da2e3ebdSchin        (( ACCESS++ ))
164da2e3ebdSchin}
165da2e3ebdSchinCOUNT=0
166da2e3ebdSchin(( COUNT++ ))
167da2e3ebdSchinif	(( COUNT != 1 || ACCESS!=2 ))
168da2e3ebdSchinthen	err_exit " set discipline failure COUNT=$COUNT ACCESS=$ACCESS"
169da2e3ebdSchinfi
170da2e3ebdSchinLANG=C > /dev/null 2>&1
171da2e3ebdSchinif	[[ $LANG != C ]]
172da2e3ebdSchinthen	err_exit "C locale not working"
173da2e3ebdSchinfi
174da2e3ebdSchinunset RANDOM
175da2e3ebdSchinunset -n foo
176da2e3ebdSchinfoo=junk
177da2e3ebdSchinfunction foo.get
178da2e3ebdSchin{
179da2e3ebdSchin	.sh.value=stuff
180da2e3ebdSchin	unset -f foo.get
181da2e3ebdSchin}
182da2e3ebdSchinif	[[ $foo != stuff ]]
183da2e3ebdSchinthen	err_exit "foo.get discipline not working"
184da2e3ebdSchinfi
185da2e3ebdSchinif	[[ $foo != junk ]]
186da2e3ebdSchinthen	err_exit "foo.get discipline not working after unset"
187da2e3ebdSchinfi
188da2e3ebdSchin# special variables
189da2e3ebdSchinset -- 1 2 3 4 5 6 7 8 9 10
190da2e3ebdSchinsleep 1000 &
191da2e3ebdSchinif	[[ $(print -r -- ${#10}) != 2 ]]
192da2e3ebdSchinthen	err_exit '${#10}, where ${10}=10 not working'
193da2e3ebdSchinfi
194da2e3ebdSchinfor i in @ '*' ! '#' - '?' '$'
195da2e3ebdSchindo	false
196da2e3ebdSchin	eval foo='$'$i bar='$'{$i}
197da2e3ebdSchin	if	[[ ${foo} != "${bar}" ]]
198da2e3ebdSchin	then	err_exit "\$$i not equal to \${$i}"
199da2e3ebdSchin	fi
200da2e3ebdSchin	command eval bar='$'{$i%?} 2> /dev/null || err_exit "\${$i%?} gives syntax error"
201da2e3ebdSchin	if	[[ $i != [@*] && ${foo%?} != "$bar"  ]]
202da2e3ebdSchin	then	err_exit "\${$i%?} not correct"
203da2e3ebdSchin	fi
204da2e3ebdSchin	command eval bar='$'{$i#?} 2> /dev/null || err_exit "\${$i#?} gives syntax error"
205da2e3ebdSchin	if	[[ $i != [@*] && ${foo#?} != "$bar"  ]]
206da2e3ebdSchin	then	err_exit "\${$i#?} not correct"
207da2e3ebdSchin	fi
208da2e3ebdSchin	command eval foo='$'{$i} bar='$'{#$i} || err_exit "\${#$i} gives synta
209da2e3ebdSchinx error"
210da2e3ebdSchin	if	[[ $i != @([@*]) && ${#foo} != "$bar" ]]
211da2e3ebdSchin	then	err_exit "\${#$i} not correct"
212da2e3ebdSchin	fi
213da2e3ebdSchindone
214da2e3ebdSchinkill $!
215da2e3ebdSchinunset x
216da2e3ebdSchinCDPATH=/
21734f9b3eeSRoland Mainzx=$(cd ${tmp#/})
21834f9b3eeSRoland Mainzif	[[ $x != $tmp ]]
219da2e3ebdSchinthen	err_exit 'CDPATH does not display new directory'
220da2e3ebdSchinfi
221da2e3ebdSchinCDPATH=/:
22234f9b3eeSRoland Mainzx=$(cd ${tmp%/*}; cd ${tmp##*/})
223da2e3ebdSchinif	[[ $x ]]
224da2e3ebdSchinthen	err_exit 'CDPATH displays new directory when not used'
225da2e3ebdSchinfi
22634f9b3eeSRoland Mainzx=$(cd ${tmp#/})
22734f9b3eeSRoland Mainzif	[[ $x != $tmp ]]
22834f9b3eeSRoland Mainzthen	err_exit "CDPATH ${tmp#/} does not display new directory"
229da2e3ebdSchinfi
230da2e3ebdSchinTMOUT=100
231da2e3ebdSchin(TMOUT=20)
232da2e3ebdSchinif	(( TMOUT !=100 ))
233da2e3ebdSchinthen	err_exit 'setting TMOUT in subshell affects parent'
234da2e3ebdSchinfi
235da2e3ebdSchinunset y
236da2e3ebdSchinfunction setdisc # var
237da2e3ebdSchin{
238da2e3ebdSchin        eval function $1.get'
239da2e3ebdSchin        {
240da2e3ebdSchin                .sh.value=good
241da2e3ebdSchin        }
242da2e3ebdSchin        '
243da2e3ebdSchin}
244da2e3ebdSchiny=bad
245da2e3ebdSchinsetdisc y
246da2e3ebdSchinif	[[ $y != good ]]
247da2e3ebdSchinthen	err_exit 'setdisc function not working'
248da2e3ebdSchinfi
249da2e3ebdSchininteger x=$LINENO
250da2e3ebdSchin: $'\
251da2e3ebdSchin'
252da2e3ebdSchinif	(( LINENO != x+3  ))
253da2e3ebdSchinthen	err_exit '\<newline> gets linenumber count wrong'
254da2e3ebdSchinfi
255da2e3ebdSchinset --
256da2e3ebdSchinset -- "${@-}"
257da2e3ebdSchinif	(( $# !=1 ))
258da2e3ebdSchinthen	err_exit	'"${@-}" not expanding to null string'
259da2e3ebdSchinfi
2607c2fbfb3SApril Chinfor i in : % + / 3b '**' '***' '@@' '{' '[' '}' !!  '*a' '$foo'
261da2e3ebdSchindo      (eval : \${"$i"} 2> /dev/null) && err_exit "\${$i} not an syntax error"
262da2e3ebdSchindone
263da2e3ebdSchinunset IFS
264da2e3ebdSchin( IFS='  ' ; read -r a b c <<-!
265da2e3ebdSchin	x  y z
266da2e3ebdSchin	!
267da2e3ebdSchin	if	[[ $b ]]
268da2e3ebdSchin	then	err_exit 'IFS="  " not causing adjacent space to be null string'
269da2e3ebdSchin	fi
270da2e3ebdSchin)
271da2e3ebdSchinread -r a b c <<-!
272da2e3ebdSchinx  y z
273da2e3ebdSchin!
274da2e3ebdSchinif	[[ $b != y ]]
275da2e3ebdSchinthen	err_exit 'IFS not restored after subshell'
276da2e3ebdSchinfi
277da2e3ebdSchin
278da2e3ebdSchin# The next part generates 3428 IFS set/read tests.
279da2e3ebdSchin
280da2e3ebdSchinunset IFS x
281da2e3ebdSchinfunction split
282da2e3ebdSchin{
283da2e3ebdSchin	i=$1 s=$2 r=$3
284da2e3ebdSchin	IFS=': '
285da2e3ebdSchin	set -- $i
286da2e3ebdSchin	IFS=' '
287da2e3ebdSchin	g="[$#]"
288da2e3ebdSchin	while	:
289da2e3ebdSchin	do	case $# in
290da2e3ebdSchin		0)	break ;;
291da2e3ebdSchin		esac
292da2e3ebdSchin		g="$g($1)"
293da2e3ebdSchin		shift
294da2e3ebdSchin	done
295da2e3ebdSchin	case "$g" in
296da2e3ebdSchin	"$s")	;;
297da2e3ebdSchin	*)	err_exit "IFS=': '; set -- '$i'; expected '$s' got '$g'" ;;
298da2e3ebdSchin	esac
299da2e3ebdSchin	print "$i" | IFS=": " read arg rem; g="($arg)($rem)"
300da2e3ebdSchin	case "$g" in
301da2e3ebdSchin	"$r")	;;
302da2e3ebdSchin	*)	err_exit "IFS=': '; read '$i'; expected '$r' got '$g'" ;;
303da2e3ebdSchin	esac
304da2e3ebdSchin}
305da2e3ebdSchinfor str in 	\
306da2e3ebdSchin	'-'	\
307da2e3ebdSchin	'a'	\
308da2e3ebdSchin	'- -'	\
309da2e3ebdSchin	'- a'	\
310da2e3ebdSchin	'a -'	\
311da2e3ebdSchin	'a b'	\
312da2e3ebdSchin	'- - -'	\
313da2e3ebdSchin	'- - a'	\
314da2e3ebdSchin	'- a -'	\
315da2e3ebdSchin	'- a b'	\
316da2e3ebdSchin	'a - -'	\
317da2e3ebdSchin	'a - b'	\
318da2e3ebdSchin	'a b -'	\
319da2e3ebdSchin	'a b c'
320da2e3ebdSchindo
321da2e3ebdSchin	IFS=' '
322da2e3ebdSchin	set x $str
323da2e3ebdSchin	shift
324da2e3ebdSchin	case $# in
325da2e3ebdSchin	0)	continue ;;
326da2e3ebdSchin	esac
327da2e3ebdSchin	f1=$1
328da2e3ebdSchin	case $f1 in
329da2e3ebdSchin	'-')	f1='' ;;
330da2e3ebdSchin	esac
331da2e3ebdSchin	shift
332da2e3ebdSchin	case $# in
333da2e3ebdSchin	0)	for d0 in '' ' '
334da2e3ebdSchin		do
335da2e3ebdSchin			for d1 in '' ' ' ':' ' :' ': ' ' : '
336da2e3ebdSchin			do
337da2e3ebdSchin				case $f1$d1 in
338da2e3ebdSchin				'')	split "$d0$f1$d1" "[0]" "()()" ;;
339da2e3ebdSchin				' ')	;;
340da2e3ebdSchin				*)	split "$d0$f1$d1" "[1]($f1)" "($f1)()" ;;
341da2e3ebdSchin				esac
342da2e3ebdSchin			done
343da2e3ebdSchin		done
344da2e3ebdSchin		continue
345da2e3ebdSchin		;;
346da2e3ebdSchin	esac
347da2e3ebdSchin	f2=$1
348da2e3ebdSchin	case $f2 in
349da2e3ebdSchin	'-')	f2='' ;;
350da2e3ebdSchin	esac
351da2e3ebdSchin	shift
352da2e3ebdSchin	case $# in
353da2e3ebdSchin	0)	for d0 in '' ' '
354da2e3ebdSchin		do
355da2e3ebdSchin			for d1 in ' ' ':' ' :' ': ' ' : '
356da2e3ebdSchin			do
357da2e3ebdSchin				case ' ' in
358da2e3ebdSchin				$f1$d1|$d1$f2)	continue ;;
359da2e3ebdSchin				esac
360da2e3ebdSchin				for d2 in '' ' ' ':' ' :' ': ' ' : '
361da2e3ebdSchin				do
362da2e3ebdSchin					case $f2$d2 in
363da2e3ebdSchin					'')	split "$d0$f1$d1$f2$d2" "[1]($f1)" "($f1)()" ;;
364da2e3ebdSchin					' ')	;;
365da2e3ebdSchin					*)	split "$d0$f1$d1$f2$d2" "[2]($f1)($f2)" "($f1)($f2)" ;;
366da2e3ebdSchin					esac
367da2e3ebdSchin				done
368da2e3ebdSchin			done
369da2e3ebdSchin		done
370da2e3ebdSchin		continue
371da2e3ebdSchin		;;
372da2e3ebdSchin	esac
373da2e3ebdSchin	f3=$1
374da2e3ebdSchin	case $f3 in
375da2e3ebdSchin	'-')	f3='' ;;
376da2e3ebdSchin	esac
377da2e3ebdSchin	shift
378da2e3ebdSchin	case $# in
379da2e3ebdSchin	0)	for d0 in '' ' '
380da2e3ebdSchin		do
381da2e3ebdSchin			for d1 in ':' ' :' ': ' ' : '
382da2e3ebdSchin			do
383da2e3ebdSchin				case ' ' in
384da2e3ebdSchin				$f1$d1|$d1$f2)	continue ;;
385da2e3ebdSchin				esac
386da2e3ebdSchin				for d2 in ' ' ':' ' :' ': ' ' : '
387da2e3ebdSchin				do
388da2e3ebdSchin					case $f2$d2 in
389da2e3ebdSchin					' ')	continue ;;
390da2e3ebdSchin					esac
391da2e3ebdSchin					case ' ' in
392da2e3ebdSchin					$f2$d2|$d2$f3)	continue ;;
393da2e3ebdSchin					esac
394da2e3ebdSchin					for d3 in '' ' ' ':' ' :' ': ' ' : '
395da2e3ebdSchin					do
396da2e3ebdSchin						case $f3$d3 in
397da2e3ebdSchin						'')	split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;;
398da2e3ebdSchin						' ')	;;
399da2e3ebdSchin						*)	x=$f2$d2$f3$d3
400da2e3ebdSchin							x=${x#' '}
401da2e3ebdSchin							x=${x%' '}
402da2e3ebdSchin							split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)"
403da2e3ebdSchin							;;
404da2e3ebdSchin						esac
405da2e3ebdSchin					done
406da2e3ebdSchin				done
407da2e3ebdSchin			done
408da2e3ebdSchin		done
409da2e3ebdSchin		continue
410da2e3ebdSchin		;;
411da2e3ebdSchin	esac
412da2e3ebdSchindone
413da2e3ebdSchinunset IFS
414da2e3ebdSchin
415da2e3ebdSchinif	[[ $( (print ${12345:?}) 2>&1) != *12345* ]]
41634f9b3eeSRoland Mainzthen	err_exit 'incorrect error message with ${12345?}'
417da2e3ebdSchinfi
418da2e3ebdSchinunset foobar
419da2e3ebdSchinif	[[ $( (print ${foobar:?}) 2>&1) != *foobar* ]]
42034f9b3eeSRoland Mainzthen	err_exit 'incorrect error message with ${foobar?}'
421da2e3ebdSchinfi
422da2e3ebdSchinunset bar
423da2e3ebdSchinif	[[ $( (print ${bar:?bam}) 2>&1) != *bar*bam* ]]
42434f9b3eeSRoland Mainzthen	err_exit 'incorrect error message with ${foobar?}'
425da2e3ebdSchinfi
426da2e3ebdSchin{ $SHELL -c '
427da2e3ebdSchinfunction foo
428da2e3ebdSchin{
429da2e3ebdSchin	typeset SECONDS=0
430da2e3ebdSchin	sleep 1.5
431da2e3ebdSchin	print $SECONDS
432da2e3ebdSchin
433da2e3ebdSchin}
434da2e3ebdSchinx=$(foo)
435da2e3ebdSchin(( x >1 && x < 2 ))
436da2e3ebdSchin'
437da2e3ebdSchin} 2> /dev/null   || err_exit 'SECONDS not working in function'
43834f9b3eeSRoland Mainzcat > $tmp/script <<-\!
439da2e3ebdSchin	posixfun()
440da2e3ebdSchin	{
441da2e3ebdSchin		unset x
442da2e3ebdSchin	 	nameref x=$1
443da2e3ebdSchin	 	print  -r -- "$x"
444da2e3ebdSchin	}
445da2e3ebdSchin	function fun
446da2e3ebdSchin	{
447da2e3ebdSchin	 	nameref x=$1
448da2e3ebdSchin	 	print  -r -- "$x"
449da2e3ebdSchin	}
450da2e3ebdSchin	if	[[ $1 ]]
451da2e3ebdSchin	then	file=${.sh.file}
452da2e3ebdSchin	else	print -r -- "${.sh.file}"
453da2e3ebdSchin	fi
454da2e3ebdSchin!
45534f9b3eeSRoland Mainzchmod +x $tmp/script
45634f9b3eeSRoland Mainz. $tmp/script  1
45734f9b3eeSRoland Mainz[[ $file == $tmp/script ]] || err_exit ".sh.file not working for dot scripts"
45834f9b3eeSRoland Mainz[[ $($SHELL $tmp/script) == $tmp/script ]] || err_exit ".sh.file not working for scripts"
45934f9b3eeSRoland Mainz[[ $(posixfun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for posix functions"
46034f9b3eeSRoland Mainz[[ $(fun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for functions"
461da2e3ebdSchin[[ $(posixfun .sh.fun) == posixfun ]] || err_exit ".sh.fun not working for posix functions"
462da2e3ebdSchin[[ $(fun .sh.fun) == fun ]] || err_exit ".sh.fun not working for functions"
463da2e3ebdSchin[[ $(posixfun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for posix functions"
464da2e3ebdSchin[[ $(fun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for functions"
465da2e3ebdSchin(
466da2e3ebdSchin    [[ $(posixfun .sh.subshell) == 2 ]]  || err_exit ".sh.subshell not working for posix functions in subshells"
467da2e3ebdSchin    [[ $(fun .sh.subshell) == 2 ]]  || err_exit ".sh.subshell not working for functions in subshells"
468da2e3ebdSchin    (( .sh.subshell == 1 )) || err_exit ".sh.subshell not working in a subshell"
469da2e3ebdSchin)
470da2e3ebdSchinTIMEFORMAT='this is a test'
471da2e3ebdSchin[[ $({ { time :;} 2>&1;}) == "$TIMEFORMAT" ]] || err_exit 'TIMEFORMAT not working'
472da2e3ebdSchin: ${.sh.version}
473da2e3ebdSchin[[ $(alias integer) == *.sh.* ]] && err_exit '.sh. prefixed to alias name'
474da2e3ebdSchin: ${.sh.version}
475da2e3ebdSchin[[ $(whence rm) == *.sh.* ]] && err_exit '.sh. prefixed to tracked alias name'
476da2e3ebdSchin: ${.sh.version}
4777c2fbfb3SApril Chin[[ $(cd /bin;env | grep PWD=) == *.sh.* ]] && err_exit '.sh. prefixed to PWD'
478da2e3ebdSchin# unset discipline bug fix
479da2e3ebdSchindave=dave
480da2e3ebdSchinfunction dave.unset
481da2e3ebdSchin{
482da2e3ebdSchin    unset dave
483da2e3ebdSchin}
484da2e3ebdSchinunset dave
485da2e3ebdSchin[[ $(typeset +f) == *dave.* ]] && err_exit 'unset discipline not removed'
4867c2fbfb3SApril Chin
48734f9b3eeSRoland Mainzprint 'print ${VAR}' > $tmp/script
4887c2fbfb3SApril Chinunset VAR
48934f9b3eeSRoland MainzVAR=new $tmp/script > $tmp/out
49034f9b3eeSRoland Mainzgot=$(<$tmp/out)
4917c2fbfb3SApril Chin[[ $got == new ]] || err_exit "previously unset environment variable not passed to script, expected 'new', got '$got'"
4927c2fbfb3SApril Chin[[ ! $VAR ]] || err_exit "previously unset environment variable set after script, expected '', got '$VAR'"
4937c2fbfb3SApril Chinunset VAR
4947c2fbfb3SApril ChinVAR=old
49534f9b3eeSRoland MainzVAR=new $tmp/script > $tmp/out
49634f9b3eeSRoland Mainzgot=$(<$tmp/out)
4977c2fbfb3SApril Chin[[ $got == new ]] || err_exit "environment variable covering local variable not passed to script, expected 'new', got '$got'"
4987c2fbfb3SApril Chin[[ $VAR == old ]] || err_exit "previously set local variable changed after script, expected 'old', got '$VAR'"
4997c2fbfb3SApril Chinunset VAR
5007c2fbfb3SApril Chinexport VAR=old
50134f9b3eeSRoland MainzVAR=new $tmp/script > $tmp/out
50234f9b3eeSRoland Mainzgot=$(<$tmp/out)
5037c2fbfb3SApril Chin[[ $got == new ]] || err_exit "environment variable covering environment variable not passed to script, expected 'new', got '$got'"
5047c2fbfb3SApril Chin[[ $VAR == old ]] || err_exit "previously set environment variable changed after script, expected 'old', got '$VAR'"
5057c2fbfb3SApril Chin
506da2e3ebdSchin(
507da2e3ebdSchin	unset dave
508da2e3ebdSchin	function  dave.append
509da2e3ebdSchin	{
510da2e3ebdSchin		.sh.value+=$dave
511da2e3ebdSchin		dave=
512da2e3ebdSchin	}
513da2e3ebdSchin	dave=foo; dave+=bar
514da2e3ebdSchin	[[ $dave == barfoo ]] || exit 2
515da2e3ebdSchin) 2> /dev/null
516da2e3ebdSchincase $? in
517da2e3ebdSchin0)	 ;;
518da2e3ebdSchin1)	 err_exit 'append discipline not implemented';;
519da2e3ebdSchin*)	 err_exit 'append discipline not working';;
520da2e3ebdSchinesac
521da2e3ebdSchin.sh.foobar=hello
522da2e3ebdSchin{
523da2e3ebdSchin	function .sh.foobar.get
524da2e3ebdSchin	{
525da2e3ebdSchin		.sh.value=world
526da2e3ebdSchin	}
52734f9b3eeSRoland Mainz} 2> /dev/null || err_exit "cannot add get discipline to .sh.foobar"
528da2e3ebdSchin[[ ${.sh.foobar} == world ]]  || err_exit 'get discipline for .sh.foobar not working'
529da2e3ebdSchinx='a|b'
530da2e3ebdSchinIFS='|'
531da2e3ebdSchinset -- $x
532da2e3ebdSchin[[ $2 == b ]] || err_exit '$2 should be b after set'
533da2e3ebdSchinexec 3>&2 2> /dev/null
534da2e3ebdSchinset -x
535da2e3ebdSchin( IFS= ) 2> /dev/null
536da2e3ebdSchinset +x
537da2e3ebdSchinexec 2>&3-
538da2e3ebdSchinset -- $x
539da2e3ebdSchin[[ $2 == b ]] || err_exit '$2 should be b after subshell'
540da2e3ebdSchin: & pid=$!
541da2e3ebdSchin( : & )
542da2e3ebdSchin[[ $pid == $! ]] || err_exit '$! value not preserved across subshells'
543da2e3ebdSchinunset foo
544da2e3ebdSchintypeset -A foo
545da2e3ebdSchinfunction foo.set
546da2e3ebdSchin{
547da2e3ebdSchin	case ${.sh.subscript} in
548da2e3ebdSchin	bar)	if	((.sh.value > 1 ))
549da2e3ebdSchin	        then	.sh.value=5
550da2e3ebdSchin			foo[barrier_hit]=yes
551da2e3ebdSchin		fi
552da2e3ebdSchin		;;
553da2e3ebdSchin	barrier_hit)
554da2e3ebdSchin		if	[[ ${.sh.value} = yes ]]
555da2e3ebdSchin		then	foo[barrier_not_hit]=no
556da2e3ebdSchin		else	foo[barrier_not_hit]=yes
557da2e3ebdSchin		fi
558da2e3ebdSchin		;;
559da2e3ebdSchin	esac
560da2e3ebdSchin}
561da2e3ebdSchinfoo[barrier_hit]=no
562da2e3ebdSchinfoo[bar]=1
563da2e3ebdSchin(( foo[bar] == 1 )) || err_exit 'foo[bar] should be 1'
564da2e3ebdSchin[[ ${foo[barrier_hit]} == no ]] || err_exit 'foo[barrier_hit] should be no'
565da2e3ebdSchin[[ ${foo[barrier_not_hit]} == yes ]] || err_exit 'foo[barrier_not_hit] should be yes'
566da2e3ebdSchinfoo[barrier_hit]=no
567da2e3ebdSchinfoo[bar]=2
568da2e3ebdSchin(( foo[bar] == 5 )) || err_exit 'foo[bar] should be 5'
569da2e3ebdSchin[[ ${foo[barrier_hit]} == yes ]] || err_exit 'foo[barrier_hit] should be yes'
570da2e3ebdSchin[[ ${foo[barrier_not_hit]} == no ]] || err_exit 'foo[barrier_not_hit] should be no'
571da2e3ebdSchinunset x
572da2e3ebdSchintypeset -i x
573da2e3ebdSchinfunction x.set
574da2e3ebdSchin{
575da2e3ebdSchin	typeset sub=${.sh.subscript}
576da2e3ebdSchin	(( sub > 0 )) && (( x[sub-1]= x[sub-1] + .sh.value ))
577da2e3ebdSchin}
578da2e3ebdSchinx[0]=0 x[1]=1 x[2]=2 x[3]=3
579da2e3ebdSchin[[ ${x[@]} == '12 8 5 3' ]] || err_exit 'set discipline for indexed array not working correctly'
58034f9b3eeSRoland Mainzfloat seconds
581da2e3ebdSchin((SECONDS=3*4))
58234f9b3eeSRoland Mainzseconds=SECONDS
58334f9b3eeSRoland Mainz(( seconds < 12 || seconds > 12.1 )) &&  err_exit "SECONDS is $seconds and should be close to 12"
5847c2fbfb3SApril Chinunset a
5857c2fbfb3SApril Chinfunction a.set
5867c2fbfb3SApril Chin{
5877c2fbfb3SApril Chin	print -r -- "${.sh.name}=${.sh.value}"
5887c2fbfb3SApril Chin}
5897c2fbfb3SApril Chin[[ $(a=1) == a=1 ]] || err_exit 'set discipline not working in subshell assignment'
5907c2fbfb3SApril Chin[[ $(a=1 :) == a=1 ]] || err_exit 'set discipline not working in subshell command'
5917c2fbfb3SApril Chin
5927c2fbfb3SApril Chin[[ ${.sh.subshell} == 0 ]] || err_exit '${.sh.subshell} should be 0'
5937c2fbfb3SApril Chin(
5947c2fbfb3SApril Chin	[[ ${.sh.subshell} == 1 ]] || err_exit '${.sh.subshell} should be 1'
5957c2fbfb3SApril Chin	(
5967c2fbfb3SApril Chin		[[ ${.sh.subshell} == 2 ]] || err_exit '${.sh.subshell} should be 2'
5977c2fbfb3SApril Chin	)
5987c2fbfb3SApril Chin)
5997c2fbfb3SApril Chin
6007c2fbfb3SApril Chinset -- {1..32768}
6017c2fbfb3SApril Chin(( $# == 32768 )) || err_exit "\$# failed -- expected 32768, got $#"
6027c2fbfb3SApril Chinset --
6037c2fbfb3SApril Chin
6047c2fbfb3SApril Chinunset r v x
6057c2fbfb3SApril Chinpath=$PATH
6067c2fbfb3SApril Chinx=foo
6077c2fbfb3SApril Chinfor v in EDITOR VISUAL OPTIND CDPATH FPATH PATH ENV LINENO RANDOM SECONDS _
6087c2fbfb3SApril Chindo	nameref r=$v
6097c2fbfb3SApril Chin	unset $v
6107c2fbfb3SApril Chin	if	( $SHELL -c "unset $v; : \$$v" ) 2>/dev/null
6117c2fbfb3SApril Chin	then	[[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'"
6127c2fbfb3SApril Chin		r=$x
6137c2fbfb3SApril Chin		[[ $r == $x ]] || err_exit "$v=$x failed -- expected '$x', got '$r'"
6147c2fbfb3SApril Chin	else	err_exit "unset $v; : \$$v failed"
6157c2fbfb3SApril Chin	fi
6167c2fbfb3SApril Chindone
61734f9b3eeSRoland Mainz
61834f9b3eeSRoland Mainzx=x
6197c2fbfb3SApril Chinfor v in LC_ALL LC_CTYPE LC_MESSAGES LC_COLLATE LC_NUMERIC
6207c2fbfb3SApril Chindo	nameref r=$v
6217c2fbfb3SApril Chin	unset $v
6227c2fbfb3SApril Chin	[[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'"
6237c2fbfb3SApril Chin	d=$($SHELL -c "$v=$x" 2>&1)
6247c2fbfb3SApril Chin	[[ $d ]] || err_exit "$v=$x failed -- expected locale diagnostic"
62534f9b3eeSRoland Mainz	{ g=$( r=$x; print -- $r ); } 2>/dev/null
62634f9b3eeSRoland Mainz	[[ $g == '' ]] || err_exit "$v=$x failed -- expected '', got '$g'"
62734f9b3eeSRoland Mainz	{ g=$( r=C; r=$x; print -- $r ); } 2>/dev/null
62834f9b3eeSRoland Mainz	[[ $g == 'C' ]] || err_exit "$v=C; $v=$x failed -- expected 'C', got '$g'"
6297c2fbfb3SApril Chindone
6307c2fbfb3SApril ChinPATH=$path
6317c2fbfb3SApril Chin
63234f9b3eeSRoland Mainzcd $tmp
63334f9b3eeSRoland Mainz
63434f9b3eeSRoland Mainzprint print -n zzz > zzz
63534f9b3eeSRoland Mainzchmod +x zzz
63634f9b3eeSRoland Mainzexp='aaazzz'
63734f9b3eeSRoland Mainzgot=$($SHELL -c 'unset SHLVL; print -n aaa; ./zzz' 2>&1) >/dev/null 2>&1
63834f9b3eeSRoland Mainz[[ $got == "$exp" ]] || err_exit "unset SHLVL causes script failure -- expected '$exp', got '$got'"
63934f9b3eeSRoland Mainz
64034f9b3eeSRoland Mainzmkdir glean
64134f9b3eeSRoland Mainzfor cmd in date ok
64234f9b3eeSRoland Mainzdo	exp="$cmd ok"
64334f9b3eeSRoland Mainz	rm -f $cmd
64434f9b3eeSRoland Mainz	print print $exp > glean/$cmd
64534f9b3eeSRoland Mainz	chmod +x glean/$cmd
64634f9b3eeSRoland Mainz	got=$(CDPATH=:.. $SHELL -c "PATH=:/bin:/usr/bin; date > /dev/null; cd glean && ./$cmd" 2>&1)
64734f9b3eeSRoland Mainz	[[ $got == "$exp" ]] || err_exit "cd with CDPATH after PATH change failed -- expected '$exp', got '$got'"
64834f9b3eeSRoland Mainzdone
64934f9b3eeSRoland Mainz
650*3e14f97fSRoger A. Faulknerv=LC_CTYPE
651*3e14f97fSRoger A. Faulknerunset $v
652*3e14f97fSRoger A. Faulkner[[ -v $v ]] && err_exit "unset $v; [[ -v $v ]] failed"
653*3e14f97fSRoger A. Faulknereval $v=C
654*3e14f97fSRoger A. Faulkner[[ -v $v ]] || err_exit "$v=C; [[ -v $v ]] failed"
655*3e14f97fSRoger A. Faulkner
656*3e14f97fSRoger A. Faulknercmd='set --nounset; unset foo; : ${!foo*}'
657*3e14f97fSRoger A. Faulkner$SHELL -c "$cmd" 2>/dev/null || err_exit "'$cmd' exit status $?, expected 0"
658*3e14f97fSRoger A. Faulkner
659da2e3ebdSchinexit $((Errors))
660