github.com/xmx/lua@v0.0.0-20230324063450-8a298e091302/script_test.go (about)

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