178 lines
4 KiB
Go
178 lines
4 KiB
Go
package script_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/d5/tengo/assert"
|
|
"github.com/d5/tengo/script"
|
|
)
|
|
|
|
type M map[string]interface{}
|
|
|
|
func TestCompiled_Get(t *testing.T) {
|
|
// simple script
|
|
c := compile(t, `a := 5`, nil)
|
|
compiledRun(t, c)
|
|
compiledGet(t, c, "a", int64(5))
|
|
|
|
// user-defined variables
|
|
compileError(t, `a := b`, nil) // compile error because "b" is not defined
|
|
c = compile(t, `a := b`, M{"b": "foo"}) // now compile with b = "foo" defined
|
|
compiledGet(t, c, "a", nil) // a = undefined; because it's before Compiled.Run()
|
|
compiledRun(t, c) // Compiled.Run()
|
|
compiledGet(t, c, "a", "foo") // a = "foo"
|
|
}
|
|
|
|
func TestCompiled_GetAll(t *testing.T) {
|
|
c := compile(t, `a := 5`, nil)
|
|
compiledRun(t, c)
|
|
compiledGetAll(t, c, M{"a": int64(5)})
|
|
|
|
c = compile(t, `a := b`, M{"b": "foo"})
|
|
compiledRun(t, c)
|
|
compiledGetAll(t, c, M{"a": "foo", "b": "foo"})
|
|
|
|
c = compile(t, `a := b; b = 5`, M{"b": "foo"})
|
|
compiledRun(t, c)
|
|
compiledGetAll(t, c, M{"a": "foo", "b": int64(5)})
|
|
}
|
|
|
|
func TestCompiled_IsDefined(t *testing.T) {
|
|
c := compile(t, `a := 5`, nil)
|
|
compiledIsDefined(t, c, "a", false) // a is not defined before Run()
|
|
compiledRun(t, c)
|
|
compiledIsDefined(t, c, "a", true)
|
|
compiledIsDefined(t, c, "b", false)
|
|
}
|
|
|
|
func TestCompiled_Set(t *testing.T) {
|
|
c := compile(t, `a := b`, M{"b": "foo"})
|
|
compiledRun(t, c)
|
|
compiledGet(t, c, "a", "foo")
|
|
|
|
// replace value of 'b'
|
|
err := c.Set("b", "bar")
|
|
assert.NoError(t, err)
|
|
compiledRun(t, c)
|
|
compiledGet(t, c, "a", "bar")
|
|
|
|
// try to replace undefined variable
|
|
err = c.Set("c", 1984)
|
|
assert.Error(t, err) // 'c' is not defined
|
|
|
|
// case #2
|
|
c = compile(t, `
|
|
a := func() {
|
|
return func() {
|
|
return b + 5
|
|
}()
|
|
}()`, M{"b": 5})
|
|
compiledRun(t, c)
|
|
compiledGet(t, c, "a", int64(10))
|
|
err = c.Set("b", 10)
|
|
assert.NoError(t, err)
|
|
compiledRun(t, c)
|
|
compiledGet(t, c, "a", int64(15))
|
|
}
|
|
|
|
func TestCompiled_RunContext(t *testing.T) {
|
|
// machine completes normally
|
|
c := compile(t, `a := 5`, nil)
|
|
err := c.RunContext(context.Background())
|
|
assert.NoError(t, err)
|
|
compiledGet(t, c, "a", int64(5))
|
|
|
|
// cancelled
|
|
c = compile(t, `for true {}`, nil)
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
go func() {
|
|
time.Sleep(1 * time.Millisecond)
|
|
cancel()
|
|
}()
|
|
err = c.RunContext(ctx)
|
|
assert.Equal(t, context.Canceled, err)
|
|
|
|
// timeout
|
|
c = compile(t, `for true {}`, nil)
|
|
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Millisecond)
|
|
defer cancel()
|
|
err = c.RunContext(ctx)
|
|
assert.Equal(t, context.DeadlineExceeded, err)
|
|
}
|
|
|
|
func compile(t *testing.T, input string, vars M) *script.Compiled {
|
|
s := script.New([]byte(input))
|
|
for vn, vv := range vars {
|
|
err := s.Add(vn, vv)
|
|
if !assert.NoError(t, err) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
c, err := s.Compile()
|
|
if !assert.NoError(t, err) || !assert.NotNil(t, c) {
|
|
return nil
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
func compileError(t *testing.T, input string, vars M) bool {
|
|
s := script.New([]byte(input))
|
|
for vn, vv := range vars {
|
|
err := s.Add(vn, vv)
|
|
if !assert.NoError(t, err) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
_, err := s.Compile()
|
|
|
|
return assert.Error(t, err)
|
|
}
|
|
|
|
func compiledRun(t *testing.T, c *script.Compiled) bool {
|
|
err := c.Run()
|
|
|
|
return assert.NoError(t, err)
|
|
}
|
|
|
|
func compiledGet(t *testing.T, c *script.Compiled, name string, expected interface{}) bool {
|
|
v := c.Get(name)
|
|
if !assert.NotNil(t, v) {
|
|
return false
|
|
}
|
|
|
|
return assert.Equal(t, expected, v.Value())
|
|
}
|
|
|
|
func compiledGetAll(t *testing.T, c *script.Compiled, expected M) bool {
|
|
vars := c.GetAll()
|
|
|
|
if !assert.Equal(t, len(expected), len(vars)) {
|
|
return false
|
|
}
|
|
|
|
for k, v := range expected {
|
|
var found bool
|
|
for _, e := range vars {
|
|
if e.Name() == k {
|
|
if !assert.Equal(t, v, e.Value()) {
|
|
return false
|
|
}
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
assert.Fail(t, "variable '%s' not found", k)
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func compiledIsDefined(t *testing.T, c *script.Compiled, name string, expected bool) bool {
|
|
return assert.Equal(t, expected, c.IsDefined(name))
|
|
}
|