From e1ea13a2d5ef9b991601648aef8638a092004197 Mon Sep 17 00:00:00 2001 From: Fatih Arslan Date: Tue, 7 Oct 2014 18:15:07 +0300 Subject: [PATCH] structs: fix nil pointer including, fixes #20 --- structs.go | 14 +++++++++----- structs_test.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/structs.go b/structs.go index 937b1cf..a75f523 100644 --- a/structs.go +++ b/structs.go @@ -92,7 +92,6 @@ func (s *Struct) Map() map[string]interface{} { // map[string]interface{} too finalVal = Map(val.Interface()) } else { - 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 // struct. func IsStruct(s interface{}) bool { - t := reflect.TypeOf(s) - if t.Kind() == reflect.Ptr { - t = t.Elem() + v := reflect.ValueOf(s) + if v.Kind() == reflect.Ptr { + 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 diff --git a/structs_test.go b/structs_test.go index 6020cbc..e37a337 100644 --- a/structs_test.go +++ b/structs_test.go @@ -773,3 +773,52 @@ func TestName(t *testing.T) { 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 +}