Skip to content

Commit 5e74da8

Browse files
committed
Support error type
1 parent 32b3b25 commit 5e74da8

File tree

3 files changed

+201
-6
lines changed

3 files changed

+201
-6
lines changed

mapper/function_test.go

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mapper
22

33
import (
4+
"errors"
45
"testing"
56

67
"github.com/stretchr/testify/assert"
@@ -129,3 +130,168 @@ func TestToGFunction(t *testing.T) {
129130
)
130131
}
131132
}
133+
134+
func TestToGFunctionInteroperability(t *testing.T) {
135+
type testCase struct {
136+
name string
137+
code string
138+
args map[string][]interface{}
139+
exports map[string]func(*testing.T, func(...interface{})) interface{}
140+
err error
141+
}
142+
143+
type state struct {
144+
called bool
145+
args []interface{}
146+
}
147+
148+
var (
149+
samples = []testCase{
150+
{
151+
name: "single return value",
152+
code: `local m = require("module"); m.fn1(m.fn2())`,
153+
args: map[string][]interface{}{
154+
"fn1": []interface{}{1},
155+
"fn2": nil,
156+
},
157+
exports: map[string]func(*testing.T, func(...interface{})) interface{}{
158+
"fn1": func(t *testing.T, callback func(...interface{})) interface{} {
159+
return func(x int) {
160+
callback(x)
161+
}
162+
},
163+
"fn2": func(t *testing.T, callback func(...interface{})) interface{} {
164+
return func() int {
165+
callback()
166+
return 1
167+
}
168+
},
169+
},
170+
err: nil,
171+
},
172+
// FIXME: This one is broken, we should not zip out args with in args automagicaly
173+
// {
174+
// name: "multiple return value",
175+
// code: `local m = require("module"); m.fn1(m.fn2(), m.fn3())`,
176+
// args: map[string][]interface{}{
177+
// "fn1": []interface{}{1, "hello", 1, "hello"},
178+
// "fn2": nil,
179+
// },
180+
// exports: map[string]func(*testing.T, func(...interface{})) interface{}{
181+
// "fn1": func(t *testing.T, callback func(...interface{})) interface{} {
182+
// return func(x int, y string, xx int, yy string) {
183+
// callback(x, y, xx, yy)
184+
// }
185+
// },
186+
// "fn2": func(t *testing.T, callback func(...interface{})) interface{} {
187+
// return func() (int, string) {
188+
// callback()
189+
// return 1, "hello"
190+
// }
191+
// },
192+
// "fn3": func(t *testing.T, callback func(...interface{})) interface{} {
193+
// return func() (int, string) {
194+
// callback()
195+
// return 1, "hello"
196+
// }
197+
// },
198+
// },
199+
// err: nil,
200+
// },
201+
{
202+
name: "errors",
203+
code: `local m = require("module"); m.fn1(m.fn2())`,
204+
args: map[string][]interface{}{
205+
"fn1": []interface{}{
206+
errors.New("we bring you an interface{} so you could interface{} while interface{}"),
207+
},
208+
"fn2": nil,
209+
},
210+
exports: map[string]func(*testing.T, func(...interface{})) interface{}{
211+
"fn1": func(t *testing.T, callback func(...interface{})) interface{} {
212+
return func(x error) {
213+
callback(x)
214+
}
215+
},
216+
"fn2": func(t *testing.T, callback func(...interface{})) interface{} {
217+
return func() error {
218+
callback()
219+
return errors.New("we bring you an interface{} so you could interface{} while interface{}")
220+
}
221+
},
222+
},
223+
err: nil,
224+
},
225+
}
226+
)
227+
228+
for _, sample := range samples {
229+
t.Run(
230+
sample.name,
231+
func(t *testing.T) {
232+
var (
233+
l = lua.NewState()
234+
s = map[string]*state{}
235+
loader func(l *lua.LState) int
236+
err error
237+
)
238+
239+
loader = func(l *lua.LState) int {
240+
var (
241+
exports = map[string]lua.LGFunction{}
242+
fn lua.LGFunction
243+
module *lua.LTable
244+
err error
245+
)
246+
247+
for k, v := range sample.exports {
248+
fn, err = ToGFunction(
249+
v(
250+
t,
251+
func(name string) func(...interface{}) {
252+
return func(args ...interface{}) {
253+
s[name] = &state{
254+
called: true,
255+
args: args,
256+
}
257+
}
258+
}(k),
259+
),
260+
)
261+
if err != nil {
262+
t.Error(err)
263+
return 0
264+
}
265+
266+
exports[k] = fn
267+
}
268+
269+
module = l.SetFuncs(l.NewTable(), exports)
270+
271+
l.Push(module)
272+
return 1
273+
}
274+
275+
l.PreloadModule("module", loader)
276+
277+
for n := 0; n < 1; n++ {
278+
for _, v := range s {
279+
v.called = false
280+
v.args = []interface{}{}
281+
}
282+
283+
err = l.DoString(sample.code)
284+
if err != nil {
285+
t.Error(err)
286+
return
287+
}
288+
289+
for k, v := range s {
290+
assert.Equal(t, true, v.called)
291+
assert.Equal(t, sample.args[k], v.args)
292+
}
293+
}
294+
},
295+
)
296+
}
297+
}

