JSON

func JSON(expectedJSON interface{}, params ...interface{}) TestDeep

JSON operator allows to compare the JSON representation of data against expectedJSON. expectedJSON can be a:

  • string containing JSON data like {"fullname":"Bob","age":42}
  • string containing a JSON filename, ending with “.json” (its content is ioutil.ReadFile before unmarshaling)
  • []byte containing JSON data
  • io.Reader stream containing JSON data (is ioutil.ReadAll before unmarshaling)

expectedJSON JSON value can contain placeholders. The params are for any placeholder parameters in expectedJSON. params can contain TestDeep operators as well as raw values. A placeholder can be numeric like $2 or named like $name and always references an item in params.

Numeric placeholders reference the n’th “operators” item (starting at 1). Named placeholders are used with Tag operator as follows:

td.Cmp(t, gotValue,
  td.JSON(`{"fullname": $name, "age": $2, "gender": $3}`,
    td.Tag("name", td.HasPrefix("Foo")), // matches $1 and $name
    td.Between(41, 43),                  // matches only $2
    "male"))                             // matches only $3

Note that placeholders can be double-quoted as in:

td.Cmp(t, gotValue,
  td.JSON(`{"fullname": "$name", "age": "$2", "gender": "$3"}`,
    td.Tag("name", td.HasPrefix("Foo")), // matches $1 and $name
    td.Between(41, 43),                  // matches only $2
    "male"))                             // matches only $3

It makes no difference whatever the underlying type of the replaced item is (= double quoting a placeholder matching a number is not a problem). It is just a matter of taste, double-quoting placeholders can be preferred when the JSON data has to conform to the JSON specification, like when used in a “.json” file.

Note expectedJSON can be a []byte, JSON filename or io.Reader:

td.Cmp(t, gotValue, td.JSON("file.json", td.Between(12, 34)))
td.Cmp(t, gotValue, td.JSON([]byte(`[1, $1, 3]`), td.Between(12, 34)))
td.Cmp(t, gotValue, td.JSON(osFile, td.Between(12, 34)))

A JSON filename ends with “.json”.

To avoid a legit “$” string prefix causes a bad placeholder error, just double it to escape it. Note it is only needed when the “$” is the first character of a string:

td.Cmp(t, gotValue,
  td.JSON(`{"fullname": "$name", "details": "$$info", "age": $2}`,
    td.Tag("name", td.HasPrefix("Foo")), // matches $1 and $name
    td.Between(41, 43)))                 // matches only $2

For the “details” key, the raw value “$info” is expected, no placeholders are involved here.

Note that Lax mode is automatically enabled by JSON operator to simplify numeric tests.

Comments can be embedded in JSON data:

td.Cmp(t, gotValue,
  td.JSON(`
{
  // A guy properties:
  "fullname": "$name",  // The full name of the guy
  "details":  "$$info", // Literally "$info", thanks to "$" escape
  "age":      $2        /* The age of the guy:
                           - placeholder unquoted, but could be without
                             any change
                           - to demonstrate a multi-lines comment */
}`,
    td.Tag("name", td.HasPrefix("Foo")), // matches $1 and $name
    td.Between(41, 43)))                 // matches only $2

Comments, like in go, have 2 forms. To quote the Go language specification:

  • line comments start with the character sequence // and stop at the end of the line.
  • multi-lines comments start with the character sequence /* and stop with the first subsequent character sequence */.

Last but not least, simple operators can be directly embedded in JSON data without requiring any placeholder but using directly $^OperatorName. They are operator shortcuts:

td.Cmp(t, gotValue, td.JSON(`{"id": $1}`, td.NotZero()))

can be written as:

td.Cmp(t, gotValue, td.JSON(`{"id": $^NotZero}`))

Unfortunately, only simple operators (in fact those which take no parameters) have shortcuts. They follow:

TypeBehind method returns the reflect.Type of the expectedJSON json.Unmarshal‘ed. So it can be bool, string, float64, []interface{}, map[string]interface{} or interface{} in case expectedJSON is “null”.

See also JSON godoc.

Examples

Basic example
Placeholders example
File example

CmpJSON shortcut

func CmpJSON(t TestingT, got interface{}, expectedJSON interface{}, params []interface{}, args ...interface{}) bool

CmpJSON is a shortcut for:

td.Cmp(t, got, td.JSON(expectedJSON, params...), args...)

See above for details.

Returns true if the test is OK, false if it fails.

args… are optional and allow to name the test. This name is used in case of failure to qualify the test. If len(args) > 1 and the first item of args is a string and contains a ‘%’ rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint. Do not forget it is the name of the test, not the reason of a potential failure.

See also CmpJSON godoc.

Examples

Basic example
Placeholders example
File example

T.JSON shortcut

func (t *T) JSON(got interface{}, expectedJSON interface{}, params []interface{}, args ...interface{}) bool

JSON is a shortcut for:

t.Cmp(got, td.JSON(expectedJSON, params...), args...)

See above for details.

Returns true if the test is OK, false if it fails.

args… are optional and allow to name the test. This name is used in case of failure to qualify the test. If len(args) > 1 and the first item of args is a string and contains a ‘%’ rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint. Do not forget it is the name of the test, not the reason of a potential failure.

See also T.JSON godoc.

Examples

Basic example
Placeholders example
File example