collections.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. package assertions
  2. import (
  3. "fmt"
  4. "reflect"
  5. "github.com/smartystreets/assertions/internal/oglematchers"
  6. )
  7. // ShouldContain receives exactly two parameters. The first is a slice and the
  8. // second is a proposed member. Membership is determined using ShouldEqual.
  9. func ShouldContain(actual interface{}, expected ...interface{}) string {
  10. if fail := need(1, expected); fail != success {
  11. return fail
  12. }
  13. if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil {
  14. typeName := reflect.TypeOf(actual)
  15. if fmt.Sprintf("%v", matchError) == "which is not a slice or array" {
  16. return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName)
  17. }
  18. return fmt.Sprintf(shouldHaveContained, typeName, expected[0])
  19. }
  20. return success
  21. }
  22. // ShouldNotContain receives exactly two parameters. The first is a slice and the
  23. // second is a proposed member. Membership is determinied using ShouldEqual.
  24. func ShouldNotContain(actual interface{}, expected ...interface{}) string {
  25. if fail := need(1, expected); fail != success {
  26. return fail
  27. }
  28. typeName := reflect.TypeOf(actual)
  29. if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil {
  30. if fmt.Sprintf("%v", matchError) == "which is not a slice or array" {
  31. return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName)
  32. }
  33. return success
  34. }
  35. return fmt.Sprintf(shouldNotHaveContained, typeName, expected[0])
  36. }
  37. // ShouldContainKey receives exactly two parameters. The first is a map and the
  38. // second is a proposed key. Keys are compared with a simple '=='.
  39. func ShouldContainKey(actual interface{}, expected ...interface{}) string {
  40. if fail := need(1, expected); fail != success {
  41. return fail
  42. }
  43. keys, isMap := mapKeys(actual)
  44. if !isMap {
  45. return fmt.Sprintf(shouldHaveBeenAValidMap, reflect.TypeOf(actual))
  46. }
  47. if !keyFound(keys, expected[0]) {
  48. return fmt.Sprintf(shouldHaveContainedKey, reflect.TypeOf(actual), expected)
  49. }
  50. return ""
  51. }
  52. // ShouldNotContainKey receives exactly two parameters. The first is a map and the
  53. // second is a proposed absent key. Keys are compared with a simple '=='.
  54. func ShouldNotContainKey(actual interface{}, expected ...interface{}) string {
  55. if fail := need(1, expected); fail != success {
  56. return fail
  57. }
  58. keys, isMap := mapKeys(actual)
  59. if !isMap {
  60. return fmt.Sprintf(shouldHaveBeenAValidMap, reflect.TypeOf(actual))
  61. }
  62. if keyFound(keys, expected[0]) {
  63. return fmt.Sprintf(shouldNotHaveContainedKey, reflect.TypeOf(actual), expected)
  64. }
  65. return ""
  66. }
  67. func mapKeys(m interface{}) ([]reflect.Value, bool) {
  68. value := reflect.ValueOf(m)
  69. if value.Kind() != reflect.Map {
  70. return nil, false
  71. }
  72. return value.MapKeys(), true
  73. }
  74. func keyFound(keys []reflect.Value, expectedKey interface{}) bool {
  75. found := false
  76. for _, key := range keys {
  77. if key.Interface() == expectedKey {
  78. found = true
  79. }
  80. }
  81. return found
  82. }
  83. // ShouldBeIn receives at least 2 parameters. The first is a proposed member of the collection
  84. // that is passed in either as the second parameter, or of the collection that is comprised
  85. // of all the remaining parameters. This assertion ensures that the proposed member is in
  86. // the collection (using ShouldEqual).
  87. func ShouldBeIn(actual interface{}, expected ...interface{}) string {
  88. if fail := atLeast(1, expected); fail != success {
  89. return fail
  90. }
  91. if len(expected) == 1 {
  92. return shouldBeIn(actual, expected[0])
  93. }
  94. return shouldBeIn(actual, expected)
  95. }
  96. func shouldBeIn(actual interface{}, expected interface{}) string {
  97. if matchError := oglematchers.Contains(actual).Matches(expected); matchError != nil {
  98. return fmt.Sprintf(shouldHaveBeenIn, actual, reflect.TypeOf(expected))
  99. }
  100. return success
  101. }
  102. // ShouldNotBeIn receives at least 2 parameters. The first is a proposed member of the collection
  103. // that is passed in either as the second parameter, or of the collection that is comprised
  104. // of all the remaining parameters. This assertion ensures that the proposed member is NOT in
  105. // the collection (using ShouldEqual).
  106. func ShouldNotBeIn(actual interface{}, expected ...interface{}) string {
  107. if fail := atLeast(1, expected); fail != success {
  108. return fail
  109. }
  110. if len(expected) == 1 {
  111. return shouldNotBeIn(actual, expected[0])
  112. }
  113. return shouldNotBeIn(actual, expected)
  114. }
  115. func shouldNotBeIn(actual interface{}, expected interface{}) string {
  116. if matchError := oglematchers.Contains(actual).Matches(expected); matchError == nil {
  117. return fmt.Sprintf(shouldNotHaveBeenIn, actual, reflect.TypeOf(expected))
  118. }
  119. return success
  120. }
  121. // ShouldBeEmpty receives a single parameter (actual) and determines whether or not
  122. // calling len(actual) would return `0`. It obeys the rules specified by the len
  123. // function for determining length: http://golang.org/pkg/builtin/#len
  124. func ShouldBeEmpty(actual interface{}, expected ...interface{}) string {
  125. if fail := need(0, expected); fail != success {
  126. return fail
  127. }
  128. if actual == nil {
  129. return success
  130. }
  131. value := reflect.ValueOf(actual)
  132. switch value.Kind() {
  133. case reflect.Slice:
  134. if value.Len() == 0 {
  135. return success
  136. }
  137. case reflect.Chan:
  138. if value.Len() == 0 {
  139. return success
  140. }
  141. case reflect.Map:
  142. if value.Len() == 0 {
  143. return success
  144. }
  145. case reflect.String:
  146. if value.Len() == 0 {
  147. return success
  148. }
  149. case reflect.Ptr:
  150. elem := value.Elem()
  151. kind := elem.Kind()
  152. if (kind == reflect.Slice || kind == reflect.Array) && elem.Len() == 0 {
  153. return success
  154. }
  155. }
  156. return fmt.Sprintf(shouldHaveBeenEmpty, actual)
  157. }
  158. // ShouldNotBeEmpty receives a single parameter (actual) and determines whether or not
  159. // calling len(actual) would return a value greater than zero. It obeys the rules
  160. // specified by the `len` function for determining length: http://golang.org/pkg/builtin/#len
  161. func ShouldNotBeEmpty(actual interface{}, expected ...interface{}) string {
  162. if fail := need(0, expected); fail != success {
  163. return fail
  164. }
  165. if empty := ShouldBeEmpty(actual, expected...); empty != success {
  166. return success
  167. }
  168. return fmt.Sprintf(shouldNotHaveBeenEmpty, actual)
  169. }
  170. // ShouldHaveLength receives 2 parameters. The first is a collection to check
  171. // the length of, the second being the expected length. It obeys the rules
  172. // specified by the len function for determining length:
  173. // http://golang.org/pkg/builtin/#len
  174. func ShouldHaveLength(actual interface{}, expected ...interface{}) string {
  175. if fail := need(1, expected); fail != success {
  176. return fail
  177. }
  178. var expectedLen int64
  179. lenValue := reflect.ValueOf(expected[0])
  180. switch lenValue.Kind() {
  181. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  182. expectedLen = lenValue.Int()
  183. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  184. expectedLen = int64(lenValue.Uint())
  185. default:
  186. return fmt.Sprintf(shouldHaveBeenAValidInteger, reflect.TypeOf(expected[0]))
  187. }
  188. if expectedLen < 0 {
  189. return fmt.Sprintf(shouldHaveBeenAValidLength, expected[0])
  190. }
  191. value := reflect.ValueOf(actual)
  192. switch value.Kind() {
  193. case reflect.Slice,
  194. reflect.Chan,
  195. reflect.Map,
  196. reflect.String:
  197. if int64(value.Len()) == expectedLen {
  198. return success
  199. } else {
  200. return fmt.Sprintf(shouldHaveHadLength, actual, value.Len(), expectedLen)
  201. }
  202. case reflect.Ptr:
  203. elem := value.Elem()
  204. kind := elem.Kind()
  205. if kind == reflect.Slice || kind == reflect.Array {
  206. if int64(elem.Len()) == expectedLen {
  207. return success
  208. } else {
  209. return fmt.Sprintf(shouldHaveHadLength, actual, elem.Len(), expectedLen)
  210. }
  211. }
  212. }
  213. return fmt.Sprintf(shouldHaveBeenAValidCollection, reflect.TypeOf(actual))
  214. }