checkers.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. package check
  2. import (
  3. "fmt"
  4. "reflect"
  5. "regexp"
  6. "strings"
  7. "github.com/kr/pretty"
  8. )
  9. // -----------------------------------------------------------------------
  10. // CommentInterface and Commentf helper, to attach extra information to checks.
  11. type comment struct {
  12. format string
  13. args []interface{}
  14. }
  15. // Commentf returns an infomational value to use with Assert or Check calls.
  16. // If the checker test fails, the provided arguments will be passed to
  17. // fmt.Sprintf, and will be presented next to the logged failure.
  18. //
  19. // For example:
  20. //
  21. // c.Assert(v, Equals, 42, Commentf("Iteration #%d failed.", i))
  22. //
  23. // Note that if the comment is constant, a better option is to
  24. // simply use a normal comment right above or next to the line, as
  25. // it will also get printed with any errors:
  26. //
  27. // c.Assert(l, Equals, 8192) // Ensure buffer size is correct (bug #123)
  28. //
  29. func Commentf(format string, args ...interface{}) CommentInterface {
  30. return &comment{format, args}
  31. }
  32. // CommentInterface must be implemented by types that attach extra
  33. // information to failed checks. See the Commentf function for details.
  34. type CommentInterface interface {
  35. CheckCommentString() string
  36. }
  37. func (c *comment) CheckCommentString() string {
  38. return fmt.Sprintf(c.format, c.args...)
  39. }
  40. // -----------------------------------------------------------------------
  41. // The Checker interface.
  42. // The Checker interface must be provided by checkers used with
  43. // the Assert and Check verification methods.
  44. type Checker interface {
  45. Info() *CheckerInfo
  46. Check(params []interface{}, names []string) (result bool, error string)
  47. }
  48. // See the Checker interface.
  49. type CheckerInfo struct {
  50. Name string
  51. Params []string
  52. }
  53. func (info *CheckerInfo) Info() *CheckerInfo {
  54. return info
  55. }
  56. // -----------------------------------------------------------------------
  57. // Not checker logic inverter.
  58. // The Not checker inverts the logic of the provided checker. The
  59. // resulting checker will succeed where the original one failed, and
  60. // vice-versa.
  61. //
  62. // For example:
  63. //
  64. // c.Assert(a, Not(Equals), b)
  65. //
  66. func Not(checker Checker) Checker {
  67. return &notChecker{checker}
  68. }
  69. type notChecker struct {
  70. sub Checker
  71. }
  72. func (checker *notChecker) Info() *CheckerInfo {
  73. info := *checker.sub.Info()
  74. info.Name = "Not(" + info.Name + ")"
  75. return &info
  76. }
  77. func (checker *notChecker) Check(params []interface{}, names []string) (result bool, error string) {
  78. result, error = checker.sub.Check(params, names)
  79. result = !result
  80. if result {
  81. // clear error message if the new result is true
  82. error = ""
  83. }
  84. return
  85. }
  86. // -----------------------------------------------------------------------
  87. // IsNil checker.
  88. type isNilChecker struct {
  89. *CheckerInfo
  90. }
  91. // The IsNil checker tests whether the obtained value is nil.
  92. //
  93. // For example:
  94. //
  95. // c.Assert(err, IsNil)
  96. //
  97. var IsNil Checker = &isNilChecker{
  98. &CheckerInfo{Name: "IsNil", Params: []string{"value"}},
  99. }
  100. func (checker *isNilChecker) Check(params []interface{}, names []string) (result bool, error string) {
  101. return isNil(params[0]), ""
  102. }
  103. func isNil(obtained interface{}) (result bool) {
  104. if obtained == nil {
  105. result = true
  106. } else {
  107. switch v := reflect.ValueOf(obtained); v.Kind() {
  108. case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
  109. return v.IsNil()
  110. }
  111. }
  112. return
  113. }
  114. // -----------------------------------------------------------------------
  115. // NotNil checker. Alias for Not(IsNil), since it's so common.
  116. type notNilChecker struct {
  117. *CheckerInfo
  118. }
  119. // The NotNil checker verifies that the obtained value is not nil.
  120. //
  121. // For example:
  122. //
  123. // c.Assert(iface, NotNil)
  124. //
  125. // This is an alias for Not(IsNil), made available since it's a
  126. // fairly common check.
  127. //
  128. var NotNil Checker = &notNilChecker{
  129. &CheckerInfo{Name: "NotNil", Params: []string{"value"}},
  130. }
  131. func (checker *notNilChecker) Check(params []interface{}, names []string) (result bool, error string) {
  132. return !isNil(params[0]), ""
  133. }
  134. // -----------------------------------------------------------------------
  135. // Equals checker.
  136. func diffworthy(a interface{}) bool {
  137. t := reflect.TypeOf(a)
  138. switch t.Kind() {
  139. case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct, reflect.String, reflect.Ptr:
  140. return true
  141. }
  142. return false
  143. }
  144. // formatUnequal will dump the actual and expected values into a textual
  145. // representation and return an error message containing a diff.
  146. func formatUnequal(obtained interface{}, expected interface{}) string {
  147. // We do not do diffs for basic types because go-check already
  148. // shows them very cleanly.
  149. if !diffworthy(obtained) || !diffworthy(expected) {
  150. return ""
  151. }
  152. // Handle strings, short strings are ignored (go-check formats
  153. // them very nicely already). We do multi-line strings by
  154. // generating two string slices and using kr.Diff to compare
  155. // those (kr.Diff does not do string diffs by itself).
  156. aStr, aOK := obtained.(string)
  157. bStr, bOK := expected.(string)
  158. if aOK && bOK {
  159. l1 := strings.Split(aStr, "\n")
  160. l2 := strings.Split(bStr, "\n")
  161. // the "2" here is a bit arbitrary
  162. if len(l1) > 2 && len(l2) > 2 {
  163. diff := pretty.Diff(l1, l2)
  164. return fmt.Sprintf(`String difference:
  165. %s`, formatMultiLine(strings.Join(diff, "\n"), false))
  166. }
  167. // string too short
  168. return ""
  169. }
  170. // generic diff
  171. diff := pretty.Diff(obtained, expected)
  172. if len(diff) == 0 {
  173. // No diff, this happens when e.g. just struct
  174. // pointers are different but the structs have
  175. // identical values.
  176. return ""
  177. }
  178. return fmt.Sprintf(`Difference:
  179. %s`, formatMultiLine(strings.Join(diff, "\n"), false))
  180. }
  181. type equalsChecker struct {
  182. *CheckerInfo
  183. }
  184. // The Equals checker verifies that the obtained value is equal to
  185. // the expected value, according to usual Go semantics for ==.
  186. //
  187. // For example:
  188. //
  189. // c.Assert(value, Equals, 42)
  190. //
  191. var Equals Checker = &equalsChecker{
  192. &CheckerInfo{Name: "Equals", Params: []string{"obtained", "expected"}},
  193. }
  194. func (checker *equalsChecker) Check(params []interface{}, names []string) (result bool, error string) {
  195. defer func() {
  196. if v := recover(); v != nil {
  197. result = false
  198. error = fmt.Sprint(v)
  199. }
  200. }()
  201. result = params[0] == params[1]
  202. if !result {
  203. error = formatUnequal(params[0], params[1])
  204. }
  205. return
  206. }
  207. // -----------------------------------------------------------------------
  208. // DeepEquals checker.
  209. type deepEqualsChecker struct {
  210. *CheckerInfo
  211. }
  212. // The DeepEquals checker verifies that the obtained value is deep-equal to
  213. // the expected value. The check will work correctly even when facing
  214. // slices, interfaces, and values of different types (which always fail
  215. // the test).
  216. //
  217. // For example:
  218. //
  219. // c.Assert(value, DeepEquals, 42)
  220. // c.Assert(array, DeepEquals, []string{"hi", "there"})
  221. //
  222. var DeepEquals Checker = &deepEqualsChecker{
  223. &CheckerInfo{Name: "DeepEquals", Params: []string{"obtained", "expected"}},
  224. }
  225. func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) {
  226. result = reflect.DeepEqual(params[0], params[1])
  227. if !result {
  228. error = formatUnequal(params[0], params[1])
  229. }
  230. return
  231. }
  232. // -----------------------------------------------------------------------
  233. // HasLen checker.
  234. type hasLenChecker struct {
  235. *CheckerInfo
  236. }
  237. // The HasLen checker verifies that the obtained value has the
  238. // provided length. In many cases this is superior to using Equals
  239. // in conjunction with the len function because in case the check
  240. // fails the value itself will be printed, instead of its length,
  241. // providing more details for figuring the problem.
  242. //
  243. // For example:
  244. //
  245. // c.Assert(list, HasLen, 5)
  246. //
  247. var HasLen Checker = &hasLenChecker{
  248. &CheckerInfo{Name: "HasLen", Params: []string{"obtained", "n"}},
  249. }
  250. func (checker *hasLenChecker) Check(params []interface{}, names []string) (result bool, error string) {
  251. n, ok := params[1].(int)
  252. if !ok {
  253. return false, "n must be an int"
  254. }
  255. value := reflect.ValueOf(params[0])
  256. switch value.Kind() {
  257. case reflect.Map, reflect.Array, reflect.Slice, reflect.Chan, reflect.String:
  258. default:
  259. return false, "obtained value type has no length"
  260. }
  261. return value.Len() == n, ""
  262. }
  263. // -----------------------------------------------------------------------
  264. // ErrorMatches checker.
  265. type errorMatchesChecker struct {
  266. *CheckerInfo
  267. }
  268. // The ErrorMatches checker verifies that the error value
  269. // is non nil and matches the regular expression provided.
  270. //
  271. // For example:
  272. //
  273. // c.Assert(err, ErrorMatches, "perm.*denied")
  274. //
  275. var ErrorMatches Checker = errorMatchesChecker{
  276. &CheckerInfo{Name: "ErrorMatches", Params: []string{"value", "regex"}},
  277. }
  278. func (checker errorMatchesChecker) Check(params []interface{}, names []string) (result bool, errStr string) {
  279. if params[0] == nil {
  280. return false, "Error value is nil"
  281. }
  282. err, ok := params[0].(error)
  283. if !ok {
  284. return false, "Value is not an error"
  285. }
  286. params[0] = err.Error()
  287. names[0] = "error"
  288. return matches(params[0], params[1])
  289. }
  290. // -----------------------------------------------------------------------
  291. // Matches checker.
  292. type matchesChecker struct {
  293. *CheckerInfo
  294. }
  295. // The Matches checker verifies that the string provided as the obtained
  296. // value (or the string resulting from obtained.String()) matches the
  297. // regular expression provided.
  298. //
  299. // For example:
  300. //
  301. // c.Assert(err, Matches, "perm.*denied")
  302. //
  303. var Matches Checker = &matchesChecker{
  304. &CheckerInfo{Name: "Matches", Params: []string{"value", "regex"}},
  305. }
  306. func (checker *matchesChecker) Check(params []interface{}, names []string) (result bool, error string) {
  307. return matches(params[0], params[1])
  308. }
  309. func matches(value, regex interface{}) (result bool, error string) {
  310. reStr, ok := regex.(string)
  311. if !ok {
  312. return false, "Regex must be a string"
  313. }
  314. valueStr, valueIsStr := value.(string)
  315. if !valueIsStr {
  316. if valueWithStr, valueHasStr := value.(fmt.Stringer); valueHasStr {
  317. valueStr, valueIsStr = valueWithStr.String(), true
  318. }
  319. }
  320. if valueIsStr {
  321. matches, err := regexp.MatchString("^"+reStr+"$", valueStr)
  322. if err != nil {
  323. return false, "Can't compile regex: " + err.Error()
  324. }
  325. return matches, ""
  326. }
  327. return false, "Obtained value is not a string and has no .String()"
  328. }
  329. // -----------------------------------------------------------------------
  330. // Panics checker.
  331. type panicsChecker struct {
  332. *CheckerInfo
  333. }
  334. // The Panics checker verifies that calling the provided zero-argument
  335. // function will cause a panic which is deep-equal to the provided value.
  336. //
  337. // For example:
  338. //
  339. // c.Assert(func() { f(1, 2) }, Panics, &SomeErrorType{"BOOM"}).
  340. //
  341. //
  342. var Panics Checker = &panicsChecker{
  343. &CheckerInfo{Name: "Panics", Params: []string{"function", "expected"}},
  344. }
  345. func (checker *panicsChecker) Check(params []interface{}, names []string) (result bool, error string) {
  346. f := reflect.ValueOf(params[0])
  347. if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
  348. return false, "Function must take zero arguments"
  349. }
  350. defer func() {
  351. // If the function has not panicked, then don't do the check.
  352. if error != "" {
  353. return
  354. }
  355. params[0] = recover()
  356. names[0] = "panic"
  357. result = reflect.DeepEqual(params[0], params[1])
  358. }()
  359. f.Call(nil)
  360. return false, "Function has not panicked"
  361. }
  362. type panicMatchesChecker struct {
  363. *CheckerInfo
  364. }
  365. // The PanicMatches checker verifies that calling the provided zero-argument
  366. // function will cause a panic with an error value matching
  367. // the regular expression provided.
  368. //
  369. // For example:
  370. //
  371. // c.Assert(func() { f(1, 2) }, PanicMatches, `open.*: no such file or directory`).
  372. //
  373. //
  374. var PanicMatches Checker = &panicMatchesChecker{
  375. &CheckerInfo{Name: "PanicMatches", Params: []string{"function", "expected"}},
  376. }
  377. func (checker *panicMatchesChecker) Check(params []interface{}, names []string) (result bool, errmsg string) {
  378. f := reflect.ValueOf(params[0])
  379. if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
  380. return false, "Function must take zero arguments"
  381. }
  382. defer func() {
  383. // If the function has not panicked, then don't do the check.
  384. if errmsg != "" {
  385. return
  386. }
  387. obtained := recover()
  388. names[0] = "panic"
  389. if e, ok := obtained.(error); ok {
  390. params[0] = e.Error()
  391. } else if _, ok := obtained.(string); ok {
  392. params[0] = obtained
  393. } else {
  394. errmsg = "Panic value is not a string or an error"
  395. return
  396. }
  397. result, errmsg = matches(params[0], params[1])
  398. }()
  399. f.Call(nil)
  400. return false, "Function has not panicked"
  401. }
  402. // -----------------------------------------------------------------------
  403. // FitsTypeOf checker.
  404. type fitsTypeChecker struct {
  405. *CheckerInfo
  406. }
  407. // The FitsTypeOf checker verifies that the obtained value is
  408. // assignable to a variable with the same type as the provided
  409. // sample value.
  410. //
  411. // For example:
  412. //
  413. // c.Assert(value, FitsTypeOf, int64(0))
  414. // c.Assert(value, FitsTypeOf, os.Error(nil))
  415. //
  416. var FitsTypeOf Checker = &fitsTypeChecker{
  417. &CheckerInfo{Name: "FitsTypeOf", Params: []string{"obtained", "sample"}},
  418. }
  419. func (checker *fitsTypeChecker) Check(params []interface{}, names []string) (result bool, error string) {
  420. obtained := reflect.ValueOf(params[0])
  421. sample := reflect.ValueOf(params[1])
  422. if !obtained.IsValid() {
  423. return false, ""
  424. }
  425. if !sample.IsValid() {
  426. return false, "Invalid sample value"
  427. }
  428. return obtained.Type().AssignableTo(sample.Type()), ""
  429. }
  430. // -----------------------------------------------------------------------
  431. // Implements checker.
  432. type implementsChecker struct {
  433. *CheckerInfo
  434. }
  435. // The Implements checker verifies that the obtained value
  436. // implements the interface specified via a pointer to an interface
  437. // variable.
  438. //
  439. // For example:
  440. //
  441. // var e os.Error
  442. // c.Assert(err, Implements, &e)
  443. //
  444. var Implements Checker = &implementsChecker{
  445. &CheckerInfo{Name: "Implements", Params: []string{"obtained", "ifaceptr"}},
  446. }
  447. func (checker *implementsChecker) Check(params []interface{}, names []string) (result bool, error string) {
  448. obtained := reflect.ValueOf(params[0])
  449. ifaceptr := reflect.ValueOf(params[1])
  450. if !obtained.IsValid() {
  451. return false, ""
  452. }
  453. if !ifaceptr.IsValid() || ifaceptr.Kind() != reflect.Ptr || ifaceptr.Elem().Kind() != reflect.Interface {
  454. return false, "ifaceptr should be a pointer to an interface variable"
  455. }
  456. return obtained.Type().Implements(ifaceptr.Elem().Type()), ""
  457. }