scream/vendor/src/github.com/yuin/gopher-lua/state_test.go

336 lines
8.7 KiB
Go

package lua
import (
"strings"
"testing"
)
func TestCallStackOverflow(t *testing.T) {
L := NewState(Options{
CallStackSize: 3,
})
defer L.Close()
errorIfScriptNotFail(t, L, `
local function a()
end
local function b()
a()
end
local function c()
print(_printregs())
b()
end
c()
`, "stack overflow")
}
func TestSkipOpenLibs(t *testing.T) {
L := NewState(Options{SkipOpenLibs: true})
defer L.Close()
errorIfScriptNotFail(t, L, `print("")`,
"attempt to call a non-function object")
L2 := NewState()
defer L2.Close()
errorIfScriptFail(t, L2, `print("")`)
}
func TestGetAndReplace(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LString("a"))
L.Replace(1, LString("b"))
L.Replace(0, LString("c"))
errorIfNotEqual(t, LNil, L.Get(0))
errorIfNotEqual(t, LNil, L.Get(-10))
errorIfNotEqual(t, L.Env, L.Get(EnvironIndex))
errorIfNotEqual(t, LString("b"), L.Get(1))
L.Push(LString("c"))
L.Push(LString("d"))
L.Replace(-2, LString("e"))
errorIfNotEqual(t, LString("e"), L.Get(-2))
registry := L.NewTable()
L.Replace(RegistryIndex, registry)
L.G.Registry = registry
errorIfGFuncNotFail(t, L, func(L *LState) int {
L.Replace(RegistryIndex, LNil)
return 0
}, "registry must be a table")
errorIfGFuncFail(t, L, func(L *LState) int {
env := L.NewTable()
L.Replace(EnvironIndex, env)
errorIfNotEqual(t, env, L.Get(EnvironIndex))
return 0
})
errorIfGFuncNotFail(t, L, func(L *LState) int {
L.Replace(EnvironIndex, LNil)
return 0
}, "environment must be a table")
errorIfGFuncFail(t, L, func(L *LState) int {
gbl := L.NewTable()
L.Replace(GlobalsIndex, gbl)
errorIfNotEqual(t, gbl, L.G.Global)
return 0
})
errorIfGFuncNotFail(t, L, func(L *LState) int {
L.Replace(GlobalsIndex, LNil)
return 0
}, "_G must be a table")
L2 := NewState()
defer L2.Close()
clo := L2.NewClosure(func(L2 *LState) int {
L2.Replace(UpvalueIndex(1), LNumber(3))
errorIfNotEqual(t, LNumber(3), L2.Get(UpvalueIndex(1)))
return 0
}, LNumber(1), LNumber(2))
L2.SetGlobal("clo", clo)
errorIfScriptFail(t, L2, `clo()`)
}
func TestRemove(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LString("a"))
L.Push(LString("b"))
L.Push(LString("c"))
L.Remove(4)
errorIfNotEqual(t, LString("a"), L.Get(1))
errorIfNotEqual(t, LString("b"), L.Get(2))
errorIfNotEqual(t, LString("c"), L.Get(3))
errorIfNotEqual(t, 3, L.GetTop())
L.Remove(3)
errorIfNotEqual(t, LString("a"), L.Get(1))
errorIfNotEqual(t, LString("b"), L.Get(2))
errorIfNotEqual(t, LNil, L.Get(3))
errorIfNotEqual(t, 2, L.GetTop())
L.Push(LString("c"))
L.Remove(-10)
errorIfNotEqual(t, LString("a"), L.Get(1))
errorIfNotEqual(t, LString("b"), L.Get(2))
errorIfNotEqual(t, LString("c"), L.Get(3))
errorIfNotEqual(t, 3, L.GetTop())
L.Remove(2)
errorIfNotEqual(t, LString("a"), L.Get(1))
errorIfNotEqual(t, LString("c"), L.Get(2))
errorIfNotEqual(t, LNil, L.Get(3))
errorIfNotEqual(t, 2, L.GetTop())
}
func TestToInt(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LNumber(10))
L.Push(LString("99.9"))
L.Push(L.NewTable())
errorIfNotEqual(t, 10, L.ToInt(1))
errorIfNotEqual(t, 99, L.ToInt(2))
errorIfNotEqual(t, 0, L.ToInt(3))
}
func TestToInt64(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LNumber(10))
L.Push(LString("99.9"))
L.Push(L.NewTable())
errorIfNotEqual(t, int64(10), L.ToInt64(1))
errorIfNotEqual(t, int64(99), L.ToInt64(2))
errorIfNotEqual(t, int64(0), L.ToInt64(3))
}
func TestToNumber(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LNumber(10))
L.Push(LString("99.9"))
L.Push(L.NewTable())
errorIfNotEqual(t, LNumber(10), L.ToNumber(1))
errorIfNotEqual(t, LNumber(99.9), L.ToNumber(2))
errorIfNotEqual(t, LNumber(0), L.ToNumber(3))
}
func TestToString(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LNumber(10))
L.Push(LString("99.9"))
L.Push(L.NewTable())
errorIfNotEqual(t, "10", L.ToString(1))
errorIfNotEqual(t, "99.9", L.ToString(2))
errorIfNotEqual(t, "", L.ToString(3))
}
func TestToTable(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LNumber(10))
L.Push(LString("99.9"))
L.Push(L.NewTable())
errorIfFalse(t, L.ToTable(1) == nil, "index 1 must be nil")
errorIfFalse(t, L.ToTable(2) == nil, "index 2 must be nil")
errorIfNotEqual(t, L.Get(3), L.ToTable(3))
}
func TestToFunction(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LNumber(10))
L.Push(LString("99.9"))
L.Push(L.NewFunction(func(L *LState) int { return 0 }))
errorIfFalse(t, L.ToFunction(1) == nil, "index 1 must be nil")
errorIfFalse(t, L.ToFunction(2) == nil, "index 2 must be nil")
errorIfNotEqual(t, L.Get(3), L.ToFunction(3))
}
func TestToUserData(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LNumber(10))
L.Push(LString("99.9"))
L.Push(L.NewUserData())
errorIfFalse(t, L.ToUserData(1) == nil, "index 1 must be nil")
errorIfFalse(t, L.ToUserData(2) == nil, "index 2 must be nil")
errorIfNotEqual(t, L.Get(3), L.ToUserData(3))
}
func TestToChannel(t *testing.T) {
L := NewState()
defer L.Close()
L.Push(LNumber(10))
L.Push(LString("99.9"))
var ch chan LValue
L.Push(LChannel(ch))
errorIfFalse(t, L.ToChannel(1) == nil, "index 1 must be nil")
errorIfFalse(t, L.ToChannel(2) == nil, "index 2 must be nil")
errorIfNotEqual(t, ch, L.ToChannel(3))
}
func TestObjLen(t *testing.T) {
L := NewState()
defer L.Close()
errorIfNotEqual(t, 3, L.ObjLen(LString("abc")))
tbl := L.NewTable()
tbl.Append(LTrue)
tbl.Append(LTrue)
errorIfNotEqual(t, 2, L.ObjLen(tbl))
mt := L.NewTable()
L.SetField(mt, "__len", L.NewFunction(func(L *LState) int {
tbl := L.CheckTable(1)
L.Push(LNumber(tbl.Len() + 1))
return 1
}))
L.SetMetatable(tbl, mt)
errorIfNotEqual(t, 3, L.ObjLen(tbl))
errorIfNotEqual(t, 0, L.ObjLen(LNumber(10)))
}
func TestConcat(t *testing.T) {
L := NewState()
defer L.Close()
errorIfNotEqual(t, "a1c", L.Concat(LString("a"), LNumber(1), LString("c")))
}
func TestPCall(t *testing.T) {
L := NewState()
defer L.Close()
L.Register("f1", func(L *LState) int {
panic("panic!")
return 0
})
errorIfScriptNotFail(t, L, `f1()`, "panic!")
L.Push(L.GetGlobal("f1"))
err := L.PCall(0, 0, L.NewFunction(func(L *LState) int {
L.Push(LString("by handler"))
return 1
}))
errorIfFalse(t, strings.Contains(err.Error(), "by handler"), "")
err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
L.RaiseError("error!")
return 1
}))
errorIfFalse(t, strings.Contains(err.Error(), "error!"), "")
err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
panic("panicc!")
return 1
}))
errorIfFalse(t, strings.Contains(err.Error(), "panicc!"), "")
}
func TestCoroutineApi1(t *testing.T) {
L := NewState()
defer L.Close()
co := L.NewThread()
errorIfScriptFail(t, L, `
function coro(v)
assert(v == 10)
local ret1, ret2 = coroutine.yield(1,2,3)
assert(ret1 == 11)
assert(ret2 == 12)
coroutine.yield(4)
return 5
end
`)
fn := L.GetGlobal("coro").(*LFunction)
st, err, values := L.Resume(co, fn, LNumber(10))
errorIfNotEqual(t, ResumeYield, st)
errorIfNotNil(t, err)
errorIfNotEqual(t, 3, len(values))
errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
st, err, values = L.Resume(co, fn, LNumber(11), LNumber(12))
errorIfNotEqual(t, ResumeYield, st)
errorIfNotNil(t, err)
errorIfNotEqual(t, 1, len(values))
errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
st, err, values = L.Resume(co, fn)
errorIfNotEqual(t, ResumeOK, st)
errorIfNotNil(t, err)
errorIfNotEqual(t, 1, len(values))
errorIfNotEqual(t, LNumber(5), values[0].(LNumber))
L.Register("myyield", func(L *LState) int {
return L.Yield(L.ToNumber(1))
})
errorIfScriptFail(t, L, `
function coro_error()
coroutine.yield(1,2,3)
myyield(4)
assert(false, "--failed--")
end
`)
fn = L.GetGlobal("coro_error").(*LFunction)
co = L.NewThread()
st, err, values = L.Resume(co, fn)
errorIfNotEqual(t, ResumeYield, st)
errorIfNotNil(t, err)
errorIfNotEqual(t, 3, len(values))
errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
st, err, values = L.Resume(co, fn)
errorIfNotEqual(t, ResumeYield, st)
errorIfNotNil(t, err)
errorIfNotEqual(t, 1, len(values))
errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
st, err, values = L.Resume(co, fn)
errorIfNotEqual(t, ResumeError, st)
errorIfNil(t, err)
errorIfFalse(t, strings.Contains(err.Error(), "--failed--"), "error message must be '--failed--'")
st, err, values = L.Resume(co, fn)
errorIfNotEqual(t, ResumeError, st)
errorIfNil(t, err)
errorIfFalse(t, strings.Contains(err.Error(), "can not resume a dead thread"), "can not resume a dead thread")
}