initial commit
[govpp.git] / vendor / github.com / onsi / gomega / format / format.go
1 /*
2 Gomega's format package pretty-prints objects.  It explores input objects recursively and generates formatted, indented output with type information.
3 */
4 package format
5
6 import (
7         "fmt"
8         "reflect"
9         "strconv"
10         "strings"
11         "time"
12 )
13
14 // Use MaxDepth to set the maximum recursion depth when printing deeply nested objects
15 var MaxDepth = uint(10)
16
17 /*
18 By default, all objects (even those that implement fmt.Stringer and fmt.GoStringer) are recursively inspected to generate output.
19
20 Set UseStringerRepresentation = true to use GoString (for fmt.GoStringers) or String (for fmt.Stringer) instead.
21
22 Note that GoString and String don't always have all the information you need to understand why a test failed!
23 */
24 var UseStringerRepresentation = false
25
26 /*
27 Print the content of context objects. By default it will be suppressed.
28
29 Set PrintContextObjects = true to enable printing of the context internals.
30 */
31 var PrintContextObjects = false
32
33 // Ctx interface defined here to keep backwards compatability with go < 1.7
34 // It matches the context.Context interface
35 type Ctx interface {
36         Deadline() (deadline time.Time, ok bool)
37         Done() <-chan struct{}
38         Err() error
39         Value(key interface{}) interface{}
40 }
41
42 var contextType = reflect.TypeOf((*Ctx)(nil)).Elem()
43 var timeType = reflect.TypeOf(time.Time{})
44
45 //The default indentation string emitted by the format package
46 var Indent = "    "
47
48 var longFormThreshold = 20
49
50 /*
51 Generates a formatted matcher success/failure message of the form:
52
53         Expected
54                 <pretty printed actual>
55         <message>
56                 <pretty printed expected>
57
58 If expected is omited, then the message looks like:
59
60         Expected
61                 <pretty printed actual>
62         <message>
63 */
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)
67         } else {
68                 return fmt.Sprintf("Expected\n%s\n%s\n%s", Object(actual, 1), message, Object(expected[0], 1))
69         }
70 }
71
72 /*
73
74 Generates a nicely formatted matcher success / failure message
75
76 Much like Message(...), but it attempts to pretty print diffs in strings
77
78 Expected
79     <string>: "...aaaaabaaaaa..."
80 to equal               |
81     <string>: "...aaaaazaaaaa..."
82
83 */
84
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)
90
91                 spacesBeforeFormattedMismatch := findFirstMismatch(formattedActual, formattedExpected)
92
93                 tabLength := 4
94                 spaceFromMessageToActual := tabLength + len("<string>: ") - len(message)
95                 padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|"
96                 return Message(formattedActual, message+padding, formattedExpected)
97         }
98         return Message(actual, message, expected)
99 }
100
101 func truncateAndFormat(str string, index int) string {
102         leftPadding := `...`
103         rightPadding := `...`
104
105         start := index - charactersAroundMismatchToInclude
106         if start < 0 {
107                 start = 0
108                 leftPadding = ""
109         }
110
111         // slice index must include the mis-matched character
112         lengthOfMismatchedCharacter := 1
113         end := index + charactersAroundMismatchToInclude + lengthOfMismatchedCharacter
114         if end > len(str) {
115                 end = len(str)
116                 rightPadding = ""
117
118         }
119         return fmt.Sprintf("\"%s\"", leftPadding+str[start:end]+rightPadding)
120 }
121
122 func findFirstMismatch(a, b string) int {
123         aSlice := strings.Split(a, "")
124         bSlice := strings.Split(b, "")
125
126         for index, str := range aSlice {
127                 if index > len(b) - 1 {
128                         return index
129                 }
130                 if str != bSlice[index] {
131                         return index
132                 }
133         }
134
135         if len(b) > len(a) {
136                 return len(a) + 1
137         }
138
139         return 0
140 }
141
142 const (
143         truncateThreshold                 = 50
144         charactersAroundMismatchToInclude = 5
145 )
146
147 /*
148 Pretty prints the passed in object at the passed in indentation level.
149
150 Object recurses into deeply nested objects emitting pretty-printed representations of their components.
151
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.
155
156 Set PrintContextObjects to true to print the content of objects implementing context.Context
157 */
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))
162 }
163
164 /*
165 IndentString takes a string and indents each line by the specified amount.
166 */
167 func IndentString(s string, indentation uint) string {
168         components := strings.Split(s, "\n")
169         result := ""
170         indent := strings.Repeat(Indent, int(indentation))
171         for i, component := range components {
172                 result += indent + component
173                 if i < len(components)-1 {
174                         result += "\n"
175                 }
176         }
177
178         return result
179 }
180
181 func formatType(object interface{}) string {
182         t := reflect.TypeOf(object)
183         if t == nil {
184                 return "nil"
185         }
186         switch t.Kind() {
187         case reflect.Chan:
188                 v := reflect.ValueOf(object)
189                 return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap())
190         case reflect.Ptr:
191                 return fmt.Sprintf("%T | %p", object, object)
192         case reflect.Slice:
193                 v := reflect.ValueOf(object)
194                 return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap())
195         case reflect.Map:
196                 v := reflect.ValueOf(object)
197                 return fmt.Sprintf("%T | len:%d", object, v.Len())
198         default:
199                 return fmt.Sprintf("%T", object)
200         }
201 }
202
203 func formatValue(value reflect.Value, indentation uint) string {
204         if indentation > MaxDepth {
205                 return "..."
206         }
207
208         if isNilValue(value) {
209                 return "nil"
210         }
211
212         if UseStringerRepresentation {
213                 if value.CanInterface() {
214                         obj := value.Interface()
215                         switch x := obj.(type) {
216                         case fmt.GoStringer:
217                                 return x.GoString()
218                         case fmt.Stringer:
219                                 return x.String()
220                         }
221                 }
222         }
223
224         if !PrintContextObjects {
225                 if value.Type().Implements(contextType) && indentation > 1 {
226                         return "<suppressed context>"
227                 }
228         }
229
230         switch value.Kind() {
231         case reflect.Bool:
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())
243         case reflect.Chan:
244                 return fmt.Sprintf("0x%x", value.Pointer())
245         case reflect.Func:
246                 return fmt.Sprintf("0x%x", value.Pointer())
247         case reflect.Ptr:
248                 return formatValue(value.Elem(), indentation)
249         case reflect.Slice:
250                 return formatSlice(value, indentation)
251         case reflect.String:
252                 return formatString(value.String(), indentation)
253         case reflect.Array:
254                 return formatSlice(value, indentation)
255         case reflect.Map:
256                 return formatMap(value, indentation)
257         case reflect.Struct:
258                 if value.Type() == timeType && value.CanInterface() {
259                         t, _ := value.Interface().(time.Time)
260                         return t.Format(time.RFC3339Nano)
261                 }
262                 return formatStruct(value, indentation)
263         case reflect.Interface:
264                 return formatValue(value.Elem(), indentation)
265         default:
266                 if value.CanInterface() {
267                         return fmt.Sprintf("%#v", value.Interface())
268                 } else {
269                         return fmt.Sprintf("%#v", value)
270                 }
271         }
272 }
273
274 func formatString(object interface{}, indentation uint) string {
275         if indentation == 1 {
276                 s := fmt.Sprintf("%s", object)
277                 components := strings.Split(s, "\n")
278                 result := ""
279                 for i, component := range components {
280                         if i == 0 {
281                                 result += component
282                         } else {
283                                 result += Indent + component
284                         }
285                         if i < len(components)-1 {
286                                 result += "\n"
287                         }
288                 }
289
290                 return fmt.Sprintf("%s", result)
291         } else {
292                 return fmt.Sprintf("%q", object)
293         }
294 }
295
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)
299         }
300
301         l := v.Len()
302         result := make([]string, l)
303         longest := 0
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])
308                 }
309         }
310
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)
314         } else {
315                 return fmt.Sprintf("[%s]", strings.Join(result, ", "))
316         }
317 }
318
319 func formatMap(v reflect.Value, indentation uint) string {
320         l := v.Len()
321         result := make([]string, l)
322
323         longest := 0
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])
329                 }
330         }
331
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)
335         } else {
336                 return fmt.Sprintf("{%s}", strings.Join(result, ", "))
337         }
338 }
339
340 func formatStruct(v reflect.Value, indentation uint) string {
341         t := v.Type()
342
343         l := v.NumField()
344         result := []string{}
345         longest := 0
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)
353                 }
354         }
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)
358         } else {
359                 return fmt.Sprintf("{%s}", strings.Join(result, ", "))
360         }
361 }
362
363 func isNilValue(a reflect.Value) bool {
364         switch a.Kind() {
365         case reflect.Invalid:
366                 return true
367         case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
368                 return a.IsNil()
369         }
370
371         return false
372 }
373
374 /*
375 Returns true when the string is entirely made of printable runes, false otherwise.
376 */
377 func isPrintableString(str string) bool {
378         for _, runeValue := range str {
379                 if !strconv.IsPrint(runeValue) {
380                         return false
381                 }
382         }
383         return true
384 }