Add an argumentMatcher type and MatchedBy() helper to the mock
package, enabling custom fine-grained argument matching behaviors.
This is particularly helpful when building mocks over complex argument
types where deep equality is cumbersome or can't be used. Ex, a matcher
might match over just the the URL of an argument *http.Request.
Originally the expctations required that the return values be specified
immediately after the method name and arguments, otherwise the call
setup will either panic (best case) or silently modify the *previous*
call specification (worst case).
This change moves the Return(), Run(), Once(), etc methods onto the Call
struct, and changes the chaining behaviour so that they modify the Call
data directly rather than referencing the last item in the ExpectedCalls
array.
There is race condition caused when a method being tested calls a mocked
method within a go routine. For example, caching might be done a go
routine and that caching might be mocked.
There is already a mutex protecting the lists on the Mock object -
however Return() appends to ExpectedCalls and findExpectedCall could
run at the same time.
We cannot compare two Func arguments to check if they are equal using
the reflect package. This leads to the following misleading panic:
```go
handler := func(http.ResponseWriter, *http.Request) {}
muxMock.On("HandleFunc", "/", handler)
muxMock.HandleFunc("/", handler)
// panics arguing handler != handler
```
Since we cannot fix this behaviour using reflection, this patch
provides a better panic with a meaningful workaround.
```go
handler := func(http.ResponseWriter, *http.Request) {}
muxMock.On("HandleFunc", "/", handler)
// panics recommending defining the expectatin with:
// AnythingOfType("func(http.ResponseWriter, *http.Request)")
```
Solution following the panic's instructions:
```go
handler := func(http.ResponseWriter, *http.Request) {}
muxMock.On("HandleFunc", "/",
mock.AnythingOfType("func(http.ResponseWriter, *http.Request)"))
muxMock.HandleFunc("/", handler)
```
Some methods in Go take a pointer to a struct or a map and are supposed
to set some values in the referenced argument. Using Return is not
enough to mock such methods.
We are introducing a Run method that allows setting a Call handler to
make your mock update such referenced values.
Example usage mocking a service that finds a user in a data store and
fills the values in the provided struct:
```go
m.On("Find", 1, mock.AnythingOfType(*User))
.Return(nil)
.Run(func(args mock.Arguments) {
u := args.Get(0).(*User)
u.ID = 1
u.Email = "mail@example.com"
})
```
You sometimes want to test concurrent behaviour like timeouts, but it
was not currently possible with our mocks.
This commits adds the following functions to Mock:
`After` will block m.Called for the given duration before returning.
```golang
func (m *Mock) After(d time.Duration) *Mock
Mock.On("MyMethod", arg1).After(1 * time.Millisecond)
```
`WaitUntil` is the primitive under `After`, and it's exposed in case you
want somebody wants more control over the returns. `Called` blocks until the w
channel is closed or receives a message.
```golang
func (m *Mock) WaitUntil(w <-chan time.Time) *Mock
Mock.On("MyMethod", arg1).WaitUntil(time.After(1 * time.Millisecond))
```
When using testify, I saw panic: assert: arguments: Error(0) failed because object wasn't correct type: {{ad6e7d77-1745-4761-6c4b-a79ab92a4a0f e6e975ef-3637-4047-436a-018ee9d2de52 %!s(int=17) <nil> <nil> %!s(bool=false) %!s(*string=<nil>) ...
when using the Error(index) function.
This commit simply changes to using %v for printing the unexpected structure in the Bool, Int, and Error shortcut methods.