cmp_json 0.1.0

Comparators for JSON represented by serde_json::Value
Documentation
//! A set of functions that simplifies comparison between two JSON objects. 
use serde_json::Value;

/// A compare function between two JSON Values. Compare returns a boolean true 
/// or false if the Valus are equal. Takes the `exp` argument as the base of 
/// the comparison.
/// 
/// This function compares to see that all values in the `exp` argument are also 
/// present in the `got` argument. It will still return true if `got` has extra
/// object elements not present in `exp`
/// 
/// ```rust
/// 
/// use serde_json::json;
/// use cmp_json::cmp_expected;
/// 
/// let exp = json!{{
///     "some": "value"
/// }};
/// let got_extra = json!{{
///     "some": "value",
///     "another": "element",
/// }};
/// let got_different = json!{{
///     "some": 2
/// }};
/// 
/// assert!(cmp_expected(&got_extra, &exp));
/// assert!(cmp_expected(&got_different, &exp) == false);
/// ```
/// 
pub fn cmp_expected(got: &Value, exp: &Value) -> bool {
    match exp {
        Value::Array(e_arr) => {
            match got.as_array() {
                Some(g_arr) => {
                    if e_arr.len() != g_arr.len() {
                        return false
                    }
                    e_arr.iter().zip(
                        g_arr.iter()
                    ).all(|(e, g)| cmp_expected(g, e))
                }
                None => false
            } 
        }
        Value::Object(e_obj) => {
            match got.as_object() {
                Some(g_obj) => {
                    // We only iterate through expected; if there are values in got that do
                    // not match expected, that is fine
                    e_obj.iter().all(
                        |(k, e_val)| 
                        match g_obj.get(k) {
                            Some(g_val) => cmp_expected(g_val, e_val),
                            None => false
                        }
                    )
                }
                None => false
            }
        }
        _ => got == exp
    }
}


#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::{json, Value::Null};

    #[test]
    fn null_equal() {
        let got = json!(Null);
        let exp = json!(Null);
        assert_eq!(
            cmp_expected(&got, &exp), 
            true
        );
    }

    #[test]
    fn null_unequal() {
        let got = json!("Null");
        let exp = json!(Null);
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn string_equal() {
        let got = json!("something");
        let exp = json!("something");
        assert_eq!(
            cmp_expected(&got, &exp), 
            true
        );
    }

    #[test]
    fn string_unequal() {
        let got = json!("something");
        let exp = json!("something else");
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn number_equal() {
        let got = json!(-12.3);
        let exp = json!(-12.3);
        assert_eq!(
            cmp_expected(&got, &exp), 
            true
        );
    }

    #[test]
    fn number_unequal() {
        let got = json!(-12.5);
        let exp = json!(6);
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn bool_equal() {
        let got = json!(true);
        let exp = json!(true);
        assert_eq!(
            cmp_expected(&got, &exp), 
            true
        );
    }

    #[test]
    fn bool_unequal() {
        let got = json!(true);
        let exp = json!(false);
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn vector_equal() {
        let got = json!{["string", 1234, false, [1, 2, 3]]};
        let exp = json!{["string", 1234, false, [1, 2, 3]]};
        assert_eq!(
            cmp_expected(&got, &exp), 
            true
        );
    }

    #[test]
    fn vector_unequal_values() {
        let got = json!{["string", 1234, "false"]};
        let exp = json!{["string", 1234, false]};
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn vector_unequal_lengths_exp_longer() {
        let got = json!{["string", 1234, false, "extra"]};
        let exp = json!{["string", 1234, false]};
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn vector_unequal_lengths_got_longer() {
        let got = json!{["string", 1234, false]};
        let exp = json!{["string", 1234, false, "extra"]};
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn vector_unequal_nested() {
        let got = json!{["string", 1234, false, [1, 2, 3, "wrong"]]};
        let exp = json!{["string", 1234, false, [1, 2, 3]]};
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn object_equal() {
        let got = json!{{
            "foo": "bar",
            "baz": [
                {"first": true},
                {"second": 2, "third": Null},
            ],
        }};
        let exp = json!{{
            "foo": "bar",
            "baz": [
                {"first": true},
                {"second": 2, "third": Null},
            ],
        }};
        assert_eq!(
            cmp_expected(&got, &exp), 
            true
        );
    }

    #[test]
    fn object_equal_extra_got() {
        let got = json!{{
            "foo": "bar",
            "baz": [
                {"first": true},
                {"second": 2, "third": Null},
            ],
            "another": "field",
        }};
        let exp = json!{{
            "foo": "bar",
            "baz": [
                {"first": true},
                {"second": 2, "third": Null},
            ],
        }};
        assert_eq!(
            cmp_expected(&got, &exp), 
            true
        );
    }

    #[test]
    fn object_unequal_extra_exp() {
        let got = json!{{
            "foo": "bar",
            "baz": [
                {"first": true},
                {"second": 2, "third": Null},
            ],
        }};
        let exp = json!{{
            "foo": "bar",
            "baz": [
                {"first": true},
                {"second": 2, "third": Null},
            ],
            "another": "field",
        }};
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }

    #[test]
    fn object_unequal_values() {
        let got = json!{{
            "foo": "bar!!",
            "baz": [
                {"first": true},
                {"second": 2, "third": Null},
            ],
        }};
        let exp = json!{{
            "foo": "bar",
            "baz": [
                {"first": true},
                {"second": 2, "third": Null},
            ],
        }};
        assert_eq!(
            cmp_expected(&got, &exp), 
            false
        );
    }
}