assert.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*Package assert provides assertions for comparing expected values to actual
  2. values. When an assertion fails a helpful error message is printed.
  3. Assert and Check
  4. Assert() and Check() both accept a Comparison, and fail the test when the
  5. comparison fails. The one difference is that Assert() will end the test execution
  6. immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
  7. return the value of the comparison, then proceed with the rest of the test case.
  8. Example usage
  9. The example below shows assert used with some common types.
  10. import (
  11. "testing"
  12. "gotest.tools/assert"
  13. is "gotest.tools/assert/cmp"
  14. )
  15. func TestEverything(t *testing.T) {
  16. // booleans
  17. assert.Assert(t, ok)
  18. assert.Assert(t, !missing)
  19. // primitives
  20. assert.Equal(t, count, 1)
  21. assert.Equal(t, msg, "the message")
  22. assert.Assert(t, total != 10) // NotEqual
  23. // errors
  24. assert.NilError(t, closer.Close())
  25. assert.Error(t, err, "the exact error message")
  26. assert.ErrorContains(t, err, "includes this")
  27. assert.ErrorType(t, err, os.IsNotExist)
  28. // complex types
  29. assert.DeepEqual(t, result, myStruct{Name: "title"})
  30. assert.Assert(t, is.Len(items, 3))
  31. assert.Assert(t, len(sequence) != 0) // NotEmpty
  32. assert.Assert(t, is.Contains(mapping, "key"))
  33. // pointers and interface
  34. assert.Assert(t, is.Nil(ref))
  35. assert.Assert(t, ref != nil) // NotNil
  36. }
  37. Comparisons
  38. Package https://godoc.org/gotest.tools/assert/cmp provides
  39. many common comparisons. Additional comparisons can be written to compare
  40. values in other ways. See the example Assert (CustomComparison).
  41. Automated migration from testify
  42. gty-migrate-from-testify is a binary which can update source code which uses
  43. testify assertions to use the assertions provided by this package.
  44. See http://bit.do/cmd-gty-migrate-from-testify.
  45. */
  46. package assert // import "gotest.tools/assert"
  47. import (
  48. "fmt"
  49. "go/ast"
  50. "go/token"
  51. gocmp "github.com/google/go-cmp/cmp"
  52. "gotest.tools/assert/cmp"
  53. "gotest.tools/internal/format"
  54. "gotest.tools/internal/source"
  55. )
  56. // BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
  57. type BoolOrComparison interface{}
  58. // TestingT is the subset of testing.T used by the assert package.
  59. type TestingT interface {
  60. FailNow()
  61. Fail()
  62. Log(args ...interface{})
  63. }
  64. type helperT interface {
  65. Helper()
  66. }
  67. const failureMessage = "assertion failed: "
  68. // nolint: gocyclo
  69. func assert(
  70. t TestingT,
  71. failer func(),
  72. argSelector argSelector,
  73. comparison BoolOrComparison,
  74. msgAndArgs ...interface{},
  75. ) bool {
  76. if ht, ok := t.(helperT); ok {
  77. ht.Helper()
  78. }
  79. var success bool
  80. switch check := comparison.(type) {
  81. case bool:
  82. if check {
  83. return true
  84. }
  85. logFailureFromBool(t, msgAndArgs...)
  86. // Undocumented legacy comparison without Result type
  87. case func() (success bool, message string):
  88. success = runCompareFunc(t, check, msgAndArgs...)
  89. case nil:
  90. return true
  91. case error:
  92. msg := "error is not nil: "
  93. t.Log(format.WithCustomMessage(failureMessage+msg+check.Error(), msgAndArgs...))
  94. case cmp.Comparison:
  95. success = runComparison(t, argSelector, check, msgAndArgs...)
  96. case func() cmp.Result:
  97. success = runComparison(t, argSelector, check, msgAndArgs...)
  98. default:
  99. t.Log(fmt.Sprintf("invalid Comparison: %v (%T)", check, check))
  100. }
  101. if success {
  102. return true
  103. }
  104. failer()
  105. return false
  106. }
  107. func runCompareFunc(
  108. t TestingT,
  109. f func() (success bool, message string),
  110. msgAndArgs ...interface{},
  111. ) bool {
  112. if ht, ok := t.(helperT); ok {
  113. ht.Helper()
  114. }
  115. if success, message := f(); !success {
  116. t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
  117. return false
  118. }
  119. return true
  120. }
  121. func logFailureFromBool(t TestingT, msgAndArgs ...interface{}) {
  122. if ht, ok := t.(helperT); ok {
  123. ht.Helper()
  124. }
  125. const stackIndex = 3 // Assert()/Check(), assert(), formatFailureFromBool()
  126. const comparisonArgPos = 1
  127. args, err := source.CallExprArgs(stackIndex)
  128. if err != nil {
  129. t.Log(err.Error())
  130. return
  131. }
  132. msg, err := boolFailureMessage(args[comparisonArgPos])
  133. if err != nil {
  134. t.Log(err.Error())
  135. msg = "expression is false"
  136. }
  137. t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
  138. }
  139. func boolFailureMessage(expr ast.Expr) (string, error) {
  140. if binaryExpr, ok := expr.(*ast.BinaryExpr); ok && binaryExpr.Op == token.NEQ {
  141. x, err := source.FormatNode(binaryExpr.X)
  142. if err != nil {
  143. return "", err
  144. }
  145. y, err := source.FormatNode(binaryExpr.Y)
  146. if err != nil {
  147. return "", err
  148. }
  149. return x + " is " + y, nil
  150. }
  151. if unaryExpr, ok := expr.(*ast.UnaryExpr); ok && unaryExpr.Op == token.NOT {
  152. x, err := source.FormatNode(unaryExpr.X)
  153. if err != nil {
  154. return "", err
  155. }
  156. return x + " is true", nil
  157. }
  158. formatted, err := source.FormatNode(expr)
  159. if err != nil {
  160. return "", err
  161. }
  162. return "expression is false: " + formatted, nil
  163. }
  164. // Assert performs a comparison. If the comparison fails the test is marked as
  165. // failed, a failure message is logged, and execution is stopped immediately.
  166. //
  167. // The comparison argument may be one of three types: bool, cmp.Comparison or
  168. // error.
  169. // When called with a bool the failure message will contain the literal source
  170. // code of the expression.
  171. // When called with a cmp.Comparison the comparison is responsible for producing
  172. // a helpful failure message.
  173. // When called with an error a nil value is considered success. A non-nil error
  174. // is a failure, and Error() is used as the failure message.
  175. func Assert(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) {
  176. if ht, ok := t.(helperT); ok {
  177. ht.Helper()
  178. }
  179. assert(t, t.FailNow, argsFromComparisonCall, comparison, msgAndArgs...)
  180. }
  181. // Check performs a comparison. If the comparison fails the test is marked as
  182. // failed, a failure message is logged, and Check returns false. Otherwise returns
  183. // true.
  184. //
  185. // See Assert for details about the comparison arg and failure messages.
  186. func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) bool {
  187. if ht, ok := t.(helperT); ok {
  188. ht.Helper()
  189. }
  190. return assert(t, t.Fail, argsFromComparisonCall, comparison, msgAndArgs...)
  191. }
  192. // NilError fails the test immediately if err is not nil.
  193. // This is equivalent to Assert(t, err)
  194. func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
  195. if ht, ok := t.(helperT); ok {
  196. ht.Helper()
  197. }
  198. assert(t, t.FailNow, argsAfterT, err, msgAndArgs...)
  199. }
  200. // Equal uses the == operator to assert two values are equal and fails the test
  201. // if they are not equal.
  202. //
  203. // If the comparison fails Equal will use the variable names for x and y as part
  204. // of the failure message to identify the actual and expected values.
  205. //
  206. // If either x or y are a multi-line string the failure message will include a
  207. // unified diff of the two values. If the values only differ by whitespace
  208. // the unified diff will be augmented by replacing whitespace characters with
  209. // visible characters to identify the whitespace difference.
  210. //
  211. // This is equivalent to Assert(t, cmp.Equal(x, y)).
  212. func Equal(t TestingT, x, y interface{}, msgAndArgs ...interface{}) {
  213. if ht, ok := t.(helperT); ok {
  214. ht.Helper()
  215. }
  216. assert(t, t.FailNow, argsAfterT, cmp.Equal(x, y), msgAndArgs...)
  217. }
  218. // DeepEqual uses google/go-cmp (http://bit.do/go-cmp) to assert two values are
  219. // equal and fails the test if they are not equal.
  220. //
  221. // Package https://godoc.org/gotest.tools/assert/opt provides some additional
  222. // commonly used Options.
  223. //
  224. // This is equivalent to Assert(t, cmp.DeepEqual(x, y)).
  225. func DeepEqual(t TestingT, x, y interface{}, opts ...gocmp.Option) {
  226. if ht, ok := t.(helperT); ok {
  227. ht.Helper()
  228. }
  229. assert(t, t.FailNow, argsAfterT, cmp.DeepEqual(x, y, opts...))
  230. }
  231. // Error fails the test if err is nil, or the error message is not the expected
  232. // message.
  233. // Equivalent to Assert(t, cmp.Error(err, message)).
  234. func Error(t TestingT, err error, message string, msgAndArgs ...interface{}) {
  235. if ht, ok := t.(helperT); ok {
  236. ht.Helper()
  237. }
  238. assert(t, t.FailNow, argsAfterT, cmp.Error(err, message), msgAndArgs...)
  239. }
  240. // ErrorContains fails the test if err is nil, or the error message does not
  241. // contain the expected substring.
  242. // Equivalent to Assert(t, cmp.ErrorContains(err, substring)).
  243. func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interface{}) {
  244. if ht, ok := t.(helperT); ok {
  245. ht.Helper()
  246. }
  247. assert(t, t.FailNow, argsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...)
  248. }
  249. // ErrorType fails the test if err is nil, or err is not the expected type.
  250. //
  251. // Expected can be one of:
  252. // a func(error) bool which returns true if the error is the expected type,
  253. // an instance of (or a pointer to) a struct of the expected type,
  254. // a pointer to an interface the error is expected to implement,
  255. // a reflect.Type of the expected struct or interface.
  256. //
  257. // Equivalent to Assert(t, cmp.ErrorType(err, expected)).
  258. func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interface{}) {
  259. if ht, ok := t.(helperT); ok {
  260. ht.Helper()
  261. }
  262. assert(t, t.FailNow, argsAfterT, cmp.ErrorType(err, expected), msgAndArgs...)
  263. }