1 # spec/ysh-builtin-error
2
3 ## our_shell: ysh
4
5 #### User errors behave like builtin errors
6 func divide(a, b) {
7 if (b === 0) {
8 error 'divide by zero' (code=3)
9 }
10
11 return (a / b)
12 }
13
14 # errors can be caught with try
15 try { = divide(42, 0) }
16 echo status=$_status
17
18 = divide(42, 0)
19
20 ## status: 3
21 ## STDOUT:
22 status=3
23 ## END
24
25 #### _error register is initially empty dict
26
27 echo $[type(_error)]
28 echo $[len(_error)]
29
30 ## STDOUT:
31 Dict
32 0
33 ## END
34
35 #### error builtin sets _error.message, which can be used by programs
36
37 func divide(a, b) {
38 if (b === 0) {
39 error "divide by zero: $a / $b" (code=3)
40 }
41 return (a / b)
42 }
43
44 try { = divide(42, 0) }
45 echo status=$_status
46 echo message=$[_error.message]
47
48 proc p {
49 echo $[divide(5, 0)]
50 }
51
52 try { p }
53 echo status=$_status
54 echo message=$[_error.message]
55
56 ## STDOUT:
57 status=3
58 message=divide by zero: 42 / 0
59 status=3
60 message=divide by zero: 5 / 0
61 ## END
62
63 #### error builtin adds named args as properties on _error Dict
64
65 try {
66 error 'bad' (code=99)
67 }
68 pp test_ (_error)
69
70 # Note: myData co
71 try {
72 error 'bad' (code=99, myData={spam:'eggs'})
73 }
74 pp test_ (_error)
75
76 try {
77 error 'bad' (code=99, message='cannot override')
78 }
79 pp test_ (_error)
80
81 ## STDOUT:
82 (Dict) {"code":99,"message":"bad"}
83 (Dict) {"myData":{"spam":"eggs"},"code":99,"message":"bad"}
84 (Dict) {"message":"bad","code":99}
85 ## END
86
87 #### Errors within multiple functions
88 func inverse(x) {
89 if (x === 0) {
90 error '0 does not have an inverse' # default status is 1
91 }
92
93 return (1 / x)
94 }
95
96 func invertList(list) {
97 var result = []
98 for item in (list) {
99 call result->append(inverse(item))
100 }
101 return (result)
102 }
103
104 = invertList([1, 2, 0])
105 ## status: 10
106 ## STDOUT:
107 ## END
108
109 #### Impact of errors on var declaration
110 func alwaysError() {
111 error "it's an error" (status=100)
112 }
113
114 try {
115 var mylist = [1 + 2, alwaysError()]
116
117 echo this will never be printed
118 }
119 = mylist # undefined! status becomes 1
120 ## status: 1
121 ## STDOUT:
122 ## END
123
124 #### default error code is 10
125 error 'some error'
126 ## status: 10
127 ## STDOUT:
128 ## END
129
130 #### error code should be an integer
131 error 'error' (code='a string?')
132 ## status: 3
133 ## STDOUT:
134 ## END
135
136 #### Error code should be named arg, not positional
137 error msg (100)
138 ## status: 3
139 ## STDOUT:
140 ## END
141
142 #### error cannot take word args
143 error uh-oh ('error', status=1)
144 ## status: 3
145 ## STDOUT:
146 ## END
147
148 #### error requires arguments
149 error
150 ## status: 2
151 ## STDOUT:
152 ## END
153
154 #### error cannot have a code of 0
155 error ('error', code=0)
156 ## status: 2
157 ## STDOUT:
158 ## END
159
160 #### try { error oops }
161
162 try { error oops }
163 echo status=$_status
164
165 ## STDOUT:
166 status=10
167 ## END
168
169 #### Handle _error.code
170
171 proc failing {
172 error 'failed' (code=99)
173 }
174
175 try {
176 failing
177 }
178 if (_error.code === 99) {
179 echo PASS
180 }
181
182 try {
183 failing
184 }
185 case (_error.code) {
186 (0) { echo success }
187 (1) { echo one }
188 (else) { echo CASE PASS }
189 }
190
191 ## STDOUT:
192 PASS
193 CASE PASS
194 ## END
195
196
197 #### failed builtin usage
198
199 set +o errexit
200
201 try { echo ok }
202
203 failed (42)
204 echo status=$?
205
206 try { echo ok }
207
208 # Too many args
209 failed a b
210 echo status=$?
211
212 ## STDOUT:
213 ok
214 status=2
215 ok
216 status=2
217 ## END
218
219 #### failed builtin
220
221 try {
222 echo hi
223 }
224 if failed {
225 echo 'should not get here'
226 } else {
227 echo 'ok 1'
228 }
229
230 try {
231 #test -n ''
232
233 # Hm json read sets the regular error
234 # Should we raise error.Structured?
235 #json read <<< '{'
236
237 var x = fromJson('{')
238
239 # Hm the error is in a SUBPROCESS HERE
240 #echo '{' | json read
241 }
242 if failed {
243 echo 'ok 2'
244 } else {
245 echo 'should not get here'
246 }
247
248 ## STDOUT:
249 hi
250 ok 1
251 ok 2
252 ## END
253
254
255 #### assert on values
256
257 try {
258 $[ENV.SH] -c '
259 assert (true)
260 echo passed
261 '
262 }
263 echo code $[_error.code]
264 echo
265
266 try {
267 $[ENV.SH] -c '
268 func f() { return (false) }
269
270 assert (f())
271 echo "unreachable"
272 ' | grep -v Value
273 }
274 echo code $[_error.code]
275 echo
276
277 try {
278 $[ENV.SH] -c '
279 assert (null)
280 echo "unreachable"
281 ' | grep -v Value
282 }
283 echo code $[_error.code]
284 echo
285
286 try {
287 $[ENV.SH] -c '
288 func f() { return (false) }
289
290 assert (true === f())
291 echo "unreachable"
292 ' | grep -v Value
293 }
294 echo code $[_error.code]
295 echo
296
297 try {
298 $[ENV.SH] -c '
299 assert (42 === 42)
300 echo passed
301 '
302 }
303 echo code $[_error.code]
304 echo
305
306 ## STDOUT:
307 passed
308 code 0
309
310
311 code 3
312
313
314 code 3
315
316
317 code 3
318
319 passed
320 code 0
321
322 ## END
323
324
325 #### assert on expressions
326
327 try {
328 $[ENV.SH] -c '
329 assert [true]
330 echo passed
331 '
332 }
333 echo code $[_error.code]
334 echo
335
336 try {
337 $[ENV.SH] -c '
338 func f() { return (false) }
339
340 assert [f()]
341 echo "unreachable"
342 '
343 }
344 echo code $[_error.code]
345 echo
346
347 try {
348 $[ENV.SH] -c '
349 assert [null]
350 echo "unreachable"
351 '
352 }
353 echo code $[_error.code]
354 echo
355
356 try {
357 $[ENV.SH] -c '
358 func f() { return (false) }
359
360 assert [true === f()]
361 echo "unreachable"
362 ' | grep -v '(Bool)'
363 }
364 echo code $[_error.code]
365 echo
366
367 try {
368 $[ENV.SH] -c '
369 assert [42 === 42]
370 echo passed
371 '
372 }
373 echo code $[_error.code]
374 echo
375
376 ## STDOUT:
377 passed
378 code 0
379
380 code 3
381
382 code 3
383
384
385 code 3
386
387 passed
388 code 0
389
390 ## END
391
392
393 #### assert on expression that fails
394
395 try {
396 $[ENV.SH] -c '
397 assert [NAN === 1/0] # not true
398 echo unreachable
399 '
400 }
401 echo code $[_error.code]
402 echo
403
404 try {
405 $[ENV.SH] -c '
406 assert ["oof" === $(false)]
407 echo unreachable
408 '
409 }
410 echo code $[_error.code]
411 echo
412
413
414 ## STDOUT:
415 code 3
416
417 code 1
418
419 ## END
420
421 #### assert on chained comparison expression is not special
422
423 try {
424 $[ENV.SH] -c '
425 #pp test_ (42 === 42 === 43)
426 assert [42 === 42 === 43]
427 echo unreachable
428 '
429 }
430 echo code $[_error.code]
431 echo
432
433 ## STDOUT:
434 code 3
435
436 ## END