OILS / spec / introspect.test.sh View on Github | oilshell.org

287 lines, 169 significant
1## compare_shells: bash
2
3# Test call stack introspection. There are a bunch of special variables
4# defined here:
5#
6# https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
7#
8# - The shell function ${FUNCNAME[$i]} is defined in the file
9# ${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}
10#
11# - ${BASH_LINENO[$i]} is the line number in the source file
12# (${BASH_SOURCE[$i+1]}) where ${FUNCNAME[$i]} was called (or
13# ${BASH_LINENO[$i-1]} if referenced within another shell function).
14#
15# - For instance, ${FUNCNAME[$i]} was called from the file
16# ${BASH_SOURCE[$i+1]} at line number ${BASH_LINENO[$i]}. The caller builtin
17# displays the current call stack using this information.
18#
19# So ${BASH_SOURCE[@]} doesn't line up with ${BASH_LINENO}. But
20# ${BASH_SOURCE[0]} does line up with $LINENO!
21#
22# Geez.
23#
24# In other words, BASH_SOURCE is about the DEFINITION. While FUNCNAME and
25# BASH_LINENO are about the CALL.
26
27
28#### ${FUNCNAME[@]} array
29g() {
30 argv.py "${FUNCNAME[@]}"
31}
32f() {
33 argv.py "${FUNCNAME[@]}"
34 g
35 argv.py "${FUNCNAME[@]}"
36}
37f
38## STDOUT:
39['f']
40['g', 'f']
41['f']
42## END
43
44#### FUNCNAME with source (scalar or array)
45cd $REPO_ROOT
46
47# Comments on bash quirk:
48# https://github.com/oilshell/oil/pull/656#issuecomment-599162211
49
50f() {
51 . spec/testdata/echo-funcname.sh
52}
53g() {
54 f
55}
56
57g
58echo -----
59
60. spec/testdata/echo-funcname.sh
61echo -----
62
63argv.py "${FUNCNAME[@]}"
64
65# Show bash inconsistency. FUNCNAME doesn't behave like a normal array.
66case $SH in
67 (bash)
68 echo -----
69 a=('A')
70 argv.py ' @' "${a[@]}"
71 argv.py ' 0' "${a[0]}"
72 argv.py '${}' "${a}"
73 argv.py ' $' "$a"
74 ;;
75esac
76
77## STDOUT:
78[' @', 'source', 'f', 'g']
79[' 0', 'source']
80['${}', 'source']
81[' $', 'source']
82-----
83[' @', 'source']
84[' 0', 'source']
85['${}', 'source']
86[' $', 'source']
87-----
88[]
89## END
90## BUG bash STDOUT:
91[' @', 'source', 'f', 'g']
92[' 0', 'source']
93['${}', 'source']
94[' $', 'source']
95-----
96[' @']
97[' 0', '']
98['${}', '']
99[' $', '']
100-----
101[]
102-----
103[' @', 'A']
104[' 0', 'A']
105['${}', 'A']
106[' $', 'A']
107## END
108
109
110#### BASH_SOURCE and BASH_LINENO scalar or array (e.g. for virtualenv)
111cd $REPO_ROOT
112
113# https://github.com/pypa/virtualenv/blob/master/virtualenv_embedded/activate.sh
114# https://github.com/akinomyoga/ble.sh/blob/6f6c2e5/ble.pp#L374
115
116argv.py "$BASH_SOURCE" # SimpleVarSub
117argv.py "${BASH_SOURCE}" # BracedVarSub
118argv.py "$BASH_LINENO" # SimpleVarSub
119argv.py "${BASH_LINENO}" # BracedVarSub
120argv.py "$FUNCNAME" # SimpleVarSub
121argv.py "${FUNCNAME}" # BracedVarSub
122echo __
123source spec/testdata/bash-source-string.sh
124
125## STDOUT:
126['']
127['']
128['']
129['']
130['']
131['']
132__
133['spec/testdata/bash-source-string.sh']
134['spec/testdata/bash-source-string.sh']
135['11']
136['11']
137____
138['spec/testdata/bash-source-string2.sh']
139['spec/testdata/bash-source-string2.sh']
140['11']
141['11']
142## END
143
144
145#### ${FUNCNAME} with prefix/suffix operators
146
147check() {
148 argv.py "${#FUNCNAME}"
149 argv.py "${FUNCNAME::1}"
150 argv.py "${FUNCNAME:1}"
151}
152check
153## STDOUT:
154['5']
155['c']
156['heck']
157## END
158
159#### operators on FUNCNAME
160check() {
161 argv.py "${FUNCNAME}"
162 argv.py "${#FUNCNAME}"
163 argv.py "${FUNCNAME::1}"
164 argv.py "${FUNCNAME:1}"
165}
166check
167## status: 0
168## STDOUT:
169['check']
170['5']
171['c']
172['heck']
173## END
174
175#### ${FUNCNAME} and "set -u" (OSH regression)
176set -u
177argv.py "$FUNCNAME"
178## status: 1
179## stdout-json: ""
180
181#### $((BASH_LINENO)) (scalar form in arith)
182check() {
183 echo $((BASH_LINENO))
184}
185check
186## stdout: 4
187
188#### ${BASH_SOURCE[@]} with source and function name
189cd $REPO_ROOT
190
191argv.py "${BASH_SOURCE[@]}"
192source spec/testdata/bash-source-simple.sh
193f
194## STDOUT:
195[]
196['spec/testdata/bash-source-simple.sh']
197['spec/testdata/bash-source-simple.sh']
198## END
199
200#### ${BASH_SOURCE[@]} with line numbers
201cd $REPO_ROOT
202
203$SH spec/testdata/bash-source.sh
204## STDOUT:
205['begin F funcs', 'f', 'main']
206['begin F files', 'spec/testdata/bash-source.sh', 'spec/testdata/bash-source.sh']
207['begin F lines', '21', '0']
208['G funcs', 'g', 'f', 'main']
209['G files', 'spec/testdata/bash-source-2.sh', 'spec/testdata/bash-source.sh', 'spec/testdata/bash-source.sh']
210['G lines', '15', '21', '0']
211['end F funcs', 'f', 'main']
212['end F', 'spec/testdata/bash-source.sh', 'spec/testdata/bash-source.sh']
213['end F lines', '21', '0']
214## END
215
216#### ${BASH_LINENO[@]} is a stack of line numbers for function calls
217# note: it's CALLS, not DEFINITIONS.
218g() {
219 argv.py G "${BASH_LINENO[@]}"
220}
221f() {
222 argv.py 'begin F' "${BASH_LINENO[@]}"
223 g # line 6
224 argv.py 'end F' "${BASH_LINENO[@]}"
225}
226argv.py ${BASH_LINENO[@]}
227f # line 9
228## STDOUT:
229[]
230['begin F', '10']
231['G', '6', '10']
232['end F', '10']
233## END
234
235#### Locations with temp frame
236
237cd $REPO_ROOT
238
239$SH spec/testdata/bash-source-pushtemp.sh
240
241## STDOUT:
242F
243G
244STACK:spec/testdata/bash-source-pushtemp.sh:g:3
245STACK:spec/testdata/bash-source-pushtemp.sh:f:19
246STACK:spec/testdata/bash-source-pushtemp.sh:main:0
247## END
248
249#### Locations when sourcing
250
251cd $REPO_ROOT
252
253# like above test case, but we source
254
255# bash location doesn't make sense:
256# - It says 'source' happens at line 1 of bash-source-pushtemp. Well I think
257# - It really happens at line 2 of '-c' ! I guess that's to line up
258# with the 'main' frame
259
260$SH -c 'true;
261source spec/testdata/bash-source-pushtemp.sh'
262
263## STDOUT:
264F
265G
266STACK:spec/testdata/bash-source-pushtemp.sh:g:3
267STACK:spec/testdata/bash-source-pushtemp.sh:f:19
268STACK:spec/testdata/bash-source-pushtemp.sh:source:2
269## END
270
271#### Sourcing inside function grows the debug stack
272
273cd $REPO_ROOT
274
275$SH spec/testdata/bash-source-source.sh
276
277## STDOUT:
278F
279G
280STACK:spec/testdata/bash-source-pushtemp.sh:g:3
281STACK:spec/testdata/bash-source-pushtemp.sh:f:19
282STACK:spec/testdata/bash-source-pushtemp.sh:source:2
283STACK:spec/testdata/bash-source-source.sh:mainfunc:6
284STACK:spec/testdata/bash-source-source.sh:main2:10
285STACK:spec/testdata/bash-source-source.sh:main1:13
286STACK:spec/testdata/bash-source-source.sh:main:0
287## END