mapper/value.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ func ToValue(gv interface{}) (lua.LValue, error) {
6060

6161
case time.Duration:
6262
return lua.LNumber(v), nil
63+
case error:
64+
return &lua.LUserData{
65+
Value: v,
66+
Env: nil,
67+
Metatable: &lua.LTable{},
68+
}, nil
6369
}
6470

6571
// XXX: If you are looking for a way to map reflect.Func into lua.LFunction
@@ -130,6 +136,8 @@ func FromValue(lv lua.LValue) (interface{}, error) {
130136
return string(v), nil
131137
case lua.LNumber:
132138
return float64(v), nil
139+
case *lua.LUserData:
140+
return v.Value, nil
133141
case *lua.LTable:
134142
var (
135143
n = v.MaxN()

mapper/value_test.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mapper
22

33
import (
4+
"errors"
45
"testing"
56

67
"github.com/corpix/reflect"
@@ -37,8 +38,8 @@ func TestToValue(t *testing.T) {
3738
err: nil,
3839
},
3940
{
40-
name: "float64",
41-
input: float64(0),
41+
name: "uint64",
42+
input: uint64(0),
4243
output: lua.LNumber(0),
4344
err: nil,
4445
},
@@ -49,11 +50,21 @@ func TestToValue(t *testing.T) {
4950
err: nil,
5051
},
5152
{
52-
name: "uint64",
53-
input: uint64(0),
53+
name: "float64",
54+
input: float64(0),
5455
output: lua.LNumber(0),
5556
err: nil,
5657
},
58+
{
59+
name: "error",
60+
input: errors.New("hello, this is a bad way to create error"),
61+
output: &lua.LUserData{
62+
Value: errors.New("hello, this is a bad way to create error"),
63+
Env: nil,
64+
Metatable: &lua.LTable{},
65+
},
66+
err: nil,
67+
},
5768
{
5869
name: "table",
5970
input: map[interface{}]interface{}{},
@@ -122,7 +133,7 @@ func TestToValue(t *testing.T) {
122133

123134
v, err = ToValue(sample.input)
124135
assert.IsType(t, sample.err, err)
125-
assert.EqualValues(t, sample.output, v)
136+
assert.Equal(t, sample.output, v)
126137
},
127138
)
128139
}
@@ -162,6 +173,16 @@ func TestFromValue(t *testing.T) {
162173
output: float64(0),
163174
err: nil,
164175
},
176+
{
177+
name: "error",
178+
input: &lua.LUserData{
179+
Value: errors.New("hello, this is a bad way to create error"),
180+
Env: nil,
181+
Metatable: &lua.LTable{},
182+
},
183+
output: errors.New("hello, this is a bad way to create error"),
184+
err: nil,
185+
},
165186
{
166187
name: "table",
167188
input: &lua.LTable{},
@@ -219,7 +240,7 @@ func TestFromValue(t *testing.T) {
219240

220241
v, err = FromValue(sample.input)
221242
assert.IsType(t, sample.err, err)
222-
assert.EqualValues(t, sample.output, v)
243+
assert.Equal(t, sample.output, v)
223244
},
224245
)
225246
}

0 commit comments

Comments
 (0)