From 79a06aa4b64b526c242dfa41f2c7bc24e1352d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Wed, 7 Nov 2018 08:59:21 +0100 Subject: 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. --- tpl/collections/complement_test.go | 19 +++++++++++++++---- tpl/collections/reflect_helpers.go | 4 +--- tpl/collections/symdiff_test.go | 8 ++++---- 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'tpl/collections') diff --git a/tpl/collections/complement_test.go b/tpl/collections/complement_test.go index 4cae7556f..e5edb23d3 100644 --- a/tpl/collections/complement_test.go +++ b/tpl/collections/complement_test.go @@ -23,6 +23,13 @@ import ( "github.com/stretchr/testify/require" ) +type StructWithSlice struct { + A string + B []string +} + +type StructWithSlicePointers []*StructWithSlice + func TestComplement(t *testing.T) { 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"}} 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 := []*StructWithSlice{xa, xb, xd, xe} + sp2 := []*StructWithSlice{xb, xe} - sp1 := []*TstX{xa, &TstX{A: "b"}, xd, &TstX{A: "e"}} - sp2 := []*TstX{&TstX{A: "b"}, &TstX{A: "e"}} + sp1_2 := StructWithSlicePointers{xa, xb, xd, xe} + sp2_2 := StructWithSlicePointers{xb, xe} for i, test := range []struct { 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{}{[]int64{1, 3}}, []int{2, 4, 5}}, {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 {[]string{"a", "b", "c"}, []interface{}{"error"}, false}, diff --git a/tpl/collections/reflect_helpers.go b/tpl/collections/reflect_helpers.go index 85aa389ce..fca65481f 100644 --- a/tpl/collections/reflect_helpers.go +++ b/tpl/collections/reflect_helpers.go @@ -43,7 +43,6 @@ func numberToFloat(v reflect.Value) (float64, error) { } // normalizes different numeric types to make them comparable. -// If not, any pointer will be unwrapped. func normalize(v reflect.Value) interface{} { k := v.Kind() @@ -53,8 +52,6 @@ func normalize(v reflect.Value) interface{} { if err == nil { return f } - case k == reflect.Ptr: - v = v.Elem() } return v.Interface() @@ -70,6 +67,7 @@ func collectIdentities(seqs ...interface{}) (map[interface{}]bool, error) { case reflect.Array, reflect.Slice: for i := 0; i < v.Len(); i++ { ev, _ := indirectInterface(v.Index(i)) + if !ev.Type().Comparable() { return nil, errors.New("elements must be comparable") } diff --git a/tpl/collections/symdiff_test.go b/tpl/collections/symdiff_test.go index d44999730..4024ffe7a 100644 --- a/tpl/collections/symdiff_test.go +++ b/tpl/collections/symdiff_test.go @@ -33,10 +33,10 @@ func TestSymDiff(t *testing.T) { s1 := []TstX{TstX{A: "a"}, TstX{A: "b"}} 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"}} - sp2 := []*TstX{&TstX{A: "b"}, &TstX{A: "e"}} + sp1 := []*StructWithSlice{xa, xb, xd, xe} + sp2 := []*StructWithSlice{xb, xe} for i, test := range []struct { 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}, []int64{3, 4}, []int{1, 2, 4}}, {s1, s2, []TstX{TstX{A: "b"}, TstX{A: "e"}}}, - {sp1, sp2, []*TstX{xa, xd}}, + {sp1, sp2, []*StructWithSlice{xa, xd}}, // Errors {"error", "error", false}, -- cgit v1.2.3