diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go | 280 |
1 files changed, 169 insertions, 111 deletions
diff --git a/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go b/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go index fa8747e29..111a281b4 100644 --- a/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go +++ b/Godeps/_workspace/src/github.com/stretchr/testify/mock/mock.go @@ -2,13 +2,15 @@ package mock import ( "fmt" - "github.com/stretchr/objx" - "github.com/stretchr/testify/assert" "reflect" + "regexp" "runtime" "strings" "sync" "time" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" ) // TestingT is an interface wrapper around *testing.T @@ -24,6 +26,7 @@ type TestingT interface { // Call represents a method call and is used for setting expectations, // as well as recording activity. type Call struct { + Parent *Mock // The name of the method that was or will be called. Method string @@ -46,112 +49,79 @@ type Call struct { // Holds a handler used to manipulate arguments content that are passed by // reference. It's useful when mocking methods such as unmarshalers or // decoders. - Run func(Arguments) -} - -// Mock is the workhorse used to track activity on another object. -// For an example of its usage, refer to the "Example Usage" section at the top of this document. -type Mock struct { - - // The method name that is currently - // being referred to by the On method. - onMethodName string - - // An array of the arguments that are - // currently being referred to by the On method. - onMethodArguments Arguments - - // Represents the calls that are expected of - // an object. - ExpectedCalls []Call - - // Holds the calls that were made to this mocked object. - Calls []Call - - // TestData holds any data that might be useful for testing. Testify ignores - // this data completely allowing you to do whatever you like with it. - testData objx.Map - - mutex sync.Mutex + RunFn func(Arguments) } -// TestData holds any data that might be useful for testing. Testify ignores -// this data completely allowing you to do whatever you like with it. -func (m *Mock) TestData() objx.Map { - - if m.testData == nil { - m.testData = make(objx.Map) +func newCall(parent *Mock, methodName string, methodArguments ...interface{}) *Call { + return &Call{ + Parent: parent, + Method: methodName, + Arguments: methodArguments, + ReturnArguments: make([]interface{}, 0), + Repeatability: 0, + WaitFor: nil, + RunFn: nil, } - - return m.testData } -/* - Setting expectations -*/ +func (self *Call) lock() { + self.Parent.mutex.Lock() +} -// On starts a description of an expectation of the specified method -// being called. -// -// Mock.On("MyMethod", arg1, arg2) -func (m *Mock) On(methodName string, arguments ...interface{}) *Mock { - m.onMethodName = methodName - m.onMethodArguments = arguments +func (self *Call) unlock() { + self.Parent.mutex.Unlock() +} - for _, arg := range arguments { - if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { - panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) - } - } +func (self *Call) Return(returnArguments ...interface{}) *Call { + self.lock() + defer self.unlock() - return m -} + self.ReturnArguments = returnArguments -// Return finishes a description of an expectation of the method (and arguments) -// specified in the most recent On method call. -// -// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2) -func (m *Mock) Return(returnArguments ...interface{}) *Mock { - m.ExpectedCalls = append(m.ExpectedCalls, Call{m.onMethodName, m.onMethodArguments, returnArguments, 0, nil, nil}) - return m + return self } // Once indicates that that the mock should only return the value once. // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() -func (m *Mock) Once() { - m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 1 +func (self *Call) Once() *Call { + return self.Times(1) } // Twice indicates that that the mock should only return the value twice. // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() -func (m *Mock) Twice() { - m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = 2 +func (self *Call) Twice() *Call { + return self.Times(2) } // Times indicates that that the mock should only return the indicated number // of times. // // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) -func (m *Mock) Times(i int) { - m.ExpectedCalls[len(m.ExpectedCalls)-1].Repeatability = i +func (self *Call) Times(i int) *Call { + self.lock() + defer self.unlock() + self.Repeatability = i + return self } // WaitUntil sets the channel that will block the mock's return until its closed // or a message is received. // // Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) -func (m *Mock) WaitUntil(w <-chan time.Time) *Mock { - m.ExpectedCalls[len(m.ExpectedCalls)-1].WaitFor = w - return m +func (self *Call) WaitUntil(w <-chan time.Time) *Call { + self.lock() + defer self.unlock() + self.WaitFor = w + return self } // After sets how long to block until the call returns // // Mock.On("MyMethod", arg1, arg2).After(time.Second) -func (m *Mock) After(d time.Duration) *Mock { - return m.WaitUntil(time.After(d)) +func (self *Call) After(d time.Duration) *Call { + return self.WaitUntil(time.After(d)) } // Run sets a handler to be called before returning. It can be used when @@ -162,22 +132,87 @@ func (m *Mock) After(d time.Duration) *Mock { // arg := args.Get(0).(*map[string]interface{}) // arg["foo"] = "bar" // }) -func (m *Mock) Run(fn func(Arguments)) *Mock { - m.ExpectedCalls[len(m.ExpectedCalls)-1].Run = fn - return m +func (self *Call) Run(fn func(Arguments)) *Call { + self.lock() + defer self.unlock() + self.RunFn = fn + return self +} + +// On chains a new expectation description onto the mocked interface. This +// allows syntax like. +// +// Mock. +// On("MyMethod", 1).Return(nil). +// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) +func (self *Call) On(methodName string, arguments ...interface{}) *Call { + return self.Parent.On(methodName, arguments...) +} + +// Mock is the workhorse used to track activity on another object. +// For an example of its usage, refer to the "Example Usage" section at the top +// of this document. +type Mock struct { + // Represents the calls that are expected of + // an object. + ExpectedCalls []*Call + + // Holds the calls that were made to this mocked object. + Calls []Call + + // TestData holds any data that might be useful for testing. Testify ignores + // this data completely allowing you to do whatever you like with it. + testData objx.Map + + mutex sync.Mutex +} + +// TestData holds any data that might be useful for testing. Testify ignores +// this data completely allowing you to do whatever you like with it. +func (m *Mock) TestData() objx.Map { + + if m.testData == nil { + m.testData = make(objx.Map) + } + + return m.testData } /* - Recording and responding to activity + Setting expectations */ +// On starts a description of an expectation of the specified method +// being called. +// +// Mock.On("MyMethod", arg1, arg2) +func (self *Mock) On(methodName string, arguments ...interface{}) *Call { + for _, arg := range arguments { + if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { + panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) + } + } + + self.mutex.Lock() + defer self.mutex.Unlock() + c := newCall(self, methodName, arguments...) + self.ExpectedCalls = append(self.ExpectedCalls, c) + return c +} + +// /* +// Recording and responding to activity +// */ + 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 { _, diffCount := call.Arguments.Diff(arguments) if diffCount == 0 { - return i, &call + return i, call } } @@ -186,17 +221,16 @@ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, * } func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) { - diffCount := 0 var closestCall *Call = nil - for _, call := range m.ExpectedCalls { + for _, call := range m.expectedCalls() { if call.Method == method { _, tempDiffCount := call.Arguments.Diff(arguments) if tempDiffCount < diffCount || diffCount == 0 { diffCount = tempDiffCount - closestCall = &call + closestCall = call } } @@ -215,7 +249,7 @@ func callString(method string, arguments Arguments, includeArgumentValues bool) if includeArgumentValues { var argVals []string for argIndex, arg := range arguments { - argVals = append(argVals, fmt.Sprintf("%d: %v", argIndex, arg)) + argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg)) } argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) } @@ -228,22 +262,26 @@ func callString(method string, arguments Arguments, includeArgumentValues bool) // appropriate .On .Return() calls) // If Call.WaitFor is set, blocks until the channel is closed or receives a message. func (m *Mock) Called(arguments ...interface{}) Arguments { - defer m.mutex.Unlock() - m.mutex.Lock() - // get the calling function's name pc, _, _, ok := runtime.Caller(1) if !ok { panic("Couldn't get the caller information") } 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 + //With GCCGO we need to remove interface information starting from pN<dd>. + re := regexp.MustCompile("\\.pN\\d+_") + if re.MatchString(functionPath) { + functionPath = re.Split(functionPath, -1)[0] + } parts := strings.Split(functionPath, ".") functionName := parts[len(parts)-1] found, call := m.findExpectedCall(functionName, arguments...) - switch { - case found < 0: + if found < 0 { // we have to fail here - because we don't know what to do // as the return arguments. This is because: // @@ -258,28 +296,33 @@ func (m *Mock) Called(arguments ...interface{}) 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())) } - case call.Repeatability == 1: - call.Repeatability = -1 - m.ExpectedCalls[found] = *call - case call.Repeatability > 1: - call.Repeatability -= 1 - m.ExpectedCalls[found] = *call + } else { + m.mutex.Lock() + switch { + case call.Repeatability == 1: + call.Repeatability = -1 + + case call.Repeatability > 1: + call.Repeatability -= 1 + } + m.mutex.Unlock() } // add the call - m.Calls = append(m.Calls, Call{functionName, arguments, make([]interface{}, 0), 0, nil, nil}) + m.mutex.Lock() + m.Calls = append(m.Calls, *newCall(m, functionName, arguments...)) + m.mutex.Unlock() // block if specified if call.WaitFor != nil { <-call.WaitFor } - if call.Run != nil { - call.Run(arguments) + if call.RunFn != nil { + call.RunFn(arguments) } return call.ReturnArguments - } /* @@ -302,27 +345,30 @@ 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 { - var somethingMissing bool = false var failedExpectations int = 0 // iterate through each expectation - for _, expectedCall := range m.ExpectedCalls { - switch { - case !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments): + expectedCalls := m.expectedCalls() + for _, expectedCall := range expectedCalls { + if !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) { somethingMissing = true failedExpectations++ t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) - case expectedCall.Repeatability > 0: - somethingMissing = true - failedExpectations++ - default: - t.Logf("\u2705\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() } } if somethingMissing { - 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(m.ExpectedCalls)-failedExpectations, len(m.ExpectedCalls), failedExpectations, assert.CallerInfo()) + 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()) } return !somethingMissing @@ -331,18 +377,18 @@ 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 { var actualCalls int = 0 - for _, call := range m.Calls { + for _, call := range m.calls() { if call.Method == methodName { actualCalls++ } } - return assert.Equal(t, actualCalls, expectedCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls)) + return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls)) } // AssertCalled asserts that the method was called. func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool { 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) + t.Logf("%v", m.expectedCalls()) return false } return true @@ -351,14 +397,14 @@ func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interfac // AssertNotCalled asserts that the method was not called. func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool { 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) + t.Logf("%v", m.expectedCalls()) return false } return true } func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { - for _, call := range m.Calls { + for _, call := range m.calls() { if call.Method == methodName { _, differences := Arguments(expected).Diff(call.Arguments) @@ -374,6 +420,18 @@ func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { return false } +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...) +} + /* Arguments */ |