Go plugin: keep float parameters typed (#33162)
This commit is contained in:
parent
022171ffde
commit
9beca9b22f
2 changed files with 86 additions and 1 deletions
16
plugin/go.go
16
plugin/go.go
|
|
@ -202,11 +202,25 @@ func (p *Go) evaluate(vm *interp.Interpreter) (res any, err error) {
|
||||||
|
|
||||||
func (p *Go) setParam(vm *interp.Interpreter) func(param string, val any) error {
|
func (p *Go) setParam(vm *interp.Interpreter) func(param string, val any) error {
|
||||||
return func(param string, val any) error {
|
return func(param string, val any) error {
|
||||||
_, err := vm.Eval(fmt.Sprintf("%s := %#v;", param, val))
|
_, err := vm.Eval(fmt.Sprintf("%s := %s;", param, goLiteral(val)))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// goLiteral renders val as Go source. Floats need their type spelled out:
|
||||||
|
// %#v prints float64(100) as `100`, which the interpreter infers as int. Any
|
||||||
|
// arithmetic mixing the parameter with a float constant then fails to compile.
|
||||||
|
func goLiteral(val any) string {
|
||||||
|
switch v := val.(type) {
|
||||||
|
case float32:
|
||||||
|
return fmt.Sprintf("float32(%v)", v)
|
||||||
|
case float64:
|
||||||
|
return fmt.Sprintf("float64(%v)", v)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%#v", val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var _ IntSetter = (*Go)(nil)
|
var _ IntSetter = (*Go)(nil)
|
||||||
|
|
||||||
// IntSetter sends int request
|
// IntSetter sends int request
|
||||||
|
|
|
||||||
71
plugin/go_test.go
Normal file
71
plugin/go_test.go
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A float parameter must keep its type inside the interpreter even when the
|
||||||
|
// value is a whole number. Otherwise arithmetic mixing it with a float constant
|
||||||
|
// fails with "invalid operation: mismatched types int and untyped float".
|
||||||
|
func TestGoFloatParam(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
value float64
|
||||||
|
want int64
|
||||||
|
}{
|
||||||
|
{11000, 73},
|
||||||
|
{15000, 100},
|
||||||
|
{0, 0},
|
||||||
|
{11000.5, 73},
|
||||||
|
} {
|
||||||
|
p, err := NewGoPluginFromConfig(t.Context(), map[string]any{
|
||||||
|
"in": []map[string]any{{
|
||||||
|
"name": "limit",
|
||||||
|
"type": "float",
|
||||||
|
"config": map[string]any{"source": "const", "value": tc.value},
|
||||||
|
}},
|
||||||
|
"script": "int(limit*100/15000 + 0.5)",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
g, err := p.(IntGetter).IntGetter()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
v, err := g()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tc.want, v, tc.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// int parameters keep integer semantics
|
||||||
|
func TestGoIntParam(t *testing.T) {
|
||||||
|
p, err := NewGoPluginFromConfig(t.Context(), map[string]any{
|
||||||
|
"in": []map[string]any{{
|
||||||
|
"name": "mode",
|
||||||
|
"type": "int",
|
||||||
|
"config": map[string]any{"source": "const", "value": 3},
|
||||||
|
}},
|
||||||
|
"script": "mode & 1",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
g, err := p.(IntGetter).IntGetter()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
v, err := g()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int64(1), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the value handed to a setter is a parameter, too
|
||||||
|
func TestGoFloatSetter(t *testing.T) {
|
||||||
|
p, err := NewGoPluginFromConfig(t.Context(), map[string]any{
|
||||||
|
"script": "int(limit*100/15000 + 0.5)",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
s, err := p.(FloatSetter).FloatSetter("limit")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, s(11000))
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue