File: compile_effect_test.elvts

package info (click to toggle)
elvish 0.21.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,372 kB
  • sloc: javascript: 236; sh: 130; python: 104; makefile: 88; xml: 9
file content (422 lines) | stat: -rw-r--r-- 10,257 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
/////////
# chunk #
/////////

## empty chunk ##
~> 

## outputs of pipelines in a chunk are concatenated ##
~> put x; put y; put z
▶ x
▶ y
▶ z

## a failed pipeline cause the whole chunk to fail ##
~> put a; fail bad; put b
▶ a
Exception: bad
  [tty]:1:8-15: put a; fail bad; put b

////////////
# pipeline #
////////////

## pure byte pipeline on Unix ##
//only-on unix
~> echo "Albert\nAllan\nAlbraham\nBerlin" | sed s/l/1/g | grep e
A1bert
Ber1in

## pure byte pipeline on Windows ##
//only-on windows
~> echo "Albert\nAllan\nAlbraham\nBerlin" | findstr e
Albert
Berlin

## pure value pipeline ##
~> put 233 42 19 | each {|x|+ $x 10}
▶ (num 243)
▶ (num 52)
▶ (num 29)

## pipeline draining ##
~> range 100 | put x
▶ x

// TODO: Add a useful hybrid pipeline sample

## reader gone ##
// Internal commands writing to byte output raises ReaderGone when the reader has
// exited, which is then suppressed by the pipeline.
~> while $true { echo y } | nop
~> var reached = $false
   { while $true { echo y }; reached = $true } | nop
   put $reached
▶ $false
// Similar for value output.
~> while $true { put y } | nop
~> var reached = $false
   { while $true { put y }; reached = $true } | nop
   put $reached
▶ $false

## reader gone from SIGPIPE ##
//only-on unix
// External commands terminated by SIGPIPE due to reader exiting early raise
// ReaderGone, which is then suppressed by the pipeline.
~> yes | true
~> var reached = $false
   { yes; reached = $true } | true
   put $reached
▶ $false

///////////////////////
# background pipeline #
///////////////////////

//each:eval use file

## basic behavior ##
~> set notify-bg-job-success = $false
   var p = (file:pipe)
   { print foo > $p; file:close $p[w] }&
   slurp < $p; file:close $p[r]
▶ foo

## notification ##
//recv-bg-job-notification-in-global
~> set notify-bg-job-success = $true
   var p = (file:pipe)
   fn f { file:close $p[w] }
   f &
   slurp < $p; file:close $p[r]
   recv-bg-job-notification
▶ ''
▶ 'job f & finished'

## notification with exception ##
//recv-bg-job-notification-in-global
~> set notify-bg-job-success = $true
   var p = (file:pipe)
   fn f { file:close $p[w]; fail foo }
   f &
   slurp < $p; file:close $p[r]
   recv-bg-job-notification
▶ ''
▶ 'job f & finished, errors = foo'

///////////
# command #
///////////

~> put foo
▶ foo

## error conditions ##
// head is not a single value
~> {put put} foo
Exception: arity mismatch: command must be 1 value, but is 2 values
  [tty]:1:1-9: {put put} foo
// head is not callable or string containing slash
~> [] foo
Exception: bad value: command must be callable or string containing slash, but is []
  [tty]:1:1-2: [] foo
// argument throws
~> put [][1]
Exception: out of range: index must be from 0 to -1, but is 1
  [tty]:1:5-9: put [][1]
// option key is not string
~> put &[]=[]
Exception: bad value: option key must be string, but is list
  [tty]:1:1-10: put &[]=[]
// option evaluation throws
~> put &x=[][1]
Exception: out of range: index must be from 0 to -1, but is 1
  [tty]:1:8-12: put &x=[][1]

## regression test for b.elv.sh/1204 ##
// Ensure that the arguments of special forms are not accidentally compiled
// twice.
~> nop (and (use builtin))
   nop $builtin:echo~

