googletest_json_serde/matchers/
value_matcher.rs1#[macro_export]
24#[doc(hidden)]
25macro_rules! __json_value {
26 ($matcher:expr) => {
27 $crate::matchers::__internal_unstable_do_not_depend_on_these::JsonValueMatcher::new(
28 $matcher,
29 )
30 };
31}
32
33pub fn is_null() -> crate::matchers::__internal_unstable_do_not_depend_on_these::IsJsonNull {
34 crate::matchers::__internal_unstable_do_not_depend_on_these::IsJsonNull
35}
36
37#[doc(hidden)]
38pub mod internal {
39 use googletest::description::Description;
40 use googletest::matcher::{Matcher, MatcherBase, MatcherResult};
41 use serde_json::Value;
42
43 #[doc(hidden)]
44 #[derive(MatcherBase)]
45 pub struct JsonValueMatcher<M, T> {
46 inner: M,
47 phantom: std::marker::PhantomData<T>,
48 }
49
50 impl<M, T> JsonValueMatcher<M, T> {
51 pub fn new(inner: M) -> Self {
52 Self {
53 inner,
54 phantom: std::marker::PhantomData,
55 }
56 }
57 }
58
59 impl<M> Matcher<&Value> for JsonValueMatcher<M, String>
60 where
61 M: for<'a> Matcher<&'a str>,
62 {
63 fn matches(&self, actual: &Value) -> MatcherResult {
64 match actual {
65 Value::String(s) => self.inner.matches(s),
66 _ => MatcherResult::NoMatch,
67 }
68 }
69 fn describe(&self, r: MatcherResult) -> Description {
70 self.inner.describe(r)
71 }
72 fn explain_match(&self, actual: &Value) -> Description {
73 match actual {
74 Value::String(s) => self.inner.explain_match(s),
75 _ => Description::new().text("which is not a JSON string".to_string()),
76 }
77 }
78 }
79
80 impl<M> Matcher<&Value> for JsonValueMatcher<M, i64>
81 where
82 M: Matcher<i64>,
83 {
84 fn matches(&self, actual: &Value) -> MatcherResult {
85 match actual {
86 Value::Number(n) => n
87 .as_i64()
88 .map_or(MatcherResult::NoMatch, |i| self.inner.matches(i)),
89 _ => MatcherResult::NoMatch,
90 }
91 }
92 fn describe(&self, r: MatcherResult) -> Description {
93 self.inner.describe(r)
94 }
95 fn explain_match(&self, actual: &Value) -> Description {
96 match actual {
97 Value::Number(n) => match n.as_i64() {
98 Some(i) => self.inner.explain_match(i),
99 None => Description::new().text(format!("number out of i64 range: {n}")),
100 },
101 _ => Description::new().text("which is not a JSON number"),
102 }
103 }
104 }
105
106 impl<M> Matcher<&Value> for JsonValueMatcher<M, f64>
107 where
108 M: Matcher<f64>,
109 {
110 fn matches(&self, actual: &Value) -> MatcherResult {
111 match actual {
112 Value::Number(n) => n
113 .as_f64()
114 .map_or(MatcherResult::NoMatch, |f| self.inner.matches(f)),
115 _ => MatcherResult::NoMatch,
116 }
117 }
118 fn describe(&self, r: MatcherResult) -> Description {
119 self.inner.describe(r)
120 }
121 fn explain_match(&self, actual: &Value) -> Description {
122 match actual {
123 Value::Number(n) => match n.as_f64() {
124 Some(f) => self.inner.explain_match(f),
125 None => Description::new().text(format!("number not convertible to f64: {n}")),
126 },
127 _ => Description::new().text("which is not a JSON number"),
128 }
129 }
130 }
131
132 impl<M> Matcher<&Value> for JsonValueMatcher<M, bool>
133 where
134 M: Matcher<bool>,
135 {
136 fn matches(&self, actual: &Value) -> MatcherResult {
137 match actual {
138 Value::Bool(b) => self.inner.matches(*b),
139 _ => MatcherResult::NoMatch,
140 }
141 }
142 fn describe(&self, r: MatcherResult) -> Description {
143 self.inner.describe(r)
144 }
145 fn explain_match(&self, actual: &Value) -> Description {
146 match actual {
147 Value::Bool(b) => self.inner.explain_match(*b),
148 _ => Description::new().text("which is not a JSON boolean"),
149 }
150 }
151 }
152
153 #[derive(MatcherBase)]
154 pub struct IsJsonNull;
155 impl Matcher<&Value> for IsJsonNull {
156 fn matches(&self, actual: &Value) -> MatcherResult {
157 match actual {
158 Value::Null => MatcherResult::Match,
159 _ => MatcherResult::NoMatch,
160 }
161 }
162
163 fn describe(&self, _: MatcherResult) -> Description {
164 Description::new().text("JSON null")
165 }
166
167 fn explain_match(&self, actual: &Value) -> Description {
168 match actual {
169 Value::Null => Description::new().text("which is null"),
170 _ => Description::new().text("which is not JSON null"),
171 }
172 }
173 }
174}