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