1
0

state_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. package lua
  2. import (
  3. "golang.org/x/net/context"
  4. "strings"
  5. "testing"
  6. "time"
  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. func TestSkipOpenLibs(t *testing.T) {
  27. L := NewState(Options{SkipOpenLibs: true})
  28. defer L.Close()
  29. errorIfScriptNotFail(t, L, `print("")`,
  30. "attempt to call a non-function object")
  31. L2 := NewState()
  32. defer L2.Close()
  33. errorIfScriptFail(t, L2, `print("")`)
  34. }
  35. func TestGetAndReplace(t *testing.T) {
  36. L := NewState()
  37. defer L.Close()
  38. L.Push(LString("a"))
  39. L.Replace(1, LString("b"))
  40. L.Replace(0, LString("c"))
  41. errorIfNotEqual(t, LNil, L.Get(0))
  42. errorIfNotEqual(t, LNil, L.Get(-10))
  43. errorIfNotEqual(t, L.Env, L.Get(EnvironIndex))
  44. errorIfNotEqual(t, LString("b"), L.Get(1))
  45. L.Push(LString("c"))
  46. L.Push(LString("d"))
  47. L.Replace(-2, LString("e"))
  48. errorIfNotEqual(t, LString("e"), L.Get(-2))
  49. registry := L.NewTable()
  50. L.Replace(RegistryIndex, registry)
  51. L.G.Registry = registry
  52. errorIfGFuncNotFail(t, L, func(L *LState) int {
  53. L.Replace(RegistryIndex, LNil)
  54. return 0
  55. }, "registry must be a table")
  56. errorIfGFuncFail(t, L, func(L *LState) int {
  57. env := L.NewTable()
  58. L.Replace(EnvironIndex, env)
  59. errorIfNotEqual(t, env, L.Get(EnvironIndex))
  60. return 0
  61. })
  62. errorIfGFuncNotFail(t, L, func(L *LState) int {
  63. L.Replace(EnvironIndex, LNil)
  64. return 0
  65. }, "environment must be a table")
  66. errorIfGFuncFail(t, L, func(L *LState) int {
  67. gbl := L.NewTable()
  68. L.Replace(GlobalsIndex, gbl)
  69. errorIfNotEqual(t, gbl, L.G.Global)
  70. return 0
  71. })
  72. errorIfGFuncNotFail(t, L, func(L *LState) int {
  73. L.Replace(GlobalsIndex, LNil)
  74. return 0
  75. }, "_G must be a table")
  76. L2 := NewState()
  77. defer L2.Close()
  78. clo := L2.NewClosure(func(L2 *LState) int {
  79. L2.Replace(UpvalueIndex(1), LNumber(3))
  80. errorIfNotEqual(t, LNumber(3), L2.Get(UpvalueIndex(1)))
  81. return 0
  82. }, LNumber(1), LNumber(2))
  83. L2.SetGlobal("clo", clo)
  84. errorIfScriptFail(t, L2, `clo()`)
  85. }
  86. func TestRemove(t *testing.T) {
  87. L := NewState()
  88. defer L.Close()
  89. L.Push(LString("a"))
  90. L.Push(LString("b"))
  91. L.Push(LString("c"))
  92. L.Remove(4)
  93. errorIfNotEqual(t, LString("a"), L.Get(1))
  94. errorIfNotEqual(t, LString("b"), L.Get(2))
  95. errorIfNotEqual(t, LString("c"), L.Get(3))
  96. errorIfNotEqual(t, 3, L.GetTop())
  97. L.Remove(3)
  98. errorIfNotEqual(t, LString("a"), L.Get(1))
  99. errorIfNotEqual(t, LString("b"), L.Get(2))
  100. errorIfNotEqual(t, LNil, L.Get(3))
  101. errorIfNotEqual(t, 2, L.GetTop())
  102. L.Push(LString("c"))
  103. L.Remove(-10)
  104. errorIfNotEqual(t, LString("a"), L.Get(1))
  105. errorIfNotEqual(t, LString("b"), L.Get(2))
  106. errorIfNotEqual(t, LString("c"), L.Get(3))
  107. errorIfNotEqual(t, 3, L.GetTop())
  108. L.Remove(2)
  109. errorIfNotEqual(t, LString("a"), L.Get(1))
  110. errorIfNotEqual(t, LString("c"), L.Get(2))
  111. errorIfNotEqual(t, LNil, L.Get(3))
  112. errorIfNotEqual(t, 2, L.GetTop())
  113. }
  114. func TestToInt(t *testing.T) {
  115. L := NewState()
  116. defer L.Close()
  117. L.Push(LNumber(10))
  118. L.Push(LString("99.9"))
  119. L.Push(L.NewTable())
  120. errorIfNotEqual(t, 10, L.ToInt(1))
  121. errorIfNotEqual(t, 99, L.ToInt(2))
  122. errorIfNotEqual(t, 0, L.ToInt(3))
  123. }
  124. func TestToInt64(t *testing.T) {
  125. L := NewState()
  126. defer L.Close()
  127. L.Push(LNumber(10))
  128. L.Push(LString("99.9"))
  129. L.Push(L.NewTable())
  130. errorIfNotEqual(t, int64(10), L.ToInt64(1))
  131. errorIfNotEqual(t, int64(99), L.ToInt64(2))
  132. errorIfNotEqual(t, int64(0), L.ToInt64(3))
  133. }
  134. func TestToNumber(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, LNumber(10), L.ToNumber(1))
  141. errorIfNotEqual(t, LNumber(99.9), L.ToNumber(2))
  142. errorIfNotEqual(t, LNumber(0), L.ToNumber(3))
  143. }
  144. func TestToString(t *testing.T) {
  145. L := NewState()
  146. defer L.Close()
  147. L.Push(LNumber(10))
  148. L.Push(LString("99.9"))
  149. L.Push(L.NewTable())
  150. errorIfNotEqual(t, "10", L.ToString(1))
  151. errorIfNotEqual(t, "99.9", L.ToString(2))
  152. errorIfNotEqual(t, "", L.ToString(3))
  153. }
  154. func TestToTable(t *testing.T) {
  155. L := NewState()
  156. defer L.Close()
  157. L.Push(LNumber(10))
  158. L.Push(LString("99.9"))
  159. L.Push(L.NewTable())
  160. errorIfFalse(t, L.ToTable(1) == nil, "index 1 must be nil")
  161. errorIfFalse(t, L.ToTable(2) == nil, "index 2 must be nil")
  162. errorIfNotEqual(t, L.Get(3), L.ToTable(3))
  163. }
  164. func TestToFunction(t *testing.T) {
  165. L := NewState()
  166. defer L.Close()
  167. L.Push(LNumber(10))
  168. L.Push(LString("99.9"))
  169. L.Push(L.NewFunction(func(L *LState) int { return 0 }))
  170. errorIfFalse(t, L.ToFunction(1) == nil, "index 1 must be nil")
  171. errorIfFalse(t, L.ToFunction(2) == nil, "index 2 must be nil")
  172. errorIfNotEqual(t, L.Get(3), L.ToFunction(3))
  173. }
  174. func TestToUserData(t *testing.T) {
  175. L := NewState()
  176. defer L.Close()
  177. L.Push(LNumber(10))
  178. L.Push(LString("99.9"))
  179. L.Push(L.NewUserData())
  180. errorIfFalse(t, L.ToUserData(1) == nil, "index 1 must be nil")
  181. errorIfFalse(t, L.ToUserData(2) == nil, "index 2 must be nil")
  182. errorIfNotEqual(t, L.Get(3), L.ToUserData(3))
  183. }
  184. func TestToChannel(t *testing.T) {
  185. L := NewState()
  186. defer L.Close()
  187. L.Push(LNumber(10))
  188. L.Push(LString("99.9"))
  189. var ch chan LValue
  190. L.Push(LChannel(ch))
  191. errorIfFalse(t, L.ToChannel(1) == nil, "index 1 must be nil")
  192. errorIfFalse(t, L.ToChannel(2) == nil, "index 2 must be nil")
  193. errorIfNotEqual(t, ch, L.ToChannel(3))
  194. }
  195. func TestObjLen(t *testing.T) {
  196. L := NewState()
  197. defer L.Close()
  198. errorIfNotEqual(t, 3, L.ObjLen(LString("abc")))
  199. tbl := L.NewTable()
  200. tbl.Append(LTrue)
  201. tbl.Append(LTrue)
  202. errorIfNotEqual(t, 2, L.ObjLen(tbl))
  203. mt := L.NewTable()
  204. L.SetField(mt, "__len", L.NewFunction(func(L *LState) int {
  205. tbl := L.CheckTable(1)
  206. L.Push(LNumber(tbl.Len() + 1))
  207. return 1
  208. }))
  209. L.SetMetatable(tbl, mt)
  210. errorIfNotEqual(t, 3, L.ObjLen(tbl))
  211. errorIfNotEqual(t, 0, L.ObjLen(LNumber(10)))
  212. }
  213. func TestConcat(t *testing.T) {
  214. L := NewState()
  215. defer L.Close()
  216. errorIfNotEqual(t, "a1c", L.Concat(LString("a"), LNumber(1), LString("c")))
  217. }
  218. func TestPCall(t *testing.T) {
  219. L := NewState()
  220. defer L.Close()
  221. L.Register("f1", func(L *LState) int {
  222. panic("panic!")
  223. return 0
  224. })
  225. errorIfScriptNotFail(t, L, `f1()`, "panic!")
  226. L.Push(L.GetGlobal("f1"))
  227. err := L.PCall(0, 0, L.NewFunction(func(L *LState) int {
  228. L.Push(LString("by handler"))
  229. return 1
  230. }))
  231. errorIfFalse(t, strings.Contains(err.Error(), "by handler"), "")
  232. err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
  233. L.RaiseError("error!")
  234. return 1
  235. }))
  236. errorIfFalse(t, strings.Contains(err.Error(), "error!"), "")
  237. err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
  238. panic("panicc!")
  239. return 1
  240. }))
  241. errorIfFalse(t, strings.Contains(err.Error(), "panicc!"), "")
  242. }
  243. func TestCoroutineApi1(t *testing.T) {
  244. L := NewState()
  245. defer L.Close()
  246. co, _ := L.NewThread()
  247. errorIfScriptFail(t, L, `
  248. function coro(v)
  249. assert(v == 10)
  250. local ret1, ret2 = coroutine.yield(1,2,3)
  251. assert(ret1 == 11)
  252. assert(ret2 == 12)
  253. coroutine.yield(4)
  254. return 5
  255. end
  256. `)
  257. fn := L.GetGlobal("coro").(*LFunction)
  258. st, err, values := L.Resume(co, fn, LNumber(10))
  259. errorIfNotEqual(t, ResumeYield, st)
  260. errorIfNotNil(t, err)
  261. errorIfNotEqual(t, 3, len(values))
  262. errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
  263. errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
  264. errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
  265. st, err, values = L.Resume(co, fn, LNumber(11), LNumber(12))
  266. errorIfNotEqual(t, ResumeYield, st)
  267. errorIfNotNil(t, err)
  268. errorIfNotEqual(t, 1, len(values))
  269. errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
  270. st, err, values = L.Resume(co, fn)
  271. errorIfNotEqual(t, ResumeOK, st)
  272. errorIfNotNil(t, err)
  273. errorIfNotEqual(t, 1, len(values))
  274. errorIfNotEqual(t, LNumber(5), values[0].(LNumber))
  275. L.Register("myyield", func(L *LState) int {
  276. return L.Yield(L.ToNumber(1))
  277. })
  278. errorIfScriptFail(t, L, `
  279. function coro_error()
  280. coroutine.yield(1,2,3)
  281. myyield(4)
  282. assert(false, "--failed--")
  283. end
  284. `)
  285. fn = L.GetGlobal("coro_error").(*LFunction)
  286. co, _ = L.NewThread()
  287. st, err, values = L.Resume(co, fn)
  288. errorIfNotEqual(t, ResumeYield, st)
  289. errorIfNotNil(t, err)
  290. errorIfNotEqual(t, 3, len(values))
  291. errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
  292. errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
  293. errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
  294. st, err, values = L.Resume(co, fn)
  295. errorIfNotEqual(t, ResumeYield, st)
  296. errorIfNotNil(t, err)
  297. errorIfNotEqual(t, 1, len(values))
  298. errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
  299. st, err, values = L.Resume(co, fn)
  300. errorIfNotEqual(t, ResumeError, st)
  301. errorIfNil(t, err)
  302. errorIfFalse(t, strings.Contains(err.Error(), "--failed--"), "error message must be '--failed--'")
  303. st, err, values = L.Resume(co, fn)
  304. errorIfNotEqual(t, ResumeError, st)
  305. errorIfNil(t, err)
  306. errorIfFalse(t, strings.Contains(err.Error(), "can not resume a dead thread"), "can not resume a dead thread")
  307. }
  308. func TestContextTimeout(t *testing.T) {
  309. L := NewState()
  310. defer L.Close()
  311. ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
  312. defer cancel()
  313. L.SetContext(ctx)
  314. errorIfNotEqual(t, ctx, L.Context())
  315. err := L.DoString(`
  316. local clock = os.clock
  317. function sleep(n) -- seconds
  318. local t0 = clock()
  319. while clock() - t0 <= n do end
  320. end
  321. sleep(3)
  322. `)
  323. errorIfNil(t, err)
  324. errorIfFalse(t, strings.Contains(err.Error(), "context deadline exceeded"), "execution must be canceled")
  325. oldctx := L.RemoveContext()
  326. errorIfNotEqual(t, ctx, oldctx)
  327. errorIfNotNil(t, L.ctx)
  328. }
  329. func TestContextCancel(t *testing.T) {
  330. L := NewState()
  331. defer L.Close()
  332. ctx, cancel := context.WithCancel(context.Background())
  333. errch := make(chan error, 1)
  334. L.SetContext(ctx)
  335. go func() {
  336. errch <- L.DoString(`
  337. local clock = os.clock
  338. function sleep(n) -- seconds
  339. local t0 = clock()
  340. while clock() - t0 <= n do end
  341. end
  342. sleep(3)
  343. `)
  344. }()
  345. time.Sleep(1 * time.Second)
  346. cancel()
  347. err := <-errch
  348. errorIfNil(t, err)
  349. errorIfFalse(t, strings.Contains(err.Error(), "context canceled"), "execution must be canceled")
  350. }
  351. func TestContextWithCroutine(t *testing.T) {
  352. L := NewState()
  353. defer L.Close()
  354. ctx, cancel := context.WithCancel(context.Background())
  355. L.SetContext(ctx)
  356. defer cancel()
  357. L.DoString(`
  358. function coro()
  359. local i = 0
  360. while true do
  361. coroutine.yield(i)
  362. i = i+1
  363. end
  364. return i
  365. end
  366. `)
  367. co, cocancel := L.NewThread()
  368. defer cocancel()
  369. fn := L.GetGlobal("coro").(*LFunction)
  370. _, err, values := L.Resume(co, fn)
  371. errorIfNotNil(t, err)
  372. errorIfNotEqual(t, LNumber(0), values[0])
  373. // cancel the parent context
  374. cancel()
  375. _, err, values = L.Resume(co, fn)
  376. errorIfNil(t, err)
  377. errorIfFalse(t, strings.Contains(err.Error(), "context canceled"), "coroutine execution must be canceled when the parent context is canceled")
  378. }