blob: 0b7570f21c631b5594aa5420c090c8c88c1a879d [file] [log] [blame]
kesavandb9f54fd2021-11-25 20:08:04 +05301package 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 "runtime/debug"
15 "strings"
16 "time"
17 "unicode"
18 "unicode/utf8"
19
20 "github.com/davecgh/go-spew/spew"
21 "github.com/pmezard/go-difflib/difflib"
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +053022 "gopkg.in/yaml.v3"
kesavandb9f54fd2021-11-25 20:08:04 +053023)
24
25//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
26
27// TestingT is an interface wrapper around *testing.T
28type TestingT interface {
29 Errorf(format string, args ...interface{})
30}
31
32// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
33// for table driven tests.
34type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
35
36// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
37// for table driven tests.
38type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
39
40// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
41// for table driven tests.
42type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
43
44// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
45// for table driven tests.
46type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
47
48// Comparison is a custom function that returns true on success and false on failure
49type Comparison func() (success bool)
50
51/*
52 Helper functions
53*/
54
55// ObjectsAreEqual determines if two objects are considered equal.
56//
57// This function does no assertion of any kind.
58func ObjectsAreEqual(expected, actual interface{}) bool {
59 if expected == nil || actual == nil {
60 return expected == actual
61 }
62
63 exp, ok := expected.([]byte)
64 if !ok {
65 return reflect.DeepEqual(expected, actual)
66 }
67
68 act, ok := actual.([]byte)
69 if !ok {
70 return false
71 }
72 if exp == nil || act == nil {
73 return exp == nil && act == nil
74 }
75 return bytes.Equal(exp, act)
76}
77
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +053078// copyExportedFields iterates downward through nested data structures and creates a copy
79// that only contains the exported struct fields.
80func copyExportedFields(expected interface{}) interface{} {
81 if isNil(expected) {
82 return expected
83 }
84
85 expectedType := reflect.TypeOf(expected)
86 expectedKind := expectedType.Kind()
87 expectedValue := reflect.ValueOf(expected)
88
89 switch expectedKind {
90 case reflect.Struct:
91 result := reflect.New(expectedType).Elem()
92 for i := 0; i < expectedType.NumField(); i++ {
93 field := expectedType.Field(i)
94 isExported := field.IsExported()
95 if isExported {
96 fieldValue := expectedValue.Field(i)
97 if isNil(fieldValue) || isNil(fieldValue.Interface()) {
98 continue
99 }
100 newValue := copyExportedFields(fieldValue.Interface())
101 result.Field(i).Set(reflect.ValueOf(newValue))
102 }
103 }
104 return result.Interface()
105
106 case reflect.Ptr:
107 result := reflect.New(expectedType.Elem())
108 unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface())
109 result.Elem().Set(reflect.ValueOf(unexportedRemoved))
110 return result.Interface()
111
112 case reflect.Array, reflect.Slice:
113 var result reflect.Value
114 if expectedKind == reflect.Array {
115 result = reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem()
116 } else {
117 result = reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len())
118 }
119 for i := 0; i < expectedValue.Len(); i++ {
120 index := expectedValue.Index(i)
121 if isNil(index) {
122 continue
123 }
124 unexportedRemoved := copyExportedFields(index.Interface())
125 result.Index(i).Set(reflect.ValueOf(unexportedRemoved))
126 }
127 return result.Interface()
128
129 case reflect.Map:
130 result := reflect.MakeMap(expectedType)
131 for _, k := range expectedValue.MapKeys() {
132 index := expectedValue.MapIndex(k)
133 unexportedRemoved := copyExportedFields(index.Interface())
134 result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved))
135 }
136 return result.Interface()
137
138 default:
139 return expected
140 }
141}
142
143// ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are
144// considered equal. This comparison of only exported fields is applied recursively to nested data
145// structures.
146//
147// This function does no assertion of any kind.
148//
149// Deprecated: Use [EqualExportedValues] instead.
150func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool {
151 expectedCleaned := copyExportedFields(expected)
152 actualCleaned := copyExportedFields(actual)
153 return ObjectsAreEqualValues(expectedCleaned, actualCleaned)
154}
155
kesavandb9f54fd2021-11-25 20:08:04 +0530156// ObjectsAreEqualValues gets whether two objects are equal, or if their
157// values are equal.
158func ObjectsAreEqualValues(expected, actual interface{}) bool {
159 if ObjectsAreEqual(expected, actual) {
160 return true
161 }
162
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530163 expectedValue := reflect.ValueOf(expected)
164 actualValue := reflect.ValueOf(actual)
165 if !expectedValue.IsValid() || !actualValue.IsValid() {
kesavandb9f54fd2021-11-25 20:08:04 +0530166 return false
167 }
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530168
169 expectedType := expectedValue.Type()
170 actualType := actualValue.Type()
171 if !expectedType.ConvertibleTo(actualType) {
172 return false
kesavandb9f54fd2021-11-25 20:08:04 +0530173 }
174
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530175 if !isNumericType(expectedType) || !isNumericType(actualType) {
176 // Attempt comparison after type conversion
177 return reflect.DeepEqual(
178 expectedValue.Convert(actualType).Interface(), actual,
179 )
180 }
181
182 // If BOTH values are numeric, there are chances of false positives due
183 // to overflow or underflow. So, we need to make sure to always convert
184 // the smaller type to a larger type before comparing.
185 if expectedType.Size() >= actualType.Size() {
186 return actualValue.Convert(expectedType).Interface() == expected
187 }
188
189 return expectedValue.Convert(actualType).Interface() == actual
190}
191
192// isNumericType returns true if the type is one of:
193// int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64,
194// float32, float64, complex64, complex128
195func isNumericType(t reflect.Type) bool {
196 return t.Kind() >= reflect.Int && t.Kind() <= reflect.Complex128
kesavandb9f54fd2021-11-25 20:08:04 +0530197}
198
199/* CallerInfo is necessary because the assert functions use the testing object
200internally, causing it to print the file:line of the assert method, rather than where
201the problem actually occurred in calling code.*/
202
203// CallerInfo returns an array of strings containing the file and line number
204// of each stack frame leading from the current test to the assert call that
205// failed.
206func CallerInfo() []string {
207
208 var pc uintptr
209 var ok bool
210 var file string
211 var line int
212 var name string
213
214 callers := []string{}
215 for i := 0; ; i++ {
216 pc, file, line, ok = runtime.Caller(i)
217 if !ok {
218 // The breaks below failed to terminate the loop, and we ran off the
219 // end of the call stack.
220 break
221 }
222
223 // This is a huge edge case, but it will panic if this is the case, see #180
224 if file == "<autogenerated>" {
225 break
226 }
227
228 f := runtime.FuncForPC(pc)
229 if f == nil {
230 break
231 }
232 name = f.Name()
233
234 // testing.tRunner is the standard library function that calls
235 // tests. Subtests are called directly by tRunner, without going through
236 // the Test/Benchmark/Example function that contains the t.Run calls, so
237 // with subtests we should break when we hit tRunner, without adding it
238 // to the list of callers.
239 if name == "testing.tRunner" {
240 break
241 }
242
243 parts := strings.Split(file, "/")
kesavandb9f54fd2021-11-25 20:08:04 +0530244 if len(parts) > 1 {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530245 filename := parts[len(parts)-1]
kesavandb9f54fd2021-11-25 20:08:04 +0530246 dir := parts[len(parts)-2]
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530247 if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" {
248 callers = append(callers, fmt.Sprintf("%s:%d", file, line))
kesavandb9f54fd2021-11-25 20:08:04 +0530249 }
250 }
251
252 // Drop the package
253 segments := strings.Split(name, ".")
254 name = segments[len(segments)-1]
255 if isTest(name, "Test") ||
256 isTest(name, "Benchmark") ||
257 isTest(name, "Example") {
258 break
259 }
260 }
261
262 return callers
263}
264
265// Stolen from the `go test` tool.
266// isTest tells whether name looks like a test (or benchmark, according to prefix).
267// It is a Test (say) if there is a character after Test that is not a lower-case letter.
268// We don't want TesticularCancer.
269func isTest(name, prefix string) bool {
270 if !strings.HasPrefix(name, prefix) {
271 return false
272 }
273 if len(name) == len(prefix) { // "Test" is ok
274 return true
275 }
276 r, _ := utf8.DecodeRuneInString(name[len(prefix):])
277 return !unicode.IsLower(r)
278}
279
280func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
281 if len(msgAndArgs) == 0 || msgAndArgs == nil {
282 return ""
283 }
284 if len(msgAndArgs) == 1 {
285 msg := msgAndArgs[0]
286 if msgAsStr, ok := msg.(string); ok {
287 return msgAsStr
288 }
289 return fmt.Sprintf("%+v", msg)
290 }
291 if len(msgAndArgs) > 1 {
292 return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
293 }
294 return ""
295}
296
297// Aligns the provided message so that all lines after the first line start at the same location as the first line.
298// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab).
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530299// The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the
kesavandb9f54fd2021-11-25 20:08:04 +0530300// basis on which the alignment occurs).
301func indentMessageLines(message string, longestLabelLen int) string {
302 outBuf := new(bytes.Buffer)
303
304 for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
305 // no need to align first line because it starts at the correct location (after the label)
306 if i != 0 {
307 // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
308 outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
309 }
310 outBuf.WriteString(scanner.Text())
311 }
312
313 return outBuf.String()
314}
315
316type failNower interface {
317 FailNow()
318}
319
320// FailNow fails test
321func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
322 if h, ok := t.(tHelper); ok {
323 h.Helper()
324 }
325 Fail(t, failureMessage, msgAndArgs...)
326
327 // We cannot extend TestingT with FailNow() and
328 // maintain backwards compatibility, so we fallback
329 // to panicking when FailNow is not available in
330 // TestingT.
331 // See issue #263
332
333 if t, ok := t.(failNower); ok {
334 t.FailNow()
335 } else {
336 panic("test failed and t is missing `FailNow()`")
337 }
338 return false
339}
340
341// Fail reports a failure through
342func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
343 if h, ok := t.(tHelper); ok {
344 h.Helper()
345 }
346 content := []labeledContent{
347 {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
348 {"Error", failureMessage},
349 }
350
351 // Add test name if the Go version supports it
352 if n, ok := t.(interface {
353 Name() string
354 }); ok {
355 content = append(content, labeledContent{"Test", n.Name()})
356 }
357
358 message := messageFromMsgAndArgs(msgAndArgs...)
359 if len(message) > 0 {
360 content = append(content, labeledContent{"Messages", message})
361 }
362
363 t.Errorf("\n%s", ""+labeledOutput(content...))
364
365 return false
366}
367
368type labeledContent struct {
369 label string
370 content string
371}
372
373// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
374//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530375// \t{{label}}:{{align_spaces}}\t{{content}}\n
kesavandb9f54fd2021-11-25 20:08:04 +0530376//
377// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
378// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
379// alignment is achieved, "\t{{content}}\n" is added for the output.
380//
381// 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.
382func labeledOutput(content ...labeledContent) string {
383 longestLabel := 0
384 for _, v := range content {
385 if len(v.label) > longestLabel {
386 longestLabel = len(v.label)
387 }
388 }
389 var output string
390 for _, v := range content {
391 output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
392 }
393 return output
394}
395
396// Implements asserts that an object is implemented by the specified interface.
397//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530398// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
kesavandb9f54fd2021-11-25 20:08:04 +0530399func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
400 if h, ok := t.(tHelper); ok {
401 h.Helper()
402 }
403 interfaceType := reflect.TypeOf(interfaceObject).Elem()
404
405 if object == nil {
406 return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...)
407 }
408 if !reflect.TypeOf(object).Implements(interfaceType) {
409 return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...)
410 }
411
412 return true
413}
414
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530415// NotImplements asserts that an object does not implement the specified interface.
416//
417// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject))
418func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
419 if h, ok := t.(tHelper); ok {
420 h.Helper()
421 }
422 interfaceType := reflect.TypeOf(interfaceObject).Elem()
423
424 if object == nil {
425 return Fail(t, fmt.Sprintf("Cannot check if nil does not implement %v", interfaceType), msgAndArgs...)
426 }
427 if reflect.TypeOf(object).Implements(interfaceType) {
428 return Fail(t, fmt.Sprintf("%T implements %v", object, interfaceType), msgAndArgs...)
429 }
430
431 return true
432}
433
kesavandb9f54fd2021-11-25 20:08:04 +0530434// IsType asserts that the specified objects are of the same type.
435func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
436 if h, ok := t.(tHelper); ok {
437 h.Helper()
438 }
439
440 if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
441 return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
442 }
443
444 return true
445}
446
447// Equal asserts that two objects are equal.
448//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530449// assert.Equal(t, 123, 123)
kesavandb9f54fd2021-11-25 20:08:04 +0530450//
451// Pointer variable equality is determined based on the equality of the
452// referenced values (as opposed to the memory addresses). Function equality
453// cannot be determined and will always fail.
454func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
455 if h, ok := t.(tHelper); ok {
456 h.Helper()
457 }
458 if err := validateEqualArgs(expected, actual); err != nil {
459 return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
460 expected, actual, err), msgAndArgs...)
461 }
462
463 if !ObjectsAreEqual(expected, actual) {
464 diff := diff(expected, actual)
465 expected, actual = formatUnequalValues(expected, actual)
466 return Fail(t, fmt.Sprintf("Not equal: \n"+
467 "expected: %s\n"+
468 "actual : %s%s", expected, actual, diff), msgAndArgs...)
469 }
470
471 return true
472
473}
474
475// validateEqualArgs checks whether provided arguments can be safely used in the
476// Equal/NotEqual functions.
477func validateEqualArgs(expected, actual interface{}) error {
478 if expected == nil && actual == nil {
479 return nil
480 }
481
482 if isFunction(expected) || isFunction(actual) {
483 return errors.New("cannot take func type as argument")
484 }
485 return nil
486}
487
488// Same asserts that two pointers reference the same object.
489//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530490// assert.Same(t, ptr1, ptr2)
kesavandb9f54fd2021-11-25 20:08:04 +0530491//
492// Both arguments must be pointer variables. Pointer variable sameness is
493// determined based on the equality of both type and value.
494func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
495 if h, ok := t.(tHelper); ok {
496 h.Helper()
497 }
498
499 if !samePointers(expected, actual) {
500 return Fail(t, fmt.Sprintf("Not same: \n"+
501 "expected: %p %#v\n"+
502 "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
503 }
504
505 return true
506}
507
508// NotSame asserts that two pointers do not reference the same object.
509//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530510// assert.NotSame(t, ptr1, ptr2)
kesavandb9f54fd2021-11-25 20:08:04 +0530511//
512// Both arguments must be pointer variables. Pointer variable sameness is
513// determined based on the equality of both type and value.
514func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
515 if h, ok := t.(tHelper); ok {
516 h.Helper()
517 }
518
519 if samePointers(expected, actual) {
520 return Fail(t, fmt.Sprintf(
521 "Expected and actual point to the same object: %p %#v",
522 expected, expected), msgAndArgs...)
523 }
524 return true
525}
526
527// samePointers compares two generic interface objects and returns whether
528// they point to the same object
529func samePointers(first, second interface{}) bool {
530 firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
531 if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
532 return false
533 }
534
535 firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
536 if firstType != secondType {
537 return false
538 }
539
540 // compare pointer addresses
541 return first == second
542}
543
544// formatUnequalValues takes two values of arbitrary types and returns string
545// representations appropriate to be presented to the user.
546//
547// If the values are not of like type, the returned strings will be prefixed
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530548// with the type name, and the value will be enclosed in parentheses similar
kesavandb9f54fd2021-11-25 20:08:04 +0530549// to a type conversion in the Go grammar.
550func formatUnequalValues(expected, actual interface{}) (e string, a string) {
551 if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
552 return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)),
553 fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual))
554 }
555 switch expected.(type) {
556 case time.Duration:
557 return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
558 }
559 return truncatingFormat(expected), truncatingFormat(actual)
560}
561
562// truncatingFormat formats the data and truncates it if it's too long.
563//
564// This helps keep formatted error messages lines from exceeding the
565// bufio.MaxScanTokenSize max line length that the go testing framework imposes.
566func truncatingFormat(data interface{}) string {
567 value := fmt.Sprintf("%#v", data)
568 max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed.
569 if len(value) > max {
570 value = value[0:max] + "<... truncated>"
571 }
572 return value
573}
574
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530575// EqualValues asserts that two objects are equal or convertible to the same types
kesavandb9f54fd2021-11-25 20:08:04 +0530576// and equal.
577//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530578// assert.EqualValues(t, uint32(123), int32(123))
kesavandb9f54fd2021-11-25 20:08:04 +0530579func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
580 if h, ok := t.(tHelper); ok {
581 h.Helper()
582 }
583
584 if !ObjectsAreEqualValues(expected, actual) {
585 diff := diff(expected, actual)
586 expected, actual = formatUnequalValues(expected, actual)
587 return Fail(t, fmt.Sprintf("Not equal: \n"+
588 "expected: %s\n"+
589 "actual : %s%s", expected, actual, diff), msgAndArgs...)
590 }
591
592 return true
593
594}
595
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530596// EqualExportedValues asserts that the types of two objects are equal and their public
597// fields are also equal. This is useful for comparing structs that have private fields
598// that could potentially differ.
599//
600// type S struct {
601// Exported int
602// notExported int
603// }
604// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true
605// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false
606func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
607 if h, ok := t.(tHelper); ok {
608 h.Helper()
609 }
610
611 aType := reflect.TypeOf(expected)
612 bType := reflect.TypeOf(actual)
613
614 if aType != bType {
615 return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
616 }
617
618 if aType.Kind() == reflect.Ptr {
619 aType = aType.Elem()
620 }
621 if bType.Kind() == reflect.Ptr {
622 bType = bType.Elem()
623 }
624
625 if aType.Kind() != reflect.Struct {
626 return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to struct \n\t%v != %v", aType.Kind(), reflect.Struct), msgAndArgs...)
627 }
628
629 if bType.Kind() != reflect.Struct {
630 return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to struct \n\t%v != %v", bType.Kind(), reflect.Struct), msgAndArgs...)
631 }
632
633 expected = copyExportedFields(expected)
634 actual = copyExportedFields(actual)
635
636 if !ObjectsAreEqualValues(expected, actual) {
637 diff := diff(expected, actual)
638 expected, actual = formatUnequalValues(expected, actual)
639 return Fail(t, fmt.Sprintf("Not equal (comparing only exported fields): \n"+
640 "expected: %s\n"+
641 "actual : %s%s", expected, actual, diff), msgAndArgs...)
642 }
643
644 return true
645}
646
kesavandb9f54fd2021-11-25 20:08:04 +0530647// Exactly asserts that two objects are equal in value and type.
648//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530649// assert.Exactly(t, int32(123), int64(123))
kesavandb9f54fd2021-11-25 20:08:04 +0530650func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
651 if h, ok := t.(tHelper); ok {
652 h.Helper()
653 }
654
655 aType := reflect.TypeOf(expected)
656 bType := reflect.TypeOf(actual)
657
658 if aType != bType {
659 return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
660 }
661
662 return Equal(t, expected, actual, msgAndArgs...)
663
664}
665
666// NotNil asserts that the specified object is not nil.
667//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530668// assert.NotNil(t, err)
kesavandb9f54fd2021-11-25 20:08:04 +0530669func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
670 if !isNil(object) {
671 return true
672 }
673 if h, ok := t.(tHelper); ok {
674 h.Helper()
675 }
676 return Fail(t, "Expected value not to be nil.", msgAndArgs...)
677}
678
kesavandb9f54fd2021-11-25 20:08:04 +0530679// isNil checks if a specified object is nil or not, without Failing.
680func isNil(object interface{}) bool {
681 if object == nil {
682 return true
683 }
684
685 value := reflect.ValueOf(object)
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530686 switch value.Kind() {
687 case
688 reflect.Chan, reflect.Func,
689 reflect.Interface, reflect.Map,
690 reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
kesavandb9f54fd2021-11-25 20:08:04 +0530691
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530692 return value.IsNil()
kesavandb9f54fd2021-11-25 20:08:04 +0530693 }
694
695 return false
696}
697
698// Nil asserts that the specified object is nil.
699//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530700// assert.Nil(t, err)
kesavandb9f54fd2021-11-25 20:08:04 +0530701func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
702 if isNil(object) {
703 return true
704 }
705 if h, ok := t.(tHelper); ok {
706 h.Helper()
707 }
708 return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
709}
710
711// isEmpty gets whether the specified object is considered empty or not.
712func isEmpty(object interface{}) bool {
713
714 // get nil case out of the way
715 if object == nil {
716 return true
717 }
718
719 objValue := reflect.ValueOf(object)
720
721 switch objValue.Kind() {
722 // collection types are empty when they have no element
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530723 case reflect.Chan, reflect.Map, reflect.Slice:
kesavandb9f54fd2021-11-25 20:08:04 +0530724 return objValue.Len() == 0
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530725 // pointers are empty if nil or if the value they point to is empty
kesavandb9f54fd2021-11-25 20:08:04 +0530726 case reflect.Ptr:
727 if objValue.IsNil() {
728 return true
729 }
730 deref := objValue.Elem().Interface()
731 return isEmpty(deref)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530732 // for all other types, compare against the zero value
733 // array types are empty when they match their zero-initialized state
kesavandb9f54fd2021-11-25 20:08:04 +0530734 default:
735 zero := reflect.Zero(objValue.Type())
736 return reflect.DeepEqual(object, zero.Interface())
737 }
738}
739
740// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
741// a slice or a channel with len == 0.
742//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530743// assert.Empty(t, obj)
kesavandb9f54fd2021-11-25 20:08:04 +0530744func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
745 pass := isEmpty(object)
746 if !pass {
747 if h, ok := t.(tHelper); ok {
748 h.Helper()
749 }
750 Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
751 }
752
753 return pass
754
755}
756
757// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
758// a slice or a channel with len == 0.
759//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530760// if assert.NotEmpty(t, obj) {
761// assert.Equal(t, "two", obj[1])
762// }
kesavandb9f54fd2021-11-25 20:08:04 +0530763func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
764 pass := !isEmpty(object)
765 if !pass {
766 if h, ok := t.(tHelper); ok {
767 h.Helper()
768 }
769 Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
770 }
771
772 return pass
773
774}
775
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530776// getLen tries to get the length of an object.
777// It returns (0, false) if impossible.
778func getLen(x interface{}) (length int, ok bool) {
kesavandb9f54fd2021-11-25 20:08:04 +0530779 v := reflect.ValueOf(x)
780 defer func() {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530781 ok = recover() == nil
kesavandb9f54fd2021-11-25 20:08:04 +0530782 }()
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530783 return v.Len(), true
kesavandb9f54fd2021-11-25 20:08:04 +0530784}
785
786// Len asserts that the specified object has specific length.
787// Len also fails if the object has a type that len() not accept.
788//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530789// assert.Len(t, mySlice, 3)
kesavandb9f54fd2021-11-25 20:08:04 +0530790func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
791 if h, ok := t.(tHelper); ok {
792 h.Helper()
793 }
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530794 l, ok := getLen(object)
kesavandb9f54fd2021-11-25 20:08:04 +0530795 if !ok {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530796 return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +0530797 }
798
799 if l != length {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530800 return Fail(t, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +0530801 }
802 return true
803}
804
805// True asserts that the specified value is true.
806//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530807// assert.True(t, myBool)
kesavandb9f54fd2021-11-25 20:08:04 +0530808func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
809 if !value {
810 if h, ok := t.(tHelper); ok {
811 h.Helper()
812 }
813 return Fail(t, "Should be true", msgAndArgs...)
814 }
815
816 return true
817
818}
819
820// False asserts that the specified value is false.
821//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530822// assert.False(t, myBool)
kesavandb9f54fd2021-11-25 20:08:04 +0530823func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
824 if value {
825 if h, ok := t.(tHelper); ok {
826 h.Helper()
827 }
828 return Fail(t, "Should be false", msgAndArgs...)
829 }
830
831 return true
832
833}
834
835// NotEqual asserts that the specified values are NOT equal.
836//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530837// assert.NotEqual(t, obj1, obj2)
kesavandb9f54fd2021-11-25 20:08:04 +0530838//
839// Pointer variable equality is determined based on the equality of the
840// referenced values (as opposed to the memory addresses).
841func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
842 if h, ok := t.(tHelper); ok {
843 h.Helper()
844 }
845 if err := validateEqualArgs(expected, actual); err != nil {
846 return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
847 expected, actual, err), msgAndArgs...)
848 }
849
850 if ObjectsAreEqual(expected, actual) {
851 return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
852 }
853
854 return true
855
856}
857
858// NotEqualValues asserts that two objects are not equal even when converted to the same type
859//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530860// assert.NotEqualValues(t, obj1, obj2)
kesavandb9f54fd2021-11-25 20:08:04 +0530861func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
862 if h, ok := t.(tHelper); ok {
863 h.Helper()
864 }
865
866 if ObjectsAreEqualValues(expected, actual) {
867 return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
868 }
869
870 return true
871}
872
873// containsElement try loop over the list check if the list includes the element.
874// return (false, false) if impossible.
875// return (true, false) if element was not found.
876// return (true, true) if element was found.
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530877func containsElement(list interface{}, element interface{}) (ok, found bool) {
kesavandb9f54fd2021-11-25 20:08:04 +0530878
879 listValue := reflect.ValueOf(list)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530880 listType := reflect.TypeOf(list)
881 if listType == nil {
882 return false, false
883 }
884 listKind := listType.Kind()
kesavandb9f54fd2021-11-25 20:08:04 +0530885 defer func() {
886 if e := recover(); e != nil {
887 ok = false
888 found = false
889 }
890 }()
891
892 if listKind == reflect.String {
893 elementValue := reflect.ValueOf(element)
894 return true, strings.Contains(listValue.String(), elementValue.String())
895 }
896
897 if listKind == reflect.Map {
898 mapKeys := listValue.MapKeys()
899 for i := 0; i < len(mapKeys); i++ {
900 if ObjectsAreEqual(mapKeys[i].Interface(), element) {
901 return true, true
902 }
903 }
904 return true, false
905 }
906
907 for i := 0; i < listValue.Len(); i++ {
908 if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
909 return true, true
910 }
911 }
912 return true, false
913
914}
915
916// Contains asserts that the specified string, list(array, slice...) or map contains the
917// specified substring or element.
918//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530919// assert.Contains(t, "Hello World", "World")
920// assert.Contains(t, ["Hello", "World"], "World")
921// assert.Contains(t, {"Hello": "World"}, "Hello")
kesavandb9f54fd2021-11-25 20:08:04 +0530922func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
923 if h, ok := t.(tHelper); ok {
924 h.Helper()
925 }
926
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530927 ok, found := containsElement(s, contains)
kesavandb9f54fd2021-11-25 20:08:04 +0530928 if !ok {
929 return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
930 }
931 if !found {
932 return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...)
933 }
934
935 return true
936
937}
938
939// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
940// specified substring or element.
941//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530942// assert.NotContains(t, "Hello World", "Earth")
943// assert.NotContains(t, ["Hello", "World"], "Earth")
944// assert.NotContains(t, {"Hello": "World"}, "Earth")
kesavandb9f54fd2021-11-25 20:08:04 +0530945func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
946 if h, ok := t.(tHelper); ok {
947 h.Helper()
948 }
949
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530950 ok, found := containsElement(s, contains)
kesavandb9f54fd2021-11-25 20:08:04 +0530951 if !ok {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530952 return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +0530953 }
954 if found {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530955 return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +0530956 }
957
958 return true
959
960}
961
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530962// Subset asserts that the specified list(array, slice...) or map contains all
963// elements given in the specified subset list(array, slice...) or map.
kesavandb9f54fd2021-11-25 20:08:04 +0530964//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530965// assert.Subset(t, [1, 2, 3], [1, 2])
966// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1})
kesavandb9f54fd2021-11-25 20:08:04 +0530967func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
968 if h, ok := t.(tHelper); ok {
969 h.Helper()
970 }
971 if subset == nil {
972 return true // we consider nil to be equal to the nil set
973 }
974
kesavandb9f54fd2021-11-25 20:08:04 +0530975 listKind := reflect.TypeOf(list).Kind()
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530976 if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
kesavandb9f54fd2021-11-25 20:08:04 +0530977 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
978 }
979
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530980 subsetKind := reflect.TypeOf(subset).Kind()
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530981 if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map {
kesavandb9f54fd2021-11-25 20:08:04 +0530982 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
983 }
984
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530985 if subsetKind == reflect.Map && listKind == reflect.Map {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530986 subsetMap := reflect.ValueOf(subset)
987 actualMap := reflect.ValueOf(list)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530988
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530989 for _, k := range subsetMap.MapKeys() {
990 ev := subsetMap.MapIndex(k)
991 av := actualMap.MapIndex(k)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530992
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +0530993 if !av.IsValid() {
994 return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
995 }
996 if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
997 return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +0530998 }
999 }
1000
1001 return true
1002 }
1003
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301004 subsetList := reflect.ValueOf(subset)
1005 for i := 0; i < subsetList.Len(); i++ {
1006 element := subsetList.Index(i).Interface()
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301007 ok, found := containsElement(list, element)
kesavandb9f54fd2021-11-25 20:08:04 +05301008 if !ok {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301009 return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +05301010 }
1011 if !found {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301012 return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +05301013 }
1014 }
1015
1016 return true
1017}
1018
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301019// NotSubset asserts that the specified list(array, slice...) or map does NOT
1020// contain all elements given in the specified subset list(array, slice...) or
1021// map.
kesavandb9f54fd2021-11-25 20:08:04 +05301022//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301023// assert.NotSubset(t, [1, 3, 4], [1, 2])
1024// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
kesavandb9f54fd2021-11-25 20:08:04 +05301025func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
1026 if h, ok := t.(tHelper); ok {
1027 h.Helper()
1028 }
1029 if subset == nil {
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301030 return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +05301031 }
1032
kesavandb9f54fd2021-11-25 20:08:04 +05301033 listKind := reflect.TypeOf(list).Kind()
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301034 if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
kesavandb9f54fd2021-11-25 20:08:04 +05301035 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
1036 }
1037
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301038 subsetKind := reflect.TypeOf(subset).Kind()
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301039 if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map {
kesavandb9f54fd2021-11-25 20:08:04 +05301040 return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
1041 }
1042
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301043 if subsetKind == reflect.Map && listKind == reflect.Map {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301044 subsetMap := reflect.ValueOf(subset)
1045 actualMap := reflect.ValueOf(list)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301046
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301047 for _, k := range subsetMap.MapKeys() {
1048 ev := subsetMap.MapIndex(k)
1049 av := actualMap.MapIndex(k)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301050
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301051 if !av.IsValid() {
1052 return true
1053 }
1054 if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301055 return true
1056 }
1057 }
1058
1059 return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
1060 }
1061
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301062 subsetList := reflect.ValueOf(subset)
1063 for i := 0; i < subsetList.Len(); i++ {
1064 element := subsetList.Index(i).Interface()
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301065 ok, found := containsElement(list, element)
kesavandb9f54fd2021-11-25 20:08:04 +05301066 if !ok {
1067 return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...)
1068 }
1069 if !found {
1070 return true
1071 }
1072 }
1073
1074 return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
1075}
1076
1077// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
1078// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
1079// the number of appearances of each of them in both lists should match.
1080//
1081// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
1082func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
1083 if h, ok := t.(tHelper); ok {
1084 h.Helper()
1085 }
1086 if isEmpty(listA) && isEmpty(listB) {
1087 return true
1088 }
1089
1090 if !isList(t, listA, msgAndArgs...) || !isList(t, listB, msgAndArgs...) {
1091 return false
1092 }
1093
1094 extraA, extraB := diffLists(listA, listB)
1095
1096 if len(extraA) == 0 && len(extraB) == 0 {
1097 return true
1098 }
1099
1100 return Fail(t, formatListDiff(listA, listB, extraA, extraB), msgAndArgs...)
1101}
1102
1103// isList checks that the provided value is array or slice.
1104func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) {
1105 kind := reflect.TypeOf(list).Kind()
1106 if kind != reflect.Array && kind != reflect.Slice {
1107 return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind),
1108 msgAndArgs...)
1109 }
1110 return true
1111}
1112
1113// diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B.
1114// If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and
1115// 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored.
1116func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) {
1117 aValue := reflect.ValueOf(listA)
1118 bValue := reflect.ValueOf(listB)
1119
1120 aLen := aValue.Len()
1121 bLen := bValue.Len()
1122
1123 // Mark indexes in bValue that we already used
1124 visited := make([]bool, bLen)
1125 for i := 0; i < aLen; i++ {
1126 element := aValue.Index(i).Interface()
1127 found := false
1128 for j := 0; j < bLen; j++ {
1129 if visited[j] {
1130 continue
1131 }
1132 if ObjectsAreEqual(bValue.Index(j).Interface(), element) {
1133 visited[j] = true
1134 found = true
1135 break
1136 }
1137 }
1138 if !found {
1139 extraA = append(extraA, element)
1140 }
1141 }
1142
1143 for j := 0; j < bLen; j++ {
1144 if visited[j] {
1145 continue
1146 }
1147 extraB = append(extraB, bValue.Index(j).Interface())
1148 }
1149
1150 return
1151}
1152
1153func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string {
1154 var msg bytes.Buffer
1155
1156 msg.WriteString("elements differ")
1157 if len(extraA) > 0 {
1158 msg.WriteString("\n\nextra elements in list A:\n")
1159 msg.WriteString(spewConfig.Sdump(extraA))
1160 }
1161 if len(extraB) > 0 {
1162 msg.WriteString("\n\nextra elements in list B:\n")
1163 msg.WriteString(spewConfig.Sdump(extraB))
1164 }
1165 msg.WriteString("\n\nlistA:\n")
1166 msg.WriteString(spewConfig.Sdump(listA))
1167 msg.WriteString("\n\nlistB:\n")
1168 msg.WriteString(spewConfig.Sdump(listB))
1169
1170 return msg.String()
1171}
1172
1173// Condition uses a Comparison to assert a complex condition.
1174func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
1175 if h, ok := t.(tHelper); ok {
1176 h.Helper()
1177 }
1178 result := comp()
1179 if !result {
1180 Fail(t, "Condition failed!", msgAndArgs...)
1181 }
1182 return result
1183}
1184
1185// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
1186// methods, and represents a simple func that takes no arguments, and returns nothing.
1187type PanicTestFunc func()
1188
1189// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301190func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) {
1191 didPanic = true
kesavandb9f54fd2021-11-25 20:08:04 +05301192
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301193 defer func() {
1194 message = recover()
1195 if didPanic {
1196 stack = string(debug.Stack())
1197 }
kesavandb9f54fd2021-11-25 20:08:04 +05301198 }()
1199
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301200 // call the target function
1201 f()
1202 didPanic = false
kesavandb9f54fd2021-11-25 20:08:04 +05301203
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301204 return
kesavandb9f54fd2021-11-25 20:08:04 +05301205}
1206
1207// Panics asserts that the code inside the specified PanicTestFunc panics.
1208//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301209// assert.Panics(t, func(){ GoCrazy() })
kesavandb9f54fd2021-11-25 20:08:04 +05301210func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
1211 if h, ok := t.(tHelper); ok {
1212 h.Helper()
1213 }
1214
1215 if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic {
1216 return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
1217 }
1218
1219 return true
1220}
1221
1222// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
1223// the recovered panic value equals the expected panic value.
1224//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301225// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
kesavandb9f54fd2021-11-25 20:08:04 +05301226func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
1227 if h, ok := t.(tHelper); ok {
1228 h.Helper()
1229 }
1230
1231 funcDidPanic, panicValue, panickedStack := didPanic(f)
1232 if !funcDidPanic {
1233 return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
1234 }
1235 if panicValue != expected {
1236 return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...)
1237 }
1238
1239 return true
1240}
1241
1242// PanicsWithError asserts that the code inside the specified PanicTestFunc
1243// panics, and that the recovered panic value is an error that satisfies the
1244// EqualError comparison.
1245//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301246// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
kesavandb9f54fd2021-11-25 20:08:04 +05301247func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
1248 if h, ok := t.(tHelper); ok {
1249 h.Helper()
1250 }
1251
1252 funcDidPanic, panicValue, panickedStack := didPanic(f)
1253 if !funcDidPanic {
1254 return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
1255 }
1256 panicErr, ok := panicValue.(error)
1257 if !ok || panicErr.Error() != errString {
1258 return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...)
1259 }
1260
1261 return true
1262}
1263
1264// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
1265//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301266// assert.NotPanics(t, func(){ RemainCalm() })
kesavandb9f54fd2021-11-25 20:08:04 +05301267func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
1268 if h, ok := t.(tHelper); ok {
1269 h.Helper()
1270 }
1271
1272 if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic {
1273 return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...)
1274 }
1275
1276 return true
1277}
1278
1279// WithinDuration asserts that the two times are within duration delta of each other.
1280//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301281// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
kesavandb9f54fd2021-11-25 20:08:04 +05301282func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
1283 if h, ok := t.(tHelper); ok {
1284 h.Helper()
1285 }
1286
1287 dt := expected.Sub(actual)
1288 if dt < -delta || dt > delta {
1289 return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
1290 }
1291
1292 return true
1293}
1294
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301295// WithinRange asserts that a time is within a time range (inclusive).
1296//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301297// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301298func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool {
1299 if h, ok := t.(tHelper); ok {
1300 h.Helper()
1301 }
1302
1303 if end.Before(start) {
1304 return Fail(t, "Start should be before end", msgAndArgs...)
1305 }
1306
1307 if actual.Before(start) {
1308 return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is before the range", actual, start, end), msgAndArgs...)
1309 } else if actual.After(end) {
1310 return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is after the range", actual, start, end), msgAndArgs...)
1311 }
1312
1313 return true
1314}
1315
kesavandb9f54fd2021-11-25 20:08:04 +05301316func toFloat(x interface{}) (float64, bool) {
1317 var xf float64
1318 xok := true
1319
1320 switch xn := x.(type) {
1321 case uint:
1322 xf = float64(xn)
1323 case uint8:
1324 xf = float64(xn)
1325 case uint16:
1326 xf = float64(xn)
1327 case uint32:
1328 xf = float64(xn)
1329 case uint64:
1330 xf = float64(xn)
1331 case int:
1332 xf = float64(xn)
1333 case int8:
1334 xf = float64(xn)
1335 case int16:
1336 xf = float64(xn)
1337 case int32:
1338 xf = float64(xn)
1339 case int64:
1340 xf = float64(xn)
1341 case float32:
1342 xf = float64(xn)
1343 case float64:
1344 xf = xn
1345 case time.Duration:
1346 xf = float64(xn)
1347 default:
1348 xok = false
1349 }
1350
1351 return xf, xok
1352}
1353
1354// InDelta asserts that the two numerals are within delta of each other.
1355//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301356// assert.InDelta(t, math.Pi, 22/7.0, 0.01)
kesavandb9f54fd2021-11-25 20:08:04 +05301357func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
1358 if h, ok := t.(tHelper); ok {
1359 h.Helper()
1360 }
1361
1362 af, aok := toFloat(expected)
1363 bf, bok := toFloat(actual)
1364
1365 if !aok || !bok {
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301366 return Fail(t, "Parameters must be numerical", msgAndArgs...)
1367 }
1368
1369 if math.IsNaN(af) && math.IsNaN(bf) {
1370 return true
kesavandb9f54fd2021-11-25 20:08:04 +05301371 }
1372
1373 if math.IsNaN(af) {
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301374 return Fail(t, "Expected must not be NaN", msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +05301375 }
1376
1377 if math.IsNaN(bf) {
1378 return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
1379 }
1380
1381 dt := af - bf
1382 if dt < -delta || dt > delta {
1383 return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
1384 }
1385
1386 return true
1387}
1388
1389// InDeltaSlice is the same as InDelta, except it compares two slices.
1390func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
1391 if h, ok := t.(tHelper); ok {
1392 h.Helper()
1393 }
1394 if expected == nil || actual == nil ||
1395 reflect.TypeOf(actual).Kind() != reflect.Slice ||
1396 reflect.TypeOf(expected).Kind() != reflect.Slice {
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301397 return Fail(t, "Parameters must be slice", msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +05301398 }
1399
1400 actualSlice := reflect.ValueOf(actual)
1401 expectedSlice := reflect.ValueOf(expected)
1402
1403 for i := 0; i < actualSlice.Len(); i++ {
1404 result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...)
1405 if !result {
1406 return result
1407 }
1408 }
1409
1410 return true
1411}
1412
1413// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
1414func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
1415 if h, ok := t.(tHelper); ok {
1416 h.Helper()
1417 }
1418 if expected == nil || actual == nil ||
1419 reflect.TypeOf(actual).Kind() != reflect.Map ||
1420 reflect.TypeOf(expected).Kind() != reflect.Map {
1421 return Fail(t, "Arguments must be maps", msgAndArgs...)
1422 }
1423
1424 expectedMap := reflect.ValueOf(expected)
1425 actualMap := reflect.ValueOf(actual)
1426
1427 if expectedMap.Len() != actualMap.Len() {
1428 return Fail(t, "Arguments must have the same number of keys", msgAndArgs...)
1429 }
1430
1431 for _, k := range expectedMap.MapKeys() {
1432 ev := expectedMap.MapIndex(k)
1433 av := actualMap.MapIndex(k)
1434
1435 if !ev.IsValid() {
1436 return Fail(t, fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...)
1437 }
1438
1439 if !av.IsValid() {
1440 return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...)
1441 }
1442
1443 if !InDelta(
1444 t,
1445 ev.Interface(),
1446 av.Interface(),
1447 delta,
1448 msgAndArgs...,
1449 ) {
1450 return false
1451 }
1452 }
1453
1454 return true
1455}
1456
1457func calcRelativeError(expected, actual interface{}) (float64, error) {
1458 af, aok := toFloat(expected)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301459 bf, bok := toFloat(actual)
1460 if !aok || !bok {
1461 return 0, fmt.Errorf("Parameters must be numerical")
1462 }
1463 if math.IsNaN(af) && math.IsNaN(bf) {
1464 return 0, nil
kesavandb9f54fd2021-11-25 20:08:04 +05301465 }
1466 if math.IsNaN(af) {
1467 return 0, errors.New("expected value must not be NaN")
1468 }
1469 if af == 0 {
1470 return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
1471 }
kesavandb9f54fd2021-11-25 20:08:04 +05301472 if math.IsNaN(bf) {
1473 return 0, errors.New("actual value must not be NaN")
1474 }
1475
1476 return math.Abs(af-bf) / math.Abs(af), nil
1477}
1478
1479// InEpsilon asserts that expected and actual have a relative error less than epsilon
1480func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
1481 if h, ok := t.(tHelper); ok {
1482 h.Helper()
1483 }
1484 if math.IsNaN(epsilon) {
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301485 return Fail(t, "epsilon must not be NaN", msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +05301486 }
1487 actualEpsilon, err := calcRelativeError(expected, actual)
1488 if err != nil {
1489 return Fail(t, err.Error(), msgAndArgs...)
1490 }
1491 if actualEpsilon > epsilon {
1492 return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
1493 " < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
1494 }
1495
1496 return true
1497}
1498
1499// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
1500func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
1501 if h, ok := t.(tHelper); ok {
1502 h.Helper()
1503 }
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301504
1505 if expected == nil || actual == nil {
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301506 return Fail(t, "Parameters must be slice", msgAndArgs...)
kesavandb9f54fd2021-11-25 20:08:04 +05301507 }
1508
kesavandb9f54fd2021-11-25 20:08:04 +05301509 expectedSlice := reflect.ValueOf(expected)
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301510 actualSlice := reflect.ValueOf(actual)
kesavandb9f54fd2021-11-25 20:08:04 +05301511
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301512 if expectedSlice.Type().Kind() != reflect.Slice {
1513 return Fail(t, "Expected value must be slice", msgAndArgs...)
1514 }
1515
1516 expectedLen := expectedSlice.Len()
1517 if !IsType(t, expected, actual) || !Len(t, actual, expectedLen) {
1518 return false
1519 }
1520
1521 for i := 0; i < expectedLen; i++ {
1522 if !InEpsilon(t, expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) {
1523 return false
kesavandb9f54fd2021-11-25 20:08:04 +05301524 }
1525 }
1526
1527 return true
1528}
1529
1530/*
1531 Errors
1532*/
1533
1534// NoError asserts that a function returned no error (i.e. `nil`).
1535//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301536// actualObj, err := SomeFunction()
1537// if assert.NoError(t, err) {
1538// assert.Equal(t, expectedObj, actualObj)
1539// }
kesavandb9f54fd2021-11-25 20:08:04 +05301540func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
1541 if err != nil {
1542 if h, ok := t.(tHelper); ok {
1543 h.Helper()
1544 }
1545 return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
1546 }
1547
1548 return true
1549}
1550
1551// Error asserts that a function returned an error (i.e. not `nil`).
1552//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301553// actualObj, err := SomeFunction()
1554// if assert.Error(t, err) {
1555// assert.Equal(t, expectedError, err)
1556// }
kesavandb9f54fd2021-11-25 20:08:04 +05301557func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
1558 if err == nil {
1559 if h, ok := t.(tHelper); ok {
1560 h.Helper()
1561 }
1562 return Fail(t, "An error is expected but got nil.", msgAndArgs...)
1563 }
1564
1565 return true
1566}
1567
1568// EqualError asserts that a function returned an error (i.e. not `nil`)
1569// and that it is equal to the provided error.
1570//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301571// actualObj, err := SomeFunction()
1572// assert.EqualError(t, err, expectedErrorString)
kesavandb9f54fd2021-11-25 20:08:04 +05301573func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
1574 if h, ok := t.(tHelper); ok {
1575 h.Helper()
1576 }
1577 if !Error(t, theError, msgAndArgs...) {
1578 return false
1579 }
1580 expected := errString
1581 actual := theError.Error()
1582 // don't need to use deep equals here, we know they are both strings
1583 if expected != actual {
1584 return Fail(t, fmt.Sprintf("Error message not equal:\n"+
1585 "expected: %q\n"+
1586 "actual : %q", expected, actual), msgAndArgs...)
1587 }
1588 return true
1589}
1590
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301591// ErrorContains asserts that a function returned an error (i.e. not `nil`)
1592// and that the error contains the specified substring.
1593//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301594// actualObj, err := SomeFunction()
1595// assert.ErrorContains(t, err, expectedErrorSubString)
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301596func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool {
1597 if h, ok := t.(tHelper); ok {
1598 h.Helper()
1599 }
1600 if !Error(t, theError, msgAndArgs...) {
1601 return false
1602 }
1603
1604 actual := theError.Error()
1605 if !strings.Contains(actual, contains) {
1606 return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...)
1607 }
1608
1609 return true
1610}
1611
kesavandb9f54fd2021-11-25 20:08:04 +05301612// matchRegexp return true if a specified regexp matches a string.
1613func matchRegexp(rx interface{}, str interface{}) bool {
1614
1615 var r *regexp.Regexp
1616 if rr, ok := rx.(*regexp.Regexp); ok {
1617 r = rr
1618 } else {
1619 r = regexp.MustCompile(fmt.Sprint(rx))
1620 }
1621
1622 return (r.FindStringIndex(fmt.Sprint(str)) != nil)
1623
1624}
1625
1626// Regexp asserts that a specified regexp matches a string.
1627//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301628// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
1629// assert.Regexp(t, "start...$", "it's not starting")
kesavandb9f54fd2021-11-25 20:08:04 +05301630func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
1631 if h, ok := t.(tHelper); ok {
1632 h.Helper()
1633 }
1634
1635 match := matchRegexp(rx, str)
1636
1637 if !match {
1638 Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
1639 }
1640
1641 return match
1642}
1643
1644// NotRegexp asserts that a specified regexp does not match a string.
1645//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301646// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
1647// assert.NotRegexp(t, "^start", "it's not starting")
kesavandb9f54fd2021-11-25 20:08:04 +05301648func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
1649 if h, ok := t.(tHelper); ok {
1650 h.Helper()
1651 }
1652 match := matchRegexp(rx, str)
1653
1654 if match {
1655 Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
1656 }
1657
1658 return !match
1659
1660}
1661
1662// Zero asserts that i is the zero value for its type.
1663func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
1664 if h, ok := t.(tHelper); ok {
1665 h.Helper()
1666 }
1667 if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
1668 return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
1669 }
1670 return true
1671}
1672
1673// NotZero asserts that i is not the zero value for its type.
1674func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
1675 if h, ok := t.(tHelper); ok {
1676 h.Helper()
1677 }
1678 if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
1679 return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
1680 }
1681 return true
1682}
1683
1684// FileExists checks whether a file exists in the given path. It also fails if
1685// the path points to a directory or there is an error when trying to check the file.
1686func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
1687 if h, ok := t.(tHelper); ok {
1688 h.Helper()
1689 }
1690 info, err := os.Lstat(path)
1691 if err != nil {
1692 if os.IsNotExist(err) {
1693 return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
1694 }
1695 return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
1696 }
1697 if info.IsDir() {
1698 return Fail(t, fmt.Sprintf("%q is a directory", path), msgAndArgs...)
1699 }
1700 return true
1701}
1702
1703// NoFileExists checks whether a file does not exist in a given path. It fails
1704// if the path points to an existing _file_ only.
1705func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
1706 if h, ok := t.(tHelper); ok {
1707 h.Helper()
1708 }
1709 info, err := os.Lstat(path)
1710 if err != nil {
1711 return true
1712 }
1713 if info.IsDir() {
1714 return true
1715 }
1716 return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...)
1717}
1718
1719// DirExists checks whether a directory exists in the given path. It also fails
1720// if the path is a file rather a directory or there is an error checking whether it exists.
1721func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
1722 if h, ok := t.(tHelper); ok {
1723 h.Helper()
1724 }
1725 info, err := os.Lstat(path)
1726 if err != nil {
1727 if os.IsNotExist(err) {
1728 return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
1729 }
1730 return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
1731 }
1732 if !info.IsDir() {
1733 return Fail(t, fmt.Sprintf("%q is a file", path), msgAndArgs...)
1734 }
1735 return true
1736}
1737
1738// NoDirExists checks whether a directory does not exist in the given path.
1739// It fails if the path points to an existing _directory_ only.
1740func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
1741 if h, ok := t.(tHelper); ok {
1742 h.Helper()
1743 }
1744 info, err := os.Lstat(path)
1745 if err != nil {
1746 if os.IsNotExist(err) {
1747 return true
1748 }
1749 return true
1750 }
1751 if !info.IsDir() {
1752 return true
1753 }
1754 return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...)
1755}
1756
1757// JSONEq asserts that two JSON strings are equivalent.
1758//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301759// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
kesavandb9f54fd2021-11-25 20:08:04 +05301760func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
1761 if h, ok := t.(tHelper); ok {
1762 h.Helper()
1763 }
1764 var expectedJSONAsInterface, actualJSONAsInterface interface{}
1765
1766 if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
1767 return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
1768 }
1769
1770 if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
1771 return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
1772 }
1773
1774 return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
1775}
1776
1777// YAMLEq asserts that two YAML strings are equivalent.
1778func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
1779 if h, ok := t.(tHelper); ok {
1780 h.Helper()
1781 }
1782 var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
1783
1784 if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
1785 return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
1786 }
1787
1788 if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
1789 return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
1790 }
1791
1792 return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
1793}
1794
1795func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
1796 t := reflect.TypeOf(v)
1797 k := t.Kind()
1798
1799 if k == reflect.Ptr {
1800 t = t.Elem()
1801 k = t.Kind()
1802 }
1803 return t, k
1804}
1805
1806// diff returns a diff of both values as long as both are of the same type and
1807// are a struct, map, slice, array or string. Otherwise it returns an empty string.
1808func diff(expected interface{}, actual interface{}) string {
1809 if expected == nil || actual == nil {
1810 return ""
1811 }
1812
1813 et, ek := typeAndKind(expected)
1814 at, _ := typeAndKind(actual)
1815
1816 if et != at {
1817 return ""
1818 }
1819
1820 if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String {
1821 return ""
1822 }
1823
1824 var e, a string
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301825
1826 switch et {
1827 case reflect.TypeOf(""):
kesavandb9f54fd2021-11-25 20:08:04 +05301828 e = reflect.ValueOf(expected).String()
1829 a = reflect.ValueOf(actual).String()
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301830 case reflect.TypeOf(time.Time{}):
1831 e = spewConfigStringerEnabled.Sdump(expected)
1832 a = spewConfigStringerEnabled.Sdump(actual)
1833 default:
1834 e = spewConfig.Sdump(expected)
1835 a = spewConfig.Sdump(actual)
kesavandb9f54fd2021-11-25 20:08:04 +05301836 }
1837
1838 diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
1839 A: difflib.SplitLines(e),
1840 B: difflib.SplitLines(a),
1841 FromFile: "Expected",
1842 FromDate: "",
1843 ToFile: "Actual",
1844 ToDate: "",
1845 Context: 1,
1846 })
1847
1848 return "\n\nDiff:\n" + diff
1849}
1850
1851func isFunction(arg interface{}) bool {
1852 if arg == nil {
1853 return false
1854 }
1855 return reflect.TypeOf(arg).Kind() == reflect.Func
1856}
1857
1858var spewConfig = spew.ConfigState{
1859 Indent: " ",
1860 DisablePointerAddresses: true,
1861 DisableCapacities: true,
1862 SortKeys: true,
1863 DisableMethods: true,
1864 MaxDepth: 10,
1865}
1866
Akash Reddy Kankanalac6b6ca12025-06-12 14:26:57 +05301867var spewConfigStringerEnabled = spew.ConfigState{
1868 Indent: " ",
1869 DisablePointerAddresses: true,
1870 DisableCapacities: true,
1871 SortKeys: true,
1872 MaxDepth: 10,
1873}
1874
kesavandb9f54fd2021-11-25 20:08:04 +05301875type tHelper interface {
1876 Helper()
1877}
1878
1879// Eventually asserts that given condition will be met in waitFor time,
1880// periodically checking target function each tick.
1881//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301882// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
kesavandb9f54fd2021-11-25 20:08:04 +05301883func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
1884 if h, ok := t.(tHelper); ok {
1885 h.Helper()
1886 }
1887
1888 ch := make(chan bool, 1)
1889
1890 timer := time.NewTimer(waitFor)
1891 defer timer.Stop()
1892
1893 ticker := time.NewTicker(tick)
1894 defer ticker.Stop()
1895
1896 for tick := ticker.C; ; {
1897 select {
1898 case <-timer.C:
1899 return Fail(t, "Condition never satisfied", msgAndArgs...)
1900 case <-tick:
1901 tick = nil
1902 go func() { ch <- condition() }()
1903 case v := <-ch:
1904 if v {
1905 return true
1906 }
1907 tick = ticker.C
1908 }
1909 }
1910}
1911
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301912// CollectT implements the TestingT interface and collects all errors.
1913type CollectT struct {
1914 errors []error
1915}
1916
1917// Errorf collects the error.
1918func (c *CollectT) Errorf(format string, args ...interface{}) {
1919 c.errors = append(c.errors, fmt.Errorf(format, args...))
1920}
1921
1922// FailNow panics.
1923func (*CollectT) FailNow() {
1924 panic("Assertion failed")
1925}
1926
1927// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
1928func (*CollectT) Reset() {
1929 panic("Reset() is deprecated")
1930}
1931
1932// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
1933func (*CollectT) Copy(TestingT) {
1934 panic("Copy() is deprecated")
1935}
1936
1937// EventuallyWithT asserts that given condition will be met in waitFor time,
1938// periodically checking target function each tick. In contrast to Eventually,
1939// it supplies a CollectT to the condition function, so that the condition
1940// function can use the CollectT to call other assertions.
1941// The condition is considered "met" if no errors are raised in a tick.
1942// The supplied CollectT collects all errors from one tick (if there are any).
1943// If the condition is not met before waitFor, the collected errors of
1944// the last tick are copied to t.
1945//
1946// externalValue := false
1947// go func() {
1948// time.Sleep(8*time.Second)
1949// externalValue = true
1950// }()
1951// assert.EventuallyWithT(t, func(c *assert.CollectT) {
1952// // add assertions as needed; any assertion failure will fail the current tick
1953// assert.True(c, externalValue, "expected 'externalValue' to be true")
1954// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
1955func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
1956 if h, ok := t.(tHelper); ok {
1957 h.Helper()
1958 }
1959
1960 var lastFinishedTickErrs []error
1961 ch := make(chan []error, 1)
1962
1963 timer := time.NewTimer(waitFor)
1964 defer timer.Stop()
1965
1966 ticker := time.NewTicker(tick)
1967 defer ticker.Stop()
1968
1969 for tick := ticker.C; ; {
1970 select {
1971 case <-timer.C:
1972 for _, err := range lastFinishedTickErrs {
1973 t.Errorf("%v", err)
1974 }
1975 return Fail(t, "Condition never satisfied", msgAndArgs...)
1976 case <-tick:
1977 tick = nil
1978 go func() {
1979 collect := new(CollectT)
1980 defer func() {
1981 ch <- collect.errors
1982 }()
1983 condition(collect)
1984 }()
1985 case errs := <-ch:
1986 if len(errs) == 0 {
1987 return true
1988 }
1989 // Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
1990 lastFinishedTickErrs = errs
1991 tick = ticker.C
1992 }
1993 }
1994}
1995
kesavandb9f54fd2021-11-25 20:08:04 +05301996// Never asserts that the given condition doesn't satisfy in waitFor time,
1997// periodically checking the target function each tick.
1998//
Akash Reddy Kankanalad9ec4822025-06-10 22:59:53 +05301999// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
kesavandb9f54fd2021-11-25 20:08:04 +05302000func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
2001 if h, ok := t.(tHelper); ok {
2002 h.Helper()
2003 }
2004
2005 ch := make(chan bool, 1)
2006
2007 timer := time.NewTimer(waitFor)
2008 defer timer.Stop()
2009
2010 ticker := time.NewTicker(tick)
2011 defer ticker.Stop()
2012
2013 for tick := ticker.C; ; {
2014 select {
2015 case <-timer.C:
2016 return true
2017 case <-tick:
2018 tick = nil
2019 go func() { ch <- condition() }()
2020 case v := <-ch:
2021 if v {
2022 return Fail(t, "Condition satisfied", msgAndArgs...)
2023 }
2024 tick = ticker.C
2025 }
2026 }
2027}
2028
2029// ErrorIs asserts that at least one of the errors in err's chain matches target.
2030// This is a wrapper for errors.Is.
2031func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
2032 if h, ok := t.(tHelper); ok {
2033 h.Helper()
2034 }
2035 if errors.Is(err, target) {
2036 return true
2037 }
2038
2039 var expectedText string
2040 if target != nil {
2041 expectedText = target.Error()
2042 }
2043
2044 chain := buildErrorChainString(err)
2045
2046 return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
2047 "expected: %q\n"+
2048 "in chain: %s", expectedText, chain,
2049 ), msgAndArgs...)
2050}
2051
2052// NotErrorIs asserts that at none of the errors in err's chain matches target.
2053// This is a wrapper for errors.Is.
2054func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
2055 if h, ok := t.(tHelper); ok {
2056 h.Helper()
2057 }
2058 if !errors.Is(err, target) {
2059 return true
2060 }
2061
2062 var expectedText string
2063 if target != nil {
2064 expectedText = target.Error()
2065 }
2066
2067 chain := buildErrorChainString(err)
2068
2069 return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
2070 "found: %q\n"+
2071 "in chain: %s", expectedText, chain,
2072 ), msgAndArgs...)
2073}
2074
2075// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
2076// This is a wrapper for errors.As.
2077func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool {
2078 if h, ok := t.(tHelper); ok {
2079 h.Helper()
2080 }
2081 if errors.As(err, target) {
2082 return true
2083 }
2084
2085 chain := buildErrorChainString(err)
2086
2087 return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
2088 "expected: %q\n"+
2089 "in chain: %s", target, chain,
2090 ), msgAndArgs...)
2091}
2092
2093func buildErrorChainString(err error) string {
2094 if err == nil {
2095 return ""
2096 }
2097
2098 e := errors.Unwrap(err)
2099 chain := fmt.Sprintf("%q", err.Error())
2100 for e != nil {
2101 chain += fmt.Sprintf("\n\t%q", e.Error())
2102 e = errors.Unwrap(e)
2103 }
2104 return chain
2105}