mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-28 21:21:40 -05:00
tpl/collections: Properly handle pointer types in complement/symdiff
We cannot compare them by values, because that gets `hash of unhashable type` for the prime use case.
This commit is contained in:
parent
d212f60949
commit
79a06aa4b6
3 changed files with 20 additions and 11 deletions
|
@ -23,6 +23,13 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type StructWithSlice struct {
|
||||||
|
A string
|
||||||
|
B []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructWithSlicePointers []*StructWithSlice
|
||||||
|
|
||||||
func TestComplement(t *testing.T) {
|
func TestComplement(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
@ -33,10 +40,13 @@ func TestComplement(t *testing.T) {
|
||||||
s1 := []TstX{TstX{A: "a"}, TstX{A: "b"}, TstX{A: "d"}, TstX{A: "e"}}
|
s1 := []TstX{TstX{A: "a"}, TstX{A: "b"}, TstX{A: "d"}, TstX{A: "e"}}
|
||||||
s2 := []TstX{TstX{A: "b"}, TstX{A: "e"}}
|
s2 := []TstX{TstX{A: "b"}, TstX{A: "e"}}
|
||||||
|
|
||||||
xa, xd := &TstX{A: "a"}, &TstX{A: "d"}
|
xa, xb, xd, xe := &StructWithSlice{A: "a"}, &StructWithSlice{A: "b"}, &StructWithSlice{A: "d"}, &StructWithSlice{A: "e"}
|
||||||
|
|
||||||
sp1 := []*TstX{xa, &TstX{A: "b"}, xd, &TstX{A: "e"}}
|
sp1 := []*StructWithSlice{xa, xb, xd, xe}
|
||||||
sp2 := []*TstX{&TstX{A: "b"}, &TstX{A: "e"}}
|
sp2 := []*StructWithSlice{xb, xe}
|
||||||
|
|
||||||
|
sp1_2 := StructWithSlicePointers{xa, xb, xd, xe}
|
||||||
|
sp2_2 := StructWithSlicePointers{xb, xe}
|
||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
s interface{}
|
s interface{}
|
||||||
|
@ -49,7 +59,8 @@ func TestComplement(t *testing.T) {
|
||||||
{[]int{1, 2, 3, 4, 5}, []interface{}{[]int{1, 3}, []string{"a", "b"}, []int{1, 2}}, []int{4, 5}},
|
{[]int{1, 2, 3, 4, 5}, []interface{}{[]int{1, 3}, []string{"a", "b"}, []int{1, 2}}, []int{4, 5}},
|
||||||
{[]int{1, 2, 3, 4, 5}, []interface{}{[]int64{1, 3}}, []int{2, 4, 5}},
|
{[]int{1, 2, 3, 4, 5}, []interface{}{[]int64{1, 3}}, []int{2, 4, 5}},
|
||||||
{s1, []interface{}{s2}, []TstX{TstX{A: "a"}, TstX{A: "d"}}},
|
{s1, []interface{}{s2}, []TstX{TstX{A: "a"}, TstX{A: "d"}}},
|
||||||
{sp1, []interface{}{sp2}, []*TstX{xa, xd}},
|
{sp1, []interface{}{sp2}, []*StructWithSlice{xa, xd}},
|
||||||
|
{sp1_2, []interface{}{sp2_2}, StructWithSlicePointers{xa, xd}},
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
{[]string{"a", "b", "c"}, []interface{}{"error"}, false},
|
{[]string{"a", "b", "c"}, []interface{}{"error"}, false},
|
||||||
|
|
|
@ -43,7 +43,6 @@ func numberToFloat(v reflect.Value) (float64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalizes different numeric types to make them comparable.
|
// normalizes different numeric types to make them comparable.
|
||||||
// If not, any pointer will be unwrapped.
|
|
||||||
func normalize(v reflect.Value) interface{} {
|
func normalize(v reflect.Value) interface{} {
|
||||||
k := v.Kind()
|
k := v.Kind()
|
||||||
|
|
||||||
|
@ -53,8 +52,6 @@ func normalize(v reflect.Value) interface{} {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
case k == reflect.Ptr:
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.Interface()
|
return v.Interface()
|
||||||
|
@ -70,6 +67,7 @@ func collectIdentities(seqs ...interface{}) (map[interface{}]bool, error) {
|
||||||
case reflect.Array, reflect.Slice:
|
case reflect.Array, reflect.Slice:
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
ev, _ := indirectInterface(v.Index(i))
|
ev, _ := indirectInterface(v.Index(i))
|
||||||
|
|
||||||
if !ev.Type().Comparable() {
|
if !ev.Type().Comparable() {
|
||||||
return nil, errors.New("elements must be comparable")
|
return nil, errors.New("elements must be comparable")
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,10 @@ func TestSymDiff(t *testing.T) {
|
||||||
s1 := []TstX{TstX{A: "a"}, TstX{A: "b"}}
|
s1 := []TstX{TstX{A: "a"}, TstX{A: "b"}}
|
||||||
s2 := []TstX{TstX{A: "a"}, TstX{A: "e"}}
|
s2 := []TstX{TstX{A: "a"}, TstX{A: "e"}}
|
||||||
|
|
||||||
xa, xd := &TstX{A: "a"}, &TstX{A: "d"}
|
xa, xb, xd, xe := &StructWithSlice{A: "a"}, &StructWithSlice{A: "b"}, &StructWithSlice{A: "d"}, &StructWithSlice{A: "e"}
|
||||||
|
|
||||||
sp1 := []*TstX{xa, &TstX{A: "b"}, xd, &TstX{A: "e"}}
|
sp1 := []*StructWithSlice{xa, xb, xd, xe}
|
||||||
sp2 := []*TstX{&TstX{A: "b"}, &TstX{A: "e"}}
|
sp2 := []*StructWithSlice{xb, xe}
|
||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
s1 interface{}
|
s1 interface{}
|
||||||
|
@ -49,7 +49,7 @@ func TestSymDiff(t *testing.T) {
|
||||||
{[]int{1, 2, 3}, []int{3, 4}, []int{1, 2, 4}},
|
{[]int{1, 2, 3}, []int{3, 4}, []int{1, 2, 4}},
|
||||||
{[]int{1, 2, 3}, []int64{3, 4}, []int{1, 2, 4}},
|
{[]int{1, 2, 3}, []int64{3, 4}, []int{1, 2, 4}},
|
||||||
{s1, s2, []TstX{TstX{A: "b"}, TstX{A: "e"}}},
|
{s1, s2, []TstX{TstX{A: "b"}, TstX{A: "e"}}},
|
||||||
{sp1, sp2, []*TstX{xa, xd}},
|
{sp1, sp2, []*StructWithSlice{xa, xd}},
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
{"error", "error", false},
|
{"error", "error", false},
|
||||||
|
|
Loading…
Reference in a new issue