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