2 Gomega's format package pretty-prints objects. It explores input objects recursively and generates formatted, indented output with type information.
14 // Use MaxDepth to set the maximum recursion depth when printing deeply nested objects
15 var MaxDepth = uint(10)
18 By default, all objects (even those that implement fmt.Stringer and fmt.GoStringer) are recursively inspected to generate output.
20 Set UseStringerRepresentation = true to use GoString (for fmt.GoStringers) or String (for fmt.Stringer) instead.
22 Note that GoString and String don't always have all the information you need to understand why a test failed!
24 var UseStringerRepresentation = false
27 Print the content of context objects. By default it will be suppressed.
29 Set PrintContextObjects = true to enable printing of the context internals.
31 var PrintContextObjects = false
33 // Ctx interface defined here to keep backwards compatability with go < 1.7
34 // It matches the context.Context interface
36 Deadline() (deadline time.Time, ok bool)
37 Done() <-chan struct{}
39 Value(key interface{}) interface{}
42 var contextType = reflect.TypeOf((*Ctx)(nil)).Elem()
43 var timeType = reflect.TypeOf(time.Time{})
45 //The default indentation string emitted by the format package
48 var longFormThreshold = 20
51 Generates a formatted matcher success/failure message of the form:
54 <pretty printed actual>
56 <pretty printed expected>
58 If expected is omited, then the message looks like:
61 <pretty printed actual>
64 func Message(actual interface{}, message string, expected ...interface{}) string {
65 if len(expected) == 0 {
66 return fmt.Sprintf("Expected\n%s\n%s", Object(actual, 1), message)
68 return fmt.Sprintf("Expected\n%s\n%s\n%s", Object(actual, 1), message, Object(expected[0], 1))
74 Generates a nicely formatted matcher success / failure message
76 Much like Message(...), but it attempts to pretty print diffs in strings
79 <string>: "...aaaaabaaaaa..."
81 <string>: "...aaaaazaaaaa..."
85 func MessageWithDiff(actual, message, expected string) string {
86 if len(actual) >= truncateThreshold && len(expected) >= truncateThreshold {
87 diffPoint := findFirstMismatch(actual, expected)
88 formattedActual := truncateAndFormat(actual, diffPoint)
89 formattedExpected := truncateAndFormat(expected, diffPoint)
91 spacesBeforeFormattedMismatch := findFirstMismatch(formattedActual, formattedExpected)
94 spaceFromMessageToActual := tabLength + len("<string>: ") - len(message)
95 padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|"
96 return Message(formattedActual, message+padding, formattedExpected)
98 return Message(actual, message, expected)
101 func truncateAndFormat(str string, index int) string {
103 rightPadding := `...`
105 start := index - charactersAroundMismatchToInclude
111 // slice index must include the mis-matched character
112 lengthOfMismatchedCharacter := 1
113 end := index + charactersAroundMismatchToInclude + lengthOfMismatchedCharacter
119 return fmt.Sprintf("\"%s\"", leftPadding+str[start:end]+rightPadding)
122 func findFirstMismatch(a, b string) int {
123 aSlice := strings.Split(a, "")
124 bSlice := strings.Split(b, "")
126 for index, str := range aSlice {
127 if index > len(b) - 1 {
130 if str != bSlice[index] {
143 truncateThreshold = 50
144 charactersAroundMismatchToInclude = 5
148 Pretty prints the passed in object at the passed in indentation level.
150 Object recurses into deeply nested objects emitting pretty-printed representations of their components.
152 Modify format.MaxDepth to control how deep the recursion is allowed to go
153 Set format.UseStringerRepresentation to true to return object.GoString() or object.String() when available instead of
154 recursing into the object.
156 Set PrintContextObjects to true to print the content of objects implementing context.Context
158 func Object(object interface{}, indentation uint) string {
159 indent := strings.Repeat(Indent, int(indentation))
160 value := reflect.ValueOf(object)
161 return fmt.Sprintf("%s<%s>: %s", indent, formatType(object), formatValue(value, indentation))
165 IndentString takes a string and indents each line by the specified amount.
167 func IndentString(s string, indentation uint) string {
168 components := strings.Split(s, "\n")
170 indent := strings.Repeat(Indent, int(indentation))
171 for i, component := range components {
172 result += indent + component
173 if i < len(components)-1 {
181 func formatType(object interface{}) string {
182 t := reflect.TypeOf(object)
188 v := reflect.ValueOf(object)
189 return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap())
191 return fmt.Sprintf("%T | %p", object, object)
193 v := reflect.ValueOf(object)
194 return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap())
196 v := reflect.ValueOf(object)
197 return fmt.Sprintf("%T | len:%d", object, v.Len())
199 return fmt.Sprintf("%T", object)
203 func formatValue(value reflect.Value, indentation uint) string {
204 if indentation > MaxDepth {
208 if isNilValue(value) {
212 if UseStringerRepresentation {
213 if value.CanInterface() {
214 obj := value.Interface()
215 switch x := obj.(type) {
224 if !PrintContextObjects {
225 if value.Type().Implements(contextType) && indentation > 1 {
226 return "<suppressed context>"
230 switch value.Kind() {
232 return fmt.Sprintf("%v", value.Bool())
233 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
234 return fmt.Sprintf("%v", value.Int())
235 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
236 return fmt.Sprintf("%v", value.Uint())
237 case reflect.Uintptr:
238 return fmt.Sprintf("0x%x", value.Uint())
239 case reflect.Float32, reflect.Float64:
240 return fmt.Sprintf("%v", value.Float())
241 case reflect.Complex64, reflect.Complex128:
242 return fmt.Sprintf("%v", value.Complex())
244 return fmt.Sprintf("0x%x", value.Pointer())
246 return fmt.Sprintf("0x%x", value.Pointer())
248 return formatValue(value.Elem(), indentation)
250 return formatSlice(value, indentation)
252 return formatString(value.String(), indentation)
254 return formatSlice(value, indentation)
256 return formatMap(value, indentation)
258 if value.Type() == timeType && value.CanInterface() {
259 t, _ := value.Interface().(time.Time)
260 return t.Format(time.RFC3339Nano)
262 return formatStruct(value, indentation)
263 case reflect.Interface:
264 return formatValue(value.Elem(), indentation)
266 if value.CanInterface() {
267 return fmt.Sprintf("%#v", value.Interface())
269 return fmt.Sprintf("%#v", value)
274 func formatString(object interface{}, indentation uint) string {
275 if indentation == 1 {
276 s := fmt.Sprintf("%s", object)
277 components := strings.Split(s, "\n")
279 for i, component := range components {
283 result += Indent + component
285 if i < len(components)-1 {
290 return fmt.Sprintf("%s", result)
292 return fmt.Sprintf("%q", object)
296 func formatSlice(v reflect.Value, indentation uint) string {
297 if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())) {
298 return formatString(v.Bytes(), indentation)
302 result := make([]string, l)
304 for i := 0; i < l; i++ {
305 result[i] = formatValue(v.Index(i), indentation+1)
306 if len(result[i]) > longest {
307 longest = len(result[i])
311 if longest > longFormThreshold {
312 indenter := strings.Repeat(Indent, int(indentation))
313 return fmt.Sprintf("[\n%s%s,\n%s]", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter)
315 return fmt.Sprintf("[%s]", strings.Join(result, ", "))
319 func formatMap(v reflect.Value, indentation uint) string {
321 result := make([]string, l)
324 for i, key := range v.MapKeys() {
325 value := v.MapIndex(key)
326 result[i] = fmt.Sprintf("%s: %s", formatValue(key, indentation+1), formatValue(value, indentation+1))
327 if len(result[i]) > longest {
328 longest = len(result[i])
332 if longest > longFormThreshold {
333 indenter := strings.Repeat(Indent, int(indentation))
334 return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter)
336 return fmt.Sprintf("{%s}", strings.Join(result, ", "))
340 func formatStruct(v reflect.Value, indentation uint) string {
346 for i := 0; i < l; i++ {
347 structField := t.Field(i)
348 fieldEntry := v.Field(i)
349 representation := fmt.Sprintf("%s: %s", structField.Name, formatValue(fieldEntry, indentation+1))
350 result = append(result, representation)
351 if len(representation) > longest {
352 longest = len(representation)
355 if longest > longFormThreshold {
356 indenter := strings.Repeat(Indent, int(indentation))
357 return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter)
359 return fmt.Sprintf("{%s}", strings.Join(result, ", "))
363 func isNilValue(a reflect.Value) bool {
365 case reflect.Invalid:
367 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
375 Returns true when the string is entirely made of printable runes, false otherwise.
377 func isPrintableString(str string) bool {
378 for _, runeValue := range str {
379 if !strconv.IsPrint(runeValue) {