mock.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. package mock
  2. import (
  3. "fmt"
  4. "reflect"
  5. "regexp"
  6. "runtime"
  7. "strings"
  8. "sync"
  9. "time"
  10. "github.com/davecgh/go-spew/spew"
  11. "github.com/pmezard/go-difflib/difflib"
  12. "github.com/stretchr/objx"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. func inin() {
  16. spew.Config.SortKeys = true
  17. }
  18. // TestingT is an interface wrapper around *testing.T
  19. type TestingT interface {
  20. Logf(format string, args ...interface{})
  21. Errorf(format string, args ...interface{})
  22. FailNow()
  23. }
  24. /*
  25. Call
  26. */
  27. // Call represents a method call and is used for setting expectations,
  28. // as well as recording activity.
  29. type Call struct {
  30. Parent *Mock
  31. // The name of the method that was or will be called.
  32. Method string
  33. // Holds the arguments of the method.
  34. Arguments Arguments
  35. // Holds the arguments that should be returned when
  36. // this method is called.
  37. ReturnArguments Arguments
  38. // The number of times to return the return arguments when setting
  39. // expectations. 0 means to always return the value.
  40. Repeatability int
  41. // Amount of times this call has been called
  42. totalCalls int
  43. // Holds a channel that will be used to block the Return until it either
  44. // receives a message or is closed. nil means it returns immediately.
  45. WaitFor <-chan time.Time
  46. // Holds a handler used to manipulate arguments content that are passed by
  47. // reference. It's useful when mocking methods such as unmarshalers or
  48. // decoders.
  49. RunFn func(Arguments)
  50. }
  51. func newCall(parent *Mock, methodName string, methodArguments ...interface{}) *Call {
  52. return &Call{
  53. Parent: parent,
  54. Method: methodName,
  55. Arguments: methodArguments,
  56. ReturnArguments: make([]interface{}, 0),
  57. Repeatability: 0,
  58. WaitFor: nil,
  59. RunFn: nil,
  60. }
  61. }
  62. func (c *Call) lock() {
  63. c.Parent.mutex.Lock()
  64. }
  65. func (c *Call) unlock() {
  66. c.Parent.mutex.Unlock()
  67. }
  68. // Return specifies the return arguments for the expectation.
  69. //
  70. // Mock.On("DoSomething").Return(errors.New("failed"))
  71. func (c *Call) Return(returnArguments ...interface{}) *Call {
  72. c.lock()
  73. defer c.unlock()
  74. c.ReturnArguments = returnArguments
  75. return c
  76. }
  77. // Once indicates that that the mock should only return the value once.
  78. //
  79. // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
  80. func (c *Call) Once() *Call {
  81. return c.Times(1)
  82. }
  83. // Twice indicates that that the mock should only return the value twice.
  84. //
  85. // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
  86. func (c *Call) Twice() *Call {
  87. return c.Times(2)
  88. }
  89. // Times indicates that that the mock should only return the indicated number
  90. // of times.
  91. //
  92. // Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
  93. func (c *Call) Times(i int) *Call {
  94. c.lock()
  95. defer c.unlock()
  96. c.Repeatability = i
  97. return c
  98. }
  99. // WaitUntil sets the channel that will block the mock's return until its closed
  100. // or a message is received.
  101. //
  102. // Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
  103. func (c *Call) WaitUntil(w <-chan time.Time) *Call {
  104. c.lock()
  105. defer c.unlock()
  106. c.WaitFor = w
  107. return c
  108. }
  109. // After sets how long to block until the call returns
  110. //
  111. // Mock.On("MyMethod", arg1, arg2).After(time.Second)
  112. func (c *Call) After(d time.Duration) *Call {
  113. return c.WaitUntil(time.After(d))
  114. }
  115. // Run sets a handler to be called before returning. It can be used when
  116. // mocking a method such as unmarshalers that takes a pointer to a struct and
  117. // sets properties in such struct
  118. //
  119. // Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(func(args Arguments) {
  120. // arg := args.Get(0).(*map[string]interface{})
  121. // arg["foo"] = "bar"
  122. // })
  123. func (c *Call) Run(fn func(Arguments)) *Call {
  124. c.lock()
  125. defer c.unlock()
  126. c.RunFn = fn
  127. return c
  128. }
  129. // On chains a new expectation description onto the mocked interface. This
  130. // allows syntax like.
  131. //
  132. // Mock.
  133. // On("MyMethod", 1).Return(nil).
  134. // On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
  135. func (c *Call) On(methodName string, arguments ...interface{}) *Call {
  136. return c.Parent.On(methodName, arguments...)
  137. }
  138. // Mock is the workhorse used to track activity on another object.
  139. // For an example of its usage, refer to the "Example Usage" section at the top
  140. // of this document.
  141. type Mock struct {
  142. // Represents the calls that are expected of
  143. // an object.
  144. ExpectedCalls []*Call
  145. // Holds the calls that were made to this mocked object.
  146. Calls []Call
  147. // TestData holds any data that might be useful for testing. Testify ignores
  148. // this data completely allowing you to do whatever you like with it.
  149. testData objx.Map
  150. mutex sync.Mutex
  151. }
  152. // TestData holds any data that might be useful for testing. Testify ignores
  153. // this data completely allowing you to do whatever you like with it.
  154. func (m *Mock) TestData() objx.Map {
  155. if m.testData == nil {
  156. m.testData = make(objx.Map)
  157. }
  158. return m.testData
  159. }
  160. /*
  161. Setting expectations
  162. */
  163. // On starts a description of an expectation of the specified method
  164. // being called.
  165. //
  166. // Mock.On("MyMethod", arg1, arg2)
  167. func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
  168. for _, arg := range arguments {
  169. if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
  170. panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg))
  171. }
  172. }
  173. m.mutex.Lock()
  174. defer m.mutex.Unlock()
  175. c := newCall(m, methodName, arguments...)
  176. m.ExpectedCalls = append(m.ExpectedCalls, c)
  177. return c
  178. }
  179. // /*
  180. // Recording and responding to activity
  181. // */
  182. func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
  183. m.mutex.Lock()
  184. defer m.mutex.Unlock()
  185. for i, call := range m.ExpectedCalls {
  186. if call.Method == method && call.Repeatability > -1 {
  187. _, diffCount := call.Arguments.Diff(arguments)
  188. if diffCount == 0 {
  189. return i, call
  190. }
  191. }
  192. }
  193. return -1, nil
  194. }
  195. func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) {
  196. diffCount := 0
  197. var closestCall *Call
  198. for _, call := range m.expectedCalls() {
  199. if call.Method == method {
  200. _, tempDiffCount := call.Arguments.Diff(arguments)
  201. if tempDiffCount < diffCount || diffCount == 0 {
  202. diffCount = tempDiffCount
  203. closestCall = call
  204. }
  205. }
  206. }
  207. if closestCall == nil {
  208. return false, nil
  209. }
  210. return true, closestCall
  211. }
  212. func callString(method string, arguments Arguments, includeArgumentValues bool) string {
  213. var argValsString string
  214. if includeArgumentValues {
  215. var argVals []string
  216. for argIndex, arg := range arguments {
  217. argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg))
  218. }
  219. argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
  220. }
  221. return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString)
  222. }
  223. // Called tells the mock object that a method has been called, and gets an array
  224. // of arguments to return. Panics if the call is unexpected (i.e. not preceded by
  225. // appropriate .On .Return() calls)
  226. // If Call.WaitFor is set, blocks until the channel is closed or receives a message.
  227. func (m *Mock) Called(arguments ...interface{}) Arguments {
  228. // get the calling function's name
  229. pc, _, _, ok := runtime.Caller(1)
  230. if !ok {
  231. panic("Couldn't get the caller information")
  232. }
  233. functionPath := runtime.FuncForPC(pc).Name()
  234. //Next four lines are required to use GCCGO function naming conventions.
  235. //For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock
  236. //uses inteface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree
  237. //With GCCGO we need to remove interface information starting from pN<dd>.
  238. re := regexp.MustCompile("\\.pN\\d+_")
  239. if re.MatchString(functionPath) {
  240. functionPath = re.Split(functionPath, -1)[0]
  241. }
  242. parts := strings.Split(functionPath, ".")
  243. functionName := parts[len(parts)-1]
  244. found, call := m.findExpectedCall(functionName, arguments...)
  245. if found < 0 {
  246. // we have to fail here - because we don't know what to do
  247. // as the return arguments. This is because:
  248. //
  249. // a) this is a totally unexpected call to this method,
  250. // b) the arguments are not what was expected, or
  251. // c) the developer has forgotten to add an accompanying On...Return pair.
  252. closestFound, closestCall := m.findClosestCall(functionName, arguments...)
  253. if closestFound {
  254. 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)))
  255. } else {
  256. 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()))
  257. }
  258. } else {
  259. m.mutex.Lock()
  260. switch {
  261. case call.Repeatability == 1:
  262. call.Repeatability = -1
  263. call.totalCalls++
  264. case call.Repeatability > 1:
  265. call.Repeatability--
  266. call.totalCalls++
  267. case call.Repeatability == 0:
  268. call.totalCalls++
  269. }
  270. m.mutex.Unlock()
  271. }
  272. // add the call
  273. m.mutex.Lock()
  274. m.Calls = append(m.Calls, *newCall(m, functionName, arguments...))
  275. m.mutex.Unlock()
  276. // block if specified
  277. if call.WaitFor != nil {
  278. <-call.WaitFor
  279. }
  280. if call.RunFn != nil {
  281. call.RunFn(arguments)
  282. }
  283. return call.ReturnArguments
  284. }
  285. /*
  286. Assertions
  287. */
  288. type assertExpectationser interface {
  289. AssertExpectations(TestingT) bool
  290. }
  291. // AssertExpectationsForObjects asserts that everything specified with On and Return
  292. // of the specified objects was in fact called as expected.
  293. //
  294. // Calls may have occurred in any order.
  295. func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
  296. for _, obj := range testObjects {
  297. if m, ok := obj.(Mock); ok {
  298. t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)")
  299. obj = &m
  300. }
  301. m := obj.(assertExpectationser)
  302. if !m.AssertExpectations(t) {
  303. return false
  304. }
  305. }
  306. return true
  307. }
  308. // AssertExpectations asserts that everything specified with On and Return was
  309. // in fact called as expected. Calls may have occurred in any order.
  310. func (m *Mock) AssertExpectations(t TestingT) bool {
  311. var somethingMissing bool
  312. var failedExpectations int
  313. // iterate through each expectation
  314. expectedCalls := m.expectedCalls()
  315. for _, expectedCall := range expectedCalls {
  316. if !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 {
  317. somethingMissing = true
  318. failedExpectations++
  319. t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
  320. } else {
  321. m.mutex.Lock()
  322. if expectedCall.Repeatability > 0 {
  323. somethingMissing = true
  324. failedExpectations++
  325. } else {
  326. t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
  327. }
  328. m.mutex.Unlock()
  329. }
  330. }
  331. if somethingMissing {
  332. 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())
  333. }
  334. return !somethingMissing
  335. }
  336. // AssertNumberOfCalls asserts that the method was called expectedCalls times.
  337. func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
  338. var actualCalls int
  339. for _, call := range m.calls() {
  340. if call.Method == methodName {
  341. actualCalls++
  342. }
  343. }
  344. return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls))
  345. }
  346. // AssertCalled asserts that the method was called.
  347. // It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
  348. func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
  349. 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))) {
  350. t.Logf("%v", m.expectedCalls())
  351. return false
  352. }
  353. return true
  354. }
  355. // AssertNotCalled asserts that the method was not called.
  356. // It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
  357. func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
  358. 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))) {
  359. t.Logf("%v", m.expectedCalls())
  360. return false
  361. }
  362. return true
  363. }
  364. func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
  365. for _, call := range m.calls() {
  366. if call.Method == methodName {
  367. _, differences := Arguments(expected).Diff(call.Arguments)
  368. if differences == 0 {
  369. // found the expected call
  370. return true
  371. }
  372. }
  373. }
  374. // we didn't find the expected call
  375. return false
  376. }
  377. func (m *Mock) expectedCalls() []*Call {
  378. m.mutex.Lock()
  379. defer m.mutex.Unlock()
  380. return append([]*Call{}, m.ExpectedCalls...)
  381. }
  382. func (m *Mock) calls() []Call {
  383. m.mutex.Lock()
  384. defer m.mutex.Unlock()
  385. return append([]Call{}, m.Calls...)
  386. }
  387. /*
  388. Arguments
  389. */
  390. // Arguments holds an array of method arguments or return values.
  391. type Arguments []interface{}
  392. const (
  393. // Anything is used in Diff and Assert when the argument being tested
  394. // shouldn't be taken into consideration.
  395. Anything string = "mock.Anything"
  396. )
  397. // AnythingOfTypeArgument is a string that contains the type of an argument
  398. // for use when type checking. Used in Diff and Assert.
  399. type AnythingOfTypeArgument string
  400. // AnythingOfType returns an AnythingOfTypeArgument object containing the
  401. // name of the type to check for. Used in Diff and Assert.
  402. //
  403. // For example:
  404. // Assert(t, AnythingOfType("string"), AnythingOfType("int"))
  405. func AnythingOfType(t string) AnythingOfTypeArgument {
  406. return AnythingOfTypeArgument(t)
  407. }
  408. // argumentMatcher performs custom argument matching, returning whether or
  409. // not the argument is matched by the expectation fixture function.
  410. type argumentMatcher struct {
  411. // fn is a function which accepts one argument, and returns a bool.
  412. fn reflect.Value
  413. }
  414. func (f argumentMatcher) Matches(argument interface{}) bool {
  415. expectType := f.fn.Type().In(0)
  416. if reflect.TypeOf(argument).AssignableTo(expectType) {
  417. result := f.fn.Call([]reflect.Value{reflect.ValueOf(argument)})
  418. return result[0].Bool()
  419. }
  420. return false
  421. }
  422. func (f argumentMatcher) String() string {
  423. return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).Name())
  424. }
  425. // MatchedBy can be used to match a mock call based on only certain properties
  426. // from a complex struct or some calculation. It takes a function that will be
  427. // evaluated with the called argument and will return true when there's a match
  428. // and false otherwise.
  429. //
  430. // Example:
  431. // m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" }))
  432. //
  433. // |fn|, must be a function accepting a single argument (of the expected type)
  434. // which returns a bool. If |fn| doesn't match the required signature,
  435. // MathedBy() panics.
  436. func MatchedBy(fn interface{}) argumentMatcher {
  437. fnType := reflect.TypeOf(fn)
  438. if fnType.Kind() != reflect.Func {
  439. panic(fmt.Sprintf("assert: arguments: %s is not a func", fn))
  440. }
  441. if fnType.NumIn() != 1 {
  442. panic(fmt.Sprintf("assert: arguments: %s does not take exactly one argument", fn))
  443. }
  444. if fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool {
  445. panic(fmt.Sprintf("assert: arguments: %s does not return a bool", fn))
  446. }
  447. return argumentMatcher{fn: reflect.ValueOf(fn)}
  448. }
  449. // Get Returns the argument at the specified index.
  450. func (args Arguments) Get(index int) interface{} {
  451. if index+1 > len(args) {
  452. panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args)))
  453. }
  454. return args[index]
  455. }
  456. // Is gets whether the objects match the arguments specified.
  457. func (args Arguments) Is(objects ...interface{}) bool {
  458. for i, obj := range args {
  459. if obj != objects[i] {
  460. return false
  461. }
  462. }
  463. return true
  464. }
  465. // Diff gets a string describing the differences between the arguments
  466. // and the specified objects.
  467. //
  468. // Returns the diff string and number of differences found.
  469. func (args Arguments) Diff(objects []interface{}) (string, int) {
  470. var output = "\n"
  471. var differences int
  472. var maxArgCount = len(args)
  473. if len(objects) > maxArgCount {
  474. maxArgCount = len(objects)
  475. }
  476. for i := 0; i < maxArgCount; i++ {
  477. var actual, expected interface{}
  478. if len(objects) <= i {
  479. actual = "(Missing)"
  480. } else {
  481. actual = objects[i]
  482. }
  483. if len(args) <= i {
  484. expected = "(Missing)"
  485. } else {
  486. expected = args[i]
  487. }
  488. if matcher, ok := expected.(argumentMatcher); ok {
  489. if matcher.Matches(actual) {
  490. output = fmt.Sprintf("%s\t%d: \u2705 %s matched by %s\n", output, i, actual, matcher)
  491. } else {
  492. differences++
  493. output = fmt.Sprintf("%s\t%d: \u2705 %s not matched by %s\n", output, i, actual, matcher)
  494. }
  495. } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
  496. // type checking
  497. if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
  498. // not match
  499. differences++
  500. output = fmt.Sprintf("%s\t%d: \u274C type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actual)
  501. }
  502. } else {
  503. // normal checking
  504. if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
  505. // match
  506. output = fmt.Sprintf("%s\t%d: \u2705 %s == %s\n", output, i, actual, expected)
  507. } else {
  508. // not match
  509. differences++
  510. output = fmt.Sprintf("%s\t%d: \u274C %s != %s\n", output, i, actual, expected)
  511. }
  512. }
  513. }
  514. if differences == 0 {
  515. return "No differences.", differences
  516. }
  517. return output, differences
  518. }
  519. // Assert compares the arguments with the specified objects and fails if
  520. // they do not exactly match.
  521. func (args Arguments) Assert(t TestingT, objects ...interface{}) bool {
  522. // get the differences
  523. diff, diffCount := args.Diff(objects)
  524. if diffCount == 0 {
  525. return true
  526. }
  527. // there are differences... report them...
  528. t.Logf(diff)
  529. t.Errorf("%sArguments do not match.", assert.CallerInfo())
  530. return false
  531. }
  532. // String gets the argument at the specified index. Panics if there is no argument, or
  533. // if the argument is of the wrong type.
  534. //
  535. // If no index is provided, String() returns a complete string representation
  536. // of the arguments.
  537. func (args Arguments) String(indexOrNil ...int) string {
  538. if len(indexOrNil) == 0 {
  539. // normal String() method - return a string representation of the args
  540. var argsStr []string
  541. for _, arg := range args {
  542. argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg)))
  543. }
  544. return strings.Join(argsStr, ",")
  545. } else if len(indexOrNil) == 1 {
  546. // Index has been specified - get the argument at that index
  547. var index = indexOrNil[0]
  548. var s string
  549. var ok bool
  550. if s, ok = args.Get(index).(string); !ok {
  551. panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index)))
  552. }
  553. return s
  554. }
  555. panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String. Must be 0 or 1, not %d", len(indexOrNil)))
  556. }
  557. // Int gets the argument at the specified index. Panics if there is no argument, or
  558. // if the argument is of the wrong type.
  559. func (args Arguments) Int(index int) int {
  560. var s int
  561. var ok bool
  562. if s, ok = args.Get(index).(int); !ok {
  563. panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
  564. }
  565. return s
  566. }
  567. // Error gets the argument at the specified index. Panics if there is no argument, or
  568. // if the argument is of the wrong type.
  569. func (args Arguments) Error(index int) error {
  570. obj := args.Get(index)
  571. var s error
  572. var ok bool
  573. if obj == nil {
  574. return nil
  575. }
  576. if s, ok = obj.(error); !ok {
  577. panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
  578. }
  579. return s
  580. }
  581. // Bool gets the argument at the specified index. Panics if there is no argument, or
  582. // if the argument is of the wrong type.
  583. func (args Arguments) Bool(index int) bool {
  584. var s bool
  585. var ok bool
  586. if s, ok = args.Get(index).(bool); !ok {
  587. panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
  588. }
  589. return s
  590. }
  591. func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
  592. t := reflect.TypeOf(v)
  593. k := t.Kind()
  594. if k == reflect.Ptr {
  595. t = t.Elem()
  596. k = t.Kind()
  597. }
  598. return t, k
  599. }
  600. func diffArguments(expected Arguments, actual Arguments) string {
  601. for x := range expected {
  602. if diffString := diff(expected[x], actual[x]); diffString != "" {
  603. return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString)
  604. }
  605. }
  606. return ""
  607. }
  608. // diff returns a diff of both values as long as both are of the same type and
  609. // are a struct, map, slice or array. Otherwise it returns an empty string.
  610. func diff(expected interface{}, actual interface{}) string {
  611. if expected == nil || actual == nil {
  612. return ""
  613. }
  614. et, ek := typeAndKind(expected)
  615. at, _ := typeAndKind(actual)
  616. if et != at {
  617. return ""
  618. }
  619. if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {
  620. return ""
  621. }
  622. e := spew.Sdump(expected)
  623. a := spew.Sdump(actual)
  624. diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
  625. A: difflib.SplitLines(e),
  626. B: difflib.SplitLines(a),
  627. FromFile: "Expected",
  628. FromDate: "",
  629. ToFile: "Actual",
  630. ToDate: "",
  631. Context: 1,
  632. })
  633. return diff
  634. }