/////////////////////////////
# external command as value #
/////////////////////////////
~> kind-of (external true)
▶ fn
~> repr (external true)
<external true>
~> put [&(external true)=$true][(external true)]
▶ $true

////////////////////////////////
# external commands invocation #
////////////////////////////////

## common behavior ##
// Doesn't support options
~> (external foo) &option
Exception: external commands don't accept elvish options
  [tty]:1:1-22: (external foo) &option

## external command from PATH ##
//in-temp-dir
//unset-env PATH
~> use os
   os:mkdir bin
   to-lines ['#!/bin/sh' 'echo hello'] > bin/say-hello
   os:chmod 0o700 bin/say-hello
   to-lines ['@echo hello'] > bin/say-hello.bat
   set paths = [$pwd/bin]
~> say-hello
hello
// Explicit e:
~> e:say-hello
hello
// Dynamic string does not work for finding external commands from PATH
~> var x = say-hello
   $x
Exception: bad value: command must be callable or string containing slash, but is say-hello
  [tty]:2:1-2: $x
// Command searching is affected by the unknown-command pragma
~> { pragma unknown-command = disallow; say-hello }
Compilation error: unknown command disallowed by current pragma
  [tty]:1:38-46: { pragma unknown-command = disallow; say-hello }
~> { pragma unknown-command = disallow; { say-hello } }
Compilation error: unknown command disallowed by current pragma
  [tty]:1:40-48: { pragma unknown-command = disallow; { say-hello } }
~> { pragma unknown-command = external; say-hello }
hello
// But explicit e: is always allowed
~> { pragma unknown-command = disallow; e:say-hello }
hello

## external command relative to working directory ##
//in-temp-dir
~> use os
   fn make-echo-script {|name msg|
     to-lines ['#!/bin/sh' 'echo '$msg] > $name
     os:chmod 0o700 $name
     to-lines ['@echo '$msg] > $name.bat
   }
   make-echo-script say-hello hello
   os:mkdir lorem
   make-echo-script lorem/ipsum 'lorem ipsum'
~> ./say-hello
hello
~> ./lorem/ipsum
lorem ipsum
~> lorem/ipsum
lorem ipsum
// Explicit e:
~> e:./say-hello
hello
~> e:./lorem/ipsum
lorem ipsum
~> e:lorem/ipsum
lorem ipsum
// Dynamic string
~> var x = ./say-hello
   $x
hello
~> var x = ./lorem/ipsum
   $x
lorem ipsum
~> var x = lorem/ipsum
   $x
lorem ipsum
// Relative external commands are not affected by the unknown-command pragma
~> { pragma unknown-command = disallow; ./say-hello }
hello
~> { pragma unknown-command = disallow; lorem/ipsum }
lorem ipsum
~> { pragma unknown-command = disallow; var x = ./say-hello; $x }
hello

## non-existent command on Unix ##
//only-on unix
//unset-env PATH
~> set paths = []
~> nonexistent-command
Exception: exec: "nonexistent-command": executable file not found in $PATH
  [tty]:1:1-19: nonexistent-command

## non-existent command on Windows ##
//only-on windows
//unset-env PATH
~> set paths = []
~> nonexistent-command
Exception: exec: "nonexistent-command": executable file not found in %PATH%
  [tty]:1:1-19: nonexistent-command

///////////////
# implicit cd #
///////////////

//in-temp-dir
//deprecation-level 21
~> use os
   use path
   os:mkdir new-dir
   var old-pwd = $pwd
~> ./new-dir
Deprecation: implicit cd is deprecated; use cd or location mode instead
  [tty]:1:1-9: ./new-dir
~> eq $pwd (path:join $old-pwd new-dir)
▶ $true

///////////////
# redirection #
///////////////

//each:in-temp-dir

## output and input redirection ##
~> echo 233 > out1
   slurp < out1
▶ "233\n"

## append ##
~> echo 1 > out; echo 2 >> out; slurp < out
▶ "1\n2\n"

