summaryrefslogtreecommitdiffstats
path: root/common/collections
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2023-06-14 09:00:28 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2023-06-14 20:18:54 +0200
commitd178fe94fe26ce2cf8096f330f3d160af3ec818d (patch)
treeb65e8931a62ad3854a2444c5817a7926b0a45577 /common/collections
parent732dcb848f6455ad8f1d5ec2351257015c87eec7 (diff)
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.go29
-rw-r--r--common/collections/append_test.go45
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)
+ }
+ }
+
+}