summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/stretchr/testify/mock
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/stretchr/testify/mock')
-rw-r--r--vendor/github.com/stretchr/testify/mock/mock.go141
-rw-r--r--vendor/github.com/stretchr/testify/mock/mock_test.go236
2 files changed, 324 insertions, 53 deletions
diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go
index 20d7b8b1f..208b838a3 100644
--- a/vendor/github.com/stretchr/testify/mock/mock.go
+++ b/vendor/github.com/stretchr/testify/mock/mock.go
@@ -1,6 +1,7 @@
package mock
import (
+ "errors"
"fmt"
"reflect"
"regexp"
@@ -15,10 +16,6 @@ import (
"github.com/stretchr/testify/assert"
)
-func inin() {
- spew.Config.SortKeys = true
-}
-
// TestingT is an interface wrapper around *testing.T
type TestingT interface {
Logf(format string, args ...interface{})
@@ -52,10 +49,15 @@ type Call struct {
// Amount of times this call has been called
totalCalls int
+ // Call to this method can be optional
+ optional bool
+
// Holds a channel that will be used to block the Return until it either
// receives a message or is closed. nil means it returns immediately.
WaitFor <-chan time.Time
+ waitTime time.Duration
+
// Holds a handler used to manipulate arguments content that are passed by
// reference. It's useful when mocking methods such as unmarshalers or
// decoders.
@@ -134,7 +136,10 @@ func (c *Call) WaitUntil(w <-chan time.Time) *Call {
//
// Mock.On("MyMethod", arg1, arg2).After(time.Second)
func (c *Call) After(d time.Duration) *Call {
- return c.WaitUntil(time.After(d))
+ c.lock()
+ defer c.unlock()
+ c.waitTime = d
+ return c
}
// Run sets a handler to be called before returning. It can be used when
@@ -145,13 +150,22 @@ func (c *Call) After(d time.Duration) *Call {
// arg := args.Get(0).(*map[string]interface{})
// arg["foo"] = "bar"
// })
-func (c *Call) Run(fn func(Arguments)) *Call {
+func (c *Call) Run(fn func(args Arguments)) *Call {
c.lock()
defer c.unlock()
c.RunFn = fn
return c
}
+// Maybe allows the method call to be optional. Not calling an optional method
+// will not cause an error while asserting expectations
+func (c *Call) Maybe() *Call {
+ c.lock()
+ defer c.unlock()
+ c.optional = true
+ return c
+}
+
// On chains a new expectation description onto the mocked interface. This
// allows syntax like.
//
@@ -218,8 +232,6 @@ func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
// */
func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
- m.mutex.Lock()
- defer m.mutex.Unlock()
for i, call := range m.ExpectedCalls {
if call.Method == method && call.Repeatability > -1 {
@@ -283,7 +295,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
functionPath := runtime.FuncForPC(pc).Name()
//Next four lines are required to use GCCGO function naming conventions.
//For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock
- //uses inteface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree
+ //uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree
//With GCCGO we need to remove interface information starting from pN<dd>.
re := regexp.MustCompile("\\.pN\\d+_")
if re.MatchString(functionPath) {
@@ -291,8 +303,16 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
}
parts := strings.Split(functionPath, ".")
functionName := parts[len(parts)-1]
+ return m.MethodCalled(functionName, arguments...)
+}
- found, call := m.findExpectedCall(functionName, arguments...)
+// MethodCalled tells the mock object that the given method has been called, and gets
+// an array of arguments to return. Panics if the call is unexpected (i.e. not preceded
+// by appropriate .On .Return() calls)
+// If Call.WaitFor is set, blocks until the channel is closed or receives a message.
+func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments {
+ m.mutex.Lock()
+ found, call := m.findExpectedCall(methodName, arguments...)
if found < 0 {
// we have to fail here - because we don't know what to do
@@ -302,45 +322,47 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
// b) the arguments are not what was expected, or
// c) the developer has forgotten to add an accompanying On...Return pair.
- closestFound, closestCall := m.findClosestCall(functionName, arguments...)
+ closestFound, closestCall := m.findClosestCall(methodName, arguments...)
+ m.mutex.Unlock()
if closestFound {
- panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\n", callString(functionName, arguments, true), callString(functionName, closestCall.Arguments, true), diffArguments(arguments, closestCall.Arguments)))
+ panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\n", callString(methodName, arguments, true), callString(methodName, closestCall.Arguments, true), diffArguments(closestCall.Arguments, arguments)))
} else {
- panic(fmt.Sprintf("\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", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo()))
- }
- } else {
- m.mutex.Lock()
- switch {
- case call.Repeatability == 1:
- call.Repeatability = -1
- call.totalCalls++
-
- case call.Repeatability > 1:
- call.Repeatability--
- call.totalCalls++
-
- case call.Repeatability == 0:
- call.totalCalls++
+ panic(fmt.Sprintf("\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()))
}
- m.mutex.Unlock()
}
+ if call.Repeatability == 1 {
+ call.Repeatability = -1
+ } else if call.Repeatability > 1 {
+ call.Repeatability--
+ }
+ call.totalCalls++
+
// add the call
- m.mutex.Lock()
- m.Calls = append(m.Calls, *newCall(m, functionName, arguments...))
+ m.Calls = append(m.Calls, *newCall(m, methodName, arguments...))
m.mutex.Unlock()
// block if specified
if call.WaitFor != nil {
<-call.WaitFor
+ } else {
+ time.Sleep(call.waitTime)
}
- if call.RunFn != nil {
- call.RunFn(arguments)
+ m.mutex.Lock()
+ runFn := call.RunFn
+ m.mutex.Unlock()
+
+ if runFn != nil {
+ runFn(arguments)
}
- return call.ReturnArguments
+ m.mutex.Lock()
+ returnArgs := call.ReturnArguments
+ m.mutex.Unlock()
+
+ return returnArgs
}
/*
@@ -372,25 +394,25 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
// AssertExpectations asserts that everything specified with On and Return was
// in fact called as expected. Calls may have occurred in any order.
func (m *Mock) AssertExpectations(t TestingT) bool {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
var somethingMissing bool
var failedExpectations int
// iterate through each expectation
expectedCalls := m.expectedCalls()
for _, expectedCall := range expectedCalls {
- if !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 {
+ if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 {
somethingMissing = true
failedExpectations++
t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
} else {
- m.mutex.Lock()
if expectedCall.Repeatability > 0 {
somethingMissing = true
failedExpectations++
} else {
t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
}
- m.mutex.Unlock()
}
}
@@ -403,6 +425,8 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
// AssertNumberOfCalls asserts that the method was called expectedCalls times.
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
var actualCalls int
for _, call := range m.calls() {
if call.Method == methodName {
@@ -415,6 +439,8 @@ func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls
// AssertCalled asserts that the method was called.
// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) {
t.Logf("%v", m.expectedCalls())
return false
@@ -425,6 +451,8 @@ func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interfac
// AssertNotCalled asserts that the method was not called.
// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) {
t.Logf("%v", m.expectedCalls())
return false
@@ -450,14 +478,10 @@ func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
}
func (m *Mock) expectedCalls() []*Call {
- m.mutex.Lock()
- defer m.mutex.Unlock()
return append([]*Call{}, m.ExpectedCalls...)
}
func (m *Mock) calls() []Call {
- m.mutex.Lock()
- defer m.mutex.Unlock()
return append([]Call{}, m.Calls...)
}
@@ -496,9 +520,25 @@ type argumentMatcher struct {
func (f argumentMatcher) Matches(argument interface{}) bool {
expectType := f.fn.Type().In(0)
+ expectTypeNilSupported := false
+ switch expectType.Kind() {
+ case reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Ptr:
+ expectTypeNilSupported = true
+ }
- if reflect.TypeOf(argument).AssignableTo(expectType) {
- result := f.fn.Call([]reflect.Value{reflect.ValueOf(argument)})
+ argType := reflect.TypeOf(argument)
+ var arg reflect.Value
+ if argType == nil {
+ arg = reflect.New(expectType).Elem()
+ } else {
+ arg = reflect.ValueOf(argument)
+ }
+
+ if argType == nil && !expectTypeNilSupported {
+ panic(errors.New("attempting to call matcher with nil for non-nil expected type"))
+ }
+ if argType == nil || argType.AssignableTo(expectType) {
+ result := f.fn.Call([]reflect.Value{arg})
return result[0].Bool()
}
return false
@@ -518,7 +558,7 @@ func (f argumentMatcher) String() string {
//
// |fn|, must be a function accepting a single argument (of the expected type)
// which returns a bool. If |fn| doesn't match the required signature,
-// MathedBy() panics.
+// MatchedBy() panics.
func MatchedBy(fn interface{}) argumentMatcher {
fnType := reflect.TypeOf(fn)
@@ -719,6 +759,10 @@ func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
}
func diffArguments(expected Arguments, actual Arguments) string {
+ if len(expected) != len(actual) {
+ return fmt.Sprintf("Provided %v arguments, mocked for %v arguments", len(expected), len(actual))
+ }
+
for x := range expected {
if diffString := diff(expected[x], actual[x]); diffString != "" {
return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString)
@@ -746,8 +790,8 @@ func diff(expected interface{}, actual interface{}) string {
return ""
}
- e := spew.Sdump(expected)
- a := spew.Sdump(actual)
+ e := spewConfig.Sdump(expected)
+ a := spewConfig.Sdump(actual)
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(e),
@@ -761,3 +805,10 @@ func diff(expected interface{}, actual interface{}) string {
return diff
}
+
+var spewConfig = spew.ConfigState{
+ Indent: " ",
+ DisablePointerAddresses: true,
+ DisableCapacities: true,
+ SortKeys: true,
+}
diff --git a/vendor/github.com/stretchr/testify/mock/mock_test.go b/vendor/github.com/stretchr/testify/mock/mock_test.go
index 8cb4615db..cb245ba59 100644
--- a/vendor/github.com/stretchr/testify/mock/mock_test.go
+++ b/vendor/github.com/stretchr/testify/mock/mock_test.go
@@ -2,10 +2,13 @@ package mock
import (
"errors"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
+ "fmt"
+ "sync"
"testing"
"time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
/*
@@ -40,6 +43,26 @@ func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error {
return args.Error(0)
}
+func (i *TestExampleImplementation) TheExampleMethod4(v ExampleInterface) error {
+ args := i.Called(v)
+ return args.Error(0)
+}
+
+func (i *TestExampleImplementation) TheExampleMethod5(ch chan struct{}) error {
+ args := i.Called(ch)
+ return args.Error(0)
+}
+
+func (i *TestExampleImplementation) TheExampleMethod6(m map[string]bool) error {
+ args := i.Called(m)
+ return args.Error(0)
+}
+
+func (i *TestExampleImplementation) TheExampleMethod7(slice []bool) error {
+ args := i.Called(slice)
+ return args.Error(0)
+}
+
func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error {
args := i.Called(fn)
return args.Error(0)
@@ -55,6 +78,11 @@ func (i *TestExampleImplementation) TheExampleMethodVariadicInterface(a ...inter
return args.Error(0)
}
+func (i *TestExampleImplementation) TheExampleMethodMixedVariadic(a int, b ...int) error {
+ args := i.Called(a, b)
+ return args.Error(0)
+}
+
type ExampleFuncType func(string) error
func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error {
@@ -174,15 +202,20 @@ func Test_Mock_On_WithPtrArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation
mockedService.On("TheExampleMethod3",
- MatchedBy(func(a *ExampleType) bool { return a.ran == true }),
+ MatchedBy(func(a *ExampleType) bool { return a != nil && a.ran == true }),
).Return(nil)
mockedService.On("TheExampleMethod3",
- MatchedBy(func(a *ExampleType) bool { return a.ran == false }),
+ MatchedBy(func(a *ExampleType) bool { return a != nil && a.ran == false }),
).Return(errors.New("error"))
+ mockedService.On("TheExampleMethod3",
+ MatchedBy(func(a *ExampleType) bool { return a == nil }),
+ ).Return(errors.New("error2"))
+
assert.Equal(t, mockedService.TheExampleMethod3(&ExampleType{true}), nil)
assert.EqualError(t, mockedService.TheExampleMethod3(&ExampleType{false}), "error")
+ assert.EqualError(t, mockedService.TheExampleMethod3(nil), "error2")
}
func Test_Mock_On_WithFuncArgMatcher(t *testing.T) {
@@ -191,17 +224,62 @@ func Test_Mock_On_WithFuncArgMatcher(t *testing.T) {
fixture1, fixture2 := errors.New("fixture1"), errors.New("fixture2")
mockedService.On("TheExampleMethodFunc",
- MatchedBy(func(a func(string) error) bool { return a("string") == fixture1 }),
+ MatchedBy(func(a func(string) error) bool { return a != nil && a("string") == fixture1 }),
).Return(errors.New("fixture1"))
mockedService.On("TheExampleMethodFunc",
- MatchedBy(func(a func(string) error) bool { return a("string") == fixture2 }),
+ MatchedBy(func(a func(string) error) bool { return a != nil && a("string") == fixture2 }),
).Return(errors.New("fixture2"))
+ mockedService.On("TheExampleMethodFunc",
+ MatchedBy(func(a func(string) error) bool { return a == nil }),
+ ).Return(errors.New("fixture3"))
+
assert.EqualError(t, mockedService.TheExampleMethodFunc(
func(string) error { return fixture1 }), "fixture1")
assert.EqualError(t, mockedService.TheExampleMethodFunc(
func(string) error { return fixture2 }), "fixture2")
+ assert.EqualError(t, mockedService.TheExampleMethodFunc(nil), "fixture3")
+}
+
+func Test_Mock_On_WithInterfaceArgMatcher(t *testing.T) {
+ var mockedService TestExampleImplementation
+
+ mockedService.On("TheExampleMethod4",
+ MatchedBy(func(a ExampleInterface) bool { return a == nil }),
+ ).Return(errors.New("fixture1"))
+
+ assert.EqualError(t, mockedService.TheExampleMethod4(nil), "fixture1")
+}
+
+func Test_Mock_On_WithChannelArgMatcher(t *testing.T) {
+ var mockedService TestExampleImplementation
+
+ mockedService.On("TheExampleMethod5",
+ MatchedBy(func(ch chan struct{}) bool { return ch == nil }),
+ ).Return(errors.New("fixture1"))
+
+ assert.EqualError(t, mockedService.TheExampleMethod5(nil), "fixture1")
+}
+
+func Test_Mock_On_WithMapArgMatcher(t *testing.T) {
+ var mockedService TestExampleImplementation
+
+ mockedService.On("TheExampleMethod6",
+ MatchedBy(func(m map[string]bool) bool { return m == nil }),
+ ).Return(errors.New("fixture1"))
+
+ assert.EqualError(t, mockedService.TheExampleMethod6(nil), "fixture1")
+}
+
+func Test_Mock_On_WithSliceArgMatcher(t *testing.T) {
+ var mockedService TestExampleImplementation
+
+ mockedService.On("TheExampleMethod7",
+ MatchedBy(func(slice []bool) bool { return slice == nil }),
+ ).Return(errors.New("fixture1"))
+
+ assert.EqualError(t, mockedService.TheExampleMethod7(nil), "fixture1")
}
func Test_Mock_On_WithVariadicFunc(t *testing.T) {
@@ -226,6 +304,29 @@ func Test_Mock_On_WithVariadicFunc(t *testing.T) {
}
+func Test_Mock_On_WithMixedVariadicFunc(t *testing.T) {
+
+ // make a test impl object
+ var mockedService = new(TestExampleImplementation)
+
+ c := mockedService.
+ On("TheExampleMethodMixedVariadic", 1, []int{2, 3, 4}).
+ Return(nil)
+
+ assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+ assert.Equal(t, 2, len(c.Arguments))
+ assert.Equal(t, 1, c.Arguments[0])
+ assert.Equal(t, []int{2, 3, 4}, c.Arguments[1])
+
+ assert.NotPanics(t, func() {
+ mockedService.TheExampleMethodMixedVariadic(1, 2, 3, 4)
+ })
+ assert.Panics(t, func() {
+ mockedService.TheExampleMethodMixedVariadic(1, 2, 3, 5)
+ })
+
+}
+
func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) {
// make a test impl object
@@ -726,7 +827,7 @@ func Test_AssertExpectationsForObjects_Helper(t *testing.T) {
mockedService2.Called(2)
mockedService3.Called(3)
- assert.True(t, AssertExpectationsForObjects(t, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
+ assert.True(t, AssertExpectationsForObjects(t, &mockedService1.Mock, &mockedService2.Mock, &mockedService3.Mock))
assert.True(t, AssertExpectationsForObjects(t, mockedService1, mockedService2, mockedService3))
}
@@ -745,7 +846,7 @@ func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) {
mockedService3.Called(3)
tt := new(testing.T)
- assert.False(t, AssertExpectationsForObjects(tt, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
+ assert.False(t, AssertExpectationsForObjects(tt, &mockedService1.Mock, &mockedService2.Mock, &mockedService3.Mock))
assert.False(t, AssertExpectationsForObjects(tt, mockedService1, mockedService2, mockedService3))
}
@@ -969,6 +1070,31 @@ func Test_Mock_AssertNotCalled(t *testing.T) {
}
+func Test_Mock_AssertOptional(t *testing.T) {
+ // Optional called
+ var ms1 = new(TestExampleImplementation)
+ ms1.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil)
+ ms1.TheExampleMethod(1, 2, 3)
+
+ tt1 := new(testing.T)
+ assert.Equal(t, true, ms1.AssertExpectations(tt1))
+
+ // Optional not called
+ var ms2 = new(TestExampleImplementation)
+ ms2.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil)
+
+ tt2 := new(testing.T)
+ assert.Equal(t, true, ms2.AssertExpectations(tt2))
+
+ // Non-optional called
+ var ms3 = new(TestExampleImplementation)
+ ms3.On("TheExampleMethod", 1, 2, 3).Return(4, nil)
+ ms3.TheExampleMethod(1, 2, 3)
+
+ tt3 := new(testing.T)
+ assert.Equal(t, true, ms3.AssertExpectations(tt3))
+}
+
/*
Arguments helper methods
*/
@@ -1130,3 +1256,97 @@ func Test_Arguments_Bool(t *testing.T) {
assert.Equal(t, true, args.Bool(2))
}
+
+func Test_WaitUntil_Parallel(t *testing.T) {
+
+ // make a test impl object
+ var mockedService *TestExampleImplementation = new(TestExampleImplementation)
+
+ ch1 := make(chan time.Time)
+ ch2 := make(chan time.Time)
+
+ mockedService.Mock.On("TheExampleMethod2", true).Return().WaitUntil(ch2).Run(func(args Arguments) {
+ ch1 <- time.Now()
+ })
+
+ mockedService.Mock.On("TheExampleMethod2", false).Return().WaitUntil(ch1)
+
+ // Lock both goroutines on the .WaitUntil method
+ go func() {
+ mockedService.TheExampleMethod2(false)
+ }()
+ go func() {
+ mockedService.TheExampleMethod2(true)
+ }()
+
+ // Allow the first call to execute, so the second one executes afterwards
+ ch2 <- time.Now()
+}
+
+func Test_MockMethodCalled(t *testing.T) {
+ m := new(Mock)
+ m.On("foo", "hello").Return("world")
+
+ retArgs := m.MethodCalled("foo", "hello")
+ require.True(t, len(retArgs) == 1)
+ require.Equal(t, "world", retArgs[0])
+ m.AssertExpectations(t)
+}
+
+// Test to validate fix for racy concurrent call access in MethodCalled()
+func Test_MockReturnAndCalledConcurrent(t *testing.T) {
+ iterations := 1000
+ m := &Mock{}
+ call := m.On("ConcurrencyTestMethod")
+
+ wg := sync.WaitGroup{}
+ wg.Add(2)
+
+ go func() {
+ for i := 0; i < iterations; i++ {
+ call.Return(10)
+ }
+ wg.Done()
+ }()
+ go func() {
+ for i := 0; i < iterations; i++ {
+ ConcurrencyTestMethod(m)
+ }
+ wg.Done()
+ }()
+ wg.Wait()
+}
+
+type timer struct{ Mock }
+
+func (s *timer) GetTime(i int) string {
+ return s.Called(i).Get(0).(string)
+}
+
+func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
+ waitDuration := 1
+ total, waitMs := 5, time.Millisecond*time.Duration(waitDuration)
+ aTimer := new(timer)
+ for i := 0; i < total; i++ {
+ aTimer.On("GetTime", i).After(waitMs).Return(fmt.Sprintf("Time%d", i)).Once()
+ }
+ time.Sleep(waitMs)
+ start := time.Now()
+ var results []string
+
+ for i := 0; i < total; i++ {
+ results = append(results, aTimer.GetTime(i))
+ }
+
+ end := time.Now()
+ elapsedTime := end.Sub(start)
+ assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be atleast greater than %v", elapsedTime, waitMs))
+ assert.Equal(t, total, len(results))
+ for i, _ := range results {
+ assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same")
+ }
+}
+
+func ConcurrencyTestMethod(m *Mock) {
+ m.Called()
+}