object.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. package httpexpect
  2. import (
  3. "reflect"
  4. )
  5. // Object provides methods to inspect attached map[string]interface{} object
  6. // (Go representation of JSON object).
  7. type Object struct {
  8. chain chain
  9. value map[string]interface{}
  10. }
  11. // NewObject returns a new Object given a reporter used to report failures
  12. // and value to be inspected.
  13. //
  14. // Both reporter and value should not be nil. If value is nil, failure is
  15. // reported.
  16. //
  17. // Example:
  18. // object := NewObject(t, map[string]interface{}{"foo": 123})
  19. func NewObject(reporter Reporter, value map[string]interface{}) *Object {
  20. chain := makeChain(reporter)
  21. if value == nil {
  22. chain.fail("expected non-nil map value")
  23. } else {
  24. value, _ = canonMap(&chain, value)
  25. }
  26. return &Object{chain, value}
  27. }
  28. // Raw returns underlying value attached to Object.
  29. // This is the value originally passed to NewObject, converted to canonical form.
  30. //
  31. // Example:
  32. // object := NewObject(t, map[string]interface{}{"foo": 123})
  33. // assert.Equal(t, map[string]interface{}{"foo": 123.0}, object.Raw())
  34. func (o *Object) Raw() map[string]interface{} {
  35. return o.value
  36. }
  37. // Path is similar to Value.Path.
  38. func (o *Object) Path(path string) *Value {
  39. return getPath(&o.chain, o.value, path)
  40. }
  41. // Schema is similar to Value.Schema.
  42. func (o *Object) Schema(schema interface{}) *Object {
  43. checkSchema(&o.chain, o.value, schema)
  44. return o
  45. }
  46. // Keys returns a new Array object that may be used to inspect objects keys.
  47. //
  48. // Example:
  49. // object := NewObject(t, map[string]interface{}{"foo": 123, "bar": 456})
  50. // object.Keys().ContainsOnly("foo", "bar")
  51. func (o *Object) Keys() *Array {
  52. keys := []interface{}{}
  53. for k := range o.value {
  54. keys = append(keys, k)
  55. }
  56. return &Array{o.chain, keys}
  57. }
  58. // Values returns a new Array object that may be used to inspect objects values.
  59. //
  60. // Example:
  61. // object := NewObject(t, map[string]interface{}{"foo": 123, "bar": 456})
  62. // object.Values().ContainsOnly(123, 456)
  63. func (o *Object) Values() *Array {
  64. values := []interface{}{}
  65. for _, v := range o.value {
  66. values = append(values, v)
  67. }
  68. return &Array{o.chain, values}
  69. }
  70. // Value returns a new Value object that may be used to inspect single value
  71. // for given key.
  72. //
  73. // Example:
  74. // object := NewObject(t, map[string]interface{}{"foo": 123})
  75. // object.Value("foo").Number().Equal(123)
  76. func (o *Object) Value(key string) *Value {
  77. value, ok := o.value[key]
  78. if !ok {
  79. o.chain.fail("\nexpected object containing key '%s', but got:\n%s",
  80. key, dumpValue(o.value))
  81. return &Value{o.chain, nil}
  82. }
  83. return &Value{o.chain, value}
  84. }
  85. // Empty succeeds if object is empty.
  86. //
  87. // Example:
  88. // object := NewObject(t, map[string]interface{}{})
  89. // object.Empty()
  90. func (o *Object) Empty() *Object {
  91. return o.Equal(map[string]interface{}{})
  92. }
  93. // NotEmpty succeeds if object is non-empty.
  94. //
  95. // Example:
  96. // object := NewObject(t, map[string]interface{}{"foo": 123})
  97. // object.NotEmpty()
  98. func (o *Object) NotEmpty() *Object {
  99. return o.NotEqual(map[string]interface{}{})
  100. }
  101. // Equal succeeds if object is equal to another object.
  102. // Before comparison, both objects are converted to canonical form.
  103. //
  104. // value should map[string]interface{} or struct.
  105. //
  106. // Example:
  107. // object := NewObject(t, map[string]interface{}{"foo": 123})
  108. // object.Equal(map[string]interface{}{"foo": 123})
  109. func (o *Object) Equal(value interface{}) *Object {
  110. expected, ok := canonMap(&o.chain, value)
  111. if !ok {
  112. return o
  113. }
  114. if !reflect.DeepEqual(expected, o.value) {
  115. o.chain.fail("\nexpected object equal to:\n%s\n\nbut got:\n%s\n\ndiff:\n%s",
  116. dumpValue(expected),
  117. dumpValue(o.value),
  118. diffValues(expected, o.value))
  119. }
  120. return o
  121. }
  122. // NotEqual succeeds if object is not equal to another object.
  123. // Before comparison, both objects are converted to canonical form.
  124. //
  125. // value should map[string]interface{} or struct.
  126. //
  127. // Example:
  128. // object := NewObject(t, map[string]interface{}{"foo": 123})
  129. // object.Equal(map[string]interface{}{"bar": 123})
  130. func (o *Object) NotEqual(v interface{}) *Object {
  131. expected, ok := canonMap(&o.chain, v)
  132. if !ok {
  133. return o
  134. }
  135. if reflect.DeepEqual(expected, o.value) {
  136. o.chain.fail("\nexpected object not equal to:\n%s",
  137. dumpValue(expected))
  138. }
  139. return o
  140. }
  141. // ContainsKey succeeds if object contains given key.
  142. //
  143. // Example:
  144. // object := NewObject(t, map[string]interface{}{"foo": 123})
  145. // object.ContainsKey("foo")
  146. func (o *Object) ContainsKey(key string) *Object {
  147. if !o.containsKey(key) {
  148. o.chain.fail("\nexpected object containing key '%s', but got:\n%s",
  149. key, dumpValue(o.value))
  150. }
  151. return o
  152. }
  153. // NotContainsKey succeeds if object doesn't contain given key.
  154. //
  155. // Example:
  156. // object := NewObject(t, map[string]interface{}{"foo": 123})
  157. // object.NotContainsKey("bar")
  158. func (o *Object) NotContainsKey(key string) *Object {
  159. if o.containsKey(key) {
  160. o.chain.fail(
  161. "\nexpected object not containing key '%s', but got:\n%s", key,
  162. dumpValue(o.value))
  163. }
  164. return o
  165. }
  166. // ContainsMap succeeds if object contains given sub-object.
  167. // Before comparison, both objects are converted to canonical form.
  168. //
  169. // value should map[string]interface{} or struct.
  170. //
  171. // Example:
  172. // object := NewObject(t, map[string]interface{}{
  173. // "foo": 123,
  174. // "bar": []interface{}{"x", "y"},
  175. // "bar": map[string]interface{}{
  176. // "a": true,
  177. // "b": false,
  178. // },
  179. // })
  180. //
  181. // object.ContainsMap(map[string]interface{}{ // success
  182. // "foo": 123,
  183. // "bar": map[string]interface{}{
  184. // "a": true,
  185. // },
  186. // })
  187. //
  188. // object.ContainsMap(map[string]interface{}{ // failure
  189. // "foo": 123,
  190. // "qux": 456,
  191. // })
  192. //
  193. // object.ContainsMap(map[string]interface{}{ // failure, slices should match exactly
  194. // "bar": []interface{}{"x"},
  195. // })
  196. func (o *Object) ContainsMap(value interface{}) *Object {
  197. if !o.containsMap(value) {
  198. o.chain.fail("\nexpected object containing sub-object:\n%s\n\nbut got:\n%s",
  199. dumpValue(value), dumpValue(o.value))
  200. }
  201. return o
  202. }
  203. // NotContainsMap succeeds if object doesn't contain given sub-object exactly.
  204. // Before comparison, both objects are converted to canonical form.
  205. //
  206. // value should map[string]interface{} or struct.
  207. //
  208. // Example:
  209. // object := NewObject(t, map[string]interface{}{"foo": 123, "bar": 456})
  210. // object.NotContainsMap(map[string]interface{}{"foo": 123, "bar": "no-no-no"})
  211. func (o *Object) NotContainsMap(value interface{}) *Object {
  212. if o.containsMap(value) {
  213. o.chain.fail("\nexpected object not containing sub-object:\n%s\n\nbut got:\n%s",
  214. dumpValue(value), dumpValue(o.value))
  215. }
  216. return o
  217. }
  218. // ValueEqual succeeds if object's value for given key is equal to given value.
  219. // Before comparison, both values are converted to canonical form.
  220. //
  221. // value should map[string]interface{} or struct.
  222. //
  223. // Example:
  224. // object := NewObject(t, map[string]interface{}{"foo": 123})
  225. // object.ValueEqual("foo", 123)
  226. func (o *Object) ValueEqual(key string, value interface{}) *Object {
  227. if !o.containsKey(key) {
  228. o.chain.fail("\nexpected object containing key '%s', but got:\n%s",
  229. key, dumpValue(o.value))
  230. return o
  231. }
  232. expected, ok := canonValue(&o.chain, value)
  233. if !ok {
  234. return o
  235. }
  236. if !reflect.DeepEqual(expected, o.value[key]) {
  237. o.chain.fail(
  238. "\nexpected value for key '%s' equal to:\n%s\n\nbut got:\n%s\n\ndiff:\n%s",
  239. key,
  240. dumpValue(expected),
  241. dumpValue(o.value[key]),
  242. diffValues(expected, o.value[key]))
  243. }
  244. return o
  245. }
  246. // ValueNotEqual succeeds if object's value for given key is not equal to given value.
  247. // Before comparison, both values are converted to canonical form.
  248. //
  249. // value should map[string]interface{} or struct.
  250. //
  251. // If object doesn't contain any value for given key, failure is reported.
  252. //
  253. // Example:
  254. // object := NewObject(t, map[string]interface{}{"foo": 123})
  255. // object.ValueNotEqual("foo", "bad value") // success
  256. // object.ValueNotEqual("bar", "bad value") // failure! (key is missing)
  257. func (o *Object) ValueNotEqual(key string, value interface{}) *Object {
  258. if !o.containsKey(key) {
  259. o.chain.fail("\nexpected object containing key '%s', but got:\n%s",
  260. key, dumpValue(o.value))
  261. return o
  262. }
  263. expected, ok := canonValue(&o.chain, value)
  264. if !ok {
  265. return o
  266. }
  267. if reflect.DeepEqual(expected, o.value[key]) {
  268. o.chain.fail("\nexpected value for key '%s' not equal to:\n%s",
  269. key, dumpValue(expected))
  270. }
  271. return o
  272. }
  273. func (o *Object) containsKey(key string) bool {
  274. for k := range o.value {
  275. if k == key {
  276. return true
  277. }
  278. }
  279. return false
  280. }
  281. func (o *Object) containsMap(sm interface{}) bool {
  282. submap, ok := canonMap(&o.chain, sm)
  283. if !ok {
  284. return false
  285. }
  286. return checkContainsMap(o.value, submap)
  287. }
  288. func checkContainsMap(outer, inner map[string]interface{}) bool {
  289. for k, iv := range inner {
  290. ov, ok := outer[k]
  291. if !ok {
  292. return false
  293. }
  294. if ovm, ok := ov.(map[string]interface{}); ok {
  295. if ivm, ok := iv.(map[string]interface{}); ok {
  296. if !checkContainsMap(ovm, ivm) {
  297. return false
  298. }
  299. continue
  300. }
  301. }
  302. if !reflect.DeepEqual(ov, iv) {
  303. return false
  304. }
  305. }
  306. return true
  307. }