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  }