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  }