package luar import ( "reflect" "strings" "testing" "github.com/yuin/gopher-lua" ) func Test_luar_complex128(t *testing.T) { L := lua.NewState() defer L.Close() a := complex(float64(1), float64(2)) L.SetGlobal("a", New(L, a)) testReturn(t, L, `b = a`) b := L.GetGlobal("b").(*lua.LUserData).Value.(complex128) if a != b { t.Fatalf("expected a = b, got %v", b) } } type ChanAlias chan string func (ChanAlias) Test() string { return `I'm a "chan string" alias` } func (ChanAlias) hidden() { } type SliceAlias []string func (s SliceAlias) Len() int { return len(s) } func (s *SliceAlias) Append(v string) { *s = append(*s, v) } type MapAlias map[string]int func (m MapAlias) Y() int { return len(m) } func Test_type_methods(t *testing.T) { L := lua.NewState() defer L.Close() a := make(ChanAlias) var b SliceAlias = []string{"Hello", "world"} c := MapAlias{ "x": 15, } L.SetGlobal("a", New(L, a)) L.SetGlobal("b", New(L, &b)) L.SetGlobal("c", New(L, c)) testReturn(t, L, `return a:Test()`, `I'm a "chan string" alias`) testReturn(t, L, `len1 = b:Len(); b:Append("!")`) testReturn(t, L, `return len1, b:len()`, "2", "3") testReturn(t, L, `return c.x, c:y()`, "15", "1") } func Test_comparisons(t *testing.T) { L := lua.NewState() defer L.Close() { s := make([]int, 10) L.SetGlobal("s1", New(L, s)) L.SetGlobal("sp1", New(L, &s)) L.SetGlobal("s2", New(L, s)) L.SetGlobal("sp2", New(L, &s)) } { m := make(map[string]int, 10) L.SetGlobal("m1", New(L, m)) L.SetGlobal("mp1", New(L, &m)) L.SetGlobal("m2", New(L, m)) L.SetGlobal("mp2", New(L, &m)) } { c := make(chan string) L.SetGlobal("c1", New(L, c)) L.SetGlobal("cp1", New(L, &c)) L.SetGlobal("c2", New(L, c)) c3 := make(chan string) L.SetGlobal("c3", New(L, c3)) } { s := "" L.SetGlobal("sp1", New(L, &s)) L.SetGlobal("sp2", New(L, &s)) } testReturn(t, L, `return s1 == s1`, "true") testReturn(t, L, `return sp1 == sp2`, "true") testReturn(t, L, `return m1 == m1`, "true") testReturn(t, L, `return mp1 == mp2`, "true") testReturn(t, L, `return c1 == c1`, "true") testReturn(t, L, `return c1 == c3`, "false") testReturn(t, L, `return sp1 == sp2`, "true") } type TestSliceConversion struct { S []string } func Test_sliceconversion(t *testing.T) { L := lua.NewState() defer L.Close() e := &TestSliceConversion{} L.SetGlobal("e", New(L, e)) testReturn(t, L, `e.S = {"a", "b", "", "c"}`) valid := true expecting := []string{"a", "b", "", "c"} if len(e.S) != len(expecting) { valid = false } else { for i, item := range e.S { if item != expecting[i] { valid = false break } } } if !valid { t.Fatalf("expecting %#v, got %#v", expecting, e.S) } } type TestMapConversion struct { S map[string]string } func Test_mapconversion(t *testing.T) { L := lua.NewState() defer L.Close() e := &TestMapConversion{} L.SetGlobal("e", New(L, e)) testReturn(t, L, `e.S = {b = nil, c = "hello"}`) valid := true expecting := map[string]string{ "c": "hello", } if len(e.S) != len(expecting) { valid = false } else { for key, value := range e.S { expected, ok := expecting[key] if !ok || value != expected { valid = false break } } } if !valid { t.Fatalf("expecting %#v, got %#v", expecting, e.S) } if _, ok := e.S["b"]; ok { t.Fatal(`e.S["b"] should not be set`) } } func Test_udconversion(t *testing.T) { L := lua.NewState() defer L.Close() ud := L.NewUserData() ud.Value = "hello world" L.SetGlobal("ud", ud) var out int L.SetGlobal("out", New(L, &out)) testError(t, L, `_ = out ^ ud`, "cannot use hello world (type string) as type int") } func Test_arrayconversion(t *testing.T) { L := lua.NewState() defer L.Close() var arr [3]int L.SetGlobal("arr", New(L, &arr)) testReturn(t, L, `arr = arr ^ {10, 20, 11}; return arr[1], arr[2], arr[3]`, "10", "20", "11") } type Test_interface_struct struct{} func Test_interface(t *testing.T) { tbl := []struct { Code string Var func(L *lua.LState) lua.LValue Expected interface{} ExpectedType reflect.Type }{ { Code: `nil`, Expected: interface{}(nil), }, { Code: `"Hello"`, Expected: string("Hello"), }, { Code: `true`, Expected: bool(true), }, { Code: `1`, Expected: float64(1), }, { Code: `function(a, b) end`, ExpectedType: reflect.TypeOf(func(...interface{}) []interface{} { return nil }), }, { Code: `{hello = "world", [123] = 321}`, Expected: map[interface{}]interface{}{ string("hello"): string("world"), float64(123): float64(321), }, }, { Code: `var`, Var: func(L *lua.LState) lua.LValue { ud := L.NewUserData() ud.Value = "Hello World" return ud }, Expected: string("Hello World"), }, // TODO: LChannel // TODO: *LState } for _, cur := range tbl { func() { L := lua.NewState() defer L.Close() var out interface{} = Test_interface_struct{} L.SetGlobal("out", New(L, &out)) if cur.Var != nil { L.SetGlobal("var", cur.Var(L)) } if err := L.DoString(`_ = out ^ ` + cur.Code); err != nil { t.Fatal(err) } if cur.ExpectedType != nil { if reflect.TypeOf(out) != cur.ExpectedType { t.Fatalf("expected conversion of %#v = type %s, got type %s\n", cur.Code, cur.ExpectedType, reflect.TypeOf(out)) } } else if !reflect.DeepEqual(out, cur.Expected) { t.Fatalf("expected conversion of %#v = %#v (%T), got %#v (%T)\n", cur.Code, cur.Expected, cur.Expected, out, out) } }() } } func Test_recursivetable(t *testing.T) { L := lua.NewState() defer L.Close() var x interface{} L.SetGlobal("x", New(L, &x)) if err := L.DoString(`local tbl = {}; tbl.inner = tbl; _ = x ^ tbl`); err != nil { t.Fatal(err) } } func Test_tostringfallback(t *testing.T) { L := lua.NewState() defer L.Close() type Struct struct { } var out string L.SetGlobal("struct", New(L, &Struct{})) L.SetGlobal("out", New(L, &out)) if err := L.DoString(`_ = out ^ tostring(struct)`); err != nil { t.Fatal(err) } if !strings.HasPrefix(out, "userdata: ") { t.Fatalf("invalid tostring %#v\n", out) } }