github.com/erikdubbelboer/gopher-lua@v0.0.0-20160512044044-e68f0dc85040/state_test.go (about) 1 package lua 2 3 import ( 4 "strings" 5 "testing" 6 ) 7 8 func TestCallStackOverflow(t *testing.T) { 9 L := NewState(Options{ 10 CallStackSize: 3, 11 }) 12 defer L.Close() 13 errorIfScriptNotFail(t, L, ` 14 local function a() 15 end 16 local function b() 17 a() 18 end 19 local function c() 20 print(_printregs()) 21 b() 22 end 23 c() 24 `, "stack overflow") 25 } 26 27 func TestSkipOpenLibs(t *testing.T) { 28 L := NewState(Options{SkipOpenLibs: true}) 29 defer L.Close() 30 errorIfScriptNotFail(t, L, `print("")`, 31 "attempt to call a non-function object") 32 L2 := NewState() 33 defer L2.Close() 34 errorIfScriptFail(t, L2, `print("")`) 35 } 36 37 func TestGetAndReplace(t *testing.T) { 38 L := NewState() 39 defer L.Close() 40 L.Push(LString("a")) 41 L.Replace(1, LString("b")) 42 L.Replace(0, LString("c")) 43 errorIfNotEqual(t, LNil, L.Get(0)) 44 errorIfNotEqual(t, LNil, L.Get(-10)) 45 errorIfNotEqual(t, L.Env, L.Get(EnvironIndex)) 46 errorIfNotEqual(t, LString("b"), L.Get(1)) 47 L.Push(LString("c")) 48 L.Push(LString("d")) 49 L.Replace(-2, LString("e")) 50 errorIfNotEqual(t, LString("e"), L.Get(-2)) 51 registry := L.NewTable() 52 L.Replace(RegistryIndex, registry) 53 L.G.Registry = registry 54 errorIfGFuncNotFail(t, L, func(L *LState) int { 55 L.Replace(RegistryIndex, LNil) 56 return 0 57 }, "registry must be a table") 58 errorIfGFuncFail(t, L, func(L *LState) int { 59 env := L.NewTable() 60 L.Replace(EnvironIndex, env) 61 errorIfNotEqual(t, env, L.Get(EnvironIndex)) 62 return 0 63 }) 64 errorIfGFuncNotFail(t, L, func(L *LState) int { 65 L.Replace(EnvironIndex, LNil) 66 return 0 67 }, "environment must be a table") 68 errorIfGFuncFail(t, L, func(L *LState) int { 69 gbl := L.NewTable() 70 L.Replace(GlobalsIndex, gbl) 71 errorIfNotEqual(t, gbl, L.G.Global) 72 return 0 73 }) 74 errorIfGFuncNotFail(t, L, func(L *LState) int { 75 L.Replace(GlobalsIndex, LNil) 76 return 0 77 }, "_G must be a table") 78 79 L2 := NewState() 80 defer L2.Close() 81 clo := L2.NewClosure(func(L2 *LState) int { 82 L2.Replace(UpvalueIndex(1), LNumber(3)) 83 errorIfNotEqual(t, LNumber(3), L2.Get(UpvalueIndex(1))) 84 return 0 85 }, LNumber(1), LNumber(2)) 86 L2.SetGlobal("clo", clo) 87 errorIfScriptFail(t, L2, `clo()`) 88 } 89 90 func TestRemove(t *testing.T) { 91 L := NewState() 92 defer L.Close() 93 L.Push(LString("a")) 94 L.Push(LString("b")) 95 L.Push(LString("c")) 96 97 L.Remove(4) 98 errorIfNotEqual(t, LString("a"), L.Get(1)) 99 errorIfNotEqual(t, LString("b"), L.Get(2)) 100 errorIfNotEqual(t, LString("c"), L.Get(3)) 101 errorIfNotEqual(t, 3, L.GetTop()) 102 103 L.Remove(3) 104 errorIfNotEqual(t, LString("a"), L.Get(1)) 105 errorIfNotEqual(t, LString("b"), L.Get(2)) 106 errorIfNotEqual(t, LNil, L.Get(3)) 107 errorIfNotEqual(t, 2, L.GetTop()) 108 L.Push(LString("c")) 109 110 L.Remove(-10) 111 errorIfNotEqual(t, LString("a"), L.Get(1)) 112 errorIfNotEqual(t, LString("b"), L.Get(2)) 113 errorIfNotEqual(t, LString("c"), L.Get(3)) 114 errorIfNotEqual(t, 3, L.GetTop()) 115 116 L.Remove(2) 117 errorIfNotEqual(t, LString("a"), L.Get(1)) 118 errorIfNotEqual(t, LString("c"), L.Get(2)) 119 errorIfNotEqual(t, LNil, L.Get(3)) 120 errorIfNotEqual(t, 2, L.GetTop()) 121 } 122 123 func TestToInt(t *testing.T) { 124 L := NewState() 125 defer L.Close() 126 L.Push(LNumber(10)) 127 L.Push(LString("99.9")) 128 L.Push(L.NewTable()) 129 errorIfNotEqual(t, 10, L.ToInt(1)) 130 errorIfNotEqual(t, 99, L.ToInt(2)) 131 errorIfNotEqual(t, 0, L.ToInt(3)) 132 } 133 134 func TestToInt64(t *testing.T) { 135 L := NewState() 136 defer L.Close() 137 L.Push(LNumber(10)) 138 L.Push(LString("99.9")) 139 L.Push(L.NewTable()) 140 errorIfNotEqual(t, int64(10), L.ToInt64(1)) 141 errorIfNotEqual(t, int64(99), L.ToInt64(2)) 142 errorIfNotEqual(t, int64(0), L.ToInt64(3)) 143 } 144 145 func TestToNumber(t *testing.T) { 146 L := NewState() 147 defer L.Close() 148 L.Push(LNumber(10)) 149 L.Push(LString("99.9")) 150 L.Push(L.NewTable()) 151 errorIfNotEqual(t, LNumber(10), L.ToNumber(1)) 152 errorIfNotEqual(t, LNumber(99.9), L.ToNumber(2)) 153 errorIfNotEqual(t, LNumber(0), L.ToNumber(3)) 154 } 155 156 func TestToString(t *testing.T) { 157 L := NewState() 158 defer L.Close() 159 L.Push(LNumber(10)) 160 L.Push(LString("99.9")) 161 L.Push(L.NewTable()) 162 errorIfNotEqual(t, "10", L.ToString(1)) 163 errorIfNotEqual(t, "99.9", L.ToString(2)) 164 errorIfNotEqual(t, "", L.ToString(3)) 165 } 166 167 func TestToTable(t *testing.T) { 168 L := NewState() 169 defer L.Close() 170 L.Push(LNumber(10)) 171 L.Push(LString("99.9")) 172 L.Push(L.NewTable()) 173 errorIfFalse(t, L.ToTable(1) == nil, "index 1 must be nil") 174 errorIfFalse(t, L.ToTable(2) == nil, "index 2 must be nil") 175 errorIfNotEqual(t, L.Get(3), L.ToTable(3)) 176 } 177 178 func TestToFunction(t *testing.T) { 179 L := NewState() 180 defer L.Close() 181 L.Push(LNumber(10)) 182 L.Push(LString("99.9")) 183 L.Push(L.NewFunction(func(L *LState) int { return 0 })) 184 errorIfFalse(t, L.ToFunction(1) == nil, "index 1 must be nil") 185 errorIfFalse(t, L.ToFunction(2) == nil, "index 2 must be nil") 186 errorIfNotEqual(t, L.Get(3), L.ToFunction(3)) 187 } 188 189 func TestToUserData(t *testing.T) { 190 L := NewState() 191 defer L.Close() 192 L.Push(LNumber(10)) 193 L.Push(LString("99.9")) 194 L.Push(L.NewUserData()) 195 errorIfFalse(t, L.ToUserData(1) == nil, "index 1 must be nil") 196 errorIfFalse(t, L.ToUserData(2) == nil, "index 2 must be nil") 197 errorIfNotEqual(t, L.Get(3), L.ToUserData(3)) 198 } 199 200 func TestToChannel(t *testing.T) { 201 L := NewState() 202 defer L.Close() 203 L.Push(LNumber(10)) 204 L.Push(LString("99.9")) 205 var ch chan LValue 206 L.Push(LChannel(ch)) 207 errorIfFalse(t, L.ToChannel(1) == nil, "index 1 must be nil") 208 errorIfFalse(t, L.ToChannel(2) == nil, "index 2 must be nil") 209 errorIfNotEqual(t, ch, L.ToChannel(3)) 210 } 211 212 func TestObjLen(t *testing.T) { 213 L := NewState() 214 defer L.Close() 215 errorIfNotEqual(t, 3, L.ObjLen(LString("abc"))) 216 tbl := L.NewTable() 217 tbl.Append(LTrue) 218 tbl.Append(LTrue) 219 errorIfNotEqual(t, 2, L.ObjLen(tbl)) 220 mt := L.NewTable() 221 L.SetField(mt, "__len", L.NewFunction(func(L *LState) int { 222 tbl := L.CheckTable(1) 223 L.Push(LNumber(tbl.Len() + 1)) 224 return 1 225 })) 226 L.SetMetatable(tbl, mt) 227 errorIfNotEqual(t, 3, L.ObjLen(tbl)) 228 errorIfNotEqual(t, 0, L.ObjLen(LNumber(10))) 229 } 230 231 func TestConcat(t *testing.T) { 232 L := NewState() 233 defer L.Close() 234 errorIfNotEqual(t, "a1c", L.Concat(LString("a"), LNumber(1), LString("c"))) 235 } 236 237 func TestPCall(t *testing.T) { 238 L := NewState() 239 defer L.Close() 240 L.Register("f1", func(L *LState) int { 241 panic("panic!") 242 return 0 243 }) 244 errorIfScriptNotFail(t, L, `f1()`, "panic!") 245 L.Push(L.GetGlobal("f1")) 246 err := L.PCall(0, 0, L.NewFunction(func(L *LState) int { 247 L.Push(LString("by handler")) 248 return 1 249 })) 250 errorIfFalse(t, strings.Contains(err.Error(), "by handler"), "") 251 252 err = L.PCall(0, 0, L.NewFunction(func(L *LState) int { 253 L.RaiseError("error!") 254 return 1 255 })) 256 errorIfFalse(t, strings.Contains(err.Error(), "error!"), "") 257 258 err = L.PCall(0, 0, L.NewFunction(func(L *LState) int { 259 panic("panicc!") 260 return 1 261 })) 262 errorIfFalse(t, strings.Contains(err.Error(), "panicc!"), "") 263 } 264 265 func TestCoroutineApi1(t *testing.T) { 266 L := NewState() 267 defer L.Close() 268 co := L.NewThread() 269 errorIfScriptFail(t, L, ` 270 function coro(v) 271 assert(v == 10) 272 local ret1, ret2 = coroutine.yield(1,2,3) 273 assert(ret1 == 11) 274 assert(ret2 == 12) 275 coroutine.yield(4) 276 return 5 277 end 278 `) 279 fn := L.GetGlobal("coro").(*LFunction) 280 st, err, values := L.Resume(co, fn, LNumber(10)) 281 errorIfNotEqual(t, ResumeYield, st) 282 errorIfNotNil(t, err) 283 errorIfNotEqual(t, 3, len(values)) 284 errorIfNotEqual(t, LNumber(1), values[0].(LNumber)) 285 errorIfNotEqual(t, LNumber(2), values[1].(LNumber)) 286 errorIfNotEqual(t, LNumber(3), values[2].(LNumber)) 287 288 st, err, values = L.Resume(co, fn, LNumber(11), LNumber(12)) 289 errorIfNotEqual(t, ResumeYield, st) 290 errorIfNotNil(t, err) 291 errorIfNotEqual(t, 1, len(values)) 292 errorIfNotEqual(t, LNumber(4), values[0].(LNumber)) 293 294 st, err, values = L.Resume(co, fn) 295 errorIfNotEqual(t, ResumeOK, st) 296 errorIfNotNil(t, err) 297 errorIfNotEqual(t, 1, len(values)) 298 errorIfNotEqual(t, LNumber(5), values[0].(LNumber)) 299 300 L.Register("myyield", func(L *LState) int { 301 return L.Yield(L.ToNumber(1)) 302 }) 303 errorIfScriptFail(t, L, ` 304 function coro_error() 305 coroutine.yield(1,2,3) 306 myyield(4) 307 assert(false, "--failed--") 308 end 309 `) 310 fn = L.GetGlobal("coro_error").(*LFunction) 311 co = L.NewThread() 312 st, err, values = L.Resume(co, fn) 313 errorIfNotEqual(t, ResumeYield, st) 314 errorIfNotNil(t, err) 315 errorIfNotEqual(t, 3, len(values)) 316 errorIfNotEqual(t, LNumber(1), values[0].(LNumber)) 317 errorIfNotEqual(t, LNumber(2), values[1].(LNumber)) 318 errorIfNotEqual(t, LNumber(3), values[2].(LNumber)) 319 320 st, err, values = L.Resume(co, fn) 321 errorIfNotEqual(t, ResumeYield, st) 322 errorIfNotNil(t, err) 323 errorIfNotEqual(t, 1, len(values)) 324 errorIfNotEqual(t, LNumber(4), values[0].(LNumber)) 325 326 st, err, values = L.Resume(co, fn) 327 errorIfNotEqual(t, ResumeError, st) 328 errorIfNil(t, err) 329 errorIfFalse(t, strings.Contains(err.Error(), "--failed--"), "error message must be '--failed--'") 330 st, err, values = L.Resume(co, fn) 331 errorIfNotEqual(t, ResumeError, st) 332 errorIfNil(t, err) 333 errorIfFalse(t, strings.Contains(err.Error(), "can not resume a dead thread"), "can not resume a dead thread") 334 335 }