initial commit
[govpp.git] / vendor / github.com / onsi / gomega / format / format_test.go
1 package format_test
2
3 import (
4         "fmt"
5         "strings"
6         "time"
7
8         . "github.com/onsi/ginkgo"
9         . "github.com/onsi/gomega"
10         . "github.com/onsi/gomega/format"
11         "github.com/onsi/gomega/types"
12 )
13
14 //recursive struct
15
16 type StringAlias string
17 type ByteAlias []byte
18 type IntAlias int
19
20 type AStruct struct {
21         Exported string
22 }
23
24 type SimpleStruct struct {
25         Name        string
26         Enumeration int
27         Veritas     bool
28         Data        []byte
29         secret      uint32
30 }
31
32 type ComplexStruct struct {
33         Strings      []string
34         SimpleThings []*SimpleStruct
35         DataMaps     map[int]ByteAlias
36 }
37
38 type SecretiveStruct struct {
39         boolValue      bool
40         intValue       int
41         uintValue      uint
42         uintptrValue   uintptr
43         floatValue     float32
44         complexValue   complex64
45         chanValue      chan bool
46         funcValue      func()
47         pointerValue   *int
48         sliceValue     []string
49         byteSliceValue []byte
50         stringValue    string
51         arrValue       [3]int
52         byteArrValue   [3]byte
53         mapValue       map[string]int
54         structValue    AStruct
55         interfaceValue interface{}
56 }
57
58 type GoStringer struct {
59 }
60
61 func (g GoStringer) GoString() string {
62         return "go-string"
63 }
64
65 func (g GoStringer) String() string {
66         return "string"
67 }
68
69 type Stringer struct {
70 }
71
72 func (g Stringer) String() string {
73         return "string"
74 }
75
76 type ctx struct {
77 }
78
79 func (c *ctx) Deadline() (deadline time.Time, ok bool) {
80         return time.Time{}, false
81 }
82
83 func (c *ctx) Done() <-chan struct{} {
84         return nil
85 }
86
87 func (c *ctx) Err() error {
88         return nil
89 }
90
91 func (c *ctx) Value(key interface{}) interface{} {
92         return nil
93 }
94
95 var _ = Describe("Format", func() {
96         match := func(typeRepresentation string, valueRepresentation string, args ...interface{}) types.GomegaMatcher {
97                 if len(args) > 0 {
98                         valueRepresentation = fmt.Sprintf(valueRepresentation, args...)
99                 }
100                 return Equal(fmt.Sprintf("%s<%s>: %s", Indent, typeRepresentation, valueRepresentation))
101         }
102
103         matchRegexp := func(typeRepresentation string, valueRepresentation string, args ...interface{}) types.GomegaMatcher {
104                 if len(args) > 0 {
105                         valueRepresentation = fmt.Sprintf(valueRepresentation, args...)
106                 }
107                 return MatchRegexp(fmt.Sprintf("%s<%s>: %s", Indent, typeRepresentation, valueRepresentation))
108         }
109
110         hashMatchingRegexp := func(entries ...string) string {
111                 entriesSwitch := "(" + strings.Join(entries, "|") + ")"
112                 arr := make([]string, len(entries))
113                 for i := range arr {
114                         arr[i] = entriesSwitch
115                 }
116                 return "{" + strings.Join(arr, ", ") + "}"
117         }
118
119         Describe("Message", func() {
120                 Context("with only an actual value", func() {
121                         It("should print out an indented formatted representation of the value and the message", func() {
122                                 Ω(Message(3, "to be three.")).Should(Equal("Expected\n    <int>: 3\nto be three."))
123                         })
124                 })
125
126                 Context("with an actual and an expected value", func() {
127                         It("should print out an indented formatted representatino of both values, and the message", func() {
128                                 Ω(Message(3, "to equal", 4)).Should(Equal("Expected\n    <int>: 3\nto equal\n    <int>: 4"))
129                         })
130                 })
131         })
132
133         Describe("MessageWithDiff", func() {
134                 It("shows the exact point where two long strings differ", func() {
135                         stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
136                         stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
137
138                         Ω(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedLongStringFailureMessage))
139                 })
140
141                 It("truncates the start of long strings that differ only at their end", func() {
142                         stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
143                         stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz"
144
145                         Ω(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedStartStringFailureMessage))
146                 })
147
148                 It("truncates the start of long strings that differ only in length", func() {
149                         smallString := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
150                         largeString := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
151
152                         Ω(MessageWithDiff(largeString, "to equal", smallString)).Should(Equal(expectedTruncatedStartSizeFailureMessage))
153                         Ω(MessageWithDiff(smallString, "to equal", largeString)).Should(Equal(expectedTruncatedStartSizeSwappedFailureMessage))
154                 })
155
156                 It("truncates the end of long strings that differ only at their start", func() {
157                         stringWithB := "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
158                         stringWithZ := "zaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
159
160                         Ω(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedEndStringFailureMessage))
161                 })
162         })
163
164         Describe("IndentString", func() {
165                 It("should indent the string", func() {
166                         Ω(IndentString("foo\n  bar\nbaz", 2)).Should(Equal("        foo\n          bar\n        baz"))
167                 })
168         })
169
170         Describe("Object", func() {
171                 Describe("formatting boolean values", func() {
172                         It("should give the type and format values correctly", func() {
173                                 Ω(Object(true, 1)).Should(match("bool", "true"))
174                                 Ω(Object(false, 1)).Should(match("bool", "false"))
175                         })
176                 })
177
178                 Describe("formatting numbers", func() {
179                         It("should give the type and format values correctly", func() {
180                                 Ω(Object(int(3), 1)).Should(match("int", "3"))
181                                 Ω(Object(int8(3), 1)).Should(match("int8", "3"))
182                                 Ω(Object(int16(3), 1)).Should(match("int16", "3"))
183                                 Ω(Object(int32(3), 1)).Should(match("int32", "3"))
184                                 Ω(Object(int64(3), 1)).Should(match("int64", "3"))
185
186                                 Ω(Object(uint(3), 1)).Should(match("uint", "3"))
187                                 Ω(Object(uint8(3), 1)).Should(match("uint8", "3"))
188                                 Ω(Object(uint16(3), 1)).Should(match("uint16", "3"))
189                                 Ω(Object(uint32(3), 1)).Should(match("uint32", "3"))
190                                 Ω(Object(uint64(3), 1)).Should(match("uint64", "3"))
191                         })
192
193                         It("should handle uintptr differently", func() {
194                                 Ω(Object(uintptr(3), 1)).Should(match("uintptr", "0x3"))
195                         })
196                 })
197
198                 Describe("formatting channels", func() {
199                         It("should give the type and format values correctly", func() {
200                                 c := make(chan<- bool, 3)
201                                 c <- true
202                                 c <- false
203                                 Ω(Object(c, 1)).Should(match("chan<- bool | len:2, cap:3", "%v", c))
204                         })
205                 })
206
207                 Describe("formatting strings", func() {
208                         It("should give the type and format values correctly", func() {
209                                 s := "a\nb\nc"
210                                 Ω(Object(s, 1)).Should(match("string", `a
211     b
212     c`))
213                         })
214                 })
215
216                 Describe("formatting []byte slices", func() {
217                         Context("when the slice is made of printable bytes", func() {
218                                 It("should present it as string", func() {
219                                         b := []byte("a b c")
220                                         Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`))
221                                 })
222                         })
223                         Context("when the slice contains non-printable bytes", func() {
224                                 It("should present it as slice", func() {
225                                         b := []byte("a b c\n\x01\x02\x03\xff\x1bH")
226                                         Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`))
227                                 })
228                         })
229                 })
230
231                 Describe("formatting functions", func() {
232                         It("should give the type and format values correctly", func() {
233                                 f := func(a string, b []int) ([]byte, error) {
234                                         return []byte("abc"), nil
235                                 }
236                                 Ω(Object(f, 1)).Should(match("func(string, []int) ([]uint8, error)", "%v", f))
237                         })
238                 })
239
240                 Describe("formatting pointers", func() {
241                         It("should give the type and dereference the value to format it correctly", func() {
242                                 a := 3
243                                 Ω(Object(&a, 1)).Should(match(fmt.Sprintf("*int | %p", &a), "3"))
244                         })
245
246                         Context("when there are pointers to pointers...", func() {
247                                 It("should recursively deference the pointer until it gets to a value", func() {
248                                         a := 3
249                                         var b *int
250                                         var c **int
251                                         var d ***int
252                                         b = &a
253                                         c = &b
254                                         d = &c
255
256                                         Ω(Object(d, 1)).Should(match(fmt.Sprintf("***int | %p", d), "3"))
257                                 })
258                         })
259
260                         Context("when the pointer points to nil", func() {
261                                 It("should say nil and not explode", func() {
262                                         var a *AStruct
263                                         Ω(Object(a, 1)).Should(match("*format_test.AStruct | 0x0", "nil"))
264                                 })
265                         })
266                 })
267
268                 Describe("formatting arrays", func() {
269                         It("should give the type and format values correctly", func() {
270                                 w := [3]string{"Jed Bartlet", "Toby Ziegler", "CJ Cregg"}
271                                 Ω(Object(w, 1)).Should(match("[3]string", `["Jed Bartlet", "Toby Ziegler", "CJ Cregg"]`))
272                         })
273
274                         Context("with byte arrays", func() {
275                                 It("should give the type and format values correctly", func() {
276                                         w := [3]byte{17, 28, 19}
277                                         Ω(Object(w, 1)).Should(match("[3]uint8", `[17, 28, 19]`))
278                                 })
279                         })
280                 })
281
282                 Describe("formatting slices", func() {
283                         It("should include the length and capacity in the type information", func() {
284                                 s := make([]bool, 3, 4)
285                                 Ω(Object(s, 1)).Should(match("[]bool | len:3, cap:4", "[false, false, false]"))
286                         })
287
288                         Context("when the slice contains long entries", func() {
289                                 It("should format the entries with newlines", func() {
290                                         w := []string{"Josiah Edward Bartlet", "Toby Ziegler", "CJ Cregg"}
291                                         expected := `[
292         "Josiah Edward Bartlet",
293         "Toby Ziegler",
294         "CJ Cregg",
295     ]`
296                                         Ω(Object(w, 1)).Should(match("[]string | len:3, cap:3", expected))
297                                 })
298                         })
299                 })
300
301                 Describe("formatting maps", func() {
302                         It("should include the length in the type information", func() {
303                                 m := make(map[int]bool, 5)
304                                 m[3] = true
305                                 m[4] = false
306                                 Ω(Object(m, 1)).Should(matchRegexp(`map\[int\]bool \| len:2`, hashMatchingRegexp("3: true", "4: false")))
307                         })
308
309                         Context("when the slice contains long entries", func() {
310                                 It("should format the entries with newlines", func() {
311                                         m := map[string][]byte{}
312                                         m["Josiah Edward Bartlet"] = []byte("Martin Sheen")
313                                         m["Toby Ziegler"] = []byte("Richard Schiff")
314                                         m["CJ Cregg"] = []byte("Allison Janney")
315                                         expected := `{
316         ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
317         ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
318         ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
319     }`
320                                         Ω(Object(m, 1)).Should(matchRegexp(`map\[string\]\[\]uint8 \| len:3`, expected))
321                                 })
322                         })
323                 })
324
325                 Describe("formatting structs", func() {
326                         It("should include the struct name and the field names", func() {
327                                 s := SimpleStruct{
328                                         Name:        "Oswald",
329                                         Enumeration: 17,
330                                         Veritas:     true,
331                                         Data:        []byte("datum"),
332                                         secret:      1983,
333                                 }
334
335                                 Ω(Object(s, 1)).Should(match("format_test.SimpleStruct", `{Name: "Oswald", Enumeration: 17, Veritas: true, Data: "datum", secret: 1983}`))
336                         })
337
338                         Context("when the struct contains long entries", func() {
339                                 It("should format the entries with new lines", func() {
340                                         s := &SimpleStruct{
341                                                 Name:        "Mithrandir Gandalf Greyhame",
342                                                 Enumeration: 2021,
343                                                 Veritas:     true,
344                                                 Data:        []byte("wizard"),
345                                                 secret:      3,
346                                         }
347
348                                         Ω(Object(s, 1)).Should(match(fmt.Sprintf("*format_test.SimpleStruct | %p", s), `{
349         Name: "Mithrandir Gandalf Greyhame",
350         Enumeration: 2021,
351         Veritas: true,
352         Data: "wizard",
353         secret: 3,
354     }`))
355                                 })
356                         })
357                 })
358
359                 Describe("formatting nil values", func() {
360                         It("should print out nil", func() {
361                                 Ω(Object(nil, 1)).Should(match("nil", "nil"))
362                                 var typedNil *AStruct
363                                 Ω(Object(typedNil, 1)).Should(match("*format_test.AStruct | 0x0", "nil"))
364                                 var c chan<- bool
365                                 Ω(Object(c, 1)).Should(match("chan<- bool | len:0, cap:0", "nil"))
366                                 var s []string
367                                 Ω(Object(s, 1)).Should(match("[]string | len:0, cap:0", "nil"))
368                                 var m map[string]bool
369                                 Ω(Object(m, 1)).Should(match("map[string]bool | len:0", "nil"))
370                         })
371                 })
372
373                 Describe("formatting aliased types", func() {
374                         It("should print out the correct alias type", func() {
375                                 Ω(Object(StringAlias("alias"), 1)).Should(match("format_test.StringAlias", `alias`))
376                                 Ω(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `alias`))
377                                 Ω(Object(IntAlias(3), 1)).Should(match("format_test.IntAlias", "3"))
378                         })
379                 })
380
381                 Describe("handling nested things", func() {
382                         It("should produce a correctly nested representation", func() {
383                                 s := ComplexStruct{
384                                         Strings: []string{"lots", "of", "short", "strings"},
385                                         SimpleThings: []*SimpleStruct{
386                                                 {"short", 7, true, []byte("succinct"), 17},
387                                                 {"something longer", 427, true, []byte("designed to wrap around nicely"), 30},
388                                         },
389                                         DataMaps: map[int]ByteAlias{
390                                                 17:   ByteAlias("some substantially longer chunks of data"),
391                                                 1138: ByteAlias("that should make things wrap"),
392                                         },
393                                 }
394                                 expected := `{
395         Strings: \["lots", "of", "short", "strings"\],
396         SimpleThings: \[
397             {Name: "short", Enumeration: 7, Veritas: true, Data: "succinct", secret: 17},
398             {
399                 Name: "something longer",
400                 Enumeration: 427,
401                 Veritas: true,
402                 Data: "designed to wrap around nicely",
403                 secret: 30,
404             },
405         \],
406         DataMaps: {
407             (17: "some substantially longer chunks of data"|1138: "that should make things wrap"),
408             (17: "some substantially longer chunks of data"|1138: "that should make things wrap"),
409         },
410     }`
411                                 Ω(Object(s, 1)).Should(matchRegexp(`format_test\.ComplexStruct`, expected))
412                         })
413                 })
414
415                 Describe("formatting times", func() {
416                         It("should format time as RFC3339", func() {
417                                 t := time.Date(2016, 10, 31, 9, 57, 23, 12345, time.UTC)
418                                 Ω(Object(t, 1)).Should(match("time.Time", `2016-10-31T09:57:23.000012345Z`))
419                         })
420                 })
421         })
422
423         Describe("Handling unexported fields in structs", func() {
424                 It("should handle all the various types correctly", func() {
425                         a := int(5)
426                         s := SecretiveStruct{
427                                 boolValue:      true,
428                                 intValue:       3,
429                                 uintValue:      4,
430                                 uintptrValue:   5,
431                                 floatValue:     6.0,
432                                 complexValue:   complex(5.0, 3.0),
433                                 chanValue:      make(chan bool, 2),
434                                 funcValue:      func() {},
435                                 pointerValue:   &a,
436                                 sliceValue:     []string{"string", "slice"},
437                                 byteSliceValue: []byte("bytes"),
438                                 stringValue:    "a string",
439                                 arrValue:       [3]int{11, 12, 13},
440                                 byteArrValue:   [3]byte{17, 20, 32},
441                                 mapValue:       map[string]int{"a key": 20, "b key": 30},
442                                 structValue:    AStruct{"exported"},
443                                 interfaceValue: map[string]int{"a key": 17},
444                         }
445
446                         expected := fmt.Sprintf(`{
447         boolValue: true,
448         intValue: 3,
449         uintValue: 4,
450         uintptrValue: 0x5,
451         floatValue: 6,
452         complexValue: \(5\+3i\),
453         chanValue: %p,
454         funcValue: %p,
455         pointerValue: 5,
456         sliceValue: \["string", "slice"\],
457         byteSliceValue: "bytes",
458         stringValue: "a string",
459         arrValue: \[11, 12, 13\],
460         byteArrValue: \[17, 20, 32\],
461         mapValue: %s,
462         structValue: {Exported: "exported"},
463         interfaceValue: {"a key": 17},
464     }`, s.chanValue, s.funcValue, hashMatchingRegexp(`"a key": 20`, `"b key": 30`))
465
466                         Ω(Object(s, 1)).Should(matchRegexp(`format_test\.SecretiveStruct`, expected))
467                 })
468         })
469
470         Describe("Handling interfaces", func() {
471                 It("should unpack the interface", func() {
472                         outerHash := map[string]interface{}{}
473                         innerHash := map[string]int{}
474
475                         innerHash["inner"] = 3
476                         outerHash["integer"] = 2
477                         outerHash["map"] = innerHash
478
479                         expected := hashMatchingRegexp(`"integer": 2`, `"map": {"inner": 3}`)
480                         Ω(Object(outerHash, 1)).Should(matchRegexp(`map\[string\]interface {} \| len:2`, expected))
481                 })
482         })
483
484         Describe("Handling recursive things", func() {
485                 It("should not go crazy...", func() {
486                         m := map[string]interface{}{}
487                         m["integer"] = 2
488                         m["map"] = m
489                         Ω(Object(m, 1)).Should(ContainSubstring("..."))
490                 })
491
492                 It("really should not go crazy...", func() {
493                         type complexKey struct {
494                                 Value map[interface{}]int
495                         }
496
497                         complexObject := complexKey{}
498                         complexObject.Value = make(map[interface{}]int)
499
500                         complexObject.Value[&complexObject] = 2
501                         Ω(Object(complexObject, 1)).Should(ContainSubstring("..."))
502                 })
503         })
504
505         Describe("When instructed to use the Stringer representation", func() {
506                 BeforeEach(func() {
507                         UseStringerRepresentation = true
508                 })
509
510                 AfterEach(func() {
511                         UseStringerRepresentation = false
512                 })
513
514                 Context("when passed a GoStringer", func() {
515                         It("should use what GoString() returns", func() {
516                                 Ω(Object(GoStringer{}, 1)).Should(ContainSubstring("<format_test.GoStringer>: go-string"))
517                         })
518                 })
519
520                 Context("when passed a stringer", func() {
521                         It("should use what String() returns", func() {
522                                 Ω(Object(Stringer{}, 1)).Should(ContainSubstring("<format_test.Stringer>: string"))
523                         })
524                 })
525         })
526
527         Describe("Printing a context.Context field", func() {
528
529                 type structWithContext struct {
530                         Context Ctx
531                         Value   string
532                 }
533
534                 context := ctx{}
535                 objWithContext := structWithContext{Value: "some-value", Context: &context}
536
537                 It("Suppresses the content by default", func() {
538                         Ω(Object(objWithContext, 1)).Should(ContainSubstring("<suppressed context>"))
539                 })
540
541                 It("Doesn't supress the context if it's the object being printed", func() {
542                         Ω(Object(context, 1)).ShouldNot(MatchRegexp("^.*<suppressed context>$"))
543                 })
544
545                 Context("PrintContextObjects is set", func() {
546                         BeforeEach(func() {
547                                 PrintContextObjects = true
548                         })
549
550                         AfterEach(func() {
551                                 PrintContextObjects = false
552                         })
553
554                         It("Prints the context", func() {
555                                 Ω(Object(objWithContext, 1)).ShouldNot(ContainSubstring("<suppressed context>"))
556                         })
557                 })
558         })
559 })
560
561 var expectedLongStringFailureMessage = strings.TrimSpace(`
562 Expected
563     <string>: "...aaaaabaaaaa..."
564 to equal               |
565     <string>: "...aaaaazaaaaa..."
566 `)
567 var expectedTruncatedEndStringFailureMessage = strings.TrimSpace(`
568 Expected
569     <string>: "baaaaa..."
570 to equal       |
571     <string>: "zaaaaa..."
572 `)
573 var expectedTruncatedStartStringFailureMessage = strings.TrimSpace(`
574 Expected
575     <string>: "...aaaaab"
576 to equal               |
577     <string>: "...aaaaaz"
578 `)
579 var expectedTruncatedStartSizeFailureMessage = strings.TrimSpace(`
580 Expected
581     <string>: "...aaaaaa"
582 to equal               |
583     <string>: "...aaaaa"
584 `)
585 var expectedTruncatedStartSizeSwappedFailureMessage = strings.TrimSpace(`
586 Expected
587     <string>: "...aaaa"
588 to equal              |
589     <string>: "...aaaaa"
590 `)