github.com/dfcfw/lua@v0.0.0-20230325031207-0cc7ffb7b8b9/luar/func_test.go (about)

     1  package luar
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/dfcfw/lua"
     8  )
     9  
    10  func Test_func_variableargs(t *testing.T) {
    11  	L := lua.NewState()
    12  	defer L.Close()
    13  
    14  	fn := func(str string, extra ...int) {
    15  		switch str {
    16  		case "a":
    17  			if len(extra) != 3 || extra[0] != 1 || extra[1] != 2 || extra[2] != 3 {
    18  				t.Fatalf("unexpected variable arguments: %v", extra)
    19  			}
    20  		case "b":
    21  			if len(extra) != 0 {
    22  				t.Fatalf("unexpected variable arguments: %v", extra)
    23  			}
    24  		case "c":
    25  			if len(extra) != 1 || extra[0] != 4 {
    26  				t.Fatalf("unexpected variable arguments: %v", extra)
    27  			}
    28  		}
    29  	}
    30  
    31  	L.SetGlobal("fn", New(L, fn))
    32  
    33  	testReturn(t, L, `return fn("a", 1, 2, 3)`)
    34  	testReturn(t, L, `return fn("b")`)
    35  	testReturn(t, L, `return fn("c", 4)`)
    36  }
    37  
    38  func Test_func_structarg(t *testing.T) {
    39  	L := lua.NewState()
    40  	defer L.Close()
    41  
    42  	tim := &StructTestPerson{
    43  		Name: "Tim",
    44  	}
    45  
    46  	fn := func(p *StructTestPerson) string {
    47  		return "Hello, " + p.Name
    48  	}
    49  
    50  	L.SetGlobal("person", New(L, tim))
    51  	L.SetGlobal("getHello", New(L, fn))
    52  
    53  	testReturn(t, L, `return getHello(person)`, "Hello, Tim")
    54  }
    55  
    56  func Test_func_nilreference(t *testing.T) {
    57  	L := lua.NewState()
    58  	defer L.Close()
    59  
    60  	var fn func()
    61  
    62  	L.SetGlobal("fn", New(L, fn))
    63  
    64  	testReturn(t, L, `return fn`, "nil")
    65  }
    66  
    67  func Test_func_arrayarg(t *testing.T) {
    68  	L := lua.NewState()
    69  	defer L.Close()
    70  
    71  	arr := [3]int{1, 2, 3}
    72  	fn := func(val [3]int) {
    73  		if val != arr {
    74  			t.Fatalf("expecting %v, got %v", arr, val)
    75  		}
    76  	}
    77  
    78  	L.SetGlobal("fn", New(L, fn))
    79  	L.SetGlobal("arr", New(L, arr))
    80  
    81  	testReturn(t, L, `return fn(arr)`)
    82  }
    83  
    84  func Test_func_luareturntype(t *testing.T) {
    85  	L := lua.NewState()
    86  	defer L.Close()
    87  
    88  	fn := func(x ...float64) *lua.LTable {
    89  		tbl := L.NewTable()
    90  		for i := len(x) - 1; i >= 0; i-- {
    91  			tbl.Insert(len(x)-i, lua.LNumber(x[i]))
    92  		}
    93  		return tbl
    94  	}
    95  
    96  	L.SetGlobal("fn", New(L, fn))
    97  
    98  	testReturn(
    99  		t,
   100  		L,
   101  		`
   102  		local t = {}
   103  		for _, x in ipairs(fn(1, 2, 3)) do
   104  			table.insert(t, x)
   105  		end
   106  		return t[1], t[2], t[3]`,
   107  		"3", "2", "1",
   108  	)
   109  
   110  	testReturn(
   111  		t,
   112  		L,
   113  		`
   114  		local t = {}
   115  		for _, x in ipairs(fn()) do
   116  			table.insert(t, x)
   117  		end
   118  		return t[1]`,
   119  		"nil",
   120  	)
   121  }
   122  
   123  type TestLuaFuncRef struct {
   124  	F1 *lua.LFunction
   125  }
   126  
   127  func Test_func_luafuncref(t *testing.T) {
   128  	L := lua.NewState()
   129  	defer L.Close()
   130  
   131  	e := &TestLuaFuncRef{}
   132  	L.SetGlobal("e", New(L, e))
   133  
   134  	testReturn(
   135  		t,
   136  		L,
   137  		`
   138  		e.F1 = function(str)
   139  			return "Hello World", 123
   140  		end
   141  		`,
   142  	)
   143  
   144  	L.Push(e.F1)
   145  	L.Call(0, 2)
   146  
   147  	if L.GetTop() != 2 || L.Get(1).String() != "Hello World" || L.Get(2).String() != "123" {
   148  		t.Fatal("incorrect return values")
   149  	}
   150  }
   151  
   152  type TestFuncCall struct {
   153  	Fn  func(a string) (string, int)
   154  	Fn2 func(a string, b ...int) string
   155  }
   156  
   157  func Test_func_luafunccall(t *testing.T) {
   158  	L := lua.NewState()
   159  	defer L.Close()
   160  
   161  	e := &TestFuncCall{}
   162  	L.SetGlobal("x", New(L, e))
   163  
   164  	testReturn(
   165  		t,
   166  		L,
   167  		`
   168  		i = 0
   169  		x.Fn = function(str)
   170  			i = i + 1
   171  			return ">" .. str .. "<", i
   172  		end
   173  
   174  		x.Fn2 = function(str, a, b, c)
   175  			if type(a) == "number" and type(b) == "number" and type(c) == "number" then
   176  				return str
   177  			end
   178  			return ""
   179  		end
   180  		`,
   181  	)
   182  
   183  	if str, i := e.Fn("A"); str != ">A<" || i != 1 {
   184  		t.Fatal("unexpected return values")
   185  	}
   186  
   187  	if str, i := e.Fn("B"); str != ">B<" || i != 2 {
   188  		t.Fatal("unexpected return values")
   189  	}
   190  
   191  	if val := e.Fn2("hello", 1, 2); val != "" {
   192  		t.Fatal("unexpected return value")
   193  	}
   194  
   195  	if val := e.Fn2("hello", 1, 2, 3); val != "hello" {
   196  		t.Fatal("unexpected return value")
   197  	}
   198  
   199  	if L.GetTop() != 0 {
   200  		t.Fatalf("expecting GetTop to return 0, got %d", L.GetTop())
   201  	}
   202  }
   203  
   204  func Test_func_argerror(t *testing.T) {
   205  	L := lua.NewState()
   206  	defer L.Close()
   207  
   208  	fn := func(v uint8) {
   209  	}
   210  
   211  	L.SetGlobal("fn", New(L, fn))
   212  
   213  	testError(t, L, `fn("hello world")`, "bad argument #1 to fn (cannot use hello world (type lua.LString) as type uint8)")
   214  }
   215  
   216  func Test_func_conversionstack(t *testing.T) {
   217  	L := lua.NewState()
   218  	defer L.Close()
   219  
   220  	var fn interface{}
   221  	L.SetGlobal("fn", New(L, &fn))
   222  	if err := L.DoString(`_ = fn ^ function() return "hello", true, 123 end`); err != nil {
   223  		t.Fatal(err)
   224  	}
   225  
   226  	callable, ok := fn.(func(...interface{}) []interface{})
   227  	if !ok {
   228  		t.Fatal("invalid function signature")
   229  	}
   230  	values := callable()
   231  
   232  	expected := []interface{}{
   233  		string("hello"),
   234  		bool(true),
   235  		float64(123),
   236  	}
   237  
   238  	if !reflect.DeepEqual(expected, values) {
   239  		t.Fatalf("expected return %#v, got %#v", expected, values)
   240  	}
   241  }