Skip to content

Commit 07088d8

Browse files
don't panic on unexported struct key in map
1 parent 429ee0b commit 07088d8

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

assert/assertions.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,6 +1928,23 @@ func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
19281928
return t, k
19291929
}
19301930

1931+
func isStructWithUnexportedMapField(t reflect.Type) bool {
1932+
if t.Kind() != reflect.Struct {
1933+
return false
1934+
}
1935+
1936+
for i := 0; i < t.NumField(); i++ {
1937+
field := t.Field(i)
1938+
if !field.IsExported() &&
1939+
field.Type.Kind() == reflect.Map &&
1940+
field.Type.Key().Kind() == reflect.Array {
1941+
return true
1942+
}
1943+
}
1944+
1945+
return false
1946+
}
1947+
19311948
// diff returns a diff of both values as long as both are of the same type and
19321949
// are a struct, map, slice, array or string. Otherwise it returns an empty string.
19331950
func diff(expected interface{}, actual interface{}) string {
@@ -1948,13 +1965,16 @@ func diff(expected interface{}, actual interface{}) string {
19481965

19491966
var e, a string
19501967

1951-
switch et {
1952-
case reflect.TypeOf(""):
1968+
switch {
1969+
case et == reflect.TypeOf(""):
19531970
e = reflect.ValueOf(expected).String()
19541971
a = reflect.ValueOf(actual).String()
1955-
case reflect.TypeOf(time.Time{}):
1972+
case et == reflect.TypeOf(time.Time{}):
19561973
e = spewConfigStringerEnabled.Sdump(expected)
19571974
a = spewConfigStringerEnabled.Sdump(actual)
1975+
case isStructWithUnexportedMapField(et):
1976+
e = reflect.ValueOf(expected).String()
1977+
a = reflect.ValueOf(actual).String()
19581978
default:
19591979
e = spewConfig.Sdump(expected)
19601980
a = spewConfig.Sdump(actual)

assert/assertions_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,10 @@ func TestEqual(t *testing.T) {
593593
mockT := new(testing.T)
594594
var m map[string]interface{}
595595

596+
type unexportedKeyType struct {
597+
m map[[1]byte]*struct{}
598+
}
599+
596600
cases := []struct {
597601
expected interface{}
598602
actual interface{}
@@ -613,6 +617,40 @@ func TestEqual(t *testing.T) {
613617
{m["bar"], "something", false, ""},
614618
{myType("1"), myType("2"), false, ""},
615619

620+
// Test cases for struct with unexported map field containing array keys
621+
{
622+
unexportedKeyType{
623+
map[[1]byte]*struct{}{
624+
{1}: nil,
625+
{2}: nil,
626+
},
627+
},
628+
unexportedKeyType{
629+
map[[1]byte]*struct{}{
630+
{1}: nil,
631+
{2}: nil,
632+
},
633+
},
634+
true,
635+
"",
636+
},
637+
{
638+
unexportedKeyType{
639+
map[[1]byte]*struct{}{
640+
{1}: {},
641+
{2}: {},
642+
},
643+
},
644+
unexportedKeyType{
645+
map[[1]byte]*struct{}{
646+
{3}: {},
647+
{4}: {},
648+
},
649+
},
650+
false,
651+
"structs with unexported map fields using array keys are not equal when keys differ",
652+
},
653+
616654
// A case that might be confusing, especially with numeric literals
617655
{10, uint(10), false, ""},
618656
}

0 commit comments

Comments
 (0)