## read and write ##
// TODO: Add a meaningful use case that actually uses both read and write.
~> echo 233 <> out1
   slurp < out1
▶ "233\n"

## redirections from special form ##
~> for x [lorem ipsum] { echo $x } > out2
   slurp < out2
▶ "lorem\nipsum\n"

## using numeric FDs as source and destination ##
~> { echo foobar >&2 } 2> out3
   slurp < out3
▶ "foobar\n"

## using named FDs as source and destination ##
~> echo 233 stdout> out1
   slurp stdin< out1
▶ "233\n"

## using named FDs (stderr) as source and destination ##
~> { echo foobar >&stderr } stderr> out4
   slurp < out4
▶ "foobar\n"

## using a new FD as source throws an exception ##
~> echo foo >&4
Exception: invalid fd: 4
  [tty]:1:10-12: echo foo >&4

## using a new FD as destination is OK, and makes it available ##
~> { echo foo >&4 } 4>out5
   slurp < out5
▶ "foo\n"

## using a new FD for external command is OK ##
// Regression test against b.elv.sh/788.
//only-on unix
// TODO: Enable for Windows too.
~> /bin/sh -c 'echo ok' 5</dev/null
ok

## redirections from file objects ##
~> use file
   echo haha > out3
   var f = (file:open out3)
   slurp <$f
   file:close $f
▶ "haha\n"

## redirections from pipe objects ##
~> use file
   var p = (file:pipe)
   echo haha > $p
   file:close $p[w]
   slurp < $p
   file:close $p[r]
▶ "haha\n"

## regression test for b.elv.sh/1010 ##
// Don't hang when iterating over input from a file.
~> echo abc > bytes
   each $echo~ < bytes
abc
~> echo def > bytes
   only-values < bytes | count
▶ (num 0)

## writing value output to file throws an exception ##
~> put foo >a
Exception: port does not support value output
  [tty]:1:1-10: put foo >a

## writing value output to closed port throws an exception ##
~> put foo >&-
Exception: port does not support value output
  [tty]:1:1-11: put foo >&-

## invalid redirection destination ##
~> echo []> test
Exception: bad value: redirection destination must be fd name or number, but is []
  [tty]:1:6-7: echo []> test

## invalid fd redirection source ##
~> echo >&test
Exception: bad value: redirection source must be fd name or number or '-', but is test
  [tty]:1:8-11: echo >&test

## invalid redirection source ##
~> echo > []
Exception: bad value: redirection source must be string, file or map, but is list
  [tty]:1:8-9: echo > []

## invalid map for redirection ##
~> echo < [&]
Exception: bad value: map for input redirection must be map with file in the 'r' field, but is [&]
  [tty]:1:8-10: echo < [&]
~> echo > [&]
Exception: bad value: map for output redirection must be map with file in the 'w' field, but is [&]
  [tty]:1:8-10: echo > [&]

## exception when evaluating source or destination ##
~> echo > (fail foo)
Exception: foo
  [tty]:1:9-16: echo > (fail foo)
~> echo (fail foo)> file
Exception: foo
  [tty]:1:7-14: echo (fail foo)> file

////////////////
# stack traces #
////////////////

// Stack traces of increasing depths.
~> fail oops
Exception: oops
  [tty]:1:1-9: fail oops
~> fn f { fail oops }
   f
Exception: oops
  [tty]:1:8-17: fn f { fail oops }
  [tty]:2:1-1: f
~> fn f { fail oops }
   fn g { f }
   g
Exception: oops
  [tty]:1:8-17: fn f { fail oops }
  [tty]:2:8-9: fn g { f }
  [tty]:3:1-1: g
// Error thrown before execution.
~> fn f { }
   f a
Exception: arity mismatch: arguments must be 0 values, but is 1 value
  [tty]:2:1-3: f a
// Error from builtin.
~> count 1 2 3
Exception: arity mismatch: arguments must be 0 to 1 values, but is 3 values
  [tty]:1:1-11: count 1 2 3