elvish/eval/eval_test.go

167 lines
4.5 KiB
Go
Raw Normal View History

package eval
import (
"reflect"
"strconv"
2014-01-29 21:17:04 +08:00
"syscall"
"testing"
2014-10-30 03:50:10 +08:00
"github.com/elves/elvish/parse"
)
func TestNewEvaluator(t *testing.T) {
ev := NewEvaluator(nil, "")
pid := strconv.Itoa(syscall.Getpid())
if toString(ev.builtin["pid"].Get()) != pid {
t.Errorf(`ev.builtin["pid"] = %v, want %v`, ev.builtin["pid"], pid)
}
}
func mustParse(name, text string) *parse.Chunk {
n, e := parse.Parse(name, text)
if e != nil {
panic("parser error")
}
return n
}
func stringValues(ss ...string) []Value {
vs := make([]Value, len(ss))
for i, s := range ss {
2015-01-27 02:05:07 +08:00
vs[i] = str(s)
}
return vs
}
var evalTests = []struct {
2014-09-26 05:43:52 +08:00
text string
wanted []Value
wantError bool
}{
2014-09-25 06:08:37 +08:00
// Empty chunk
2014-09-26 05:43:52 +08:00
{"", []Value{}, false},
2014-09-25 06:08:37 +08:00
// Trivial command
2014-09-26 05:43:52 +08:00
{"put 233 lorem ipsum", stringValues("233", "lorem", "ipsum"), false},
2014-09-25 06:08:37 +08:00
// Byte Pipeline
{`echo "Albert\nAllan\nAlbraham\nBerlin" | sed s/l/1/g | grep e | feedchan`,
2014-09-26 05:43:52 +08:00
stringValues("A1bert", "Ber1in"), false},
2014-09-25 06:08:37 +08:00
// Arithmetics
// TODO test more edge cases
2014-09-26 05:43:52 +08:00
{"* 353 661", stringValues("233333"), false},
{"+ 233100 233", stringValues("233333"), false},
{"- 233333 233100", stringValues("233"), false},
{"/ 233333 353", stringValues("661"), false},
{"/ 1 0", stringValues("+Inf"), false},
2014-09-25 06:08:37 +08:00
// String literal
2014-09-26 05:43:52 +08:00
{"put `such \\\"``literal`", stringValues("such \\\"`literal"), false},
2014-09-25 06:08:37 +08:00
{`put "much \n\033[31;1m$cool\033[m"`,
2014-09-26 05:43:52 +08:00
stringValues("much \n\033[31;1m$cool\033[m"), false},
2014-09-25 06:08:37 +08:00
// Compounding list primaries
2014-09-26 05:47:27 +08:00
{"put {fi elvi}sh{1 2}",
stringValues("fish1", "fish2", "elvish1", "elvish2"), false},
2014-09-25 06:08:37 +08:00
// Table and subscript
{"println [a b c &key value] | feedchan",
2014-09-26 05:43:52 +08:00
stringValues("[a b c &key value]"), false},
{"put [a b c &key value][2]", stringValues("c"), false},
{"put [a b c &key value][key]", stringValues("value"), false},
2014-09-25 06:08:37 +08:00
// Variable and compounding
{"var $x string = `SHELL`\nput `WOW, SUCH `$x`, MUCH COOL`\n",
2014-09-26 05:43:52 +08:00
stringValues("WOW, SUCH SHELL, MUCH COOL"), false},
2014-09-25 06:18:37 +08:00
2014-09-26 05:26:56 +08:00
// var and set
{"var $x $y string = SUCH VAR; put $x $y",
2014-09-26 05:47:27 +08:00
stringValues("SUCH", "VAR"), false},
{"var $x $y string; set $x $y = SUCH SET; put $x $y",
2014-09-26 05:43:52 +08:00
stringValues("SUCH", "SET"), false},
{"var $x", stringValues(), false},
{"var $x string $y", stringValues(), false},
2015-01-20 05:19:13 +08:00
{"var $x table; set $x = [lorem ipsum]; put $x[1]",
stringValues("ipsum"), false},
2014-09-26 05:26:56 +08:00
2015-01-21 04:33:01 +08:00
// Channel capture
{"put (put lorem ipsum)", stringValues("lorem", "ipsum"), false},
2014-09-25 06:18:37 +08:00
// Status capture
2014-09-26 05:47:27 +08:00
{"put ?(true|false|false)",
[]Value{success, newFailure("1"), newFailure("1")}, false},
// Closure evaluation
{"{ }", stringValues(), false},
{"{|$x| put $x} foo", stringValues("foo"), false},
// Variable enclosure
{"var $x = lorem; { put $x; set $x = ipsum }; put $x",
stringValues("lorem", "ipsum"), false},
2015-01-21 05:20:56 +08:00
// Shadowing
{"var $x = ipsum; { var $x = lorem; put $x }; put $x",
stringValues("lorem", "ipsum"), false},
// Shadowing by argument
{"var $x = ipsum; { |$x| put $x; set $x = BAD } lorem; put $x",
stringValues("lorem", "ipsum"), false},
// fn
{"fn f $x { put $x ipsum }; f lorem",
stringValues("lorem", "ipsum"), false},
// if
{"if $true { put x }", stringValues("x"), false},
{"if $true $false { put x } else if $true { put y }",
stringValues("y"), false},
{"if $true $false { put x } else if $false { put y } else { put z }",
stringValues("z"), false},
// Namespaces
// Pseudo-namespaces local: and up:
{"var $true = lorem; { var $true = ipsum; put $up:true $local:true $builtin:true }",
2015-01-27 02:05:07 +08:00
[]Value{str("lorem"), str("ipsum"), boolean(true)}, false},
{"var $x = lorem; { set $up:x = ipsum }; put $x",
stringValues("ipsum"), false},
// Pseudo-namespace env:
{"set $env:foo = lorem; put $env:foo", stringValues("lorem"), false},
{"del $env:foo; put $env:foo", stringValues(""), false},
}
func TestEval(t *testing.T) {
name := "<eval test>"
for _, tt := range evalTests {
n := mustParse(name, tt.text)
ev := NewEvaluator(nil, ".")
out := make(chan Value, len(tt.wanted))
outs := []Value{}
exhausted := make(chan struct{})
go func() {
for v := range out {
outs = append(outs, v)
}
exhausted <- struct{}{}
}()
2014-09-25 06:18:37 +08:00
ev.ports[1].ch = out
e := ev.Eval(name, tt.text, ".", n)
close(out)
<-exhausted
2014-09-26 05:43:52 +08:00
if tt.wantError {
// Test for error, ignore output
if e == nil {
t.Errorf("ev.Eval(*, %q, *) => <nil>, want non-nil", tt.text)
}
} else {
// Test for output
if e != nil {
t.Errorf("ev.Eval(*, %q, *) => %v, want <nil>", tt.text, e)
}
if !reflect.DeepEqual(outs, tt.wanted) {
t.Errorf("Evalling %q outputs %v, want %v", tt.text, outs, tt.wanted)
}
}
}
}