value.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. package httpexpect
  2. import (
  3. "reflect"
  4. )
  5. // Value provides methods to inspect attached interface{} object
  6. // (Go representation of arbitrary JSON value) and cast it to
  7. // concrete type.
  8. type Value struct {
  9. chain chain
  10. value interface{}
  11. }
  12. // NewValue returns a new Value given a reporter used to report failures
  13. // and value to be inspected.
  14. //
  15. // reporter should not be nil, but value may be nil.
  16. //
  17. // Example:
  18. // value := NewValue(t, map[string]interface{}{"foo": 123})
  19. // value.Object()
  20. //
  21. // value := NewValue(t, []interface{}{"foo", 123})
  22. // value.Array()
  23. //
  24. // value := NewValue(t, "foo")
  25. // value.String()
  26. //
  27. // value := NewValue(t, 123)
  28. // value.Number()
  29. //
  30. // value := NewValue(t, true)
  31. // value.Boolean()
  32. //
  33. // value := NewValue(t, nil)
  34. // value.Null()
  35. func NewValue(reporter Reporter, value interface{}) *Value {
  36. chain := makeChain(reporter)
  37. if value != nil {
  38. value, _ = canonValue(&chain, value)
  39. }
  40. return &Value{chain, value}
  41. }
  42. // Raw returns underlying value attached to Value.
  43. // This is the value originally passed to NewValue, converted to canonical form.
  44. //
  45. // Example:
  46. // value := NewValue(t, "foo")
  47. // assert.Equal(t, "foo", number.Raw().(string))
  48. func (v *Value) Raw() interface{} {
  49. return v.value
  50. }
  51. // Path returns a new Value object for child object(s) matching given
  52. // JSONPath expression.
  53. //
  54. // JSONPath is a simple XPath-like query language.
  55. // See http://goessner.net/articles/JsonPath/.
  56. //
  57. // We currently use https://github.com/yalp/jsonpath, which implements
  58. // only a subset of JSONPath, yet useful for simple queries. It doesn't
  59. // support filters and requires double quotes for strings.
  60. //
  61. // Example 1:
  62. // json := `{"users": [{"name": "john"}, {"name": "bob"}]}`
  63. // value := NewValue(t, json)
  64. //
  65. // value.Path("$.users[0].name").String().Equal("john")
  66. // value.Path("$.users[1].name").String().Equal("bob")
  67. //
  68. // Example 2:
  69. // json := `{"yfGH2a": {"user": "john"}, "f7GsDd": {"user": "john"}}`
  70. // value := NewValue(t, json)
  71. //
  72. // for _, user := range value.Path("$..user").Array().Iter() {
  73. // user.String().Equal("john")
  74. // }
  75. func (v *Value) Path(path string) *Value {
  76. return getPath(&v.chain, v.value, path)
  77. }
  78. // Schema succeeds if value matches given JSON Schema.
  79. //
  80. // JSON Schema specifies a JSON-based format to define the structure of
  81. // JSON data. See http://json-schema.org/.
  82. // We use https://github.com/xeipuuv/gojsonschema implementation.
  83. //
  84. // schema should be one of the following:
  85. // - go value that can be json.Marshal-ed to a valid schema
  86. // - type convertible to string containing valid schema
  87. // - type convertible to string containing valid http:// or file:// URI,
  88. // pointing to reachable and valid schema
  89. //
  90. // Example 1:
  91. // schema := `{
  92. // "type": "object",
  93. // "properties": {
  94. // "foo": {
  95. // "type": "string"
  96. // },
  97. // "bar": {
  98. // "type": "integer"
  99. // }
  100. // },
  101. // "require": ["foo", "bar"]
  102. // }`
  103. //
  104. // value := NewValue(t, map[string]interface{}{
  105. // "foo": "a",
  106. // "bar": 1,
  107. // })
  108. //
  109. // value.Schema(schema)
  110. //
  111. // Example 2:
  112. // value := NewValue(t, data)
  113. // value.Schema("http://example.com/schema.json")
  114. func (v *Value) Schema(schema interface{}) *Value {
  115. checkSchema(&v.chain, v.value, schema)
  116. return v
  117. }
  118. // Object returns a new Object attached to underlying value.
  119. //
  120. // If underlying value is not an object (map[string]interface{}), failure is reported
  121. // and empty (but non-nil) value is returned.
  122. //
  123. // Example:
  124. // value := NewValue(t, map[string]interface{}{"foo": 123})
  125. // value.Object().ContainsKey("foo")
  126. func (v *Value) Object() *Object {
  127. data, ok := v.value.(map[string]interface{})
  128. if !ok {
  129. v.chain.fail("\nexpected object value (map or struct), but got:\n%s",
  130. dumpValue(v.value))
  131. }
  132. return &Object{v.chain, data}
  133. }
  134. // Array returns a new Array attached to underlying value.
  135. //
  136. // If underlying value is not an array ([]interface{}), failure is reported and empty
  137. // (but non-nil) value is returned.
  138. //
  139. // Example:
  140. // value := NewValue(t, []interface{}{"foo", 123})
  141. // value.Array().Elements("foo", 123)
  142. func (v *Value) Array() *Array {
  143. data, ok := v.value.([]interface{})
  144. if !ok {
  145. v.chain.fail("\nexpected array value, but got:\n%s",
  146. dumpValue(v.value))
  147. }
  148. return &Array{v.chain, data}
  149. }
  150. // String returns a new String attached to underlying value.
  151. //
  152. // If underlying value is not string, failure is reported and empty (but non-nil)
  153. // value is returned.
  154. //
  155. // Example:
  156. // value := NewValue(t, "foo")
  157. // value.String().EqualFold("FOO")
  158. func (v *Value) String() *String {
  159. data, ok := v.value.(string)
  160. if !ok {
  161. v.chain.fail("\nexpected string value, but got:\n%s",
  162. dumpValue(v.value))
  163. }
  164. return &String{v.chain, data}
  165. }
  166. // Number returns a new Number attached to underlying value.
  167. //
  168. // If underlying value is not a number (numeric type convertible to float64), failure
  169. // is reported and empty (but non-nil) value is returned.
  170. //
  171. // Example:
  172. // value := NewValue(t, 123)
  173. // value.Number().InRange(100, 200)
  174. func (v *Value) Number() *Number {
  175. data, ok := v.value.(float64)
  176. if !ok {
  177. v.chain.fail("\nexpected numeric value, but got:\n%s",
  178. dumpValue(v.value))
  179. }
  180. return &Number{v.chain, data}
  181. }
  182. // Boolean returns a new Boolean attached to underlying value.
  183. //
  184. // If underlying value is not a bool, failure is reported and empty (but non-nil)
  185. // value is returned.
  186. //
  187. // Example:
  188. // value := NewValue(t, true)
  189. // value.Boolean().True()
  190. func (v *Value) Boolean() *Boolean {
  191. data, ok := v.value.(bool)
  192. if !ok {
  193. v.chain.fail("\nexpected boolean value, but got:\n%s",
  194. dumpValue(v.value))
  195. }
  196. return &Boolean{v.chain, data}
  197. }
  198. // Null succeeds if value is nil.
  199. //
  200. // Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
  201. // is also treated as null value. Empty (non-nil) slice or map, empty string, and
  202. // zero number are not treated as null value.
  203. //
  204. // Example:
  205. // value := NewValue(t, nil)
  206. // value.Null()
  207. //
  208. // value := NewValue(t, []interface{}(nil))
  209. // value.Null()
  210. func (v *Value) Null() *Value {
  211. if v.value != nil {
  212. v.chain.fail("\nexpected nil value, but got:\n%s",
  213. dumpValue(v.value))
  214. }
  215. return v
  216. }
  217. // NotNull succeeds if value is not nil.
  218. //
  219. // Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
  220. // is also treated as null value. Empty (non-nil) slice or map, empty string, and
  221. // zero number are not treated as null value.
  222. //
  223. // Example:
  224. // value := NewValue(t, "")
  225. // value.NotNull()
  226. //
  227. // value := NewValue(t, make([]interface{}, 0)
  228. // value.Null()
  229. func (v *Value) NotNull() *Value {
  230. if v.value == nil {
  231. v.chain.fail("\nexpected non-nil value, but got:\n%s",
  232. dumpValue(v.value))
  233. }
  234. return v
  235. }
  236. // Equal succeeds if value is equal to another value.
  237. // Before comparison, both values are converted to canonical form.
  238. //
  239. // Example:
  240. // value := NewValue(t, "foo")
  241. // value.Equal("foo")
  242. func (v *Value) Equal(value interface{}) *Value {
  243. expected, ok := canonValue(&v.chain, value)
  244. if !ok {
  245. return v
  246. }
  247. if !reflect.DeepEqual(expected, v.value) {
  248. v.chain.fail("\nexpected value equal to:\n%s\n\nbut got:\n%s\n\ndiff:\n%s",
  249. dumpValue(expected),
  250. dumpValue(v.value),
  251. diffValues(expected, v.value))
  252. }
  253. return v
  254. }
  255. // NotEqual succeeds if value is not equal to another value.
  256. // Before comparison, both values are converted to canonical form.
  257. //
  258. // Example:
  259. // value := NewValue(t, "foo")
  260. // value.NorEqual("bar")
  261. func (v *Value) NotEqual(value interface{}) *Value {
  262. expected, ok := canonValue(&v.chain, value)
  263. if !ok {
  264. return v
  265. }
  266. if reflect.DeepEqual(expected, v.value) {
  267. v.chain.fail("\nexpected value not equal to:\n%s",
  268. dumpValue(expected))
  269. }
  270. return v
  271. }