Skip to content

Instantly share code, notes, and snippets.

@rewop
Last active November 19, 2020 14:03
Show Gist options
  • Save rewop/0cb63a1c19720349c80c3962295f3c7f to your computer and use it in GitHub Desktop.
Save rewop/0cb63a1c19720349c80c3962295f3c7f to your computer and use it in GitHub Desktop.
Go json diff

This is a simple piece of code that I used to show a friend how I would compare two json object in Go. It exposes a function to compare two JSON given as []byte.

The code assumes that the json object are small enough to be loaded in memory.

package jsoncompare
import (
"encoding/json"
"reflect"
)
func Compare(ajson, bjson []byte) (bool, error) {
var aval, bval interface{}
err := json.Unmarshal(ajson, &aval)
if err != nil {
return false, err
}
err = json.Unmarshal(bjson, &bval)
if err != nil {
return false, err
}
return reflect.DeepEqual(aval, bval), nil
}
package jsoncompare
import (
"encoding/json"
"errors"
"testing"
)
func TestCompare(t *testing.T) {
tests := []struct {
Usecase string
A string
B string
Want bool
Error error
}{
{
"It should return false for simple json",
`{ "a": "test", "b": 2 }`,
`{ "a": "test", "b": 3 }`,
false,
nil,
},
{
"It should return true for simple json",
`{ "a": "test", "b": 2 }`,
`{ "a": "test", "b": 2 }`,
true,
nil,
},
{
"It should return true for json with keys in different order",
`{ "a": "test", "b": 2 }`,
`{ "b": 2, "a": "test" }`,
true,
nil,
},
{
"It should return true for nested json",
`{ "a": "test", "b": 2, "c": { "foo": "bar" } }`,
`{ "b": 2, "a": "test", "c": { "foo": "bar" } }`,
true,
nil,
},
{
"It should return false for nested json",
`{ "a": "test", "b": 2, "c": { "foo": "bar" } }`,
`{ "b": 2, "a": "test", "c": { "foo": "bar2" } }`,
false,
nil,
},
{
"It should return true for complex nested json with different order",
`{ "a": "test", "b": 2, "c": { "foo1": "bar1", "foo2": false, "foo3": 4 } }`,
`{ "a": "test", "b": 2, "c": { "foo2": false, "foo3": 4, "foo1": "bar1" } }`,
true,
nil,
},
{
"It should return true for nesterd arrays",
`{ "a": "test", "b": 2, "c": ["a", "b", 3] }`,
`{ "a": "test", "b": 2, "c": ["a", "b", 3] }`,
true,
nil,
},
{
"It should return false for nested arrays",
`{ "a": "test", "b": 2, "c": ["a", "b", 3] }`,
`{ "a": "test", "b": 2, "c": ["a", "b", 4] }`,
false,
nil,
},
{
"It should return true for root arrays",
`[{ "a": "test", "b": 2, "c": ["a", "b", 3] }, { "foo": "bar" }]`,
`[{ "a": "test", "b": 2, "c": ["a", "b", 3] }, { "foo": "bar" }]`,
true,
nil,
},
{
"It should return false for root arrays",
`[{ "a": "test", "b": 2, "c": ["a", "b", 3] }, { "foo": "bar" }]`,
`[{ "a": "test", "b": 2, "c": ["a", "b", 3] }, { "foo": "barw" }]`,
false,
nil,
},
{
"It should return false if arrays have samve values but on different indexes",
`[{ "a": "test", "b": 2, "c": ["a", "b", 3] }, { "foo": "bar" }]`,
`[{ "foo": "bar" }, { "a": "test", "b": 2, "c": ["a", "b", 3] }]`,
false,
nil,
},
{
"It should return false for arrays with different orders",
`{ "a": "test", "b": 2, "c": ["a", "b", 3] }`,
`{ "a": "test", "b": 2, "c": ["a", 4, "b"] }`,
false,
nil,
},
{
"It should accept string as valid json",
`"foo"`,
`"foo"`,
true,
nil,
},
{
"It should accept string as valid json and compare to false",
`"foo"`,
`"bar"`,
false,
nil,
},
{
"It should accept numbers as valid json",
`10`,
`10`,
true,
nil,
},
{
"It should accept numbers as valid json and compare to false",
`10`,
`20`,
false,
nil,
},
{
"It should accept bools as valid json",
`true`,
`true`,
true,
nil,
},
{
"It should accept bools as valid json and compare to false",
`true`,
`false`,
false,
nil,
},
{
"It should return error if first value is not valid json",
`"{ foo: "bar" }`,
`"{ foo: "bar" }`,
false,
&json.SyntaxError{},
},
{
"It should return error if first value is not valid json",
`"{ "foo": "bar" }`,
`"{ foo: "bar" }`,
false,
&json.SyntaxError{},
},
}
for _, test := range tests {
res, err := Compare([]byte(test.A), []byte(test.B))
if err != nil && test.Error == nil {
t.Errorf("Test failed with error: %s", err)
} else if err != nil && test.Error != nil && !errors.As(test.Error, &err) {
t.Errorf("\nTest failed: %s\n\tWant error: %s, Got error: %s", test.Usecase, test.Error, err)
} else if err == nil && test.Error != nil {
t.Errorf("\nTest failed: %s\n\tWant error: %s, Got nil", test.Usecase, test.Error)
} else if res != test.Want {
t.Errorf("\nTest failed: %s\n\tWant: %t, Got: %t", test.Usecase, test.Want, res)
}
}
}
module github.com/rewop/go-jsondiff
go 1.13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment