googletest_json_serde/matchers/
json_matcher.rs1use crate::matchers::__internal_unstable_do_not_depend_on_these::JsonPredicateMatcher;
4
5pub fn is_null() -> JsonPredicateMatcher {
7 JsonPredicateMatcher::new(|v| v.is_null(), "JSON null", "which is not JSON null")
8}
9
10pub fn any_value() -> JsonPredicateMatcher {
12 JsonPredicateMatcher::new(
13 |v| !v.is_null(),
14 "any JSON value",
15 "which is not any JSON value",
16 )
17}
18
19pub fn is_string() -> JsonPredicateMatcher {
21 JsonPredicateMatcher::new(
22 |v| v.is_string(),
23 "a JSON string",
24 "which is not a JSON string",
25 )
26}
27
28pub fn is_number() -> JsonPredicateMatcher {
30 JsonPredicateMatcher::new(
31 |v| v.is_number(),
32 "a JSON number",
33 "which is not a JSON number",
34 )
35}
36
37pub fn is_boolean() -> JsonPredicateMatcher {
39 JsonPredicateMatcher::new(
40 |v| v.is_boolean(),
41 "a JSON boolean",
42 "which is not a JSON boolean",
43 )
44}
45
46pub fn is_array() -> JsonPredicateMatcher {
48 JsonPredicateMatcher::new(
49 |v| v.is_array(),
50 "a JSON array",
51 "which is not a JSON array",
52 )
53}
54
55pub fn is_object() -> JsonPredicateMatcher {
57 JsonPredicateMatcher::new(
58 |v| v.is_object(),
59 "a JSON object",
60 "which is not a JSON object",
61 )
62}
63
64#[doc(hidden)]
65pub mod internal {
66 use googletest::description::Description;
67 use googletest::matcher::MatcherResult::{Match, NoMatch};
68 use googletest::matcher::{Matcher, MatcherBase, MatcherResult};
69 use serde_json::Value;
70
71 #[derive(MatcherBase)]
72 pub struct JsonPredicateMatcher {
73 predicate: fn(&Value) -> bool,
74 positive_description: &'static str,
75 negative_description: &'static str,
76 }
77 impl JsonMatcher for JsonPredicateMatcher {}
78
79 impl JsonPredicateMatcher {
80 pub fn new(
81 predicate: fn(&Value) -> bool,
82 positive_description: &'static str,
83 negative_description: &'static str,
84 ) -> Self {
85 Self {
86 predicate,
87 positive_description,
88 negative_description,
89 }
90 }
91 }
92 impl Matcher<&Value> for JsonPredicateMatcher {
93 fn matches(&self, actual: &Value) -> MatcherResult {
94 match (self.predicate)(actual) {
95 true => Match,
96 false => NoMatch,
97 }
98 }
99
100 fn describe(&self, matcher_result: MatcherResult) -> Description {
101 match matcher_result {
102 Match => self.positive_description.into(),
103 NoMatch => self.negative_description.into(),
104 }
105 }
106 fn explain_match(&self, actual: &Value) -> Description {
107 let kind = match actual {
108 Value::String(_) => "a JSON string",
109 Value::Number(_) => "a JSON number",
110 Value::Bool(_) => "a JSON boolean",
111 Value::Null => "a JSON null",
112 Value::Array(_) => "a JSON array",
113 Value::Object(_) => "a JSON object",
114 };
115 Description::new().text(format!("which is {kind}"))
116 }
117 }
118
119 pub trait JsonMatcher: for<'a> Matcher<&'a Value> {}
121
122 pub trait IntoJsonMatcher<T> {
124 fn into_json_matcher(self) -> Box<dyn for<'a> Matcher<&'a Value>>;
125 }
126
127 impl<J> IntoJsonMatcher<()> for J
128 where
129 J: JsonMatcher + 'static,
130 {
131 fn into_json_matcher(self) -> Box<dyn for<'a> Matcher<&'a Value>> {
132 Box::new(self)
133 }
134 }
135}