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 }