github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/eval/compile_effect_test.go (about) 1 package eval_test 2 3 import ( 4 "testing" 5 6 . "src.elv.sh/pkg/eval" 7 "src.elv.sh/pkg/eval/errs" 8 . "src.elv.sh/pkg/eval/evaltest" 9 "src.elv.sh/pkg/eval/vals" 10 "src.elv.sh/pkg/testutil" 11 ) 12 13 func TestChunk(t *testing.T) { 14 Test(t, 15 // Empty chunk 16 That("").DoesNothing(), 17 // Outputs of pipelines in a chunk are concatenated 18 That("put x; put y; put z").Puts("x", "y", "z"), 19 // A failed pipeline cause the whole chunk to fail 20 That("put a; e:false; put b").Puts("a").Throws(AnyError), 21 ) 22 } 23 24 func TestPipeline(t *testing.T) { 25 Test(t, 26 // Pure byte pipeline 27 That(`echo "Albert\nAllan\nAlbraham\nBerlin" | sed s/l/1/g | grep e`). 28 Prints("A1bert\nBer1in\n"), 29 // Pure value pipeline 30 That(`put 233 42 19 | each [x]{+ $x 10}`).Puts(243, 52, 29), 31 // Pipeline draining. 32 That(`range 100 | put x`).Puts("x"), 33 // Background pipeline. 34 That( 35 "notify-bg-job-success = $false", 36 "p = (pipe)", 37 "{ print foo > $p; pwclose $p }&", 38 "slurp < $p", 39 "prclose $p").Puts("foo"), 40 // TODO: Add a useful hybrid pipeline sample 41 ) 42 } 43 44 func TestCommand(t *testing.T) { 45 Test(t, 46 That("put foo").Puts("foo"), 47 // Command errors when the head is not a single value. 48 That("{put put} foo").Throws( 49 errs.ArityMismatch{ 50 What: "command", ValidLow: 1, ValidHigh: 1, Actual: 2}, 51 "{put put}"), 52 // Command errors when the head is not callable or string containing slash. 53 That("[] foo").Throws( 54 errs.BadValue{ 55 What: "command", 56 Valid: "callable or string containing slash", 57 Actual: "list"}, 58 "[]"), 59 // Command errors when when argument errors. 60 That("put [][1]").Throws(ErrorWithType(errs.OutOfRange{}), "[][1]"), 61 // Command errors when an option key is not string. 62 That("put &[]=[]").Throws( 63 errs.BadValue{What: "option key", Valid: "string", Actual: "list"}, 64 "put &[]=[]"), 65 // Command errors when any optional evaluation errors. 66 That("put &x=[][1]").Throws(ErrorWithType(errs.OutOfRange{}), "[][1]"), 67 ) 68 } 69 70 func TestCommand_Special(t *testing.T) { 71 Test(t, 72 // Regression test for #1204; ensures that the arguments of special 73 // forms are not accidentally compiled twice. 74 That("nop (and (use builtin)); nop $builtin:echo~").DoesNothing(), 75 76 // Behavior of individual special commands are tested in 77 // builtin_special_test.go. 78 ) 79 } 80 81 func TestCommand_Assignment(t *testing.T) { 82 // NOTE: TestClosure has more tests for the interaction between assignment 83 // and variable scoping. 84 85 Test(t, 86 // Spacey assignment. 87 That("a = foo; put $a").Puts("foo"), 88 That("a b = foo bar; put $a $b").Puts("foo", "bar"), 89 That("a @b = 2 3 foo; put $a $b").Puts("2", vals.MakeList("3", "foo")), 90 That("a @b c = 1 2 3 4; put $a $b $c"). 91 Puts("1", vals.MakeList("2", "3"), "4"), 92 That("a @b c = 1 2; put $a $b $c").Puts("1", vals.EmptyList, "2"), 93 That("@a = ; put $a").Puts(vals.EmptyList), 94 95 // List element assignment 96 That("var li = [foo bar]; set li[0] = 233; put $@li").Puts("233", "bar"), 97 // Variable in list assignment must already be defined. Regression test 98 // for b.elv.sh/889. 99 That("set foobarlorem[0] = a").DoesNotCompile(), 100 // Map element assignment 101 That("var di = [&k=v]; set di[k] = lorem; set di[k2] = ipsum", 102 "put $di[k] $di[k2]").Puts("lorem", "ipsum"), 103 That("var d = [&a=[&b=v]]; put $d[a][b]; set d[a][b] = u; put $d[a][b]"). 104 Puts("v", "u"), 105 106 // Temporary assignment. 107 That("var a b = alice bob; {a,@b}=(put amy ben) put $a $@b; put $a $b"). 108 Puts("amy", "ben", "alice", "bob"), 109 // Temporary assignment of list element. 110 That("l = [a]; l[0]=x put $l[0]; put $l[0]").Puts("x", "a"), 111 // Temporary assignment of map element. 112 That("m = [&k=v]; m[k]=v2 put $m[k]; put $m[k]").Puts("v2", "v"), 113 // Temporary assignment before special form. 114 That("li=[foo bar] for x $li { put $x }").Puts("foo", "bar"), 115 // Multiple LHSs in temporary assignments. 116 That("{a b}={foo bar} put $a $b").Puts("foo", "bar"), 117 That("@a=(put a b) put $@a").Puts("a", "b"), 118 That("{a,@b}=(put a b c) put $@b").Puts("b", "c"), 119 // Spacey assignment with temporary assignment 120 That("x = 1; x=2 y = (+ 1 $x); put $x $y").Puts("1", 3), 121 // Using syntax of temporary assignment for non-temporary assignment no 122 // longer compiles 123 That("x=y").DoesNotCompile(), 124 125 // Concurrently creating a new variable and accessing existing variable. 126 // Run with "go test -race". 127 That("x = 1", "put $x | y = (all)").DoesNothing(), 128 That("nop (x = 1) | nop").DoesNothing(), 129 130 // Assignment errors when the RHS errors. 131 That("x = [][1]").Throws(ErrorWithType(errs.OutOfRange{}), "[][1]"), 132 // Assignment to read-only var is an error. 133 That("nil = 1").Throws(errs.SetReadOnlyVar{VarName: "nil"}, "nil"), 134 That("a true b = 1 2 3").Throws(errs.SetReadOnlyVar{VarName: "true"}, "true"), 135 That("@true = 1").Throws(errs.SetReadOnlyVar{VarName: "@true"}, "@true"), 136 // A readonly var as a target for the `except` clause should error. 137 That("try { fail reason } except nil { }").Throws(errs.SetReadOnlyVar{VarName: "nil"}, "nil"), 138 That("try { fail reason } except x { }").DoesNothing(), 139 // Evaluation of the assignability occurs at run-time so, if no exception is raised, this 140 // otherwise invalid use of `nil` is okay. 141 That("try { } except nil { }").DoesNothing(), 142 // Arity mismatch. 143 That("x = 1 2").Throws( 144 errs.ArityMismatch{ 145 What: "assignment right-hand-side", 146 ValidLow: 1, ValidHigh: 1, Actual: 2}, 147 "x = 1 2"), 148 That("x y = 1").Throws( 149 errs.ArityMismatch{ 150 What: "assignment right-hand-side", 151 ValidLow: 2, ValidHigh: 2, Actual: 1}, 152 "x y = 1"), 153 That("x y @z = 1").Throws( 154 errs.ArityMismatch{ 155 What: "assignment right-hand-side", 156 ValidLow: 2, ValidHigh: -1, Actual: 1}, 157 "x y @z = 1"), 158 159 // Trying to add a new name in a namespace throws an exception. 160 // Regression test for #1214. 161 That("ns: = (ns [&]); ns:a = b").Throws(NoSuchVariable("ns:a"), "ns:a = b"), 162 ) 163 } 164 165 func TestCommand_Redir(t *testing.T) { 166 _, cleanup := testutil.InTestDir() 167 defer cleanup() 168 169 Test(t, 170 // Output and input redirection. 171 That("echo 233 > out1", " slurp < out1").Puts("233\n"), 172 // Append. 173 That("echo 1 > out; echo 2 >> out; slurp < out").Puts("1\n2\n"), 174 175 // Redirections from special form. 176 That(`for x [lorem ipsum] { echo $x } > out2`, `slurp < out2`). 177 Puts("lorem\nipsum\n"), 178 179 // Using numeric FDs as source and destination. 180 That(`{ echo foobar >&2 } 2> out3`, `slurp < out3`). 181 Puts("foobar\n"), 182 // Using named FDs as source and destination. 183 That(`{ echo foobar >&stderr } stderr> out4`, `slurp < out4`). 184 Puts("foobar\n"), 185 // Using a new FD as source throws an exception. 186 That(`echo foo >&4`).Throws(AnyError), 187 // Using a new FD as destination is OK, and makes it available. 188 That(`{ echo foo >&4 } 4>out5`, `slurp < out5`).Puts("foo\n"), 189 190 // Redirections from File object. 191 That(`echo haha > out3`, `f = (fopen out3)`, `slurp <$f`, ` fclose $f`). 192 Puts("haha\n"), 193 // Redirections from Pipe object. 194 That(`p = (pipe); echo haha > $p; pwclose $p; slurp < $p; prclose $p`). 195 Puts("haha\n"), 196 197 // We can't read values from a file and shouldn't hang when iterating 198 // over input from a file. 199 // Regression test for https://src.elv.sh/issues/1010 200 That("echo abc > bytes", "each $echo~ < bytes").Prints("abc\n"), 201 That("echo def > bytes", "only-values < bytes | count").Puts(0), 202 203 // Invalid redirection destination. 204 That("echo []> test").Throws( 205 errs.BadValue{ 206 What: "redirection destination", 207 Valid: "fd name or number", Actual: "[]"}, 208 "[]"), 209 // Invalid fd redirection source. 210 That("echo >&test").Throws( 211 errs.BadValue{ 212 What: "redirection source", 213 Valid: "fd name or number or '-'", Actual: "test"}, 214 "test"), 215 // Invalid redirection source. 216 That("echo > []").Throws( 217 errs.BadValue{ 218 What: "redirection source", 219 Valid: "string, file or pipe", Actual: "list"}, 220 "[]"), 221 ) 222 } 223 224 func TestCommand_Stacktrace(t *testing.T) { 225 oops := ErrorWithMessage("oops") 226 Test(t, 227 // Stack traces. 228 That("fail oops").Throws(oops, "fail oops"), 229 That("fn f { fail oops }", "f").Throws(oops, "fail oops ", "f"), 230 That("fn f { fail oops }", "fn g { f }", "g").Throws( 231 oops, "fail oops ", "f ", "g"), 232 // Error thrown before execution. 233 That("fn f { }", "f a").Throws(ErrorWithType(errs.ArityMismatch{}), "f a"), 234 // Error from builtin. 235 That("count 1 2 3").Throws( 236 ErrorWithType(errs.ArityMismatch{}), "count 1 2 3"), 237 ) 238 }