Added assertion/requirement that checks if two JSON strings represent equivalent objects

pull/217/head
Julian Cooper 2015-09-23 10:34:52 -07:00
parent b8dc1cecf1
commit 930ea90dbd
8 changed files with 248 additions and 1 deletions

View File

@ -3,6 +3,7 @@ package assert
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"math"
"reflect"
@ -909,3 +910,37 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
}
return true
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
expectSlice := false
expectedJSONAsMap := make(map[string]interface{})
expectedJSONAsSlice := make([]interface{}, 0, 0)
actualJSONAsMap := make(map[string]interface{})
actualJSONAsSlice := make([]interface{}, 0, 0)
if err := json.Unmarshal([]byte(expected), &expectedJSONAsMap); err != nil {
if err := json.Unmarshal([]byte(expected), &expectedJSONAsSlice); err == nil {
expectSlice = true
} else {
return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
}
}
if expectSlice {
if err := json.Unmarshal([]byte(actual), &actualJSONAsSlice); err != nil {
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
}
return Equal(t, expectedJSONAsSlice, actualJSONAsSlice, msgAndArgs...)
} else {
if err := json.Unmarshal([]byte(actual), &actualJSONAsMap); err != nil {
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
}
return Equal(t, expectedJSONAsMap, actualJSONAsMap, msgAndArgs...)
}
}

View File

@ -11,7 +11,7 @@ import (
)
var (
i interface{}
i interface{}
zeros = []interface{}{
false,
byte(0),
@ -903,3 +903,18 @@ func TestNotZero(t *testing.T) {
True(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
}
}
func TestJSONEq(t *testing.T) {
mockT := new(testing.T)
True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`))
True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`))
True(t, JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}"))
True(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`))
False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`))
False(t, JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`))
False(t, JSONEq(mockT, `{"foo": "bar"}`, "Not JSON"))
False(t, JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`))
False(t, JSONEq(mockT, "Not JSON", "Not JSON"))
}

View File

@ -273,3 +273,12 @@ func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
return NotZero(a.t, i, msgAndArgs...)
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
return JSONEq(a.t, expected, actual, msgAndArgs...)
}

View File

@ -535,3 +535,44 @@ func TestNotZeroWrapper(t *testing.T) {
assert.True(mockAssert.NotZero(test), "Zero should return false for %v", test)
}
}
func TestJSONEqWrapper(t *testing.T) {
assert := New(new(testing.T))
if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) {
t.Error("JSONEq should return true")
}
if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return true")
}
if !assert.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") {
t.Error("JSONEq should return true")
}
if !assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) {
t.Error("JSONEq should return true")
}
if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) {
t.Error("JSONEq should return false")
}
if assert.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return false")
}
if assert.JSONEq(`{"foo": "bar"}`, "Not JSON") {
t.Error("JSONEq should return false for invalid JSON")
}
if assert.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) {
t.Error("JSONEq should return false")
}
if assert.JSONEq("Not JSON", "Not JSON") {
t.Error("JSONEq should return false")
}
}

View File

@ -219,3 +219,12 @@ func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
NotZero(a.t, i, msgAndArgs...)
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
JSONEq(a.t, expected, actual, msgAndArgs...)
}

View File

@ -282,3 +282,56 @@ func TestNotZeroWrapper(t *testing.T) {
t.Error("Check should fail")
}
}
func TestJSONEqWrapper(t *testing.T) {
// mockRequire := New(new(testing.T))
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)
if mockT.Failed {
t.Error("JSONEq should pass")
}
mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if mockT.Failed {
t.Error("JSONEq should pass")
}
mockRequire.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")
if mockT.Failed {
t.Error("JSONEq should pass")
}
mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)
if mockT.Failed {
t.Error("JSONEq should pass")
}
mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)
if !mockT.Failed {
t.Error("JSONEq should fail")
}
mockRequire.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
t.Error("JSONEq should fail")
}
mockRequire.JSONEq(`{"foo": "bar"}`, "Not JSON")
if !mockT.Failed {
t.Error("JSONEq should fail")
}
mockRequire.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
t.Error("JSONEq should fail")
}
mockRequire.JSONEq("Not JSON", "Not JSON")
if !mockT.Failed {
t.Error("JSONEq should fail")
}
}

View File

@ -1,6 +1,7 @@
package require
import (
"encoding/json"
"time"
"github.com/stretchr/testify/assert"
@ -228,6 +229,40 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
}
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
expectSlice := false
expectedJSONAsMap := make(map[string]interface{})
expectedJSONAsSlice := make([]interface{}, 0, 0)
actualJSONAsMap := make(map[string]interface{})
actualJSONAsSlice := make([]interface{}, 0, 0)
if err := json.Unmarshal([]byte(expected), &expectedJSONAsMap); err != nil {
if err := json.Unmarshal([]byte(expected), &expectedJSONAsSlice); err == nil {
expectSlice = true
} else {
t.FailNow()
}
}
if expectSlice {
if err := json.Unmarshal([]byte(actual), &actualJSONAsSlice); err != nil {
t.FailNow()
}
Equal(t, expectedJSONAsSlice, actualJSONAsSlice, msgAndArgs...)
} else {
if err := json.Unmarshal([]byte(actual), &actualJSONAsMap); err != nil {
t.FailNow()
}
Equal(t, expectedJSONAsMap, actualJSONAsMap, msgAndArgs...)
}
}
/*
Errors
*/

View File

@ -286,3 +286,53 @@ func TestNotZero(t *testing.T) {
t.Error("Check should fail")
}
}
func TestJSONEq(t *testing.T) {
mockT := new(MockT)
JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)
if mockT.Failed {
t.Error("Check should pass")
}
JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if mockT.Failed {
t.Error("Check should pass")
}
JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
"{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")
if mockT.Failed {
t.Error("Check should pass")
}
JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)
if mockT.Failed {
t.Error("Check should pass")
}
JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)
if !mockT.Failed {
t.Error("Check should fail")
}
JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
t.Error("Check should fail")
}
JSONEq(mockT, `{"foo": "bar"}`, "Not JSON")
if !mockT.Failed {
t.Error("Check should fail")
}
JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`)
if !mockT.Failed {
t.Error("Check should fail")
}
JSONEq(mockT, "Not JSON", "Not JSON")
if !mockT.Failed {
t.Error("Check should fail")
}
}