1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-30 06:59:03 +01:00
liquid/values/call_test.go
nsf 1a2066b87e Properly handle variadic functions.
This commit addresses two issues:

1. For variadic functions 'convertCallArguments' was allocating exactly
   'len(args)' arguments, which might be less than required, as a result
   zero/default filling loop would panic with out of bounds error.

2. Even if we correctly allocate a proper amount of arguments, zero/default
   filling loop doesn't handle special variadic function type case, when last
   argument has a slice type and reflect API expects plain values as arguments.
   But actually we don't need that, because it's okay to omit variadic values
   altogether, hence the total amount of allocated arguments is
   max(len(args), rt.NumIn()-1).
2018-05-30 19:44:29 +05:00

79 lines
2.2 KiB
Go

package values
import (
"fmt"
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestCall(t *testing.T) {
fn := func(a, b string) string {
return a + "," + b + "."
}
value, err := Call(reflect.ValueOf(fn), []interface{}{5, 10})
require.NoError(t, err)
require.Equal(t, "5,10.", value)
// extra arguments (variadic)
fnVaridic := func(a string, b ...string) string {
return a + "," + strings.Join(b, ",") + "."
}
value, err = Call(reflect.ValueOf(fnVaridic), []interface{}{5, 10})
require.NoError(t, err)
require.Equal(t, "5,10.", value)
value, err = Call(reflect.ValueOf(fnVaridic), []interface{}{5, 10, 15, 20})
require.NoError(t, err)
require.Equal(t, "5,10,15,20.", value)
// extra arguments (non variadic)
_, err = Call(reflect.ValueOf(fn), []interface{}{5, 10, 20})
require.Error(t, err)
require.Contains(t, err.Error(), "wrong number of arguments")
require.Contains(t, err.Error(), "given 3")
require.Contains(t, err.Error(), "expected 2")
// error return
fn2 := func(int) (int, error) { return 0, fmt.Errorf("expected error") }
_, err = Call(reflect.ValueOf(fn2), []interface{}{2})
require.Error(t, err)
require.Contains(t, err.Error(), "expected error")
}
func TestCall_optional(t *testing.T) {
fn := func(a string, b func(string) string) string {
return a + "," + b("default") + "."
}
value, err := Call(reflect.ValueOf(fn), []interface{}{5})
require.NoError(t, err)
require.Equal(t, "5,default.", value)
value, err = Call(reflect.ValueOf(fn), []interface{}{5, 10})
require.NoError(t, err)
require.Equal(t, "5,10.", value)
}
func TestCall_variadic(t *testing.T) {
fn := func(sep func(string) string, args ...string) string {
return "[" + strings.Join(args, sep(",")) + "]"
}
value, err := Call(reflect.ValueOf(fn), []interface{}{",", "a"})
require.NoError(t, err)
require.Equal(t, "[a]", value)
value, err = Call(reflect.ValueOf(fn), []interface{}{",", "a", "b"})
require.NoError(t, err)
require.Equal(t, "[a,b]", value)
value, err = Call(reflect.ValueOf(fn), []interface{}{","})
require.NoError(t, err)
require.Equal(t, "[]", value)
value, err = Call(reflect.ValueOf(fn), []interface{}{})
require.NoError(t, err)
require.Equal(t, "[]", value)
}