1
0

mock.go 22 KB

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