src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/compile_effect_test.elvts (about)

     1  /////////
     2  # chunk #
     3  /////////
     4  
     5  ## empty chunk ##
     6  ~> 
     7  
     8  ## outputs of pipelines in a chunk are concatenated ##
     9  ~> put x; put y; put z
    10  ▶ x
    11  ▶ y
    12  ▶ z
    13  
    14  ## a failed pipeline cause the whole chunk to fail ##
    15  ~> put a; fail bad; put b
    16  ▶ a
    17  Exception: bad
    18    [tty]:1:8-15: put a; fail bad; put b
    19  
    20  ////////////
    21  # pipeline #
    22  ////////////
    23  
    24  ## pure byte pipeline on Unix ##
    25  //only-on unix
    26  ~> echo "Albert\nAllan\nAlbraham\nBerlin" | sed s/l/1/g | grep e
    27  A1bert
    28  Ber1in
    29  
    30  ## pure byte pipeline on Windows ##
    31  //only-on windows
    32  ~> echo "Albert\nAllan\nAlbraham\nBerlin" | findstr e
    33  Albert
    34  Berlin
    35  
    36  ## pure value pipeline ##
    37  ~> put 233 42 19 | each {|x|+ $x 10}
    38  ▶ (num 243)
    39  ▶ (num 52)
    40  ▶ (num 29)
    41  
    42  ## pipeline draining ##
    43  ~> range 100 | put x
    44  ▶ x
    45  
    46  // TODO: Add a useful hybrid pipeline sample
    47  
    48  ## reader gone ##
    49  // Internal commands writing to byte output raises ReaderGone when the reader has
    50  // exited, which is then suppressed by the pipeline.
    51  ~> while $true { echo y } | nop
    52  ~> var reached = $false
    53     { while $true { echo y }; reached = $true } | nop
    54     put $reached
    55  ▶ $false
    56  // Similar for value output.
    57  ~> while $true { put y } | nop
    58  ~> var reached = $false
    59     { while $true { put y }; reached = $true } | nop
    60     put $reached
    61  ▶ $false
    62  
    63  ## reader gone from SIGPIPE ##
    64  //only-on unix
    65  // External commands terminated by SIGPIPE due to reader exiting early raise
    66  // ReaderGone, which is then suppressed by the pipeline.
    67  ~> yes | true
    68  ~> var reached = $false
    69     { yes; reached = $true } | true
    70     put $reached
    71  ▶ $false
    72  
    73  ///////////////////////
    74  # background pipeline #
    75  ///////////////////////
    76  
    77  //each:eval use file
    78  
    79  ## basic behavior ##
    80  ~> set notify-bg-job-success = $false
    81     var p = (file:pipe)
    82     { print foo > $p; file:close $p[w] }&
    83     slurp < $p; file:close $p[r]
    84  ▶ foo
    85  
    86  ## notification ##
    87  //recv-bg-job-notification-in-global
    88  ~> set notify-bg-job-success = $true
    89     var p = (file:pipe)
    90     fn f { file:close $p[w] }
    91     f &
    92     slurp < $p; file:close $p[r]
    93     recv-bg-job-notification
    94  ▶ ''
    95  ▶ 'job f & finished'
    96  
    97  ## notification with exception ##
    98  //recv-bg-job-notification-in-global
    99  ~> set notify-bg-job-success = $true
   100     var p = (file:pipe)
   101     fn f { file:close $p[w]; fail foo }
   102     f &
   103     slurp < $p; file:close $p[r]
   104     recv-bg-job-notification
   105  ▶ ''
   106  ▶ 'job f & finished, errors = foo'
   107  
   108  ///////////
   109  # command #
   110  ///////////
   111  
   112  ~> put foo
   113  ▶ foo
   114  
   115  ## error conditions ##
   116  // head is not a single value
   117  ~> {put put} foo
   118  Exception: arity mismatch: command must be 1 value, but is 2 values
   119    [tty]:1:1-9: {put put} foo
   120  // head is not callable or string containing slash
   121  ~> [] foo
   122  Exception: bad value: command must be callable or string containing slash, but is []
   123    [tty]:1:1-2: [] foo
   124  // argument throws
   125  ~> put [][1]
   126  Exception: out of range: index must be from 0 to -1, but is 1
   127    [tty]:1:5-9: put [][1]
   128  // option key is not string
   129  ~> put &[]=[]
   130  Exception: bad value: option key must be string, but is list
   131    [tty]:1:1-10: put &[]=[]
   132  // option evaluation throws
   133  ~> put &x=[][1]
   134  Exception: out of range: index must be from 0 to -1, but is 1
   135    [tty]:1:8-12: put &x=[][1]
   136  
   137  ## regression test for b.elv.sh/1204 ##
   138  // Ensure that the arguments of special forms are not accidentally compiled
   139  // twice.
   140  ~> nop (and (use builtin))
   141     nop $builtin:echo~
   142  
   143  /////////////////////////////
   144  # external command as value #
   145  /////////////////////////////
   146  ~> kind-of (external true)
   147  ▶ fn
   148  ~> repr (external true)
   149  <external true>
   150  ~> put [&(external true)=$true][(external true)]
   151  ▶ $true
   152  
   153  ////////////////////////////////
   154  # external commands invocation #
   155  ////////////////////////////////
   156  
   157  ## common behavior ##
   158  // Doesn't support options
   159  ~> (external foo) &option
   160  Exception: external commands don't accept elvish options
   161    [tty]:1:1-22: (external foo) &option
   162  
   163  ## external command from PATH ##
   164  //in-temp-dir
   165  //unset-env PATH
   166  ~> use os
   167     os:mkdir bin
   168     to-lines ['#!/bin/sh' 'echo hello'] > bin/say-hello
   169     os:chmod 0o700 bin/say-hello
   170     to-lines ['@echo hello'] > bin/say-hello.bat
   171     set paths = [$pwd/bin]
   172  ~> say-hello
   173  hello
   174  // Explicit e:
   175  ~> e:say-hello
   176  hello
   177  // Dynamic string does not work for finding external commands from PATH
   178  ~> var x = say-hello
   179     $x
   180  Exception: bad value: command must be callable or string containing slash, but is say-hello
   181    [tty]:2:1-2: $x
   182  // Command searching is affected by the unknown-command pragma
   183  ~> { pragma unknown-command = disallow; say-hello }
   184  Compilation error: unknown command disallowed by current pragma
   185    [tty]:1:38-46: { pragma unknown-command = disallow; say-hello }
   186  ~> { pragma unknown-command = disallow; { say-hello } }
   187  Compilation error: unknown command disallowed by current pragma
   188    [tty]:1:40-48: { pragma unknown-command = disallow; { say-hello } }
   189  ~> { pragma unknown-command = external; say-hello }
   190  hello
   191  // But explicit e: is always allowed
   192  ~> { pragma unknown-command = disallow; e:say-hello }
   193  hello
   194  
   195  ## external command relative to working directory ##
   196  //in-temp-dir
   197  ~> use os
   198     fn make-echo-script {|name msg|
   199       to-lines ['#!/bin/sh' 'echo '$msg] > $name
   200       os:chmod 0o700 $name
   201       to-lines ['@echo '$msg] > $name.bat
   202     }
   203     make-echo-script say-hello hello
   204     os:mkdir lorem
   205     make-echo-script lorem/ipsum 'lorem ipsum'
   206  ~> ./say-hello
   207  hello
   208  ~> ./lorem/ipsum
   209  lorem ipsum
   210  ~> lorem/ipsum
   211  lorem ipsum
   212  // Explicit e:
   213  ~> e:./say-hello
   214  hello
   215  ~> e:./lorem/ipsum
   216  lorem ipsum
   217  ~> e:lorem/ipsum
   218  lorem ipsum
   219  // Dynamic string
   220  ~> var x = ./say-hello
   221     $x
   222  hello
   223  ~> var x = ./lorem/ipsum
   224     $x
   225  lorem ipsum
   226  ~> var x = lorem/ipsum
   227     $x
   228  lorem ipsum
   229  // Relative external commands are not affected by the unknown-command pragma
   230  ~> { pragma unknown-command = disallow; ./say-hello }
   231  hello
   232  ~> { pragma unknown-command = disallow; lorem/ipsum }
   233  lorem ipsum
   234  ~> { pragma unknown-command = disallow; var x = ./say-hello; $x }
   235  hello
   236  
   237  ## non-existent command on Unix ##
   238  //only-on unix
   239  //unset-env PATH
   240  ~> set paths = []
   241  ~> nonexistent-command
   242  Exception: exec: "nonexistent-command": executable file not found in $PATH
   243    [tty]:1:1-19: nonexistent-command
   244  
   245  ## non-existent command on Windows ##
   246  //only-on windows
   247  //unset-env PATH
   248  ~> set paths = []
   249  ~> nonexistent-command
   250  Exception: exec: "nonexistent-command": executable file not found in %PATH%
   251    [tty]:1:1-19: nonexistent-command
   252  
   253  ///////////////
   254  # implicit cd #
   255  ///////////////
   256  
   257  //in-temp-dir
   258  //with-deprecation-level 21
   259  ~> use os
   260     use path
   261     os:mkdir new-dir
   262     var old-pwd = $pwd
   263  ~> ./new-dir
   264  Deprecation: implicit cd is deprecated; use cd or location mode instead
   265    [tty]:1:1-9: ./new-dir
   266  ~> eq $pwd (path:join $old-pwd new-dir)
   267  ▶ $true
   268  
   269  //////////////////////////////////////
   270  # legacy temporary assignment syntax #
   271  //////////////////////////////////////
   272  
   273  ~> var a b = alice bob; {a,@b}=(put amy ben) put $a $@b; put $a $b
   274  ▶ amy
   275  ▶ ben
   276  ▶ alice
   277  ▶ bob
   278  Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead
   279    [tty]:1:22-41: var a b = alice bob; {a,@b}=(put amy ben) put $a $@b; put $a $b
   280  
   281  ## temporary assignment of list element ##
   282  ~> var l = [a]; l[0]=x put $l[0]; put $l[0]
   283  ▶ x
   284  ▶ a
   285  Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead
   286    [tty]:1:14-19: var l = [a]; l[0]=x put $l[0]; put $l[0]
   287  
   288  ## temporary assignment of map element ##
   289  ~> var m = [&k=v]; m[k]=v2 put $m[k]; put $m[k]
   290  ▶ v2
   291  ▶ v
   292  Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead
   293    [tty]:1:17-23: var m = [&k=v]; m[k]=v2 put $m[k]; put $m[k]
   294  
   295  ## temporary assignment before special form ##
   296  ~> li=[foo bar] for x $li { put $x }
   297  ▶ foo
   298  ▶ bar
   299  Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead
   300    [tty]:1:1-12: li=[foo bar] for x $li { put $x }
   301  
   302  ## multiple LHSs in temporary assignments. ##
   303  ~> {a b}={foo bar} put $a $b
   304  ▶ foo
   305  ▶ bar
   306  Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead
   307    [tty]:1:1-15: {a b}={foo bar} put $a $b
   308  
   309  ## rest variable ##
   310  ~> @a=(put a b) put $@a
   311  ▶ a
   312  ▶ b
   313  Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead
   314    [tty]:1:1-12: @a=(put a b) put $@a
   315  
   316  ## non-rest and rest variable ##
   317  ~> {a,@b}=(put a b c) put $@b
   318  ▶ b
   319  ▶ c
   320  Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead
   321    [tty]:1:1-18: {a,@b}=(put a b c) put $@b
   322  
   323  ## using syntax of temporary assignment for non-temporary assignment no longer compiles ##
   324  ~> x=y
   325  Compilation error: using the syntax of temporary assignment for non-temporary assignment is no longer supported; use "var" or "set" instead
   326    [tty]:1:1-3: x=y
   327  
   328  ///////////////
   329  # redirection #
   330  ///////////////
   331  
   332  //each:in-temp-dir
   333  
   334  ## output and input redirection ##
   335  ~> echo 233 > out1
   336     slurp < out1
   337  ▶ "233\n"
   338  
   339  ## append ##
   340  ~> echo 1 > out; echo 2 >> out; slurp < out
   341  ▶ "1\n2\n"
   342  
   343  ## read and write ##
   344  // TODO: Add a meaningful use case that actually uses both read and write.
   345  ~> echo 233 <> out1
   346     slurp < out1
   347  ▶ "233\n"
   348  
   349  ## redirections from special form ##
   350  ~> for x [lorem ipsum] { echo $x } > out2
   351     slurp < out2
   352  ▶ "lorem\nipsum\n"
   353  
   354  ## using numeric FDs as source and destination ##
   355  ~> { echo foobar >&2 } 2> out3
   356     slurp < out3
   357  ▶ "foobar\n"
   358  
   359  ## using named FDs as source and destination ##
   360  ~> echo 233 stdout> out1
   361     slurp stdin< out1
   362  ▶ "233\n"
   363  
   364  ## using named FDs (stderr) as source and destination ##
   365  ~> { echo foobar >&stderr } stderr> out4
   366     slurp < out4
   367  ▶ "foobar\n"
   368  
   369  ## using a new FD as source throws an exception ##
   370  ~> echo foo >&4
   371  Exception: invalid fd: 4
   372    [tty]:1:10-12: echo foo >&4
   373  
   374  ## using a new FD as destination is OK, and makes it available ##
   375  ~> { echo foo >&4 } 4>out5
   376     slurp < out5
   377  ▶ "foo\n"
   378  
   379  ## using a new FD for external command is OK ##
   380  // Regression test against b.elv.sh/788.
   381  //only-on unix
   382  // TODO: Enable for Windows too.
   383  ~> /bin/sh -c 'echo ok' 5</dev/null
   384  ok
   385  
   386  ## redirections from file objects ##
   387  ~> use file
   388     echo haha > out3
   389     var f = (file:open out3)
   390     slurp <$f
   391     file:close $f
   392  ▶ "haha\n"
   393  
   394  ## redirections from pipe objects ##
   395  ~> use file
   396     var p = (file:pipe)
   397     echo haha > $p
   398     file:close $p[w]
   399     slurp < $p
   400     file:close $p[r]
   401  ▶ "haha\n"
   402  
   403  ## regression test for b.elv.sh/1010 ##
   404  // Don't hang when iterating over input from a file.
   405  ~> echo abc > bytes
   406     each $echo~ < bytes
   407  abc
   408  ~> echo def > bytes
   409     only-values < bytes | count
   410  ▶ (num 0)
   411  
   412  ## writing value output to file throws an exception ##
   413  ~> put foo >a
   414  Exception: port does not support value output
   415    [tty]:1:1-10: put foo >a
   416  
   417  ## writing value output to closed port throws an exception ##
   418  ~> put foo >&-
   419  Exception: port does not support value output
   420    [tty]:1:1-11: put foo >&-
   421  
   422  ## invalid redirection destination ##
   423  ~> echo []> test
   424  Exception: bad value: redirection destination must be fd name or number, but is []
   425    [tty]:1:6-7: echo []> test
   426  
   427  ## invalid fd redirection source ##
   428  ~> echo >&test
   429  Exception: bad value: redirection source must be fd name or number or '-', but is test
   430    [tty]:1:8-11: echo >&test
   431  
   432  ## invalid redirection source ##
   433  ~> echo > []
   434  Exception: bad value: redirection source must be string, file or map, but is list
   435    [tty]:1:8-9: echo > []
   436  
   437  ## invalid map for redirection ##
   438  ~> echo < [&]
   439  Exception: bad value: map for input redirection must be map with file in the 'r' field, but is [&]
   440    [tty]:1:8-10: echo < [&]
   441  ~> echo > [&]
   442  Exception: bad value: map for output redirection must be map with file in the 'w' field, but is [&]
   443    [tty]:1:8-10: echo > [&]
   444  
   445  ## exception when evaluating source or destination ##
   446  ~> echo > (fail foo)
   447  Exception: foo
   448    [tty]:1:9-16: echo > (fail foo)
   449  ~> echo (fail foo)> file
   450  Exception: foo
   451    [tty]:1:7-14: echo (fail foo)> file
   452  
   453  ////////////////
   454  # stack traces #
   455  ////////////////
   456  
   457  // Stack traces of increasing depths.
   458  ~> fail oops
   459  Exception: oops
   460    [tty]:1:1-9: fail oops
   461  ~> fn f { fail oops }
   462     f
   463  Exception: oops
   464    [tty]:1:8-17: fn f { fail oops }
   465    [tty]:2:1-1: f
   466  ~> fn f { fail oops }
   467     fn g { f }
   468     g
   469  Exception: oops
   470    [tty]:1:8-17: fn f { fail oops }
   471    [tty]:2:8-9: fn g { f }
   472    [tty]:3:1-1: g
   473  // Error thrown before execution.
   474  ~> fn f { }
   475     f a
   476  Exception: arity mismatch: arguments must be 0 values, but is 1 value
   477    [tty]:2:1-3: f a
   478  // Error from builtin.
   479  ~> count 1 2 3
   480  Exception: arity mismatch: arguments must be 0 to 1 values, but is 3 values
   481    [tty]:1:1-11: count 1 2 3