tpl/collections: Fix some index cases where the indices given is a slice and be more lenient with nil inputs

See adjusted tests for detail.

Fixes #10489
This commit is contained in:
Bjørn Erik Pedersen 2022-12-02 10:37:19 +01:00
parent 7d5e3ab8a8
commit d373774cbe
2 changed files with 41 additions and 12 deletions

View file

@ -35,12 +35,9 @@ import (
func (ns *Namespace) Index(item any, args ...any) (any, error) { func (ns *Namespace) Index(item any, args ...any) (any, error) {
v := reflect.ValueOf(item) v := reflect.ValueOf(item)
if !v.IsValid() { if !v.IsValid() {
return nil, errors.New("index of untyped nil") // See issue 10489
} // This used to be an error.
return nil, nil
lowerm, ok := item.(maps.Params)
if ok {
return lowerm.Get(cast.ToStringSlice(args)...), nil
} }
var indices []any var indices []any
@ -51,18 +48,25 @@ func (ns *Namespace) Index(item any, args ...any) (any, error) {
for i := 0; i < v.Len(); i++ { for i := 0; i < v.Len(); i++ {
indices = append(indices, v.Index(i).Interface()) indices = append(indices, v.Index(i).Interface())
} }
} else {
indices = append(indices, args[0])
} }
} else {
indices = args
} }
if indices == nil { lowerm, ok := item.(maps.Params)
indices = args if ok {
return lowerm.Get(cast.ToStringSlice(indices)...), nil
} }
for _, i := range indices { for _, i := range indices {
index := reflect.ValueOf(i) index := reflect.ValueOf(i)
var isNil bool var isNil bool
if v, isNil = indirect(v); isNil { if v, isNil = indirect(v); isNil {
return nil, errors.New("index of nil pointer") // See issue 10489
// This used to be an error.
return nil, nil
} }
switch v.Kind() { switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String: case reflect.Array, reflect.Slice, reflect.String:

View file

@ -30,6 +30,11 @@ func TestIndex(t *testing.T) {
c := qt.New(t) c := qt.New(t)
ns := New(&deps.Deps{Language: langs.NewDefaultLanguage(config.New())}) ns := New(&deps.Deps{Language: langs.NewDefaultLanguage(config.New())})
var (
emptyInterface any
nilPointer *int
)
for i, test := range []struct { for i, test := range []struct {
item any item any
indices []any indices []any
@ -45,16 +50,23 @@ func TestIndex(t *testing.T) {
{map[string]map[string]string{"a": {"b": "c"}}, []any{"a", "b"}, "c", false}, {map[string]map[string]string{"a": {"b": "c"}}, []any{"a", "b"}, "c", false},
{[]map[string]map[string]string{{"a": {"b": "c"}}}, []any{0, "a", "b"}, "c", false}, {[]map[string]map[string]string{{"a": {"b": "c"}}}, []any{0, "a", "b"}, "c", false},
{map[string]map[string]any{"a": {"b": []string{"c", "d"}}}, []any{"a", "b", 1}, "d", false}, {map[string]map[string]any{"a": {"b": []string{"c", "d"}}}, []any{"a", "b", 1}, "d", false},
{map[string]map[string]string{"a": {"b": "c"}}, []any{[]string{"a", "b"}}, "c", false},
{maps.Params{"a": "av"}, []any{"A"}, "av", false}, {maps.Params{"a": "av"}, []any{"A"}, "av", false},
{maps.Params{"a": map[string]any{"b": "bv"}}, []any{"A", "B"}, "bv", false}, {maps.Params{"a": map[string]any{"b": "bv"}}, []any{"A", "B"}, "bv", false},
// These used to be errors.
// See issue 10489.
{nil, nil, nil, false},
{nil, []any{0}, nil, false},
{emptyInterface, []any{0}, nil, false},
{nilPointer, []any{0}, nil, false},
// errors // errors
{nil, nil, nil, true},
{[]int{0, 1}, []any{"1"}, nil, true}, {[]int{0, 1}, []any{"1"}, nil, true},
{[]int{0, 1}, []any{nil}, nil, true}, {[]int{0, 1}, []any{nil}, nil, true},
{tstNoStringer{}, []any{0}, nil, true}, {tstNoStringer{}, []any{0}, nil, true},
} { } {
c.Run(fmt.Sprint(i), func(c *qt.C) {
c.Run(fmt.Sprintf("vararg %d", i), func(c *qt.C) {
errMsg := qt.Commentf("[%d] %v", i, test) errMsg := qt.Commentf("[%d] %v", i, test)
result, err := ns.Index(test.item, test.indices...) result, err := ns.Index(test.item, test.indices...)
@ -66,5 +78,18 @@ func TestIndex(t *testing.T) {
c.Assert(err, qt.IsNil, errMsg) c.Assert(err, qt.IsNil, errMsg)
c.Assert(result, qt.DeepEquals, test.expect, errMsg) c.Assert(result, qt.DeepEquals, test.expect, errMsg)
}) })
c.Run(fmt.Sprintf("slice %d", i), func(c *qt.C) {
errMsg := qt.Commentf("[%d] %v", i, test)
result, err := ns.Index(test.item, test.indices)
if test.isErr {
c.Assert(err, qt.Not(qt.IsNil), errMsg)
return
}
c.Assert(err, qt.IsNil, errMsg)
c.Assert(result, qt.DeepEquals, test.expect, errMsg)
})
} }
} }