script_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package lua
  2. import (
  3. "fmt"
  4. "os"
  5. "runtime"
  6. "sync/atomic"
  7. "testing"
  8. "time"
  9. "github.com/yuin/gopher-lua/parse"
  10. )
  11. const maxMemory = 40
  12. var gluaTests []string = []string{
  13. "base.lua",
  14. "coroutine.lua",
  15. "db.lua",
  16. "issues.lua",
  17. "os.lua",
  18. "table.lua",
  19. "vm.lua",
  20. "math.lua",
  21. "strings.lua",
  22. "goto.lua",
  23. }
  24. var luaTests []string = []string{
  25. "attrib.lua",
  26. "calls.lua",
  27. "closure.lua",
  28. "constructs.lua",
  29. "events.lua",
  30. "literals.lua",
  31. "locals.lua",
  32. "math.lua",
  33. "sort.lua",
  34. "strings.lua",
  35. "vararg.lua",
  36. "pm.lua",
  37. "files.lua",
  38. }
  39. func testScriptCompile(t *testing.T, script string) {
  40. file, err := os.Open(script)
  41. if err != nil {
  42. t.Fatal(err)
  43. return
  44. }
  45. chunk, err2 := parse.Parse(file, script)
  46. if err2 != nil {
  47. t.Fatal(err2)
  48. return
  49. }
  50. parse.Dump(chunk)
  51. proto, err3 := Compile(chunk, script)
  52. if err3 != nil {
  53. t.Fatal(err3)
  54. return
  55. }
  56. nop := func(s string) {}
  57. nop(proto.String())
  58. }
  59. func testScriptDir(t *testing.T, tests []string, directory string) {
  60. if err := os.Chdir(directory); err != nil {
  61. t.Error(err)
  62. }
  63. defer os.Chdir("..")
  64. for _, script := range tests {
  65. fmt.Printf("testing %s/%s\n", directory, script)
  66. testScriptCompile(t, script)
  67. L := NewState(Options{
  68. RegistrySize: 1024 * 20,
  69. CallStackSize: 1024,
  70. IncludeGoStackTrace: true,
  71. })
  72. L.SetMx(maxMemory)
  73. if err := L.DoFile(script); err != nil {
  74. t.Error(err)
  75. }
  76. L.Close()
  77. }
  78. }
  79. var numActiveUserDatas int32 = 0
  80. type finalizerStub struct{ x byte }
  81. func allocFinalizerUserData(L *LState) int {
  82. ud := L.NewUserData()
  83. atomic.AddInt32(&numActiveUserDatas, 1)
  84. a := finalizerStub{}
  85. ud.Value = &a
  86. runtime.SetFinalizer(&a, func(aa *finalizerStub) {
  87. atomic.AddInt32(&numActiveUserDatas, -1)
  88. })
  89. L.Push(ud)
  90. return 1
  91. }
  92. func sleep(L *LState) int {
  93. time.Sleep(time.Duration(L.CheckInt(1)) * time.Millisecond)
  94. return 0
  95. }
  96. func countFinalizers(L *LState) int {
  97. L.Push(LNumber(numActiveUserDatas))
  98. return 1
  99. }
  100. // TestLocalVarFree verifies that tables and user user datas which are no longer referenced by the lua script are
  101. // correctly gc-ed. There was a bug in gopher lua where local vars were not being gc-ed in all circumstances.
  102. func TestLocalVarFree(t *testing.T) {
  103. s := `
  104. function Test(a, b, c)
  105. local a = { v = allocFinalizer() }
  106. local b = { v = allocFinalizer() }
  107. return a
  108. end
  109. Test(1,2,3)
  110. for i = 1, 100 do
  111. collectgarbage()
  112. if countFinalizers() == 0 then
  113. return
  114. end
  115. sleep(100)
  116. end
  117. error("user datas not finalized after 100 gcs")
  118. `
  119. L := NewState()
  120. L.SetGlobal("allocFinalizer", L.NewFunction(allocFinalizerUserData))
  121. L.SetGlobal("sleep", L.NewFunction(sleep))
  122. L.SetGlobal("countFinalizers", L.NewFunction(countFinalizers))
  123. defer L.Close()
  124. if err := L.DoString(s); err != nil {
  125. t.Error(err)
  126. }
  127. }
  128. func TestGlua(t *testing.T) {
  129. testScriptDir(t, gluaTests, "_glua-tests")
  130. }
  131. func TestLua(t *testing.T) {
  132. testScriptDir(t, luaTests, "_lua5.1-tests")
  133. }