structs: fix nil pointer including, fixes #20

This commit is contained in:
Fatih Arslan 2014-10-07 18:15:07 +03:00
parent 4018983491
commit e1ea13a2d5
2 changed files with 58 additions and 5 deletions

View File

@ -92,7 +92,6 @@ func (s *Struct) Map() map[string]interface{} {
// map[string]interface{} too // map[string]interface{} too
finalVal = Map(val.Interface()) finalVal = Map(val.Interface())
} else { } else {
finalVal = val.Interface() finalVal = val.Interface()
} }
@ -400,12 +399,17 @@ func HasZero(s interface{}) bool {
// IsStruct returns true if the given variable is a struct or a pointer to // IsStruct returns true if the given variable is a struct or a pointer to
// struct. // struct.
func IsStruct(s interface{}) bool { func IsStruct(s interface{}) bool {
t := reflect.TypeOf(s) v := reflect.ValueOf(s)
if t.Kind() == reflect.Ptr { if v.Kind() == reflect.Ptr {
t = t.Elem() v = v.Elem()
} }
return t.Kind() == reflect.Struct // uninitialized zero value of a struct
if v.Kind() == reflect.Invalid {
return false
}
return v.Kind() == reflect.Struct
} }
// Name returns the structs's type name within its package. It returns an // Name returns the structs's type name within its package. It returns an

View File

@ -773,3 +773,52 @@ func TestName(t *testing.T) {
Name([]string{}) Name([]string{})
} }
func TestNestedNilPointer(t *testing.T) {
type Collar struct {
Engraving string
}
type Dog struct {
Name string
Collar *Collar
}
type Person struct {
Name string
Dog *Dog
}
person := &Person{
Name: "John",
}
personWithDog := &Person{
Name: "Ron",
Dog: &Dog{
Name: "Rover",
},
}
personWithDogWithCollar := &Person{
Name: "Kon",
Dog: &Dog{
Name: "Ruffles",
Collar: &Collar{
Engraving: "If lost, call Kon",
},
},
}
defer func() {
err := recover()
if err != nil {
fmt.Printf("err %+v\n", err)
t.Error("Internal nil pointer should not panic")
}
}()
_ = Map(person) // Panics
_ = Map(personWithDog) // Panics
_ = Map(personWithDogWithCollar) // Doesn't panic
}