blob: 044da8b01f22644b8d10443c08a2d9ef073b315c [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001package assert
2
3import (
4 "bufio"
5 "bytes"
6 "encoding/json"
7 "errors"
8 "fmt"
9 "math"
10 "os"
11 "reflect"
12 "regexp"
13 "runtime"
14 "strings"
15 "time"
16 "unicode"
17 "unicode/utf8"
18
19 "github.com/davecgh/go-spew/spew"
20 "github.com/pmezard/go-difflib/difflib"
Scott Baker8461e152019-10-01 14:44:30 -070021 yaml "gopkg.in/yaml.v2"
khenaidooac637102019-01-14 15:44:34 -050022)
23
24//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
25
26// TestingT is an interface wrapper around *testing.T
27type TestingT interface {
28 Errorf(format string, args ...interface{})
29}
30
31// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
32// for table driven tests.
33type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
34
35// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
36// for table driven tests.
37type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
38
39// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
40// for table driven tests.
41type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
42
43// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
44// for table driven tests.
45type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
46
47// Comparison a custom function that returns true on success and false on failure
48type Comparison func() (success bool)
49
50/*
51 Helper functions
52*/
53
54// ObjectsAreEqual determines if two objects are considered equal.
55//
56// This function does no assertion of any kind.
57func ObjectsAreEqual(expected, actual interface{}) bool {
58 if expected == nil || actual == nil {
59 return expected == actual
60 }
61
62 exp, ok := expected.([]byte)
63 if !ok {
64 return reflect.DeepEqual(expected, actual)
65 }
66
67 act, ok := actual.([]byte)
68 if !ok {
69 return false
70 }
71 if exp == nil || act == nil {
72 return exp == nil && act == nil
73 }
74 return bytes.Equal(exp, act)
75}
76
77// ObjectsAreEqualValues gets whether two objects are equal, or if their
78// values are equal.
79func ObjectsAreEqualValues(expected, actual interface{}) bool {
80 if ObjectsAreEqual(expected, actual) {
81 return true
82 }
83
84 actualType := reflect.TypeOf(actual)
85 if actualType == nil {
86 return false
87 }
88 expectedValue := reflect.ValueOf(expected)
89 if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
90 // Attempt comparison after type conversion
91 return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
92 }
93
94 return false
95}
96
97/* CallerInfo is necessary because the assert functions use the testing object
98internally, causing it to print the file:line of the assert method, rather than where
99the problem actually occurred in calling code.*/
100
101// CallerInfo returns an array of strings containing the file and line number
102// of each stack frame leading from the current test to the assert call that
103// failed.
104func CallerInfo() []string {
105
106 pc := uintptr(0)
107 file := ""
108 line := 0
109 ok := false
110 name := ""
111
112 callers := []string{}
113 for i := 0; ; i++ {
114 pc, file, line, ok = runtime.Caller(i)
115 if !ok {
116 // The breaks below failed to terminate the loop, and we ran off the
117 // end of the call stack.
118 break
119 }
120
121 // This is a huge edge case, but it will panic if this is the case, see #180
122 if file == "<autogenerated>" {
123 break
124 }
125
126 f := runtime.FuncForPC(pc)
127 if f == nil {
128 break
129 }
130 name = f.Name()
131
132 // testing.tRunner is the standard library function that calls
133 // tests. Subtests are called directly by tRunner, without going through
134 // the Test/Benchmark/Example function that contains the t.Run calls, so
135 // with subtests we should break when we hit tRunner, without adding it
136 // to the list of callers.
137 if name == "testing.tRunner" {
138 break
139 }
140
141 parts := strings.Split(file, "/")
142 file = parts[len(parts)-1]
143 if len(parts) > 1 {
144 dir := parts[len(parts)-2]
145 if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
146 callers = append(callers, fmt.Sprintf("%s:%d", file, line))
147 }
148 }
149
150 // Drop the package
151 segments := strings.Split(name, ".")
152 name = segments[len(segments)-1]
153 if isTest(name, "Test") ||
154 isTest(name, "Benchmark") ||
155 isTest(name, "Example") {
156 break
157 }
158 }
159
160 return callers
161}
162
163// Stolen from the `go test` tool.
164// isTest tells whether name looks like a test (or benchmark, according to prefix).
165// It is a Test (say) if there is a character after Test that is not a lower-case letter.
166// We don't want TesticularCancer.
167func isTest(name, prefix string) bool {
168 if !strings.HasPrefix(name, prefix) {
169 return false
170 }
171 if len(name) == len(prefix) { // "Test" is ok
172 return true
173 }
174 rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
175 return !unicode.IsLower(rune)
176}
177
178func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
179 if len(msgAndArgs) == 0 || msgAndArgs == nil {
180 return ""
181 }
182 if len(msgAndArgs) == 1 {
183 msg := msgAndArgs[0]
184 if msgAsStr, ok := msg.(string); ok {
185 return msgAsStr
186 }
187 return fmt.Sprintf("%+v", msg)
188 }
189 if len(msgAndArgs) > 1 {
190 return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
191 }
192 return ""
193}
194
195// Aligns the provided message so that all lines after the first line start at the same location as the first line.
196// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab).
197// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the
198// basis on which the alignment occurs).
199func indentMessageLines(message string, longestLabelLen int) string {
200 outBuf := new(bytes.Buffer)
201
202 for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
203 // no need to align first line because it starts at the correct location (after the label)
204 if i != 0 {
205 // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
206 outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
207 }
208 outBuf.WriteString(scanner.Text())
209 }
210
211 return outBuf.String()
212}
213
214type failNower interface {
215 FailNow()
216}
217
218// FailNow fails test
219func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
220 if h, ok := t.(tHelper); ok {
221 h.Helper()
222 }
223 Fail(t, failureMessage, msgAndArgs...)
224
225 // We cannot extend TestingT with FailNow() and
226 // maintain backwards compatibility, so we fallback
227 // to panicking when FailNow is not available in
228 // TestingT.
229 // See issue #263
230
231 if t, ok := t.(failNower); ok {
232 t.FailNow()
233 } else {
234 panic("test failed and t is missing `FailNow()`")
235 }
236 return false
237}
238
239// Fail reports a failure through
240func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
241 if h, ok := t.(tHelper); ok {
242 h.Helper()
243 }
244 content := []labeledContent{
245 {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
246 {"Error", failureMessage},
247 }
248
249 // Add test name if the Go version supports it
250 if n, ok := t.(interface {
251 Name() string
252 }); ok {
253 content = append(content, labeledContent{"Test", n.Name()})
254 }
255
256 message := messageFromMsgAndArgs(msgAndArgs...)
257 if len(message) > 0 {
258 content = append(content, labeledContent{"Messages", message})
259 }
260
261 t.Errorf("\n%s", ""+labeledOutput(content...))
262
263 return false
264}
265
266type labeledContent struct {
267 label string
268 content string
269}
270
271// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
272//
273// \t{{label}}:{{align_spaces}}\t{{content}}\n
274//
275// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
276// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
277// alignment is achieved, "\t{{content}}\n" is added for the output.
278//
279// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line.
280func labeledOutput(content ...labeledContent) string {
281 longestLabel := 0
282 for _, v := range content {
283 if len(v.label) > longestLabel {
284 longestLabel = len(v.label)
285 }
286 }
287 var output string
288 for _, v := range content {
289 output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
290 }
291 return output
292}
293
294// Implements asserts that an object is implemented by the specified interface.
295//
296// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
297func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
298 if h, ok := t.(tHelper); ok {
299 h.Helper()
300 }
301 interfaceType := reflect.TypeOf(interfaceObject).Elem()
302
303 if object == nil {
304 return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...)
305 }
306 if !reflect.TypeOf(object).Implements(interfaceType) {
307 return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...)
308 }
309
310 return true
311}
312
313// IsType asserts that the specified objects are of the same type.
314func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
315 if h, ok := t.(tHelper); ok {
316 h.Helper()
317 }
318
319 if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
320 return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
321 }
322
323 return true
324}
325
326// Equal asserts that two objects are equal.
327//
328// assert.Equal(t, 123, 123)
329//
330// Pointer variable equality is determined based on the equality of the
331// referenced values (as opposed to the memory addresses). Function equality
332// cannot be determined and will always fail.
333func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
334 if h, ok := t.(tHelper); ok {
335 h.Helper()
336 }
337 if err := validateEqualArgs(expected, actual); err != nil {
338 return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
339 expected, actual, err), msgAndArgs...)
340 }
341
342 if !ObjectsAreEqual(expected, actual) {
343 diff := diff(expected, actual)
344 expected, actual = formatUnequalValues(expected, actual)
345 return Fail(t, fmt.Sprintf("Not equal: \n"+
346 "expected: %s\n"+
347 "actual : %s%s", expected, actual, diff), msgAndArgs...)
348 }
349
350 return true
351
352}
353
Scott Baker8461e152019-10-01 14:44:30 -0700354// Same asserts that two pointers reference the same object.
355//
356// assert.Same(t, ptr1, ptr2)
357//
358// Both arguments must be pointer variables. Pointer variable sameness is
359// determined based on the equality of both type and value.
360func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
361 if h, ok := t.(tHelper); ok {
362 h.Helper()
363 }
364
365 expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual)
366 if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr {
367 return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...)
368 }
369
370 expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual)
371 if expectedType != actualType {
372 return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v",
373 expectedType, actualType), msgAndArgs...)
374 }
375
376 if expected != actual {
377 return Fail(t, fmt.Sprintf("Not same: \n"+
378 "expected: %p %#v\n"+
379 "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
380 }
381
382 return true
383}
384
khenaidooac637102019-01-14 15:44:34 -0500385// formatUnequalValues takes two values of arbitrary types and returns string
386// representations appropriate to be presented to the user.
387//
388// If the values are not of like type, the returned strings will be prefixed
389// with the type name, and the value will be enclosed in parenthesis similar
390// to a type conversion in the Go grammar.
391func formatUnequalValues(expected, actual interface{}) (e string, a string) {
392 if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
393 return fmt.Sprintf("%T(%#v)", expected, expected),
394 fmt.Sprintf("%T(%#v)", actual, actual)
395 }
396
397 return fmt.Sprintf("%#v", expected),
398 fmt.Sprintf("%#v", actual)
399}
400
401// EqualValues asserts that two objects are equal or convertable to the same types
402// and equal.
403//
404// assert.EqualValues(t, uint32(123), int32(123))
405func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
406 if h, ok := t.(tHelper); ok {
407 h.Helper()
408 }
409
410 if !ObjectsAreEqualValues(expected, actual) {
411 diff := diff(expected, actual)
412 expected, actual = formatUnequalValues(expected, actual)
413 return Fail(t, fmt.Sprintf("Not equal: \n"+
414 "expected: %s\n"+
415 "actual : %s%s", expected, actual, diff), msgAndArgs...)
416 }
417
418 return true
419
420}
421
422// Exactly asserts that two objects are equal in value and type.
423//
424// assert.Exactly(t, int32(123), int64(123))
425func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
426 if h, ok := t.(tHelper); ok {
427 h.Helper()
428 }
429
430 aType := reflect.TypeOf(expected)
431 bType := reflect.TypeOf(actual)
432
433 if aType != bType {
434 return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
435 }
436
437 return Equal(t, expected, actual, msgAndArgs...)
438
439}
440
441// NotNil asserts that the specified object is not nil.
442//
443// assert.NotNil(t, err)
444func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
445 if h, ok := t.(tHelper); ok {
446 h.Helper()
447 }
448 if !isNil(object) {
449 return true
450 }
451 return Fail(t, "Expected value not to be nil.", msgAndArgs...)
452}
453
454// containsKind checks if a specified kind in the slice of kinds.
455func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool {
456 for i := 0; i < len(kinds); i++ {
457 if kind == kinds[i] {
458 return true
459 }
460 }
461
462 return false
463}
464
465// isNil checks if a specified object is nil or not, without Failing.
466func isNil(object interface{}) bool {
467 if object == nil {
468 return true
469 }
470
471 value := reflect.ValueOf(object)
472 kind := value.Kind()
473 isNilableKind := containsKind(
474 []reflect.Kind{
475 reflect.Chan, reflect.Func,
476 reflect.Interface, reflect.Map,
477 reflect.Ptr, reflect.Slice},
478 kind)
479
480 if isNilableKind && value.IsNil() {
481 return true
482 }
483
484 return false
485}
486
487// Nil asserts that the specified object is nil.
488//
489// assert.Nil(t, err)
490func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
491 if h, ok := t.(tHelper); ok {
492 h.Helper()
493 }
494 if isNil(object) {
495 return true
496 }
497 return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
498}
499
500// isEmpty gets whether the specified object is considered empty or not.
501func isEmpty(object interface{}) bool {
502
503 // get nil case out of the way
504 if object == nil {
505 return true
506 }
507
508 objValue := reflect.ValueOf(object)
509
510 switch objValue.Kind() {
511 // collection types are empty when they have no element
512 case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
513 return objValue.Len() == 0
Scott Baker8461e152019-10-01 14:44:30 -0700514 // pointers are empty if nil or if the value they point to is empty
khenaidooac637102019-01-14 15:44:34 -0500515 case reflect.Ptr:
516 if objValue.IsNil() {
517 return true
518 }
519 deref := objValue.Elem().Interface()
520 return isEmpty(deref)
Scott Baker8461e152019-10-01 14:44:30 -0700521 // for all other types, compare against the zero value
khenaidooac637102019-01-14 15:44:34 -0500522 default:
523 zero := reflect.Zero(objValue.Type())
524 return reflect.DeepEqual(object, zero.Interface())
525 }
526}
527
528// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
529// a slice or a channel with len == 0.
530//
531// assert.Empty(t, obj)
532func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
533 if h, ok := t.(tHelper); ok {
534 h.Helper()
535 }
536
537 pass := isEmpty(object)
538 if !pass {
539 Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
540 }
541
542 return pass
543
544}
545
546// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
547// a slice or a channel with len == 0.
548//
549// if assert.NotEmpty(t, obj) {
550// assert.Equal(t, "two", obj[1])
551// }
552func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
553 if h, ok := t.(tHelper); ok {
554 h.Helper()
555 }
556
557 pass := !isEmpty(object)
558 if !pass {
559 Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
560 }
561
562 return pass
563
564}
565
566// getLen try to get length of object.
567// return (false, 0) if impossible.
568func getLen(x interface{}) (ok bool, length int) {
569 v := reflect.ValueOf(x)
570 defer func() {
571 if e := recover(); e != nil {
572 ok = false
573 }
574 }()
575 return true, v.Len()
576}
577
578// Len asserts that the specified object has specific length.
579// Len also fails if the object has a type that len() not accept.
580//
581// assert.Len(t, mySlice, 3)
582func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
583 if h, ok := t.(tHelper); ok {
584 h.Helper()
585 }
586 ok, l := getLen(object)
587 if !ok {
588 return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
589 }
590
591 if l != length {
592 return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
593 }
594 return true
595}
596
597// True asserts that the specified value is true.
598//
599// assert.True(t, myBool)
600func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
601 if h, ok := t.(tHelper); ok {
602 h.Helper()
603 }
604 if h, ok := t.(interface {
605 Helper()
606 }); ok {
607 h.Helper()
608 }
609
610 if value != true {
611 return Fail(t, "Should be true", msgAndArgs...)
612 }
613
614 return true
615
616}
617
618// False asserts that the specified value is false.
619//
620// assert.False(t, myBool)
621func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
622 if h, ok := t.(tHelper); ok {
623 h.Helper()
624 }
625
626 if value != false {
627 return Fail(t, "Should be false", msgAndArgs...)
628 }
629
630 return true
631
632}
633
634// NotEqual asserts that the specified values are NOT equal.
635//
636// assert.NotEqual(t, obj1, obj2)
637//
638// Pointer variable equality is determined based on the equality of the
639// referenced values (as opposed to the memory addresses).
640func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
641 if h, ok := t.(tHelper); ok {
642 h.Helper()
643 }
644 if err := validateEqualArgs(expected, actual); err != nil {
645 return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
646 expected, actual, err), msgAndArgs...)
647 }
648
649 if ObjectsAreEqual(expected, actual) {
650 return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
651 }
652
653 return true
654
655}
656
657// containsElement try loop over the list check if the list includes the element.
658// return (false, false) if impossible.
659// return (true, false) if element was not found.
660// return (true, true) if element was found.
661func includeElement(list interface{}, element interface{}) (ok, found bool) {
662
663 listValue := reflect.ValueOf(list)
Scott Baker8461e152019-10-01 14:44:30 -0700664 listKind := reflect.TypeOf(list).Kind()
khenaidooac637102019-01-14 15:44:34 -0500665 defer func() {
666 if e := recover(); e != nil {
667 ok = false
668 found = false
669 }
670 }()
671
Scott Baker8461e152019-10-01 14:44:30 -0700672 if listKind == reflect.String {
673 elementValue := reflect.ValueOf(element)
khenaidooac637102019-01-14 15:44:34 -0500674 return true, strings.Contains(listValue.String(), elementValue.String())
675 }
676
Scott Baker8461e152019-10-01 14:44:30 -0700677 if listKind == reflect.Map {
khenaidooac637102019-01-14 15:44:34 -0500678 mapKeys := listValue.MapKeys()
679 for i := 0; i < len(mapKeys); i++ {
680 if ObjectsAreEqual(mapKeys[i].Interface(), element) {
681 return true, true
682 }
683 }
684 return true, false
685 }
686
687 for i := 0; i < listValue.Len(); i++ {
688 if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
689 return true, true
690 }
691 }
692 return true, false
693
694}
695
696// Contains asserts that the specified string, list(array, slice...) or map contains the
697// specified substring or element.
698//
699// assert.Contains(t, "Hello World", "World")
700// assert.Contains(t, ["Hello", "World"], "World")
701// assert.Contains(t, {"Hello": "World"}, "Hello")
702func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
703 if h, ok := t.(tHelper); ok {
704 h.Helper()
705 }
706
707 ok, found := includeElement(s, contains)
708 if !ok {
709 return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
710 }
711 if !found {
712 return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...)
713 }
714
715 return true
716
717}
718
719// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
720// specified substring or element.
721//
722// assert.NotContains(t, "Hello World", "Earth")
723// assert.NotContains(t, ["Hello", "World"], "Earth")
724// assert.NotContains(t, {"Hello": "World"}, "Earth")
725func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
726 if h, ok := t.(tHelper); ok {
727 h.Helper()
728 }
729
730 ok, found := includeElement(s, contains)
731 if !ok {
732 return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
733 }
734 if found {
735 return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...)
736 }
737
738 return true
739
740}
741
742// Subset asserts that the specified list(array, slice...) contains all
743// elements given in the specified subset(array, slice...).
744//
745// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
746func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
747 if h, ok := t.(tHelper); ok {
748 h.Helper()
749 }
750 if subset == nil {
751 return true // we consider nil to be equal to the nil set
752 }
753
754 subsetValue := reflect.ValueOf(subset)
755 defer func() {
756 if e := recover(); e != nil {
757 ok = false
758 }
759 }()
760
761 listKind := reflect.TypeOf(list).Kind()
762 subsetKind := reflect.TypeOf(subset).Kind()
763
764 if listKind != reflect.Array && listKind != reflect.Slice {
765 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
766 }
767
768 if subsetKind != reflect.Array && subsetKind != reflect.Slice {
769 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
770 }
771
772 for i := 0; i < subsetValue.Len(); i++ {
773 element := subsetValue.Index(i).Interface()
774 ok, found := includeElement(list, element)
775 if !ok {
776 return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...)
777 }
778 if !found {
779 return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, element), msgAndArgs...)
780 }
781 }
782
783 return true
784}
785
786// NotSubset asserts that the specified list(array, slice...) contains not all
787// elements given in the specified subset(array, slice...).
788//
789// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
790func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
791 if h, ok := t.(tHelper); ok {
792 h.Helper()
793 }
794 if subset == nil {
795 return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...)
796 }
797
798 subsetValue := reflect.ValueOf(subset)
799 defer func() {
800 if e := recover(); e != nil {
801 ok = false
802 }
803 }()
804
805 listKind := reflect.TypeOf(list).Kind()
806 subsetKind := reflect.TypeOf(subset).Kind()
807
808 if listKind != reflect.Array && listKind != reflect.Slice {
809 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
810 }
811
812 if subsetKind != reflect.Array && subsetKind != reflect.Slice {
813 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
814 }
815
816 for i := 0; i < subsetValue.Len(); i++ {
817 element := subsetValue.Index(i).Interface()
818 ok, found := includeElement(list, element)
819 if !ok {
820 return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...)
821 }
822 if !found {
823 return true
824 }
825 }
826
827 return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
828}
829
830// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
831// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
832// the number of appearances of each of them in both lists should match.
833//
834// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
835func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
836 if h, ok := t.(tHelper); ok {
837 h.Helper()
838 }
839 if isEmpty(listA) && isEmpty(listB) {
840 return true
841 }
842
843 aKind := reflect.TypeOf(listA).Kind()
844 bKind := reflect.TypeOf(listB).Kind()
845
846 if aKind != reflect.Array && aKind != reflect.Slice {
847 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", listA, aKind), msgAndArgs...)
848 }
849
850 if bKind != reflect.Array && bKind != reflect.Slice {
851 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", listB, bKind), msgAndArgs...)
852 }
853
854 aValue := reflect.ValueOf(listA)
855 bValue := reflect.ValueOf(listB)
856
857 aLen := aValue.Len()
858 bLen := bValue.Len()
859
860 if aLen != bLen {
861 return Fail(t, fmt.Sprintf("lengths don't match: %d != %d", aLen, bLen), msgAndArgs...)
862 }
863
864 // Mark indexes in bValue that we already used
865 visited := make([]bool, bLen)
866 for i := 0; i < aLen; i++ {
867 element := aValue.Index(i).Interface()
868 found := false
869 for j := 0; j < bLen; j++ {
870 if visited[j] {
871 continue
872 }
873 if ObjectsAreEqual(bValue.Index(j).Interface(), element) {
874 visited[j] = true
875 found = true
876 break
877 }
878 }
879 if !found {
880 return Fail(t, fmt.Sprintf("element %s appears more times in %s than in %s", element, aValue, bValue), msgAndArgs...)
881 }
882 }
883
884 return true
885}
886
887// Condition uses a Comparison to assert a complex condition.
888func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
889 if h, ok := t.(tHelper); ok {
890 h.Helper()
891 }
892 result := comp()
893 if !result {
894 Fail(t, "Condition failed!", msgAndArgs...)
895 }
896 return result
897}
898
899// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
900// methods, and represents a simple func that takes no arguments, and returns nothing.
901type PanicTestFunc func()
902
903// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
904func didPanic(f PanicTestFunc) (bool, interface{}) {
905
906 didPanic := false
907 var message interface{}
908 func() {
909
910 defer func() {
911 if message = recover(); message != nil {
912 didPanic = true
913 }
914 }()
915
916 // call the target function
917 f()
918
919 }()
920
921 return didPanic, message
922
923}
924
925// Panics asserts that the code inside the specified PanicTestFunc panics.
926//
927// assert.Panics(t, func(){ GoCrazy() })
928func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
929 if h, ok := t.(tHelper); ok {
930 h.Helper()
931 }
932
933 if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
934 return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
935 }
936
937 return true
938}
939
940// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
941// the recovered panic value equals the expected panic value.
942//
943// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
944func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
945 if h, ok := t.(tHelper); ok {
946 h.Helper()
947 }
948
949 funcDidPanic, panicValue := didPanic(f)
950 if !funcDidPanic {
951 return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
952 }
953 if panicValue != expected {
954 return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v", f, expected, panicValue), msgAndArgs...)
955 }
956
957 return true
958}
959
960// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
961//
962// assert.NotPanics(t, func(){ RemainCalm() })
963func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
964 if h, ok := t.(tHelper); ok {
965 h.Helper()
966 }
967
968 if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
969 return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v", f, panicValue), msgAndArgs...)
970 }
971
972 return true
973}
974
975// WithinDuration asserts that the two times are within duration delta of each other.
976//
977// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
978func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
979 if h, ok := t.(tHelper); ok {
980 h.Helper()
981 }
982
983 dt := expected.Sub(actual)
984 if dt < -delta || dt > delta {
985 return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
986 }
987
988 return true
989}
990
991func toFloat(x interface{}) (float64, bool) {
992 var xf float64
993 xok := true
994
995 switch xn := x.(type) {
996 case uint8:
997 xf = float64(xn)
998 case uint16:
999 xf = float64(xn)
1000 case uint32:
1001 xf = float64(xn)
1002 case uint64:
1003 xf = float64(xn)
1004 case int:
1005 xf = float64(xn)
1006 case int8:
1007 xf = float64(xn)
1008 case int16:
1009 xf = float64(xn)
1010 case int32:
1011 xf = float64(xn)
1012 case int64:
1013 xf = float64(xn)
1014 case float32:
1015 xf = float64(xn)
1016 case float64:
1017 xf = float64(xn)
1018 case time.Duration:
1019 xf = float64(xn)
1020 default:
1021 xok = false
1022 }
1023
1024 return xf, xok
1025}
1026
1027// InDelta asserts that the two numerals are within delta of each other.
1028//
1029// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
1030func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
1031 if h, ok := t.(tHelper); ok {
1032 h.Helper()
1033 }
1034
1035 af, aok := toFloat(expected)
1036 bf, bok := toFloat(actual)
1037
1038 if !aok || !bok {
1039 return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
1040 }
1041
1042 if math.IsNaN(af) {
1043 return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...)
1044 }
1045
1046 if math.IsNaN(bf) {
1047 return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
1048 }
1049
1050 dt := af - bf
1051 if dt < -delta || dt > delta {
1052 return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
1053 }
1054
1055 return true
1056}
1057
1058// InDeltaSlice is the same as InDelta, except it compares two slices.
1059func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
1060 if h, ok := t.(tHelper); ok {
1061 h.Helper()
1062 }
1063 if expected == nil || actual == nil ||
1064 reflect.TypeOf(actual).Kind() != reflect.Slice ||
1065 reflect.TypeOf(expected).Kind() != reflect.Slice {
1066 return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
1067 }
1068
1069 actualSlice := reflect.ValueOf(actual)
1070 expectedSlice := reflect.ValueOf(expected)
1071
1072 for i := 0; i < actualSlice.Len(); i++ {
1073 result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...)
1074 if !result {
1075 return result
1076 }
1077 }
1078
1079 return true
1080}
1081
1082// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
1083func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
1084 if h, ok := t.(tHelper); ok {
1085 h.Helper()
1086 }
1087 if expected == nil || actual == nil ||
1088 reflect.TypeOf(actual).Kind() != reflect.Map ||
1089 reflect.TypeOf(expected).Kind() != reflect.Map {
1090 return Fail(t, "Arguments must be maps", msgAndArgs...)
1091 }
1092
1093 expectedMap := reflect.ValueOf(expected)
1094 actualMap := reflect.ValueOf(actual)
1095
1096 if expectedMap.Len() != actualMap.Len() {
1097 return Fail(t, "Arguments must have the same number of keys", msgAndArgs...)
1098 }
1099
1100 for _, k := range expectedMap.MapKeys() {
1101 ev := expectedMap.MapIndex(k)
1102 av := actualMap.MapIndex(k)
1103
1104 if !ev.IsValid() {
1105 return Fail(t, fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...)
1106 }
1107
1108 if !av.IsValid() {
1109 return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...)
1110 }
1111
1112 if !InDelta(
1113 t,
1114 ev.Interface(),
1115 av.Interface(),
1116 delta,
1117 msgAndArgs...,
1118 ) {
1119 return false
1120 }
1121 }
1122
1123 return true
1124}
1125
1126func calcRelativeError(expected, actual interface{}) (float64, error) {
1127 af, aok := toFloat(expected)
1128 if !aok {
1129 return 0, fmt.Errorf("expected value %q cannot be converted to float", expected)
1130 }
1131 if af == 0 {
1132 return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
1133 }
1134 bf, bok := toFloat(actual)
1135 if !bok {
1136 return 0, fmt.Errorf("actual value %q cannot be converted to float", actual)
1137 }
1138
1139 return math.Abs(af-bf) / math.Abs(af), nil
1140}
1141
1142// InEpsilon asserts that expected and actual have a relative error less than epsilon
1143func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
1144 if h, ok := t.(tHelper); ok {
1145 h.Helper()
1146 }
1147 actualEpsilon, err := calcRelativeError(expected, actual)
1148 if err != nil {
1149 return Fail(t, err.Error(), msgAndArgs...)
1150 }
1151 if actualEpsilon > epsilon {
1152 return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
1153 " < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
1154 }
1155
1156 return true
1157}
1158
1159// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
1160func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
1161 if h, ok := t.(tHelper); ok {
1162 h.Helper()
1163 }
1164 if expected == nil || actual == nil ||
1165 reflect.TypeOf(actual).Kind() != reflect.Slice ||
1166 reflect.TypeOf(expected).Kind() != reflect.Slice {
1167 return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
1168 }
1169
1170 actualSlice := reflect.ValueOf(actual)
1171 expectedSlice := reflect.ValueOf(expected)
1172
1173 for i := 0; i < actualSlice.Len(); i++ {
1174 result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon)
1175 if !result {
1176 return result
1177 }
1178 }
1179
1180 return true
1181}
1182
1183/*
1184 Errors
1185*/
1186
1187// NoError asserts that a function returned no error (i.e. `nil`).
1188//
1189// actualObj, err := SomeFunction()
1190// if assert.NoError(t, err) {
1191// assert.Equal(t, expectedObj, actualObj)
1192// }
1193func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
1194 if h, ok := t.(tHelper); ok {
1195 h.Helper()
1196 }
1197 if err != nil {
1198 return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
1199 }
1200
1201 return true
1202}
1203
1204// Error asserts that a function returned an error (i.e. not `nil`).
1205//
1206// actualObj, err := SomeFunction()
1207// if assert.Error(t, err) {
1208// assert.Equal(t, expectedError, err)
1209// }
1210func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
1211 if h, ok := t.(tHelper); ok {
1212 h.Helper()
1213 }
1214
1215 if err == nil {
1216 return Fail(t, "An error is expected but got nil.", msgAndArgs...)
1217 }
1218
1219 return true
1220}
1221
1222// EqualError asserts that a function returned an error (i.e. not `nil`)
1223// and that it is equal to the provided error.
1224//
1225// actualObj, err := SomeFunction()
1226// assert.EqualError(t, err, expectedErrorString)
1227func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
1228 if h, ok := t.(tHelper); ok {
1229 h.Helper()
1230 }
1231 if !Error(t, theError, msgAndArgs...) {
1232 return false
1233 }
1234 expected := errString
1235 actual := theError.Error()
1236 // don't need to use deep equals here, we know they are both strings
1237 if expected != actual {
1238 return Fail(t, fmt.Sprintf("Error message not equal:\n"+
1239 "expected: %q\n"+
1240 "actual : %q", expected, actual), msgAndArgs...)
1241 }
1242 return true
1243}
1244
1245// matchRegexp return true if a specified regexp matches a string.
1246func matchRegexp(rx interface{}, str interface{}) bool {
1247
1248 var r *regexp.Regexp
1249 if rr, ok := rx.(*regexp.Regexp); ok {
1250 r = rr
1251 } else {
1252 r = regexp.MustCompile(fmt.Sprint(rx))
1253 }
1254
1255 return (r.FindStringIndex(fmt.Sprint(str)) != nil)
1256
1257}
1258
1259// Regexp asserts that a specified regexp matches a string.
1260//
1261// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
1262// assert.Regexp(t, "start...$", "it's not starting")
1263func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
1264 if h, ok := t.(tHelper); ok {
1265 h.Helper()
1266 }
1267
1268 match := matchRegexp(rx, str)
1269
1270 if !match {
1271 Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
1272 }
1273
1274 return match
1275}
1276
1277// NotRegexp asserts that a specified regexp does not match a string.
1278//
1279// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
1280// assert.NotRegexp(t, "^start", "it's not starting")
1281func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
1282 if h, ok := t.(tHelper); ok {
1283 h.Helper()
1284 }
1285 match := matchRegexp(rx, str)
1286
1287 if match {
1288 Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
1289 }
1290
1291 return !match
1292
1293}
1294
1295// Zero asserts that i is the zero value for its type.
1296func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
1297 if h, ok := t.(tHelper); ok {
1298 h.Helper()
1299 }
1300 if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
1301 return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
1302 }
1303 return true
1304}
1305
1306// NotZero asserts that i is not the zero value for its type.
1307func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
1308 if h, ok := t.(tHelper); ok {
1309 h.Helper()
1310 }
1311 if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
1312 return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
1313 }
1314 return true
1315}
1316
1317// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
1318func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
1319 if h, ok := t.(tHelper); ok {
1320 h.Helper()
1321 }
1322 info, err := os.Lstat(path)
1323 if err != nil {
1324 if os.IsNotExist(err) {
1325 return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
1326 }
1327 return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
1328 }
1329 if info.IsDir() {
1330 return Fail(t, fmt.Sprintf("%q is a directory", path), msgAndArgs...)
1331 }
1332 return true
1333}
1334
1335// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
1336func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
1337 if h, ok := t.(tHelper); ok {
1338 h.Helper()
1339 }
1340 info, err := os.Lstat(path)
1341 if err != nil {
1342 if os.IsNotExist(err) {
1343 return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
1344 }
1345 return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
1346 }
1347 if !info.IsDir() {
1348 return Fail(t, fmt.Sprintf("%q is a file", path), msgAndArgs...)
1349 }
1350 return true
1351}
1352
1353// JSONEq asserts that two JSON strings are equivalent.
1354//
1355// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
1356func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
1357 if h, ok := t.(tHelper); ok {
1358 h.Helper()
1359 }
1360 var expectedJSONAsInterface, actualJSONAsInterface interface{}
1361
1362 if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
1363 return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
1364 }
1365
1366 if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
1367 return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
1368 }
1369
1370 return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
1371}
1372
Scott Baker8461e152019-10-01 14:44:30 -07001373// YAMLEq asserts that two YAML strings are equivalent.
1374func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
1375 if h, ok := t.(tHelper); ok {
1376 h.Helper()
1377 }
1378 var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
1379
1380 if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
1381 return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
1382 }
1383
1384 if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
1385 return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
1386 }
1387
1388 return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
1389}
1390
khenaidooac637102019-01-14 15:44:34 -05001391func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
1392 t := reflect.TypeOf(v)
1393 k := t.Kind()
1394
1395 if k == reflect.Ptr {
1396 t = t.Elem()
1397 k = t.Kind()
1398 }
1399 return t, k
1400}
1401
1402// diff returns a diff of both values as long as both are of the same type and
1403// are a struct, map, slice, array or string. Otherwise it returns an empty string.
1404func diff(expected interface{}, actual interface{}) string {
1405 if expected == nil || actual == nil {
1406 return ""
1407 }
1408
1409 et, ek := typeAndKind(expected)
1410 at, _ := typeAndKind(actual)
1411
1412 if et != at {
1413 return ""
1414 }
1415
1416 if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String {
1417 return ""
1418 }
1419
1420 var e, a string
1421 if et != reflect.TypeOf("") {
1422 e = spewConfig.Sdump(expected)
1423 a = spewConfig.Sdump(actual)
1424 } else {
Scott Baker8461e152019-10-01 14:44:30 -07001425 e = reflect.ValueOf(expected).String()
1426 a = reflect.ValueOf(actual).String()
khenaidooac637102019-01-14 15:44:34 -05001427 }
1428
1429 diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
1430 A: difflib.SplitLines(e),
1431 B: difflib.SplitLines(a),
1432 FromFile: "Expected",
1433 FromDate: "",
1434 ToFile: "Actual",
1435 ToDate: "",
1436 Context: 1,
1437 })
1438
1439 return "\n\nDiff:\n" + diff
1440}
1441
1442// validateEqualArgs checks whether provided arguments can be safely used in the
1443// Equal/NotEqual functions.
1444func validateEqualArgs(expected, actual interface{}) error {
1445 if isFunction(expected) || isFunction(actual) {
1446 return errors.New("cannot take func type as argument")
1447 }
1448 return nil
1449}
1450
1451func isFunction(arg interface{}) bool {
1452 if arg == nil {
1453 return false
1454 }
1455 return reflect.TypeOf(arg).Kind() == reflect.Func
1456}
1457
1458var spewConfig = spew.ConfigState{
1459 Indent: " ",
1460 DisablePointerAddresses: true,
1461 DisableCapacities: true,
1462 SortKeys: true,
1463}
1464
1465type tHelper interface {
1466 Helper()
1467}
Scott Baker8461e152019-10-01 14:44:30 -07001468
1469// Eventually asserts that given condition will be met in waitFor time,
1470// periodically checking target function each tick.
1471//
1472// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
1473func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
1474 if h, ok := t.(tHelper); ok {
1475 h.Helper()
1476 }
1477
1478 timer := time.NewTimer(waitFor)
1479 ticker := time.NewTicker(tick)
1480 checkPassed := make(chan bool)
1481 defer timer.Stop()
1482 defer ticker.Stop()
1483 defer close(checkPassed)
1484 for {
1485 select {
1486 case <-timer.C:
1487 return Fail(t, "Condition never satisfied", msgAndArgs...)
1488 case result := <-checkPassed:
1489 if result {
1490 return true
1491 }
1492 case <-ticker.C:
1493 go func() {
1494 checkPassed <- condition()
1495 }()
1496 }
1497 }
1498}