json_matcher/
lib.rs

1//! Declarative JSON value matching for testing.
2//!
3//! This library provides a flexible way to assert that JSON values match expected patterns,
4//! supporting both exact matching and flexible matchers for common types like UUIDs, dates,
5//! and arbitrary values.
6//!
7//! # Basic Usage
8//!
9//! Use the [`assert_jm!`] macro to match JSON values against expected patterns:
10//!
11//! ```
12//! use serde_json::json;
13//! use json_matcher::assert_jm;
14//!
15//! let response = json!({
16//!     "status": "success",
17//!     "count": 42
18//! });
19//!
20//! // Exact match using inline JSON syntax
21//! assert_jm!(response, {
22//!     "status": "success",
23//!     "count": 42
24//! });
25//! ```
26//!
27//! # Using Matchers
28//!
29//! For flexible matching, use matcher types like [`AnyMatcher`], [`UuidMatcher`], or [`U16Matcher`]:
30//!
31//! ```
32//! use serde_json::json;
33//! use json_matcher::{assert_jm, AnyMatcher, UuidMatcher};
34//!
35//! let response = json!({
36//!     "id": "550e8400-e29b-41d4-a716-446655440000",
37//!     "timestamp": "2024-01-15T10:30:00Z",
38//!     "value": 123
39//! });
40//!
41//! assert_jm!(response, {
42//!     "id": UuidMatcher::new(),
43//!     "timestamp": AnyMatcher::not_null(),
44//!     "value": 123
45//! });
46//! ```
47//!
48//! # Error Reporting
49//!
50//! When assertions fail, [`assert_jm!`] reports all errors found (not just the first) and displays
51//! the actual JSON value for debugging:
52//!
53//! ```should_panic
54//! use serde_json::json;
55//! use json_matcher::{assert_jm, UuidMatcher};
56//!
57//! let response = json!({
58//!     "id": "not-a-uuid",
59//!     "name": "Alice",
60//!     "age": 25
61//! });
62//!
63//! // This will panic with a detailed error message showing:
64//! // - All validation errors ($.id and $.name mismatches)
65//! // - The full actual JSON value
66//! assert_jm!(response, {
67//!     "id": UuidMatcher::new(),
68//!     "name": "Bob",
69//!     "age": 25
70//! });
71//! // Output:
72//! // Json matcher failed:
73//! //   - $.id: Expected valid UUID format
74//! //   - $.name: Expected string "Bob" but got "Alice"
75//! //
76//! // Actual:
77//! // {
78//! //   "id": "not-a-uuid",
79//! //   "name": "Alice",
80//! //   "age": 25
81//! // }
82//! ```
83//!
84//! # Custom Matchers
85//!
86//! Create custom matchers by implementing the [`JsonMatcher`] trait:
87//!
88//! ```
89//! use serde_json::{json, Value};
90//! use json_matcher::{assert_jm, JsonMatcher, JsonMatcherError};
91//!
92//! struct OnlyVowels;
93//!
94//! impl JsonMatcher for OnlyVowels {
95//!     fn json_matches(&self, value: &Value) -> Vec<JsonMatcherError> {
96//!         match value.as_str() {
97//!             Some(s) if s.chars().all(|c| "aeiouAEIOU".contains(c)) => vec![],
98//!             Some(_) => vec![JsonMatcherError::at_root("String contains non-vowel characters")],
99//!             None => vec![JsonMatcherError::at_root("Expected string")],
100//!         }
101//!     }
102//! }
103//!
104//! let data = json!({
105//!     "sound": "aeiou",
106//!     "count": 5
107//! });
108//!
109//! assert_jm!(data, {
110//!     "sound": OnlyVowels,
111//!     "count": 5
112//! });
113//! ```
114//!
115
116mod matchers;
117pub use matchers::*;
118mod error;
119pub use error::*;
120mod json_matcher;
121pub use json_matcher::*;
122mod macros;
123mod uuid_matcher;
124pub use uuid_matcher::*;
125mod u16_matcher;
126pub use u16_matcher::*;
127
128#[cfg(feature = "datetime")]
129pub mod datetime;
130
131#[cfg(test)]
132pub mod test;