github.com/dfcfw/lua@v0.0.0-20230325031207-0cc7ffb7b8b9/luar/luar_test.go (about) 1 package luar 2 3 import ( 4 "reflect" 5 "strings" 6 "testing" 7 8 "github.com/dfcfw/lua" 9 ) 10 11 func Test_luar_complex128(t *testing.T) { 12 L := lua.NewState() 13 defer L.Close() 14 15 a := complex(float64(1), float64(2)) 16 17 L.SetGlobal("a", New(L, a)) 18 19 testReturn(t, L, `b = a`) 20 21 b := L.GetGlobal("b").(*lua.LUserData).Value.(complex128) 22 if a != b { 23 t.Fatalf("expected a = b, got %v", b) 24 } 25 } 26 27 type ChanAlias chan string 28 29 func (ChanAlias) Test() string { 30 return `I'm a "chan string" alias` 31 } 32 33 func (ChanAlias) hidden() { 34 } 35 36 type SliceAlias []string 37 38 func (s SliceAlias) Len() int { 39 return len(s) 40 } 41 42 func (s *SliceAlias) Append(v string) { 43 *s = append(*s, v) 44 } 45 46 type MapAlias map[string]int 47 48 func (m MapAlias) Y() int { 49 return len(m) 50 } 51 52 func Test_type_methods(t *testing.T) { 53 L := lua.NewState() 54 defer L.Close() 55 56 a := make(ChanAlias) 57 var b SliceAlias = []string{"Hello", "world"} 58 c := MapAlias{ 59 "x": 15, 60 } 61 62 L.SetGlobal("a", New(L, a)) 63 L.SetGlobal("b", New(L, &b)) 64 L.SetGlobal("c", New(L, c)) 65 66 testReturn(t, L, `return a:Test()`, `I'm a "chan string" alias`) 67 testReturn(t, L, `len1 = b:Len(); b:Append("!")`) 68 testReturn(t, L, `return len1, b:len()`, "2", "3") 69 testReturn(t, L, `return c.x, c:y()`, "15", "1") 70 } 71 72 func Test_comparisons(t *testing.T) { 73 L := lua.NewState() 74 defer L.Close() 75 76 { 77 s := make([]int, 10) 78 L.SetGlobal("s1", New(L, s)) 79 L.SetGlobal("sp1", New(L, &s)) 80 L.SetGlobal("s2", New(L, s)) 81 L.SetGlobal("sp2", New(L, &s)) 82 } 83 { 84 m := make(map[string]int, 10) 85 L.SetGlobal("m1", New(L, m)) 86 L.SetGlobal("mp1", New(L, &m)) 87 L.SetGlobal("m2", New(L, m)) 88 L.SetGlobal("mp2", New(L, &m)) 89 } 90 { 91 c := make(chan string) 92 L.SetGlobal("c1", New(L, c)) 93 L.SetGlobal("cp1", New(L, &c)) 94 L.SetGlobal("c2", New(L, c)) 95 96 c3 := make(chan string) 97 L.SetGlobal("c3", New(L, c3)) 98 } 99 { 100 s := "" 101 L.SetGlobal("sp1", New(L, &s)) 102 L.SetGlobal("sp2", New(L, &s)) 103 } 104 105 testReturn(t, L, `return s1 == s1`, "true") 106 testReturn(t, L, `return sp1 == sp2`, "true") 107 108 testReturn(t, L, `return m1 == m1`, "true") 109 testReturn(t, L, `return mp1 == mp2`, "true") 110 111 testReturn(t, L, `return c1 == c1`, "true") 112 testReturn(t, L, `return c1 == c3`, "false") 113 114 testReturn(t, L, `return sp1 == sp2`, "true") 115 } 116 117 type TestSliceConversion struct { 118 S []string 119 } 120 121 func Test_sliceconversion(t *testing.T) { 122 L := lua.NewState() 123 defer L.Close() 124 125 e := &TestSliceConversion{} 126 L.SetGlobal("e", New(L, e)) 127 128 testReturn(t, L, `e.S = {"a", "b", "", "c"}`) 129 130 valid := true 131 expecting := []string{"a", "b", "", "c"} 132 if len(e.S) != len(expecting) { 133 valid = false 134 } else { 135 for i, item := range e.S { 136 if item != expecting[i] { 137 valid = false 138 break 139 } 140 } 141 } 142 143 if !valid { 144 t.Fatalf("expecting %#v, got %#v", expecting, e.S) 145 } 146 } 147 148 type TestMapConversion struct { 149 S map[string]string 150 } 151 152 func Test_mapconversion(t *testing.T) { 153 L := lua.NewState() 154 defer L.Close() 155 156 e := &TestMapConversion{} 157 L.SetGlobal("e", New(L, e)) 158 159 testReturn(t, L, `e.S = {b = nil, c = "hello"}`) 160 161 valid := true 162 expecting := map[string]string{ 163 "c": "hello", 164 } 165 166 if len(e.S) != len(expecting) { 167 valid = false 168 } else { 169 for key, value := range e.S { 170 expected, ok := expecting[key] 171 if !ok || value != expected { 172 valid = false 173 break 174 } 175 } 176 } 177 178 if !valid { 179 t.Fatalf("expecting %#v, got %#v", expecting, e.S) 180 } 181 182 if _, ok := e.S["b"]; ok { 183 t.Fatal(`e.S["b"] should not be set`) 184 } 185 } 186 187 func Test_udconversion(t *testing.T) { 188 L := lua.NewState() 189 defer L.Close() 190 191 ud := L.NewUserData() 192 ud.Value = "hello world" 193 L.SetGlobal("ud", ud) 194 195 var out int 196 L.SetGlobal("out", New(L, &out)) 197 198 testError(t, L, `_ = out ^ ud`, "cannot use hello world (type string) as type int") 199 } 200 201 func Test_arrayconversion(t *testing.T) { 202 L := lua.NewState() 203 defer L.Close() 204 205 var arr [3]int 206 L.SetGlobal("arr", New(L, &arr)) 207 testReturn(t, L, `arr = arr ^ {10, 20, 11}; return arr[1], arr[2], arr[3]`, "10", "20", "11") 208 } 209 210 type TestInterfaceStruct struct{} 211 212 func Test_interface(t *testing.T) { 213 tbl := []struct { 214 Code string 215 Var func(L *lua.LState) lua.LValue 216 Expected interface{} 217 ExpectedType reflect.Type 218 }{ 219 { 220 Code: `nil`, 221 Expected: interface{}(nil), 222 }, 223 { 224 Code: `"Hello"`, 225 Expected: string("Hello"), 226 }, 227 { 228 Code: `true`, 229 Expected: bool(true), 230 }, 231 { 232 Code: `1`, 233 Expected: float64(1), 234 }, 235 { 236 Code: `function(a, b) end`, 237 ExpectedType: reflect.TypeOf(func(...interface{}) []interface{} { 238 return nil 239 }), 240 }, 241 { 242 Code: `{hello = "world", [123] = 321}`, 243 Expected: map[interface{}]interface{}{ 244 string("hello"): string("world"), 245 float64(123): float64(321), 246 }, 247 }, 248 { 249 Code: `var`, 250 Var: func(L *lua.LState) lua.LValue { 251 ud := L.NewUserData() 252 ud.Value = "Hello World" 253 return ud 254 }, 255 Expected: string("Hello World"), 256 }, 257 // TODO: LChannel 258 // TODO: *LState 259 } 260 261 for _, cur := range tbl { 262 func() { 263 L := lua.NewState() 264 defer L.Close() 265 266 var out interface{} = TestInterfaceStruct{} 267 L.SetGlobal("out", New(L, &out)) 268 269 if cur.Var != nil { 270 L.SetGlobal("var", cur.Var(L)) 271 } 272 273 if err := L.DoString(`_ = out ^ ` + cur.Code); err != nil { 274 t.Fatal(err) 275 } 276 277 if cur.ExpectedType != nil { 278 if reflect.TypeOf(out) != cur.ExpectedType { 279 t.Fatalf("expected conversion of %#v = type %s, got type %s\n", cur.Code, cur.ExpectedType, reflect.TypeOf(out)) 280 } 281 } else if !reflect.DeepEqual(out, cur.Expected) { 282 t.Fatalf("expected conversion of %#v = %#v (%T), got %#v (%T)\n", cur.Code, cur.Expected, cur.Expected, out, out) 283 } 284 }() 285 286 } 287 } 288 289 func Test_recursivetable(t *testing.T) { 290 L := lua.NewState() 291 defer L.Close() 292 293 var x interface{} 294 L.SetGlobal("x", New(L, &x)) 295 296 if err := L.DoString(`local tbl = {}; tbl.inner = tbl; _ = x ^ tbl`); err != nil { 297 t.Fatal(err) 298 } 299 } 300 301 func Test_tostringfallback(t *testing.T) { 302 L := lua.NewState() 303 defer L.Close() 304 305 type Struct struct { 306 } 307 var out string 308 309 L.SetGlobal("struct", New(L, &Struct{})) 310 L.SetGlobal("out", New(L, &out)) 311 if err := L.DoString(`_ = out ^ tostring(struct)`); err != nil { 312 t.Fatal(err) 313 } 314 315 if !strings.HasPrefix(out, "userdata: ") { 316 t.Fatalf("invalid tostring %#v\n", out) 317 } 318 }