elvish/pkg/eval/compile_effect_test.go
Qi Xiao f49cf9f80e pkg/eval: More tests, especially against error cases.
Also fix a bug in handling redirections from invalid types.

This addresses #944.
2020-03-31 04:58:42 +01:00

132 lines
4.4 KiB
Go

package eval
import (
"testing"
"github.com/elves/elvish/pkg/util"
)
func TestCompileEffect(t *testing.T) {
_, cleanup := util.InTestDir()
defer cleanup()
Test(t,
// Chunks
// ------
// Empty chunk
That("").DoesNothing(),
// Outputs of pipelines in a chunk are concatenated
That("put x; put y; put z").Puts("x", "y", "z"),
// A failed pipeline cause the whole chunk to fail
That("put a; e:false; put b").Puts("a").ThrowsAny(),
// Pipelines
// ---------
// Pure byte pipeline
That(`echo "Albert\nAllan\nAlbraham\nBerlin" | sed s/l/1/g | grep e`).
Prints("A1bert\nBer1in\n"),
// Pure channel pipeline
That(`put 233 42 19 | each [x]{+ $x 10}`).Puts(243.0, 52.0, 29.0),
// Pipeline draining.
That(`range 100 | put x`).Puts("x"),
// Background pipeline.
That(
"notify-bg-job-success = $false",
"p = (pipe)",
"{ print foo > $p; pwclose $p }&",
"slurp < $p",
"prclose $p").Puts("foo"),
// TODO: Add a useful hybrid pipeline sample
// Commands
// --------
That("put foo").Puts("foo"),
// Command errors when the head is not a single value.
That("{put put} foo").ThrowsMessage("head of command must be a single value; got 2 values"),
// Command errors when when argument errors.
That("put [][1]").ThrowsMessage("index out of range"),
// Command errors when any optional evaluation errors.
That("put &x=[][1]").ThrowsMessage("index out of range"),
// Assignments
// -----------
// Spacey assignment.
That("a @b = 2 3 foo; put $a $b[1]").Puts("2", "foo"),
// List element assignment
That("li=[foo bar]; li[0]=233; put $@li").Puts("233", "bar"),
// Variable in list assignment must already be defined. Regression test
// for b.elv.sh/889.
That("foobarlorem[0] = a").DoesNotCompile(),
// Map element assignment
That("di=[&k=v]; di[k]=lorem; di[k2]=ipsum; put $di[k] $di[k2]").
Puts("lorem", "ipsum"),
That("d=[&a=[&b=v]]; put $d[a][b]; d[a][b]=u; put $d[a][b]").
Puts("v", "u"),
// Multi-assignments.
That("{a,b}=(put a b); put $a $b").Puts("a", "b"),
That("@a=(put a b); put $@a").Puts("a", "b"),
That("{a,@b}=(put a b c); put $@b").Puts("b", "c"),
//That("di=[&]; di[a b]=(put a b); put $di[a] $di[b]").Puts("a", "b"),
// Temporary assignment.
That("a=alice b=bob; {a,@b}=(put amy ben) put $a $@b; put $a $b").
Puts("amy", "ben", "alice", "bob"),
// Temporary assignment of list element.
That("l = [a]; l[0]=x put $l[0]; put $l[0]").Puts("x", "a"),
// Temporary assignment of map element.
That("m = [&k=v]; m[k]=v2 put $m[k]; put $m[k]").Puts("v2", "v"),
// Temporary assignment before special form.
That("li=[foo bar] for x $li { put $x }").Puts("foo", "bar"),
// Spacey assignment with temporary assignment
That("x = 1; x=2 y = (+ 1 $x); put $x $y").Puts("1", 3.0),
// Concurrently creating a new variable and accessing existing variable.
// Run with "go test -race".
That("x = 1", "put $x | y = (all)").DoesNothing(),
// Assignment errors when the RHS errors.
That("x = [][1]").ThrowsMessage("index out of range"),
// Arity mismatch.
That("x = 1 2").Throws(ErrArityMismatch),
That("x y = 1").Throws(ErrArityMismatch),
That("x y @z = 1").Throws(ErrArityMismatch),
// Redirections
// ------------
// Output and input redirection.
That("echo 233 > out1", " slurp < out1").Puts("233\n"),
// Append.
That("echo 1 > out; echo 2 >> out; slurp < out").Puts("1\n2\n"),
// Redirections from special form.
That(`for x [lorem ipsum] { echo $x } > out2`, `slurp < out2`).
Puts("lorem\nipsum\n"),
// Using numeric FDs as source and destination.
That(`{ echo foobar >&2 } 2> out3`, `slurp < out3`).
Puts("foobar\n"),
// Using named FDs as source and destination.
That(`{ echo foobar >&stderr } stderr> out4`, `slurp < out4`).
Puts("foobar\n"),
// Using a new FD as source throws an exception.
That(`echo foo >&4`).ThrowsAny(),
// Using a new FD as destination is OK, and makes it available.
That(`{ echo foo >&4 } 4>out5`, `slurp < out5`).Puts("foo\n"),
// Redirections from File object.
That(`echo haha > out3`, `f = (fopen out3)`, `slurp <$f`, ` fclose $f`).
Puts("haha\n"),
// Redirections from Pipe object.
That(`p = (pipe); echo haha > $p; pwclose $p; slurp < $p; prclose $p`).
Puts("haha\n"),
// Using anything else in redirection throws an exception.
That("echo > []").ThrowsMessage("redirection source must be string, file or pipe; got list"),
)
}