From ac4c5c4eba818942df11fd7df55efe99f938fde9 Mon Sep 17 00:00:00 2001 From: Cyrill Schumacher Date: Mon, 7 Dec 2020 08:55:20 +0100 Subject: [PATCH] Fix panic for private fields which cannot Interface Also: Skip trailing comma. --- internal/test.go | 21 +++++++++++++++++++ repr.go | 52 +++++++++++++++++++++++++++--------------------- repr_test.go | 11 +++++++++- 3 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 internal/test.go diff --git a/internal/test.go b/internal/test.go new file mode 100644 index 0000000..a3a3d78 --- /dev/null +++ b/internal/test.go @@ -0,0 +1,21 @@ +package internal + +import ( + "time" +) + +type StructA struct { + String1 string + string2 string + Time1 time.Time + time2 time.Time +} + +func MakeStructA(s string, t time.Time) StructA { + return StructA{ + String1: s, + string2: s + "2", + Time1: t, + time2: t.Add(2 * time.Hour), + } +} diff --git a/repr.go b/repr.go index 6bc2151..f94b450 100644 --- a/repr.go +++ b/repr.go @@ -233,33 +233,39 @@ func (p *Printer) reprValue(seen map[reflect.Value]bool, v reflect.Value, indent fmt.Fprintf(p.w, "%s}", in) case reflect.Struct: - if td, ok := v.Interface().(time.Time); ok { - timeToGo(p.w, td) - } else { - if showType { - fmt.Fprintf(p.w, "%s{", v.Type()) - } else { - fmt.Fprint(p.w, "{") + + if v.CanInterface() { + switch tv := v.Interface().(type) { + case time.Time: + timeToGo(p.w, tv) + return } - if p.indent != "" && v.NumField() != 0 { - fmt.Fprintf(p.w, "\n") + } + + if showType { + fmt.Fprintf(p.w, "%s{", v.Type()) + } else { + fmt.Fprint(p.w, "{") + } + if p.indent != "" && v.NumField() != 0 { + fmt.Fprintf(p.w, "\n") + } + for i := 0; i < v.NumField(); i++ { + t := v.Type().Field(i) + f := v.Field(i) + if p.omitEmpty && isZero(f) { + continue } - for i := 0; i < v.NumField(); i++ { - t := v.Type().Field(i) - f := v.Field(i) - if p.omitEmpty && isZero(f) { - continue - } - fmt.Fprintf(p.w, "%s%s: ", ni, t.Name) - p.reprValue(seen, f, ni, true) - if p.indent != "" { - fmt.Fprintf(p.w, ",\n") - } else if i < v.NumField()-1 { - fmt.Fprintf(p.w, ", ") - } + fmt.Fprintf(p.w, "%s%s: ", ni, t.Name) + p.reprValue(seen, f, ni, true) + if p.indent != "" { + fmt.Fprintf(p.w, ",\n") + } else if i < v.NumField()-2 { + fmt.Fprintf(p.w, ", ") } - fmt.Fprintf(p.w, "%s}", indent) } + fmt.Fprintf(p.w, "%s}", indent) + case reflect.Ptr: if v.IsNil() { fmt.Fprintf(p.w, "nil") diff --git a/repr_test.go b/repr_test.go index a9fdaf2..03d6db3 100644 --- a/repr_test.go +++ b/repr_test.go @@ -6,6 +6,8 @@ import ( "strings" "testing" "time" + + "github.com/alecthomas/repr/internal" ) func equal(t *testing.T, want, have string) { @@ -185,7 +187,7 @@ func TestRecursiveIssue3(t *testing.T) { child := &data{} root := &data{children: []*data{child}} child.parent = root - want := "&repr.data{children: []*repr.data{{parent: &..., }}}" + want := "&repr.data{children: []*repr.data{{parent: &...}}}" have := String(root) equal(t, want, have) } @@ -209,3 +211,10 @@ func TestReprPrivateBytes(t *testing.T) { equal(t, "repr.MyBuffer{buf: &bytes.Buffer{buf: []byte(\"Hi th3re!\"), }}", s) } } + +func TestReprInternalTime(t *testing.T) { + obj := internal.MakeStructA("s", time.Date(2020, 12, 1, 10, 13, 45, 0, time.UTC)) + s := String(obj) + + equal(t, "internal.StructA{String1: \"s\", string2: \"s2\", Time1: time.Date(2020, 12, 1, 10, 13, 45, 0, time.UTC)time2: time.Time{ext: 63742421625}}", s) +}