Skip to content

Commit

Permalink
tpl/collections: Fix append when appending a slice to a slice of slices
Browse files Browse the repository at this point in the history
  • Loading branch information
bep committed Jun 14, 2023
1 parent 35e9b3e commit cefe74d
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 4 deletions.
29 changes: 27 additions & 2 deletions common/collections/append.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,25 +36,47 @@ 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
} else if !fromt.AssignableTo(tot) {
// Fall back to a []interface{} slice.
return appendToInterfaceSliceFromValues(tov, fromv)
}

}
}
}
Expand Down
45 changes: 43 additions & 2 deletions common/collections/append_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
}

}
31 changes: 31 additions & 0 deletions tpl/collections/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,34 @@ Desc: [map[a:3 b:3] map[a:3 b:1] map[a:3 b:1] map[a:3 b:1] map[a:3 b:0] map[a:3

}
}

// Issue #11004.
func TestAppendSliceToASliceOfSlices(t *testing.T) {
t.Parallel()

files := `
-- hugo.toml --
-- layouts/index.html --
{{ $obj := slice (slice "a") }}
{{ $obj = $obj | append (slice "b") }}
{{ $obj = $obj | append (slice "c") }}
{{ $obj }}
`

for i := 0; i < 4; i++ {

b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
},
).Build()

b.AssertFileContent("public/index.html", "[[a] [b] [c]]")

}

}

0 comments on commit cefe74d

Please sign in to comment.