github.com/dfcfw/lua@v0.0.0-20230325031207-0cc7ffb7b8b9/luar/struct_test.go (about) 1 package luar 2 3 import ( 4 "testing" 5 6 "github.com/dfcfw/lua" 7 ) 8 9 func Test_struct(t *testing.T) { 10 L := lua.NewState() 11 defer L.Close() 12 13 tim := &StructTestPerson{ 14 Name: "Tim", 15 Age: 30, 16 } 17 18 john := StructTestPerson{ 19 Name: "John", 20 Age: 40, 21 } 22 23 L.SetGlobal("user1", New(L, tim)) 24 L.SetGlobal("user2", New(L, john)) 25 26 testReturn(t, L, `return user1.Name`, "Tim") 27 testReturn(t, L, `return user1.Age`, "30") 28 testReturn(t, L, `return user1:Hello()`, "Hello, Tim") 29 30 testReturn(t, L, `return user2.Name`, "John") 31 testReturn(t, L, `return user2.Age`, "40") 32 testReturn(t, L, `local hello = user2.Hello; return hello(user2)`, "Hello, John") 33 } 34 35 func Test_struct_tostring(t *testing.T) { 36 L := lua.NewState() 37 defer L.Close() 38 39 p1 := StructTestPerson{ 40 Name: "Tim", 41 Age: 99, 42 } 43 p2 := StructTestPerson{ 44 Name: "John", 45 Age: 2, 46 } 47 48 L.SetGlobal("p1", New(L, &p1)) 49 L.SetGlobal("p2", New(L, &p2)) 50 51 testReturn(t, L, `return tostring(p1)`, `Tim (99)`) 52 testReturn(t, L, `return tostring(p2)`, `John (2)`) 53 } 54 55 func Test_struct_pointers(t *testing.T) { 56 L := lua.NewState() 57 defer L.Close() 58 59 p1 := StructTestPerson{ 60 Name: "Tim", 61 } 62 p2 := StructTestPerson{ 63 Name: "John", 64 } 65 66 L.SetGlobal("p1", New(L, &p1)) 67 L.SetGlobal("p1_alias", New(L, &p1)) 68 L.SetGlobal("p2", New(L, &p2)) 69 70 testReturn(t, L, `return -p1 == -p1`, "true") 71 testReturn(t, L, `return -p1 == -p1_alias`, "true") 72 testReturn(t, L, `return p1 == p1`, "true") 73 testReturn(t, L, `return p1 == p1_alias`, "true") 74 testReturn(t, L, `return p1 == p2`, "false") 75 } 76 77 func Test_struct_lstate(t *testing.T) { 78 L := lua.NewState() 79 defer L.Close() 80 81 p := StructTestPerson{ 82 Name: "Tim", 83 } 84 85 L.SetGlobal("p", New(L, &p)) 86 87 testReturn(t, L, `return p:AddNumbers(1, 2, 3, 4, 5)`, "Tim counts: 15") 88 } 89 90 type StructTestHidden struct { 91 Name string `luar:"name"` 92 Name2 string `luar:"Name"` 93 Str string 94 Hidden bool `luar:"-"` 95 } 96 97 func Test_struct_hiddenfields(t *testing.T) { 98 L := lua.NewState() 99 defer L.Close() 100 101 a := &StructTestHidden{ 102 Name: "tim", 103 Name2: "bob", 104 Str: "asd123", 105 Hidden: true, 106 } 107 108 L.SetGlobal("a", New(L, a)) 109 110 testReturn(t, L, `return a.name`, "tim") 111 testReturn(t, L, `return a.Name`, "bob") 112 testReturn(t, L, `return a.str`, "asd123") 113 testReturn(t, L, `return a.Str`, "asd123") 114 testReturn(t, L, `return a.Hidden`, "nil") 115 testReturn(t, L, `return a.hidden`, "nil") 116 } 117 118 func Test_struct_method(t *testing.T) { 119 L := lua.NewState() 120 defer L.Close() 121 122 p := StructTestPerson{ 123 Name: "Tim", 124 Age: 66, 125 } 126 127 L.SetGlobal("p", New(L, &p)) 128 129 testReturn(t, L, `return p:hello()`, "Hello, Tim") 130 testReturn(t, L, `return p.age`, "66") 131 } 132 133 type NestedPointer struct { 134 B NestedPointerChild 135 } 136 137 type NestedPointerChild struct { 138 } 139 140 func (*NestedPointerChild) Test() string { 141 return "Pointer test" 142 } 143 144 func Test_struct_nestedptrmethod(t *testing.T) { 145 L := lua.NewState() 146 defer L.Close() 147 148 a := NestedPointer{} 149 L.SetGlobal("a", New(L, &a)) 150 151 testReturn(t, L, `return a.b:Test()`, "Pointer test") 152 } 153 154 type TestStructEmbeddedType struct { 155 TestStructEmbeddedTypeString 156 } 157 158 type TestStructEmbeddedTypeString string 159 160 func Test_struct_embeddedtype(t *testing.T) { 161 L := lua.NewState() 162 defer L.Close() 163 164 a := TestStructEmbeddedType{ 165 TestStructEmbeddedTypeString: "hello", 166 } 167 168 L.SetGlobal("a", New(L, &a)) 169 170 testReturn(t, L, `a.TestStructEmbeddedTypeString = "world"`) 171 172 if val := a.TestStructEmbeddedTypeString; val != "world" { 173 t.Fatalf("expecting %s, got %s", "world", val) 174 } 175 } 176 177 type TestStructEmbedded struct { 178 StructTestPerson 179 P StructTestPerson 180 P2 StructTestPerson `luar:"other"` 181 } 182 183 func Test_struct_embedded(t *testing.T) { 184 L := lua.NewState() 185 defer L.Close() 186 187 e := &TestStructEmbedded{} 188 L.SetGlobal("e", New(L, e)) 189 190 testReturn( 191 t, 192 L, 193 ` 194 e.StructTestPerson = { 195 Name = "Bill", 196 Age = 33 197 } 198 e.P = { 199 Name = "Tim", 200 Age = 94, 201 Friend = { 202 Name = "Bob", 203 Age = 77 204 } 205 } 206 e.other = { 207 Name = "Dale", 208 Age = 26 209 } 210 `, 211 ) 212 213 { 214 expected := StructTestPerson{ 215 Name: "Bill", 216 Age: 33, 217 } 218 if e.StructTestPerson != expected { 219 t.Fatalf("expected %#v, got %#v", expected, e.StructTestPerson) 220 } 221 } 222 223 { 224 expected := StructTestPerson{ 225 Name: "Bob", 226 Age: 77, 227 } 228 if *(e.P.Friend) != expected { 229 t.Fatalf("expected %#v, got %#v", expected, *e.P.Friend) 230 } 231 } 232 233 { 234 expected := StructTestPerson{ 235 Name: "Dale", 236 Age: 26, 237 } 238 if e.P2 != expected { 239 t.Fatalf("expected %#v, got %#v", expected, e.P2) 240 } 241 } 242 } 243 244 type TestPointerReplaceHidden struct { 245 A string `luar:"q"` 246 B int `luar:"other"` 247 C int `luar:"-"` 248 } 249 250 func Test_struct_pointerreplacehidden(t *testing.T) { 251 L := lua.NewState() 252 defer L.Close() 253 254 e := &TestPointerReplaceHidden{} 255 L.SetGlobal("e", New(L, e)) 256 257 testReturn( 258 t, 259 L, 260 ` 261 _ = e ^ { 262 q = "Cat", 263 other = 675 264 } 265 `, 266 ) 267 268 expected := TestPointerReplaceHidden{ 269 A: "Cat", 270 B: 675, 271 } 272 273 if *e != expected { 274 t.Fatalf("expected %v, got %v", expected, *e) 275 } 276 277 testError( 278 t, 279 L, 280 ` 281 _ = e ^ { 282 C = 333 283 } 284 `, 285 `type luar.TestPointerReplaceHidden has no field C`, 286 ) 287 } 288 289 func Test_struct_ptreq(t *testing.T) { 290 L := lua.NewState() 291 defer L.Close() 292 293 p1 := StructTestPerson{ 294 Name: "Tim", 295 } 296 297 p2 := StructTestPerson{ 298 Name: "Tim", 299 } 300 301 L.SetGlobal("p1", New(L, &p1)) 302 L.SetGlobal("p2", New(L, &p2)) 303 304 if &p1 == &p2 { 305 t.Fatal("expected structs to be unequal") 306 } 307 testReturn(t, L, `return p1 == p2`, "false") 308 } 309 310 type Test_nested_child1 struct { 311 Name string 312 } 313 314 type Test_nested_child2 struct { 315 Name string 316 } 317 318 type Test_nested_parent struct { 319 Test_nested_child1 320 Test_nested_child2 321 } 322 323 func Test_ambiguous_field(t *testing.T) { 324 L := lua.NewState() 325 defer L.Close() 326 327 n := &Test_nested_parent{} 328 329 L.SetGlobal("c", New(L, n)) 330 testError(t, L, ` 331 c.Name = "Tim" 332 `, "unknown field Name") 333 334 if n.Test_nested_child1.Name != "" { 335 t.Errorf("expected Test_nested_child1.Name to be empty") 336 } 337 if n.Test_nested_child2.Name != "" { 338 t.Errorf("expected Test_nested_child2.Name to be empty") 339 } 340 } 341 342 type Test_nested_parent2 struct { 343 Test_nested_child1 344 Test_nested_child2 345 Name string 346 } 347 348 func Test_ambiguous_field2(t *testing.T) { 349 L := lua.NewState() 350 defer L.Close() 351 352 n := &Test_nested_parent2{} 353 354 L.SetGlobal("c", New(L, n)) 355 testReturn(t, L, ` 356 c.Name = "Tim" 357 return c.Name 358 `, "Tim") 359 360 if n.Name != "Tim" { 361 t.Errorf("expected Name to be set to `Tim`") 362 } 363 if n.Test_nested_child1.Name != "" { 364 t.Errorf("expected Test_nested_child1.Name to be empty") 365 } 366 if n.Test_nested_child2.Name != "" { 367 t.Errorf("expected Test_nested_child2.Name to be empty") 368 } 369 } 370 371 type test_unexport_anonymous_child struct { 372 Name string 373 } 374 375 type Test_struct_unexport_anonymous_parent struct { 376 test_unexport_anonymous_child 377 } 378 379 func Test_struct_unexport_anonymous_field(t *testing.T) { 380 L := lua.NewState() 381 defer L.Close() 382 383 n := &Test_struct_unexport_anonymous_parent{} 384 385 L.SetGlobal("c", New(L, n)) 386 testReturn(t, L, ` 387 c.Name = "Tim" 388 return c.Name 389 `, "Tim") 390 391 if n.Name != "Tim" { 392 t.Errorf("expected Name to be set to `Tim`") 393 } 394 395 // Ensure test_unexport_anonymous_child was not captured 396 mt := MT(L, *n) 397 fields := mt.RawGetString("fields").(*lua.LTable) 398 if field := fields.RawGetString("test_unexport_anonymous_child"); field != lua.LNil { 399 t.Errorf("expected test_unexport_anonymous_child to be nil, got %v", field) 400 } 401 }