#serde-json #json #matcher #googletest #gtest

googletest-json-serde

GoogleTest matchers for serde_json::Value

14 unstable releases (3 breaking)

Uses new Rust 2024

new 0.4.5 Dec 3, 2025
0.4.4 Nov 30, 2025
0.3.1 Nov 2, 2025
0.3.0 Oct 26, 2025
0.1.0 Sep 29, 2025

#163 in Testing

Download history 55/week @ 2025-09-23 140/week @ 2025-09-30 192/week @ 2025-10-07 347/week @ 2025-10-14 285/week @ 2025-10-21 108/week @ 2025-10-28 19/week @ 2025-11-04 16/week @ 2025-11-11 5/week @ 2025-11-18 59/week @ 2025-11-25

112 downloads per month

MIT/Apache

125KB
2.5K SLoC

Logo

A set of matcher macros for ergonomic JSON testing with googletest-rust.

These tiny, focused matchers make it effortless to assert on serde_json::Value in Rust tests.

Crates.io CI Docs.rs License

Overview

googletest-json-serde adds focused matcher macros for JSON so your Rust tests read like intent, not plumbing. It handles heterogeneous arrays, deep object patterns, path checks, and produces readable failure messages with path context.

Installation

Add as a dev-dependency:

cargo add googletest-json-serde --dev

Usage

use googletest::prelude::*;
use googletest_json_serde::json;
use serde_json::json as j;

let actual = j!({
    "vampire": { "name": "Nandor the Relentless", "age": 758, "familiar": "Guillermo" },
    "house": { "city": "Staten Island", "roommates": ["Laszlo", "Nadja", "Colin Robinson"] }
});

assert_that!(
    actual,
    json::pat!({
        "vampire": json::pat!({
            "name": starts_with("Nandor"),
            "age": gt(500),
            "familiar": eq("Guillermo"),
        }),
        "house": json::pat!({
            "city": eq("Staten Island"),
            "roommates": json::unordered_elements_are![
                eq("Laszlo"),
                eq("Nadja"),
                contains_substring("Robinson"),
            ],
        }),
        .. // allow extra fields
    })
);

Features

  • Object patterns:
    • json::matches_pattern! / json::pat! (strict or relaxed)
  • Arrays:
    • Ordered: json::elements_are!
    • Unordered: json::unordered_elements_are!
    • Contains-each: json::contains_each!
    • Contained-in: json::is_contained_in!
    • Length: json::len!
    • Apply to all elements: json::each!
  • Primitives and kinds:
    • json::primitive!, json::is_number/integer/fractional_number/whole_number/string/boolean, json::is_true/false, json::is_null, json::is_not_null, json::is_empty_array/object
  • Paths and shape:
    • json::has_paths, json::has_only_paths, json::has_path_with!
  • Optional fields:
    • json::optional!
  • Clear diagnostics that point to the failing path or element.

More Examples

Primitives

use googletest::prelude::*;
use googletest_json_serde::json;
use serde_json::json as j;

assert_that!(j!(42),         json::primitive!(gt(40_i64)));
assert_that!(j!("Laszlo"),   json::primitive!(starts_with("Las")));
assert_that!(j!(true),       json::is_true());
assert_that!(j!(null),       json::is_null());
assert_that!(j!(7),          json::is_integer());
assert_that!(j!(7.0),        json::is_whole_number());
assert_that!(j!(7.25),       json::is_fractional_number());

Path value matching

use googletest::prelude::*;
use googletest_json_serde::json;
use serde_json::json as j;

let value = j!({"user": {"id": 7, "name": "Ada"}});
assert_that!(value, json::has_path_with!("user.name", "Ada"));
assert_that!(value, json::has_path_with!("user.id", j!(7)));
assert_that!(value, json::has_path_with!("user.name", starts_with("A")));

Predicates

use googletest::prelude::*;
use googletest_json_serde::json;
use serde_json::json as j;

assert_that!(j!(42), json::predicate(|v| v.as_i64().map_or(false, |n| n > 0)));
assert_that!(j!("Energy vampire"), json::predicate(|v| v.as_str().map_or(false, |s| s.contains("Energy"))));

Objects

use googletest::prelude::*;
use googletest_json_serde::json;
use serde_json::json as j;

assert_that!(
    j!({"name": "Laszlo", "age": 310, "familiar": null}),
    json::pat!({
        "name": starts_with("Las"),
        "age": gt(300),
        "familiar": json::is_null(),
        .. // allow extras like hobbies or cursed hats
    })
);

Arrays

use googletest::prelude::*;
use googletest_json_serde::json;
use serde_json::json as j;

assert_that!(
    j!(["Nandor", 758, true]),
    json::elements_are![eq("Nandor"), json::is_number(), is_true()]
);

assert_that!(
    j!(["Laszlo", "Nadja", "Colin Robinson"]),
    json::unordered_elements_are![eq("Colin Robinson"), "Laszlo", "Nadja"]
);

assert_that!(
    j!(["familiar", 1, null]),
    json::contains_each![json::is_string(), json::is_not_null()]
);

Combined Example

use googletest::prelude::*;
use googletest_json_serde::json;
use serde_json::json as j;

assert_that!(
    j!({
        "guests": [
            {"name": "Baron Afanas", "age": 2000},
            {"name": "The Guide", "age": 500}
        ],
        "house": { "city": "Staten Island", "roommates": 4 }
    }),
    json::pat!({
        "guests": json::unordered_elements_are![
            json::pat!({ "name": starts_with("Baron"), "age": gt(1500) }),
            json::pat!({ "name": eq("The Guide"), "age": ge(400) })
        ],
        "house": json::pat!({ "city": eq("Staten Island"), "roommates": eq(4) }),
    })
);

Documentation

Contributing

License

Dual-licensed under MIT or Apache-2.0.

Dependencies

~3–5MB
~95K SLoC