Merge pull request #179 from ebabani/master
Suppress printing the internals of context.Context. Added a flag to o…
diff --git a/format/format.go b/format/format.go
index 952726e..5cd89bc 100644
--- a/format/format.go
+++ b/format/format.go
@@ -8,6 +8,7 @@
"reflect"
"strconv"
"strings"
+ "time"
)
// Use MaxDepth to set the maximum recursion depth when printing deeply nested objects
@@ -22,6 +23,24 @@
*/
var UseStringerRepresentation = false
+/*
+Print the content of context objects. By default it will be suppressed.
+
+Set PrintContextObjects = true to enable printing of the context internals.
+*/
+var PrintContextObjects = false
+
+// Ctx interface defined here to keep backwards compatability with go < 1.7
+// It matches the context.Context interface
+type Ctx interface {
+ Deadline() (deadline time.Time, ok bool)
+ Done() <-chan struct{}
+ Err() error
+ Value(key interface{}) interface{}
+}
+
+var contextType = reflect.TypeOf((*Ctx)(nil)).Elem()
+
//The default indentation string emitted by the format package
var Indent = " "
@@ -57,6 +76,8 @@
Modify format.MaxDepth to control how deep the recursion is allowed to go
Set format.UseStringerRepresentation to true to return object.GoString() or object.String() when available instead of
recursing into the object.
+
+Set PrintContextObjects to true to print the content of objects implementing context.Context
*/
func Object(object interface{}, indentation uint) string {
indent := strings.Repeat(Indent, int(indentation))
@@ -124,6 +145,12 @@
}
}
+ if !PrintContextObjects {
+ if value.Type().Implements(contextType) && indentation > 1 {
+ return "<suppressed context>"
+ }
+ }
+
switch value.Kind() {
case reflect.Bool:
return fmt.Sprintf("%v", value.Bool())
diff --git a/format/format_test.go b/format/format_test.go
index b27df8e..4d4b36c 100644
--- a/format/format_test.go
+++ b/format/format_test.go
@@ -3,6 +3,7 @@
import (
"fmt"
"strings"
+ "time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -72,6 +73,25 @@
return "string"
}
+type ctx struct {
+}
+
+func (c *ctx) Deadline() (deadline time.Time, ok bool) {
+ return time.Time{}, false
+}
+
+func (c *ctx) Done() <-chan struct{} {
+ return nil
+}
+
+func (c *ctx) Err() error {
+ return nil
+}
+
+func (c *ctx) Value(key interface{}) interface{} {
+ return nil
+}
+
var _ = Describe("Format", func() {
match := func(typeRepresentation string, valueRepresentation string, args ...interface{}) types.GomegaMatcher {
if len(args) > 0 {
@@ -465,4 +485,37 @@
})
})
})
+
+ Describe("Printing a context.Context field", func() {
+
+ type structWithContext struct {
+ Context Ctx
+ Value string
+ }
+
+ context := ctx{}
+ objWithContext := structWithContext{Value: "some-value", Context: &context}
+
+ It("Suppresses the content by default", func() {
+ Ω(Object(objWithContext, 1)).Should(ContainSubstring("<suppressed context>"))
+ })
+
+ It("Doesn't supress the context if it's the object being printed", func() {
+ Ω(Object(context, 1)).ShouldNot(MatchRegexp("^.*<suppressed context>$"))
+ })
+
+ Context("PrintContextObjects is set", func() {
+ BeforeEach(func() {
+ PrintContextObjects = true
+ })
+
+ AfterEach(func() {
+ PrintContextObjects = false
+ })
+
+ It("Prints the context", func() {
+ Ω(Object(objWithContext, 1)).ShouldNot(ContainSubstring("<suppressed context>"))
+ })
+ })
+ })
})