1package mock 2 3import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "regexp" 8 "runtime" 9 "strings" 10 "sync" 11 "time" 12 13 "github.com/davecgh/go-spew/spew" 14 "github.com/pmezard/go-difflib/difflib" 15 "github.com/stretchr/objx" 16 "github.com/stretchr/testify/assert" 17) 18 19// TestingT is an interface wrapper around *testing.T 20type TestingT interface { 21 Logf(format string, args ...interface{}) 22 Errorf(format string, args ...interface{}) 23 FailNow() 24} 25 26/* 27 Call 28*/ 29 30// Call represents a method call and is used for setting expectations, 31// as well as recording activity. 32type Call struct { 33 Parent *Mock 34 35 // The name of the method that was or will be called. 36 Method string 37 38 // Holds the arguments of the method. 39 Arguments Arguments 40 41 // Holds the arguments that should be returned when 42 // this method is called. 43 ReturnArguments Arguments 44 45 // Holds the caller info for the On() call 46 callerInfo []string 47 48 // The number of times to return the return arguments when setting 49 // expectations. 0 means to always return the value. 50 Repeatability int 51 52 // Amount of times this call has been called 53 totalCalls int 54 55 // Call to this method can be optional 56 optional bool 57 58 // Holds a channel that will be used to block the Return until it either 59 // receives a message or is closed. nil means it returns immediately. 60 WaitFor <-chan time.Time 61 62 waitTime time.Duration 63 64 // Holds a handler used to manipulate arguments content that are passed by 65 // reference. It's useful when mocking methods such as unmarshalers or 66 // decoders. 67 RunFn func(Arguments) 68} 69 70func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call { 71 return &Call{ 72 Parent: parent, 73 Method: methodName, 74 Arguments: methodArguments, 75 ReturnArguments: make([]interface{}, 0), 76 callerInfo: callerInfo, 77 Repeatability: 0, 78 WaitFor: nil, 79 RunFn: nil, 80 } 81} 82 83func (c *Call) lock() { 84 c.Parent.mutex.Lock() 85} 86 87func (c *Call) unlock() { 88 c.Parent.mutex.Unlock() 89} 90 91// Return specifies the return arguments for the expectation. 92// 93// Mock.On("DoSomething").Return(errors.New("failed")) 94func (c *Call) Return(returnArguments ...interface{}) *Call { 95 c.lock() 96 defer c.unlock() 97 98 c.ReturnArguments = returnArguments 99 100 return c 101} 102 103// Once indicates that that the mock should only return the value once. 104// 105// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() 106func (c *Call) Once() *Call { 107 return c.Times(1) 108} 109 110// Twice indicates that that the mock should only return the value twice. 111// 112// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() 113func (c *Call) Twice() *Call { 114 return c.Times(2) 115} 116 117// Times indicates that that the mock should only return the indicated number 118// of times. 119// 120// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) 121func (c *Call) Times(i int) *Call { 122 c.lock() 123 defer c.unlock() 124 c.Repeatability = i 125 return c 126} 127 128// WaitUntil sets the channel that will block the mock's return until its closed 129// or a message is received. 130// 131// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) 132func (c *Call) WaitUntil(w <-chan time.Time) *Call { 133 c.lock() 134 defer c.unlock() 135 c.WaitFor = w 136 return c 137} 138 139// After sets how long to block until the call returns 140// 141// Mock.On("MyMethod", arg1, arg2).After(time.Second) 142func (c *Call) After(d time.Duration) *Call { 143 c.lock() 144 defer c.unlock() 145 c.waitTime = d 146 return c 147} 148 149// Run sets a handler to be called before returning. It can be used when 150// mocking a method such as unmarshalers that takes a pointer to a struct and 151// sets properties in such struct 152// 153// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(func(args Arguments) { 154// arg := args.Get(0).(*map[string]interface{}) 155// arg["foo"] = "bar" 156// }) 157func (c *Call) Run(fn func(args Arguments)) *Call { 158 c.lock() 159 defer c.unlock() 160 c.RunFn = fn 161 return c 162} 163 164// Maybe allows the method call to be optional. Not calling an optional method 165// will not cause an error while asserting expectations 166func (c *Call) Maybe() *Call { 167 c.lock() 168 defer c.unlock() 169 c.optional = true 170 return c 171} 172 173// On chains a new expectation description onto the mocked interface. This 174// allows syntax like. 175// 176// Mock. 177// On("MyMethod", 1).Return(nil). 178// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) 179func (c *Call) On(methodName string, arguments ...interface{}) *Call { 180 return c.Parent.On(methodName, arguments...) 181} 182 183// Mock is the workhorse used to track activity on another object. 184// For an example of its usage, refer to the "Example Usage" section at the top 185// of this document. 186type Mock struct { 187 // Represents the calls that are expected of 188 // an object. 189 ExpectedCalls []*Call 190 191 // Holds the calls that were made to this mocked object. 192 Calls []Call 193 194 // test is An optional variable that holds the test struct, to be used when an 195 // invalid mock call was made. 196 test TestingT 197 198 // TestData holds any data that might be useful for testing. Testify ignores 199 // this data completely allowing you to do whatever you like with it. 200 testData objx.Map 201 202 mutex sync.Mutex 203} 204 205// TestData holds any data that might be useful for testing. Testify ignores 206// this data completely allowing you to do whatever you like with it. 207func (m *Mock) TestData() objx.Map { 208 209 if m.testData == nil { 210 m.testData = make(objx.Map) 211 } 212 213 return m.testData 214} 215 216/* 217 Setting expectations 218*/ 219 220// Test sets the test struct variable of the mock object 221func (m *Mock) Test(t TestingT) { 222 m.mutex.Lock() 223 defer m.mutex.Unlock() 224 m.test = t 225} 226 227// fail fails the current test with the given formatted format and args. 228// In case that a test was defined, it uses the test APIs for failing a test, 229// otherwise it uses panic. 230func (m *Mock) fail(format string, args ...interface{}) { 231 m.mutex.Lock() 232 defer m.mutex.Unlock() 233 234 if m.test == nil { 235 panic(fmt.Sprintf(format, args...)) 236 } 237 m.test.Errorf(format, args...) 238 m.test.FailNow() 239} 240 241// On starts a description of an expectation of the specified method 242// being called. 243// 244// Mock.On("MyMethod", arg1, arg2) 245func (m *Mock) On(methodName string, arguments ...interface{}) *Call { 246 for _, arg := range arguments { 247 if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { 248 panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) 249 } 250 } 251 252 m.mutex.Lock() 253 defer m.mutex.Unlock() 254 c := newCall(m, methodName, assert.CallerInfo(), arguments...) 255 m.ExpectedCalls = append(m.ExpectedCalls, c) 256 return c 257} 258 259// /* 260// Recording and responding to activity 261// */ 262 263func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { 264 for i, call := range m.ExpectedCalls { 265 if call.Method == method && call.Repeatability > -1 { 266 267 _, diffCount := call.Arguments.Diff(arguments) 268 if diffCount == 0 { 269 return i, call 270 } 271 272 } 273 } 274 return -1, nil 275} 276 277func (m *Mock) findClosestCall(method string, arguments ...interface{}) (*Call, string) { 278 var diffCount int 279 var closestCall *Call 280 var err string 281 282 for _, call := range m.expectedCalls() { 283 if call.Method == method { 284 285 errInfo, tempDiffCount := call.Arguments.Diff(arguments) 286 if tempDiffCount < diffCount || diffCount == 0 { 287 diffCount = tempDiffCount 288 closestCall = call 289 err = errInfo 290 } 291 292 } 293 } 294 295 return closestCall, err 296} 297 298func callString(method string, arguments Arguments, includeArgumentValues bool) string { 299 300 var argValsString string 301 if includeArgumentValues { 302 var argVals []string 303 for argIndex, arg := range arguments { 304 argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg)) 305 } 306 argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) 307 } 308 309 return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString) 310} 311 312// Called tells the mock object that a method has been called, and gets an array 313// of arguments to return. Panics if the call is unexpected (i.e. not preceded by 314// appropriate .On .Return() calls) 315// If Call.WaitFor is set, blocks until the channel is closed or receives a message. 316func (m *Mock) Called(arguments ...interface{}) Arguments { 317 // get the calling function's name 318 pc, _, _, ok := runtime.Caller(1) 319 if !ok { 320 panic("Couldn't get the caller information") 321 } 322 functionPath := runtime.FuncForPC(pc).Name() 323 //Next four lines are required to use GCCGO function naming conventions. 324 //For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock 325 //uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree 326 //With GCCGO we need to remove interface information starting from pN<dd>. 327 re := regexp.MustCompile("\\.pN\\d+_") 328 if re.MatchString(functionPath) { 329 functionPath = re.Split(functionPath, -1)[0] 330 } 331 parts := strings.Split(functionPath, ".") 332 functionName := parts[len(parts)-1] 333 return m.MethodCalled(functionName, arguments...) 334} 335 336// MethodCalled tells the mock object that the given method has been called, and gets 337// an array of arguments to return. Panics if the call is unexpected (i.e. not preceded 338// by appropriate .On .Return() calls) 339// If Call.WaitFor is set, blocks until the channel is closed or receives a message. 340func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments { 341 m.mutex.Lock() 342 //TODO: could combine expected and closes in single loop 343 found, call := m.findExpectedCall(methodName, arguments...) 344 345 if found < 0 { 346 // we have to fail here - because we don't know what to do 347 // as the return arguments. This is because: 348 // 349 // a) this is a totally unexpected call to this method, 350 // b) the arguments are not what was expected, or 351 // c) the developer has forgotten to add an accompanying On...Return pair. 352 353 closestCall, mismatch := m.findClosestCall(methodName, arguments...) 354 m.mutex.Unlock() 355 356 if closestCall != nil { 357 m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s", 358 callString(methodName, arguments, true), 359 callString(methodName, closestCall.Arguments, true), 360 diffArguments(closestCall.Arguments, arguments), 361 strings.TrimSpace(mismatch), 362 ) 363 } else { 364 m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo()) 365 } 366 } 367 368 if call.Repeatability == 1 { 369 call.Repeatability = -1 370 } else if call.Repeatability > 1 { 371 call.Repeatability-- 372 } 373 call.totalCalls++ 374 375 // add the call 376 m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments...)) 377 m.mutex.Unlock() 378 379 // block if specified 380 if call.WaitFor != nil { 381 <-call.WaitFor 382 } else { 383 time.Sleep(call.waitTime) 384 } 385 386 m.mutex.Lock() 387 runFn := call.RunFn 388 m.mutex.Unlock() 389 390 if runFn != nil { 391 runFn(arguments) 392 } 393 394 m.mutex.Lock() 395 returnArgs := call.ReturnArguments 396 m.mutex.Unlock() 397 398 return returnArgs 399} 400 401/* 402 Assertions 403*/ 404 405type assertExpectationser interface { 406 AssertExpectations(TestingT) bool 407} 408 409// AssertExpectationsForObjects asserts that everything specified with On and Return 410// of the specified objects was in fact called as expected. 411// 412// Calls may have occurred in any order. 413func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { 414 if h, ok := t.(tHelper); ok { 415 h.Helper() 416 } 417 for _, obj := range testObjects { 418 if m, ok := obj.(Mock); ok { 419 t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") 420 obj = &m 421 } 422 m := obj.(assertExpectationser) 423 if !m.AssertExpectations(t) { 424 t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m)) 425 return false 426 } 427 } 428 return true 429} 430 431// AssertExpectations asserts that everything specified with On and Return was 432// in fact called as expected. Calls may have occurred in any order. 433func (m *Mock) AssertExpectations(t TestingT) bool { 434 if h, ok := t.(tHelper); ok { 435 h.Helper() 436 } 437 m.mutex.Lock() 438 defer m.mutex.Unlock() 439 var somethingMissing bool 440 var failedExpectations int 441 442 // iterate through each expectation 443 expectedCalls := m.expectedCalls() 444 for _, expectedCall := range expectedCalls { 445 if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 { 446 somethingMissing = true 447 failedExpectations++ 448 t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo) 449 } else { 450 if expectedCall.Repeatability > 0 { 451 somethingMissing = true 452 failedExpectations++ 453 t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo) 454 } else { 455 t.Logf("PASS:\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) 456 } 457 } 458 } 459 460 if somethingMissing { 461 t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo()) 462 } 463 464 return !somethingMissing 465} 466 467// AssertNumberOfCalls asserts that the method was called expectedCalls times. 468func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { 469 if h, ok := t.(tHelper); ok { 470 h.Helper() 471 } 472 m.mutex.Lock() 473 defer m.mutex.Unlock() 474 var actualCalls int 475 for _, call := range m.calls() { 476 if call.Method == methodName { 477 actualCalls++ 478 } 479 } 480 return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls)) 481} 482 483// AssertCalled asserts that the method was called. 484// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. 485func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool { 486 if h, ok := t.(tHelper); ok { 487 h.Helper() 488 } 489 m.mutex.Lock() 490 defer m.mutex.Unlock() 491 if !m.methodWasCalled(methodName, arguments) { 492 var calledWithArgs []string 493 for _, call := range m.calls() { 494 calledWithArgs = append(calledWithArgs, fmt.Sprintf("%v", call.Arguments)) 495 } 496 if len(calledWithArgs) == 0 { 497 return assert.Fail(t, "Should have called with given arguments", 498 fmt.Sprintf("Expected %q to have been called with:\n%v\nbut no actual calls happened", methodName, arguments)) 499 } 500 return assert.Fail(t, "Should have called with given arguments", 501 fmt.Sprintf("Expected %q to have been called with:\n%v\nbut actual calls were:\n %v", methodName, arguments, strings.Join(calledWithArgs, "\n"))) 502 } 503 return true 504} 505 506// AssertNotCalled asserts that the method was not called. 507// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. 508func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool { 509 if h, ok := t.(tHelper); ok { 510 h.Helper() 511 } 512 m.mutex.Lock() 513 defer m.mutex.Unlock() 514 if m.methodWasCalled(methodName, arguments) { 515 return assert.Fail(t, "Should not have called with given arguments", 516 fmt.Sprintf("Expected %q to not have been called with:\n%v\nbut actually it was.", methodName, arguments)) 517 } 518 return true 519} 520 521func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { 522 for _, call := range m.calls() { 523 if call.Method == methodName { 524 525 _, differences := Arguments(expected).Diff(call.Arguments) 526 527 if differences == 0 { 528 // found the expected call 529 return true 530 } 531 532 } 533 } 534 // we didn't find the expected call 535 return false 536} 537 538func (m *Mock) expectedCalls() []*Call { 539 return append([]*Call{}, m.ExpectedCalls...) 540} 541 542func (m *Mock) calls() []Call { 543 return append([]Call{}, m.Calls...) 544} 545 546/* 547 Arguments 548*/ 549 550// Arguments holds an array of method arguments or return values. 551type Arguments []interface{} 552 553const ( 554 // Anything is used in Diff and Assert when the argument being tested 555 // shouldn't be taken into consideration. 556 Anything = "mock.Anything" 557) 558 559// AnythingOfTypeArgument is a string that contains the type of an argument 560// for use when type checking. Used in Diff and Assert. 561type AnythingOfTypeArgument string 562 563// AnythingOfType returns an AnythingOfTypeArgument object containing the 564// name of the type to check for. Used in Diff and Assert. 565// 566// For example: 567// Assert(t, AnythingOfType("string"), AnythingOfType("int")) 568func AnythingOfType(t string) AnythingOfTypeArgument { 569 return AnythingOfTypeArgument(t) 570} 571 572// argumentMatcher performs custom argument matching, returning whether or 573// not the argument is matched by the expectation fixture function. 574type argumentMatcher struct { 575 // fn is a function which accepts one argument, and returns a bool. 576 fn reflect.Value 577} 578 579func (f argumentMatcher) Matches(argument interface{}) bool { 580 expectType := f.fn.Type().In(0) 581 expectTypeNilSupported := false 582 switch expectType.Kind() { 583 case reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Ptr: 584 expectTypeNilSupported = true 585 } 586 587 argType := reflect.TypeOf(argument) 588 var arg reflect.Value 589 if argType == nil { 590 arg = reflect.New(expectType).Elem() 591 } else { 592 arg = reflect.ValueOf(argument) 593 } 594 595 if argType == nil && !expectTypeNilSupported { 596 panic(errors.New("attempting to call matcher with nil for non-nil expected type")) 597 } 598 if argType == nil || argType.AssignableTo(expectType) { 599 result := f.fn.Call([]reflect.Value{arg}) 600 return result[0].Bool() 601 } 602 return false 603} 604 605func (f argumentMatcher) String() string { 606 return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).Name()) 607} 608 609// MatchedBy can be used to match a mock call based on only certain properties 610// from a complex struct or some calculation. It takes a function that will be 611// evaluated with the called argument and will return true when there's a match 612// and false otherwise. 613// 614// Example: 615// m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" })) 616// 617// |fn|, must be a function accepting a single argument (of the expected type) 618// which returns a bool. If |fn| doesn't match the required signature, 619// MatchedBy() panics. 620func MatchedBy(fn interface{}) argumentMatcher { 621 fnType := reflect.TypeOf(fn) 622 623 if fnType.Kind() != reflect.Func { 624 panic(fmt.Sprintf("assert: arguments: %s is not a func", fn)) 625 } 626 if fnType.NumIn() != 1 { 627 panic(fmt.Sprintf("assert: arguments: %s does not take exactly one argument", fn)) 628 } 629 if fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool { 630 panic(fmt.Sprintf("assert: arguments: %s does not return a bool", fn)) 631 } 632 633 return argumentMatcher{fn: reflect.ValueOf(fn)} 634} 635 636// Get Returns the argument at the specified index. 637func (args Arguments) Get(index int) interface{} { 638 if index+1 > len(args) { 639 panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args))) 640 } 641 return args[index] 642} 643 644// Is gets whether the objects match the arguments specified. 645func (args Arguments) Is(objects ...interface{}) bool { 646 for i, obj := range args { 647 if obj != objects[i] { 648 return false 649 } 650 } 651 return true 652} 653 654// Diff gets a string describing the differences between the arguments 655// and the specified objects. 656// 657// Returns the diff string and number of differences found. 658func (args Arguments) Diff(objects []interface{}) (string, int) { 659 //TODO: could return string as error and nil for No difference 660 661 var output = "\n" 662 var differences int 663 664 var maxArgCount = len(args) 665 if len(objects) > maxArgCount { 666 maxArgCount = len(objects) 667 } 668 669 for i := 0; i < maxArgCount; i++ { 670 var actual, expected interface{} 671 var actualFmt, expectedFmt string 672 673 if len(objects) <= i { 674 actual = "(Missing)" 675 actualFmt = "(Missing)" 676 } else { 677 actual = objects[i] 678 actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual) 679 } 680 681 if len(args) <= i { 682 expected = "(Missing)" 683 expectedFmt = "(Missing)" 684 } else { 685 expected = args[i] 686 expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected) 687 } 688 689 if matcher, ok := expected.(argumentMatcher); ok { 690 if matcher.Matches(actual) { 691 output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher) 692 } else { 693 differences++ 694 output = fmt.Sprintf("%s\t%d: PASS: %s not matched by %s\n", output, i, actualFmt, matcher) 695 } 696 } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() { 697 698 // type checking 699 if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) { 700 // not match 701 differences++ 702 output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt) 703 } 704 705 } else { 706 707 // normal checking 708 709 if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { 710 // match 711 output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt) 712 } else { 713 // not match 714 differences++ 715 output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt) 716 } 717 } 718 719 } 720 721 if differences == 0 { 722 return "No differences.", differences 723 } 724 725 return output, differences 726 727} 728 729// Assert compares the arguments with the specified objects and fails if 730// they do not exactly match. 731func (args Arguments) Assert(t TestingT, objects ...interface{}) bool { 732 if h, ok := t.(tHelper); ok { 733 h.Helper() 734 } 735 736 // get the differences 737 diff, diffCount := args.Diff(objects) 738 739 if diffCount == 0 { 740 return true 741 } 742 743 // there are differences... report them... 744 t.Logf(diff) 745 t.Errorf("%sArguments do not match.", assert.CallerInfo()) 746 747 return false 748 749} 750 751// String gets the argument at the specified index. Panics if there is no argument, or 752// if the argument is of the wrong type. 753// 754// If no index is provided, String() returns a complete string representation 755// of the arguments. 756func (args Arguments) String(indexOrNil ...int) string { 757 758 if len(indexOrNil) == 0 { 759 // normal String() method - return a string representation of the args 760 var argsStr []string 761 for _, arg := range args { 762 argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg))) 763 } 764 return strings.Join(argsStr, ",") 765 } else if len(indexOrNil) == 1 { 766 // Index has been specified - get the argument at that index 767 var index = indexOrNil[0] 768 var s string 769 var ok bool 770 if s, ok = args.Get(index).(string); !ok { 771 panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index))) 772 } 773 return s 774 } 775 776 panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String. Must be 0 or 1, not %d", len(indexOrNil))) 777 778} 779 780// Int gets the argument at the specified index. Panics if there is no argument, or 781// if the argument is of the wrong type. 782func (args Arguments) Int(index int) int { 783 var s int 784 var ok bool 785 if s, ok = args.Get(index).(int); !ok { 786 panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index))) 787 } 788 return s 789} 790 791// Error gets the argument at the specified index. Panics if there is no argument, or 792// if the argument is of the wrong type. 793func (args Arguments) Error(index int) error { 794 obj := args.Get(index) 795 var s error 796 var ok bool 797 if obj == nil { 798 return nil 799 } 800 if s, ok = obj.(error); !ok { 801 panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index))) 802 } 803 return s 804} 805 806// Bool gets the argument at the specified index. Panics if there is no argument, or 807// if the argument is of the wrong type. 808func (args Arguments) Bool(index int) bool { 809 var s bool 810 var ok bool 811 if s, ok = args.Get(index).(bool); !ok { 812 panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index))) 813 } 814 return s 815} 816 817func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { 818 t := reflect.TypeOf(v) 819 k := t.Kind() 820 821 if k == reflect.Ptr { 822 t = t.Elem() 823 k = t.Kind() 824 } 825 return t, k 826} 827 828func diffArguments(expected Arguments, actual Arguments) string { 829 if len(expected) != len(actual) { 830 return fmt.Sprintf("Provided %v arguments, mocked for %v arguments", len(expected), len(actual)) 831 } 832 833 for x := range expected { 834 if diffString := diff(expected[x], actual[x]); diffString != "" { 835 return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString) 836 } 837 } 838 839 return "" 840} 841 842// diff returns a diff of both values as long as both are of the same type and 843// are a struct, map, slice or array. Otherwise it returns an empty string. 844func diff(expected interface{}, actual interface{}) string { 845 if expected == nil || actual == nil { 846 return "" 847 } 848 849 et, ek := typeAndKind(expected) 850 at, _ := typeAndKind(actual) 851 852 if et != at { 853 return "" 854 } 855 856 if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array { 857 return "" 858 } 859 860 e := spewConfig.Sdump(expected) 861 a := spewConfig.Sdump(actual) 862 863 diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ 864 A: difflib.SplitLines(e), 865 B: difflib.SplitLines(a), 866 FromFile: "Expected", 867 FromDate: "", 868 ToFile: "Actual", 869 ToDate: "", 870 Context: 1, 871 }) 872 873 return diff 874} 875 876var spewConfig = spew.ConfigState{ 877 Indent: " ", 878 DisablePointerAddresses: true, 879 DisableCapacities: true, 880 SortKeys: true, 881} 882 883type tHelper interface { 884 Helper() 885} 886