123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927 |
- package httpexpect
- import (
- "errors"
- "reflect"
- )
- // Value provides methods to inspect attached interface{} object
- // (Go representation of arbitrary JSON value) and cast it to
- // concrete type.
- type Value struct {
- chain *chain
- value interface{}
- }
- // NewValue returns a new Value instance.
- //
- // If reporter is nil, the function panics.
- // Value may be nil.
- //
- // Example:
- //
- // value := NewValue(t, map[string]interface{}{"foo": 123})
- // value.IsObject()
- //
- // value := NewValue(t, []interface{}{"foo", 123})
- // value.IsArray()
- //
- // value := NewValue(t, "foo")
- // value.IsString()
- //
- // value := NewValue(t, 123)
- // value.IsNumber()
- //
- // value := NewValue(t, true)
- // value.IsBoolean()
- //
- // value := NewValue(t, nil)
- // value.IsNull()
- func NewValue(reporter Reporter, value interface{}) *Value {
- return newValue(newChainWithDefaults("Value()", reporter), value)
- }
- // NewValueC returns a new Value instance with config.
- //
- // Requirements for config are same as for WithConfig function.
- // Value may be nil.
- //
- // See NewValue for usage example.
- func NewValueC(config Config, value interface{}) *Value {
- return newValue(newChainWithConfig("Value()", config.withDefaults()), value)
- }
- func newValue(parent *chain, val interface{}) *Value {
- v := &Value{parent.clone(), nil}
- opChain := v.chain.enter("")
- defer opChain.leave()
- if val != nil {
- v.value, _ = canonValue(opChain, val)
- }
- return v
- }
- // Raw returns underlying value attached to Value.
- // This is the value originally passed to NewValue, converted to canonical form.
- //
- // Example:
- //
- // value := NewValue(t, "foo")
- // assert.Equal(t, "foo", number.Raw().(string))
- func (v *Value) Raw() interface{} {
- return v.value
- }
- // Decode unmarshals the underlying value attached to the Object to a target variable
- // target should be pointer to any type.
- //
- // Example:
- //
- // type S struct {
- // Foo int `json:"foo"`
- // Bar []interface{} `json:"bar"`
- // Baz struct{ A int } `json:"baz"`
- // }
- //
- // m := map[string]interface{}{
- // "foo": 123,
- // "bar": []interface{}{"123", 456.0},
- // "baz": struct{ A int }{123},
- // }
- //
- // value = NewValue(reporter,m)
- //
- // var target S
- // value.Decode(&target)
- //
- // assert.Equal(t, S{123, []interface{}{"123", 456.0}, struct{ A int }{123}, target})
- func (v *Value) Decode(target interface{}) *Value {
- opChain := v.chain.enter("Decode()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- canonDecode(opChain, v.value, target)
- return v
- }
- // Alias returns a new Value object with alias.
- // When a test of Value object with alias is failed,
- // an assertion is displayed as a chain starting from the alias.
- //
- // Example:
- //
- // // In this example, GET /example responds "foo"
- // foo := e.GET("/example").Expect().Status(http.StatusOK).JSON().Object()
- //
- // // When a test is failed, an assertion without alias is
- // // Request("GET").Expect().JSON().Object().IsEqual()
- // foo.IsEqual("bar")
- //
- // // Set Alias
- // fooWithAlias := e.GET("/example").
- // Expect().
- // Status(http.StatusOK).JSON().Object().Alias("foo")
- //
- // // When a test is failed, an assertion with alias is
- // // foo.IsEqual()
- // fooWithAlias.IsEqual("bar")
- func (v *Value) Alias(name string) *Value {
- opChain := v.chain.enter("Alias(%q)", name)
- defer opChain.leave()
- v.chain.setAlias(name)
- return v
- }
- // Path returns a new Value object for child object(s) matching given
- // JSONPath expression.
- //
- // JSONPath is a simple XPath-like query language.
- // See http://goessner.net/articles/JsonPath/.
- //
- // We currently use https://github.com/yalp/jsonpath, which implements
- // only a subset of JSONPath, yet useful for simple queries. It doesn't
- // support filters and requires double quotes for strings.
- //
- // Example 1:
- //
- // json := `{"users": [{"name": "john"}, {"name": "bob"}]}`
- // value := NewValue(t, json)
- //
- // value.Path("$.users[0].name").String().IsEqual("john")
- // value.Path("$.users[1].name").String().IsEqual("bob")
- //
- // Example 2:
- //
- // json := `{"yfGH2a": {"user": "john"}, "f7GsDd": {"user": "john"}}`
- // value := NewValue(t, json)
- //
- // for _, user := range value.Path("$..user").Array().Iter() {
- // user.String().IsEqual("john")
- // }
- func (v *Value) Path(path string) *Value {
- opChain := v.chain.enter("Path(%q)", path)
- defer opChain.leave()
- return jsonPath(opChain, v.value, path)
- }
- // Schema succeeds if value matches given JSON Schema.
- //
- // JSON Schema specifies a JSON-based format to define the structure of
- // JSON data. See http://json-schema.org/.
- // We use https://github.com/xeipuuv/gojsonschema implementation.
- //
- // schema should be one of the following:
- // - go value that can be json.Marshal-ed to a valid schema
- // - type convertible to string containing valid schema
- // - type convertible to string containing valid http:// or file:// URI,
- // pointing to reachable and valid schema
- //
- // Example 1:
- //
- // schema := `{
- // "type": "object",
- // "properties": {
- // "foo": {
- // "type": "string"
- // },
- // "bar": {
- // "type": "integer"
- // }
- // },
- // "require": ["foo", "bar"]
- // }`
- //
- // value := NewValue(t, map[string]interface{}{
- // "foo": "a",
- // "bar": 1,
- // })
- //
- // value.Schema(schema)
- //
- // Example 2:
- //
- // value := NewValue(t, data)
- // value.Schema("http://example.com/schema.json")
- func (v *Value) Schema(schema interface{}) *Value {
- opChain := v.chain.enter("Schema()")
- defer opChain.leave()
- jsonSchema(opChain, v.value, schema)
- return v
- }
- // Object returns a new Object attached to underlying value.
- //
- // If underlying value is not an object (map[string]interface{}), failure is reported
- // and empty (but non-nil) value is returned.
- //
- // Example:
- //
- // value := NewValue(t, map[string]interface{}{"foo": 123})
- // value.Object().ContainsKey("foo")
- func (v *Value) Object() *Object {
- opChain := v.chain.enter("Object()")
- defer opChain.leave()
- if opChain.failed() {
- return newObject(opChain, nil)
- }
- data, ok := v.value.(map[string]interface{})
- if !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is object"),
- },
- })
- return newObject(opChain, nil)
- }
- return newObject(opChain, data)
- }
- // Array returns a new Array attached to underlying value.
- //
- // If underlying value is not an array ([]interface{}), failure is reported and empty
- // (but non-nil) value is returned.
- //
- // Example:
- //
- // value := NewValue(t, []interface{}{"foo", 123})
- // value.Array().ConsistsOf("foo", 123)
- func (v *Value) Array() *Array {
- opChain := v.chain.enter("Array()")
- defer opChain.leave()
- if opChain.failed() {
- return newArray(opChain, nil)
- }
- data, ok := v.value.([]interface{})
- if !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is array"),
- },
- })
- return newArray(opChain, nil)
- }
- return newArray(opChain, data)
- }
- // String returns a new String attached to underlying value.
- //
- // If underlying value is not a string, failure is reported and empty (but non-nil)
- // value is returned.
- //
- // Example:
- //
- // value := NewValue(t, "foo")
- // value.String().IsEqualFold("FOO")
- func (v *Value) String() *String {
- opChain := v.chain.enter("String()")
- defer opChain.leave()
- if opChain.failed() {
- return newString(opChain, "")
- }
- data, ok := v.value.(string)
- if !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is string"),
- },
- })
- return newString(opChain, "")
- }
- return newString(opChain, data)
- }
- // Number returns a new Number attached to underlying value.
- //
- // If underlying value is not a number (numeric type convertible to float64), failure
- // is reported and empty (but non-nil) value is returned.
- //
- // Example:
- //
- // value := NewValue(t, 123)
- // value.Number().InRange(100, 200)
- func (v *Value) Number() *Number {
- opChain := v.chain.enter("Number()")
- defer opChain.leave()
- if opChain.failed() {
- return newNumber(opChain, 0)
- }
- data, ok := v.value.(float64)
- if !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is number"),
- },
- })
- return newNumber(opChain, 0)
- }
- return newNumber(opChain, data)
- }
- // Boolean returns a new Boolean attached to underlying value.
- //
- // If underlying value is not a bool, failure is reported and empty (but non-nil)
- // value is returned.
- //
- // Example:
- //
- // value := NewValue(t, true)
- // value.Boolean().IsTrue()
- func (v *Value) Boolean() *Boolean {
- opChain := v.chain.enter("Boolean()")
- defer opChain.leave()
- if opChain.failed() {
- return newBoolean(opChain, false)
- }
- data, ok := v.value.(bool)
- if !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is boolean"),
- },
- })
- return newBoolean(opChain, false)
- }
- return newBoolean(opChain, data)
- }
- // IsNull succeeds if value is nil.
- //
- // Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
- // is also treated as null value. Empty (non-nil) slice or map, empty string, and
- // zero number are not treated as null value.
- //
- // Example:
- //
- // value := NewValue(t, nil)
- // value.IsNull()
- //
- // value := NewValue(t, []interface{}(nil))
- // value.IsNull()
- func (v *Value) IsNull() *Value {
- opChain := v.chain.enter("IsNull()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if !(v.value == nil) {
- opChain.fail(AssertionFailure{
- Type: AssertNil,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is null"),
- },
- })
- }
- return v
- }
- // NotNull succeeds if value is not nil.
- //
- // Note that non-nil interface{} that points to nil value (e.g. nil slice or map)
- // is also treated as null value. Empty (non-nil) slice or map, empty string, and
- // zero number are not treated as null value.
- //
- // Example:
- //
- // value := NewValue(t, "")
- // value.NotNull()
- //
- // value := NewValue(t, make([]interface{}, 0))
- // value.NotNull()
- func (v *Value) NotNull() *Value {
- opChain := v.chain.enter("NotNull()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if v.value == nil {
- opChain.fail(AssertionFailure{
- Type: AssertNotNil,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is non-null"),
- },
- })
- }
- return v
- }
- // Deprecated: use IsNull instead.
- func (v *Value) Null() *Value {
- return v.IsNull()
- }
- // IsObject succeeds if the underlying value is an object.
- //
- // If underlying value is not an object (map[string]interface{}), failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, map[string]interface{}{"foo": 123})
- // value.IsObject()
- func (v *Value) IsObject() *Value {
- opChain := v.chain.enter("IsObject()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.(map[string]interface{}); !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is object"),
- },
- })
- }
- return v
- }
- // NotObject succeeds if the underlying value is not an object.
- //
- // If underlying value is an object (map[string]interface{}), failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, nil)
- // value.NotObject()
- func (v *Value) NotObject() *Value {
- opChain := v.chain.enter("NotObject()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.(map[string]interface{}); ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is not object"),
- },
- })
- }
- return v
- }
- // IsArray succeeds if the underlying value is an array.
- //
- // If underlying value is not an array ([]interface{}), failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, []interface{}{"foo", "123"})
- // value.IsArray()
- func (v *Value) IsArray() *Value {
- opChain := v.chain.enter("IsArray()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.([]interface{}); !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is array"),
- },
- })
- }
- return v
- }
- // NotArray succeeds if the underlying value is not an array.
- //
- // If underlying value is an array ([]interface{}), failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, nil)
- // value.NotArray()
- func (v *Value) NotArray() *Value {
- opChain := v.chain.enter("NotArray()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.([]interface{}); ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is not array"),
- },
- })
- }
- return v
- }
- // IsString succeeds if the underlying value is a string.
- //
- // If underlying value is not a string, failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, "foo")
- // value.IsString()
- func (v *Value) IsString() *Value {
- opChain := v.chain.enter("IsString()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.(string); !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is string"),
- },
- })
- }
- return v
- }
- // NotString succeeds if the underlying value is not a string.
- //
- // If underlying value is a string, failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, nil)
- // value.NotString()
- func (v *Value) NotString() *Value {
- opChain := v.chain.enter("NotString()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.(string); ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is not string"),
- },
- })
- }
- return v
- }
- // IsNumber succeeds if the underlying value is a number.
- //
- // If underlying value is not a number (numeric type convertible to float64),
- // failure is reported
- //
- // Example:
- //
- // value := NewValue(t, 123)
- // value.IsNumber()
- func (v *Value) IsNumber() *Value {
- opChain := v.chain.enter("IsNumber()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.(float64); !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is number"),
- },
- })
- }
- return v
- }
- // NotNumber succeeds if the underlying value is a not a number.
- //
- // If underlying value is a number (numeric type convertible to float64),
- // failure is reported
- //
- // Example:
- //
- // value := NewValue(t, nil)
- // value.NotNumber()
- func (v *Value) NotNumber() *Value {
- opChain := v.chain.enter("NotNumber()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.(float64); ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is not number"),
- },
- })
- }
- return v
- }
- // IsBoolean succeeds if the underlying value is a boolean.
- //
- // If underlying value is not a boolean, failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, true)
- // value.IsBoolean()
- func (v *Value) IsBoolean() *Value {
- opChain := v.chain.enter("IsBoolean()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.(bool); !ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is boolean"),
- },
- })
- }
- return v
- }
- // NotBoolean succeeds if the underlying value is not a boolean.
- //
- // If underlying value is a boolean, failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, nil)
- // value.NotBoolean()
- func (v *Value) NotBoolean() *Value {
- opChain := v.chain.enter("NotBoolean()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if _, ok := v.value.(bool); ok {
- opChain.fail(AssertionFailure{
- Type: AssertValid,
- Actual: &AssertionValue{v.value},
- Errors: []error{
- errors.New("expected: value is not boolean"),
- },
- })
- }
- return v
- }
- // IsEqual succeeds if value is equal to another value (e.g. map, slice, string, etc).
- // Before comparison, both values are converted to canonical form.
- //
- // Example:
- //
- // value := NewValue(t, "foo")
- // value.IsEqual("foo")
- func (v *Value) IsEqual(value interface{}) *Value {
- opChain := v.chain.enter("IsEqual()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- expected, ok := canonValue(opChain, value)
- if !ok {
- return v
- }
- if !reflect.DeepEqual(expected, v.value) {
- opChain.fail(AssertionFailure{
- Type: AssertEqual,
- Actual: &AssertionValue{v.value},
- Expected: &AssertionValue{expected},
- Errors: []error{
- errors.New("expected: values are equal"),
- },
- })
- }
- return v
- }
- // NotEqual succeeds if value is not equal to another value (e.g. map, slice,
- // string, etc). Before comparison, both values are converted to canonical form.
- //
- // Example:
- //
- // value := NewValue(t, "foo")
- // value.NorEqual("bar")
- func (v *Value) NotEqual(value interface{}) *Value {
- opChain := v.chain.enter("NotEqual()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- expected, ok := canonValue(opChain, value)
- if !ok {
- return v
- }
- if reflect.DeepEqual(expected, v.value) {
- opChain.fail(AssertionFailure{
- Type: AssertNotEqual,
- Actual: &AssertionValue{v.value},
- Expected: &AssertionValue{expected},
- Errors: []error{
- errors.New("expected: values are non-equal"),
- },
- })
- }
- return v
- }
- // Deprecated: use IsEqual instead.
- func (v *Value) Equal(value interface{}) *Value {
- return v.IsEqual(value)
- }
- // InList succeeds if whole value is equal to one of the values from given
- // list of values (e.g. map, slice, string, etc). Before comparison, all
- // values are converted to canonical form.
- //
- // If at least one value has wrong type, failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, "foo")
- // value.InList("foo", 123)
- func (v *Value) InList(values ...interface{}) *Value {
- opChain := v.chain.enter("InList()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if len(values) == 0 {
- opChain.fail(AssertionFailure{
- Type: AssertUsage,
- Errors: []error{
- errors.New("unexpected empty list argument"),
- },
- })
- return v
- }
- var isListed bool
- for _, val := range values {
- expected, ok := canonValue(opChain, val)
- if !ok {
- return v
- }
- if reflect.DeepEqual(expected, v.value) {
- isListed = true
- // continue loop to check that all values are correct
- }
- }
- if !isListed {
- opChain.fail(AssertionFailure{
- Type: AssertBelongs,
- Actual: &AssertionValue{v.value},
- Expected: &AssertionValue{AssertionList(values)},
- Errors: []error{
- errors.New("expected: value is equal to one of the values"),
- },
- })
- }
- return v
- }
- // NotInList succeeds if the whole value is not equal to any of the values from
- // given list of values (e.g. map, slice, string, etc).
- // Before comparison, all values are converted to canonical form.
- //
- // If at least one value has wrong type, failure is reported.
- //
- // Example:
- //
- // value := NewValue(t, "foo")
- // value.NotInList("bar", 123)
- func (v *Value) NotInList(values ...interface{}) *Value {
- opChain := v.chain.enter("NotInList()")
- defer opChain.leave()
- if opChain.failed() {
- return v
- }
- if len(values) == 0 {
- opChain.fail(AssertionFailure{
- Type: AssertUsage,
- Errors: []error{
- errors.New("unexpected empty list argument"),
- },
- })
- return v
- }
- for _, val := range values {
- expected, ok := canonValue(opChain, val)
- if !ok {
- return v
- }
- if reflect.DeepEqual(expected, v.value) {
- opChain.fail(AssertionFailure{
- Type: AssertNotBelongs,
- Actual: &AssertionValue{v.value},
- Expected: &AssertionValue{AssertionList(values)},
- Errors: []error{
- errors.New("expected: value is not equal to any of the values"),
- },
- })
- return v
- }
- }
- return v
- }
|