diff options
author | Bjørn Erik Pedersen <[email protected]> | 2023-06-14 09:00:28 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <[email protected]> | 2023-06-14 20:18:54 +0200 |
commit | d178fe94fe26ce2cf8096f330f3d160af3ec818d (patch) | |
tree | b65e8931a62ad3854a2444c5817a7926b0a45577 /common/collections | |
parent | 732dcb848f6455ad8f1d5ec2351257015c87eec7 (diff) | |
download | hugo-d178fe94fe26ce2cf8096f330f3d160af3ec818d.tar.gz hugo-d178fe94fe26ce2cf8096f330f3d160af3ec818d.zip |
tpl/collections: Fix append when appending a slice to a slice of slices
Fixes #11093
Diffstat (limited to 'common/collections')
-rw-r--r-- | common/collections/append.go | 29 | ||||
-rw-r--r-- | common/collections/append_test.go | 45 |
2 files changed, 70 insertions, 4 deletions
diff --git a/common/collections/append.go b/common/collections/append.go index a9c14c1aa..fe8792fc4 100644 --- a/common/collections/append.go +++ b/common/collections/append.go @@ -22,6 +22,9 @@ import ( // If length of from is one and the only element is a slice of same type as to, // it will be appended. func Append(to any, from ...any) (any, error) { + if len(from) == 0 { + return to, nil + } tov, toIsNil := indirect(reflect.ValueOf(to)) toIsNil = toIsNil || to == nil @@ -33,18 +36,39 @@ func Append(to any, from ...any) (any, error) { } tot = tov.Type().Elem() + if tot.Kind() == reflect.Slice { + totvt := tot.Elem() + fromvs := make([]reflect.Value, len(from)) + for i, f := range from { + fromv := reflect.ValueOf(f) + fromt := fromv.Type() + if fromt.Kind() == reflect.Slice { + fromt = fromt.Elem() + } + if totvt != fromt { + return nil, fmt.Errorf("cannot append slice of %s to slice of %s", fromt, totvt) + } else { + fromvs[i] = fromv + } + } + return reflect.Append(tov, fromvs...).Interface(), nil + + } + toIsNil = tov.Len() == 0 if len(from) == 1 { fromv := reflect.ValueOf(from[0]) + fromt := fromv.Type() + if fromt.Kind() == reflect.Slice { + fromt = fromt.Elem() + } if fromv.Kind() == reflect.Slice { if toIsNil { // If we get nil []string, we just return the []string return from[0], nil } - fromt := reflect.TypeOf(from[0]).Elem() - // If we get []string []string, we append the from slice to to if tot == fromt { return reflect.AppendSlice(tov, fromv).Interface(), nil @@ -52,6 +76,7 @@ func Append(to any, from ...any) (any, error) { // Fall back to a []interface{} slice. return appendToInterfaceSliceFromValues(tov, fromv) } + } } } diff --git a/common/collections/append_test.go b/common/collections/append_test.go index 6df32fee6..f997e7a20 100644 --- a/common/collections/append_test.go +++ b/common/collections/append_test.go @@ -24,7 +24,7 @@ func TestAppend(t *testing.T) { t.Parallel() c := qt.New(t) - for _, test := range []struct { + for i, test := range []struct { start any addend []any expected any @@ -85,6 +85,47 @@ func TestAppend(t *testing.T) { } c.Assert(err, qt.IsNil) - c.Assert(result, qt.DeepEquals, test.expected) + c.Assert(result, qt.DeepEquals, test.expected, qt.Commentf("test: [%d] %v", i, test)) } } + +// #11093 +func TestAppendToMultiDimensionalSlice(t *testing.T) { + t.Parallel() + c := qt.New(t) + + for _, test := range []struct { + to any + from []any + expected any + }{ + {[][]string{{"a", "b"}}, + []any{[]string{"c", "d"}}, + [][]string{ + {"a", "b"}, + {"c", "d"}, + }, + }, + {[][]string{{"a", "b"}}, + []any{[]string{"c", "d"}, []string{"e", "f"}}, + [][]string{ + {"a", "b"}, + {"c", "d"}, + {"e", "f"}, + }, + }, + {[][]string{{"a", "b"}}, + []any{[]int{1, 2}}, + false, + }, + } { + result, err := Append(test.to, test.from...) + if b, ok := test.expected.(bool); ok && !b { + c.Assert(err, qt.Not(qt.IsNil)) + } else { + c.Assert(err, qt.IsNil) + c.Assert(result, qt.DeepEquals, test.expected) + } + } + +} |