equality.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. package assertions
  2. import (
  3. "errors"
  4. "fmt"
  5. "math"
  6. "reflect"
  7. "strings"
  8. "github.com/smartystreets/assertions/internal/go-render/render"
  9. "github.com/smartystreets/assertions/internal/oglematchers"
  10. )
  11. // ShouldEqual receives exactly two parameters and does an equality check
  12. // using the following semantics:
  13. // 1. If the expected and actual values implement an Equal method in the form
  14. // `func (this T) Equal(that T) bool` then call the method. If true, they are equal.
  15. // 2. The expected and actual values are judged equal or not by oglematchers.Equals.
  16. func ShouldEqual(actual interface{}, expected ...interface{}) string {
  17. if message := need(1, expected); message != success {
  18. return message
  19. }
  20. return shouldEqual(actual, expected[0])
  21. }
  22. func shouldEqual(actual, expected interface{}) (message string) {
  23. defer func() {
  24. if r := recover(); r != nil {
  25. message = serializer.serialize(expected, actual, fmt.Sprintf(shouldHaveBeenEqual, expected, actual))
  26. }
  27. }()
  28. if specification := newEqualityMethodSpecification(expected, actual); specification.IsSatisfied() {
  29. if specification.AreEqual() {
  30. return success
  31. } else {
  32. message = fmt.Sprintf(shouldHaveBeenEqual, expected, actual)
  33. return serializer.serialize(expected, actual, message)
  34. }
  35. }
  36. if matchError := oglematchers.Equals(expected).Matches(actual); matchError != nil {
  37. expectedSyntax := fmt.Sprintf("%v", expected)
  38. actualSyntax := fmt.Sprintf("%v", actual)
  39. if expectedSyntax == actualSyntax && reflect.TypeOf(expected) != reflect.TypeOf(actual) {
  40. message = fmt.Sprintf(shouldHaveBeenEqualTypeMismatch, expected, expected, actual, actual)
  41. } else {
  42. message = fmt.Sprintf(shouldHaveBeenEqual, expected, actual)
  43. }
  44. return serializer.serialize(expected, actual, message)
  45. }
  46. return success
  47. }
  48. // ShouldNotEqual receives exactly two parameters and does an inequality check.
  49. // See ShouldEqual for details on how equality is determined.
  50. func ShouldNotEqual(actual interface{}, expected ...interface{}) string {
  51. if fail := need(1, expected); fail != success {
  52. return fail
  53. } else if ShouldEqual(actual, expected[0]) == success {
  54. return fmt.Sprintf(shouldNotHaveBeenEqual, actual, expected[0])
  55. }
  56. return success
  57. }
  58. // ShouldAlmostEqual makes sure that two parameters are close enough to being equal.
  59. // The acceptable delta may be specified with a third argument,
  60. // or a very small default delta will be used.
  61. func ShouldAlmostEqual(actual interface{}, expected ...interface{}) string {
  62. actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...)
  63. if err != "" {
  64. return err
  65. }
  66. if math.Abs(actualFloat-expectedFloat) <= deltaFloat {
  67. return success
  68. } else {
  69. return fmt.Sprintf(shouldHaveBeenAlmostEqual, actualFloat, expectedFloat)
  70. }
  71. }
  72. // ShouldNotAlmostEqual is the inverse of ShouldAlmostEqual
  73. func ShouldNotAlmostEqual(actual interface{}, expected ...interface{}) string {
  74. actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...)
  75. if err != "" {
  76. return err
  77. }
  78. if math.Abs(actualFloat-expectedFloat) > deltaFloat {
  79. return success
  80. } else {
  81. return fmt.Sprintf(shouldHaveNotBeenAlmostEqual, actualFloat, expectedFloat)
  82. }
  83. }
  84. func cleanAlmostEqualInput(actual interface{}, expected ...interface{}) (float64, float64, float64, string) {
  85. deltaFloat := 0.0000000001
  86. if len(expected) == 0 {
  87. return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided neither)"
  88. } else if len(expected) == 2 {
  89. delta, err := getFloat(expected[1])
  90. if err != nil {
  91. return 0.0, 0.0, 0.0, "The delta value " + err.Error()
  92. }
  93. deltaFloat = delta
  94. } else if len(expected) > 2 {
  95. return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided more values)"
  96. }
  97. actualFloat, err := getFloat(actual)
  98. if err != nil {
  99. return 0.0, 0.0, 0.0, "The actual value " + err.Error()
  100. }
  101. expectedFloat, err := getFloat(expected[0])
  102. if err != nil {
  103. return 0.0, 0.0, 0.0, "The comparison value " + err.Error()
  104. }
  105. return actualFloat, expectedFloat, deltaFloat, ""
  106. }
  107. // returns the float value of any real number, or error if it is not a numerical type
  108. func getFloat(num interface{}) (float64, error) {
  109. numValue := reflect.ValueOf(num)
  110. numKind := numValue.Kind()
  111. if numKind == reflect.Int ||
  112. numKind == reflect.Int8 ||
  113. numKind == reflect.Int16 ||
  114. numKind == reflect.Int32 ||
  115. numKind == reflect.Int64 {
  116. return float64(numValue.Int()), nil
  117. } else if numKind == reflect.Uint ||
  118. numKind == reflect.Uint8 ||
  119. numKind == reflect.Uint16 ||
  120. numKind == reflect.Uint32 ||
  121. numKind == reflect.Uint64 {
  122. return float64(numValue.Uint()), nil
  123. } else if numKind == reflect.Float32 ||
  124. numKind == reflect.Float64 {
  125. return numValue.Float(), nil
  126. } else {
  127. return 0.0, errors.New("must be a numerical type, but was: " + numKind.String())
  128. }
  129. }
  130. // ShouldResemble receives exactly two parameters and does a deep equal check (see reflect.DeepEqual)
  131. func ShouldResemble(actual interface{}, expected ...interface{}) string {
  132. if message := need(1, expected); message != success {
  133. return message
  134. }
  135. if matchError := oglematchers.DeepEquals(expected[0]).Matches(actual); matchError != nil {
  136. return serializer.serializeDetailed(expected[0], actual,
  137. fmt.Sprintf(shouldHaveResembled, render.Render(expected[0]), render.Render(actual)))
  138. }
  139. return success
  140. }
  141. // ShouldNotResemble receives exactly two parameters and does an inverse deep equal check (see reflect.DeepEqual)
  142. func ShouldNotResemble(actual interface{}, expected ...interface{}) string {
  143. if message := need(1, expected); message != success {
  144. return message
  145. } else if ShouldResemble(actual, expected[0]) == success {
  146. return fmt.Sprintf(shouldNotHaveResembled, render.Render(actual), render.Render(expected[0]))
  147. }
  148. return success
  149. }
  150. // ShouldPointTo receives exactly two parameters and checks to see that they point to the same address.
  151. func ShouldPointTo(actual interface{}, expected ...interface{}) string {
  152. if message := need(1, expected); message != success {
  153. return message
  154. }
  155. return shouldPointTo(actual, expected[0])
  156. }
  157. func shouldPointTo(actual, expected interface{}) string {
  158. actualValue := reflect.ValueOf(actual)
  159. expectedValue := reflect.ValueOf(expected)
  160. if ShouldNotBeNil(actual) != success {
  161. return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "nil")
  162. } else if ShouldNotBeNil(expected) != success {
  163. return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "nil")
  164. } else if actualValue.Kind() != reflect.Ptr {
  165. return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "not")
  166. } else if expectedValue.Kind() != reflect.Ptr {
  167. return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "not")
  168. } else if ShouldEqual(actualValue.Pointer(), expectedValue.Pointer()) != success {
  169. actualAddress := reflect.ValueOf(actual).Pointer()
  170. expectedAddress := reflect.ValueOf(expected).Pointer()
  171. return serializer.serialize(expectedAddress, actualAddress, fmt.Sprintf(shouldHavePointedTo,
  172. actual, actualAddress,
  173. expected, expectedAddress))
  174. }
  175. return success
  176. }
  177. // ShouldNotPointTo receives exactly two parameters and checks to see that they point to different addresess.
  178. func ShouldNotPointTo(actual interface{}, expected ...interface{}) string {
  179. if message := need(1, expected); message != success {
  180. return message
  181. }
  182. compare := ShouldPointTo(actual, expected[0])
  183. if strings.HasPrefix(compare, shouldBePointers) {
  184. return compare
  185. } else if compare == success {
  186. return fmt.Sprintf(shouldNotHavePointedTo, actual, expected[0], reflect.ValueOf(actual).Pointer())
  187. }
  188. return success
  189. }
  190. // ShouldBeNil receives a single parameter and ensures that it is nil.
  191. func ShouldBeNil(actual interface{}, expected ...interface{}) string {
  192. if fail := need(0, expected); fail != success {
  193. return fail
  194. } else if actual == nil {
  195. return success
  196. } else if interfaceHasNilValue(actual) {
  197. return success
  198. }
  199. return fmt.Sprintf(shouldHaveBeenNil, actual)
  200. }
  201. func interfaceHasNilValue(actual interface{}) bool {
  202. value := reflect.ValueOf(actual)
  203. kind := value.Kind()
  204. nilable := kind == reflect.Slice ||
  205. kind == reflect.Chan ||
  206. kind == reflect.Func ||
  207. kind == reflect.Ptr ||
  208. kind == reflect.Map
  209. // Careful: reflect.Value.IsNil() will panic unless it's an interface, chan, map, func, slice, or ptr
  210. // Reference: http://golang.org/pkg/reflect/#Value.IsNil
  211. return nilable && value.IsNil()
  212. }
  213. // ShouldNotBeNil receives a single parameter and ensures that it is not nil.
  214. func ShouldNotBeNil(actual interface{}, expected ...interface{}) string {
  215. if fail := need(0, expected); fail != success {
  216. return fail
  217. } else if ShouldBeNil(actual) == success {
  218. return fmt.Sprintf(shouldNotHaveBeenNil, actual)
  219. }
  220. return success
  221. }
  222. // ShouldBeTrue receives a single parameter and ensures that it is true.
  223. func ShouldBeTrue(actual interface{}, expected ...interface{}) string {
  224. if fail := need(0, expected); fail != success {
  225. return fail
  226. } else if actual != true {
  227. return fmt.Sprintf(shouldHaveBeenTrue, actual)
  228. }
  229. return success
  230. }
  231. // ShouldBeFalse receives a single parameter and ensures that it is false.
  232. func ShouldBeFalse(actual interface{}, expected ...interface{}) string {
  233. if fail := need(0, expected); fail != success {
  234. return fail
  235. } else if actual != false {
  236. return fmt.Sprintf(shouldHaveBeenFalse, actual)
  237. }
  238. return success
  239. }
  240. // ShouldBeZeroValue receives a single parameter and ensures that it is
  241. // the Go equivalent of the default value, or "zero" value.
  242. func ShouldBeZeroValue(actual interface{}, expected ...interface{}) string {
  243. if fail := need(0, expected); fail != success {
  244. return fail
  245. }
  246. zeroVal := reflect.Zero(reflect.TypeOf(actual)).Interface()
  247. if !reflect.DeepEqual(zeroVal, actual) {
  248. return serializer.serialize(zeroVal, actual, fmt.Sprintf(shouldHaveBeenZeroValue, actual))
  249. }
  250. return success
  251. }