GithubHelp home page GithubHelp logo

davidpdrsn / assert-json-diff Goto Github PK

View Code? Open in Web Editor NEW
79.0 6.0 17.0 48 KB

Easily compare two JSON values and get great output

Home Page: https://crates.io/crates/assert-json-diff

License: MIT License

Shell 2.63% Rust 97.37%

assert-json-diff's Introduction

Crates.io Docs dependency status Build status maintenance-status

assert-json-diff

This crate includes macros for comparing two serializable values by diffing their JSON representations. It is designed to give much more helpful error messages than the standard assert_eq!. It basically does a diff of the two objects and tells you the exact differences. This is useful when asserting that two large JSON objects are the same.

It uses the serde and serde_json to perform the serialization.

Partial matching

If you want to assert that one JSON value is "included" in another use assert_json_include:

use assert_json_diff::assert_json_include;
use serde_json::json;

let a = json!({
    "data": {
        "users": [
            {
                "id": 1,
                "country": {
                    "name": "Denmark"
                }
            },
            {
                "id": 24,
                "country": {
                    "name": "Denmark"
                }
            }
        ]
    }
});

let b = json!({
    "data": {
        "users": [
            {
                "id": 1,
                "country": {
                    "name": "Sweden"
                }
            },
            {
                "id": 2,
                "country": {
                    "name": "Denmark"
                }
            }
        ]
    }
});

assert_json_include!(actual: a, expected: b)

This will panic with the error message:

json atoms at path ".data.users[0].country.name" are not equal:
    expected:
        "Sweden"
    actual:
        "Denmark"

json atoms at path ".data.users[1].id" are not equal:
    expected:
        2
    actual:
        24

assert_json_include allows extra data in actual but not in expected. That is so you can verify just a part of the JSON without having to specify the whole thing. For example this test passes:

use assert_json_diff::assert_json_include;
use serde_json::json;

assert_json_include!(
    actual: json!({
        "a": { "b": 1 },
    }),
    expected: json!({
        "a": {},
    })
)

However expected cannot contain additional data so this test fails:

use assert_json_diff::assert_json_include;
use serde_json::json;

assert_json_include!(
    actual: json!({
        "a": {},
    }),
    expected: json!({
        "a": { "b": 1 },
    })
)

That will print

json atom at path ".a.b" is missing from actual

Exact matching

If you want to ensure two JSON values are exactly the same, use assert_json_eq.

use assert_json_diff::assert_json_eq;
use serde_json::json;

assert_json_eq!(
    json!({ "a": { "b": 1 } }),
    json!({ "a": {} })
)

This will panic with the error message:

json atom at path ".a.b" is missing from lhs

Further customization

You can use [assert_json_matches] to further customize the comparison.

License: MIT

assert-json-diff's People

Contributors

davidpdrsn avatar jyn514 avatar kate-shine avatar rfairley avatar yagince avatar yanns avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

assert-json-diff's Issues

Allow error message like standard library assertions

It would be great if the assertion macros were to support specifying an error message with format parameters as the standard library assertions do.

Example:

assert_eq!(1, 2, "Numbers in test case {} didn't match", case);

Feature Request: assert that key is present but ignore value

I was wondering if you'd be open to including some kind of flag within the macro that indicates that it should check that the key exists, but ignores the value (or just accepts any value).

The main reason for doing this would be for values such as decimals where checking for exact equality isn't likely to work eg:

json atoms at path ".price" are not equal:
    expected:
        2.97
    actual:
        2.9699999999999998

Update to Rust 2018

cargo fix —edition 2018 and adding edition = “2018” to Cargo.toml should do the trick.

Shallow vs deep inclusive compare

I ran the following test just now, which passed:

        assert_json_include!(actual: &serialized, expected: serde_json::json!({
            "x": [0],
            "y": [1, 3],
        }))

Then I changed it to

        assert_json_include!(actual: &serialized, expected: serde_json::json!({
            "x": [0, 2],
            "y": [1, 3],
        }))

which also passed.

I think what's going on is that the Inclusive compare mode is being passed recursively, instead of only for the outer object. That's very non-intuitive for me, I'd expect it to only be for the keys and not the inner values. Would it be possible to add a new mode that does a shallow inclusive compare instead of a deep inclusive compare?

Feature request: approximate float equality

It would be really cool if we could configure the assertion to ignore tiny differences in float values, e.g.

let assert_config = assert_json_diff::Config::new(assert_json_diff::CompareMode::Strict)
    .numeric_mode(assert_json_diff::NumericMode::AssumeFloat)
    .float_eq_epsilon(0.001);

assert_json_diff::assert_json_matches!(
    serde_json::json!({"a": 1.1000001}),
    serde_json::json!({"a": 1.1000002}),
    assert_config
);

This should work, but right now will fail with

json atoms at path ".a" are not equal:
    lhs:
        1.1000001
    rhs:
        1.1000002

It would also more elegantly solve the discussion over at #17.

NumericMode::AssumeFloat strictness

I'm using NumericMode::AssumeFloat in assert_json_diff::assert_json_matches as described in https://docs.rs/assert-json-diff/2.0.1/assert_json_diff/macro.assert_json_matches.html I've confirmed the documented example works as expected.

But given how floats might be serialized, the matcher is not easy to use in practice.

My example that fails:

#[test]
fn json_comparison() {
    let config = Config::new(CompareMode::Strict).numeric_mode(NumericMode::AssumeFloat);

    // both are f32
    let params = Params {
        field_name_2: 0.6,
        field_name_1: 0.2,
    };
    let actual_json = serde_json::to_value(&params).unwrap();

    let expected_json = json!({
        "field_name_2": 0.6,
        "field_name_1": 0.2,
    });

    // comparing Value to Value types
    assert_json_matches!(actual_json, expected_json, config);
}

With this difference:

json atoms at path ".field_name_1" are not equal:
    lhs:
        0.20000000298023224
    rhs:
        0.2

json atoms at path ".field_name_2" are not equal:
    lhs:
        0.6000000238418579
    rhs:
        0.6

Sure enough, if I println! my actual_json I can see:

{
  "field_name_1":0.20000000298023224,
  "field_name_2":0.6000000238418579
}

I can blame this on serde_json but wdyt? Can there be a within_precision option to handle this? Not sure what level to fix at.

Dependencies:

assert-json-diff = "2"
serde_json = "1.0"
serde = { version = "1", features = ["derive"] }

Non-panicking variation

I would have liked to use this as part of a build script, but I didn't want to panic if there's a difference. It would be helpful to expose the comparison functions themselves.

1.0?

I've seen using this at work for some time now and I'm happy with the API.

I guess it would make sense to bump to 1.0 just to signal that this works.

Converting T to serde_json::Value?

Would it be problematic to allow the assert macros to automatically serialize values to a serde_json::Value? Something like:

pub fn diff<'a, Lhs, Rhs>(lhs: &'a Lhs, rhs: &'a Rhs, mode: Mode) -> Vec<Difference<'a>>
where
  Lhs: Serialize,
  Rhs: Serialize,
{
  let lhs = serde_json::to_value(lhs);
  let rhs = serde_json::to_value(rhs);
  // ...
}

(ignore the lifetime for my example, hah)

My use case is that my actual (specifically) is usually an unserialized json type and my tests are cluttered with things like:

let resp: Json<Foo> = req().unwrap();
let resp = serde_json::to_value(resp.into_inner()).unwrap();
assert_json_eq!(resp, json!("foo"));

Not a big deal, just wondering if it has a downside. If there's no downside it seems like a nice improvement to accept more types which can naturally be serialized to Value. Thoughts?

Breaking change between 1.0.2 and 1.0.3

function assert_json_no_panic and Mode were made private, which breaks mockito library

log:

   Compiling mockito v0.23.2
error[E0603]: function `assert_json_no_panic` is private
   --> /Users/lbi/.cargo/registry/src/github.com-1ecc6299db9ec823/mockito-0.23.2/src/lib.rs:565:24
    |
565 | use assert_json_diff::{assert_json_no_panic, Mode};
    |                        ^^^^^^^^^^^^^^^^^^^^

error[E0603]: enum `Mode` is private
   --> /Users/lbi/.cargo/registry/src/github.com-1ecc6299db9ec823/mockito-0.23.2/src/lib.rs:565:46
    |
565 | use assert_json_diff::{assert_json_no_panic, Mode};
    |                                              ^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0603`.
error: could not compile `mockito`.

Steps to reproduce:

  • create new crate
  • add mockito = "0.23.2" to dependencies
  • build fails
  • add assert-json-diff = "=1.0.2"
  • build succeeds

This should be 2.0 release due to that

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.