googletest_json_serde/matchers/
primitive_matcher.rs1#[deprecated(since = "0.2.0", note = "please use `json::primitive!` instead")]
24#[macro_export]
25#[doc(hidden)]
26macro_rules! __json_value {
27 ($matcher:expr) => {
28 $crate::__json_primitive!($matcher)
29 };
30}
31
32#[macro_export]
53#[doc(hidden)]
54macro_rules! __json_primitive {
55 ($matcher:expr) => {
56 $crate::matchers::__internal_unstable_do_not_depend_on_these::JsonPrimitiveMatcher::new(
57 $matcher,
58 )
59 };
60}
61
62#[doc(hidden)]
63pub mod internal {
64 use crate::matchers::json_matcher::internal::{IntoJsonMatcher, JsonMatcher};
65 use googletest::description::Description;
66 use googletest::matcher::{Matcher, MatcherBase, MatcherResult};
67 use serde_json::Value;
68
69 #[doc(hidden)]
70 #[derive(MatcherBase)]
71 pub struct JsonPrimitiveMatcher<M, T> {
72 inner: M,
73 phantom: std::marker::PhantomData<T>,
74 }
75
76 impl<M, T> JsonPrimitiveMatcher<M, T> {
77 pub fn new(inner: M) -> Self {
78 Self {
79 inner,
80 phantom: std::marker::PhantomData,
81 }
82 }
83 }
84
85 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, String>
86 where
87 M: for<'a> Matcher<&'a str>,
88 {
89 fn matches(&self, actual: &Value) -> MatcherResult {
90 match actual {
91 Value::String(s) => self.inner.matches(s),
92 _ => MatcherResult::NoMatch,
93 }
94 }
95 fn describe(&self, r: MatcherResult) -> Description {
96 self.inner.describe(r)
97 }
98 fn explain_match(&self, actual: &Value) -> Description {
99 match actual {
100 Value::String(s) => self.inner.explain_match(s),
101 _ => Description::new().text("which is not a JSON string".to_string()),
102 }
103 }
104 }
105
106 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, i64>
107 where
108 M: Matcher<i64>,
109 {
110 fn matches(&self, actual: &Value) -> MatcherResult {
111 match actual {
112 Value::Number(n) => n
113 .as_i64()
114 .map_or(MatcherResult::NoMatch, |i| self.inner.matches(i)),
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_i64() {
124 Some(i) => self.inner.explain_match(i),
125 None => Description::new().text(format!("number out of i64 range: {n}")),
126 },
127 _ => Description::new().text("which is not a JSON number"),
128 }
129 }
130 }
131
132 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, f64>
133 where
134 M: Matcher<f64>,
135 {
136 fn matches(&self, actual: &Value) -> MatcherResult {
137 match actual {
138 Value::Number(n) => n
139 .as_f64()
140 .map_or(MatcherResult::NoMatch, |f| self.inner.matches(f)),
141 _ => MatcherResult::NoMatch,
142 }
143 }
144 fn describe(&self, r: MatcherResult) -> Description {
145 self.inner.describe(r)
146 }
147 fn explain_match(&self, actual: &Value) -> Description {
148 match actual {
149 Value::Number(n) => match n.as_f64() {
150 Some(f) => self.inner.explain_match(f),
151 None => Description::new().text(format!("number not convertible to f64: {n}")),
152 },
153 _ => Description::new().text("which is not a JSON number"),
154 }
155 }
156 }
157
158 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, bool>
159 where
160 M: Matcher<bool>,
161 {
162 fn matches(&self, actual: &Value) -> MatcherResult {
163 match actual {
164 Value::Bool(b) => self.inner.matches(*b),
165 _ => MatcherResult::NoMatch,
166 }
167 }
168 fn describe(&self, r: MatcherResult) -> Description {
169 self.inner.describe(r)
170 }
171 fn explain_match(&self, actual: &Value) -> Description {
172 match actual {
173 Value::Bool(b) => self.inner.explain_match(*b),
174 _ => Description::new().text("which is not a JSON boolean"),
175 }
176 }
177 }
178
179 impl<M, T> JsonMatcher for JsonPrimitiveMatcher<M, T> where
180 JsonPrimitiveMatcher<M, T>: for<'a> Matcher<&'a Value>
181 {
182 }
183
184 impl<M> IntoJsonMatcher<i64> for M
186 where
187 M: Matcher<i64> + 'static,
188 {
189 fn into_json_matcher(self) -> Box<dyn for<'a> Matcher<&'a Value>> {
190 Box::new(JsonPrimitiveMatcher::<M, i64>::new(self))
191 }
192 }
193
194 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, u64>
195 where
196 M: Matcher<u64>,
197 {
198 fn matches(&self, actual: &Value) -> MatcherResult {
199 match actual {
200 Value::Number(n) => n
201 .as_u64()
202 .map_or(MatcherResult::NoMatch, |u| self.inner.matches(u)),
203 _ => MatcherResult::NoMatch,
204 }
205 }
206 fn describe(&self, r: MatcherResult) -> Description {
207 self.inner.describe(r)
208 }
209 fn explain_match(&self, actual: &Value) -> Description {
210 match actual {
211 Value::Number(n) => match n.as_u64() {
212 Some(u) => self.inner.explain_match(u),
213 None => Description::new().text(format!("number out of u64 range: {n}")),
214 },
215 _ => Description::new().text("which is not a JSON number"),
216 }
217 }
218 }
219
220 impl<M> IntoJsonMatcher<u64> for M
221 where
222 M: Matcher<u64> + 'static,
223 {
224 fn into_json_matcher(self) -> Box<dyn for<'a> Matcher<&'a Value>> {
225 Box::new(JsonPrimitiveMatcher::<M, u64>::new(self))
226 }
227 }
228
229 impl<M> IntoJsonMatcher<f64> for M
230 where
231 M: Matcher<f64> + 'static,
232 {
233 fn into_json_matcher(self) -> Box<dyn for<'a> Matcher<&'a Value>> {
234 Box::new(JsonPrimitiveMatcher::<M, f64>::new(self))
235 }
236 }
237
238 impl<M> IntoJsonMatcher<String> for M
239 where
240 M: for<'a> Matcher<&'a str> + 'static,
241 {
242 fn into_json_matcher(self) -> Box<dyn for<'a> Matcher<&'a Value>> {
243 Box::new(JsonPrimitiveMatcher::<M, String>::new(self))
244 }
245 }
246
247 impl<M> IntoJsonMatcher<bool> for M
248 where
249 M: Matcher<bool> + 'static,
250 {
251 fn into_json_matcher(self) -> Box<dyn for<'a> Matcher<&'a Value>> {
252 Box::new(JsonPrimitiveMatcher::<M, bool>::new(self))
253 }
254 }
255
256 impl<M> Matcher<&Value> for JsonPrimitiveMatcher<M, i32>
257 where
258 M: Matcher<i32>,
259 {
260 fn matches(&self, actual: &Value) -> MatcherResult {
261 match actual {
262 Value::Number(n) => match n.as_i64() {
263 Some(i) => match i32::try_from(i) {
264 Ok(i32_val) => self.inner.matches(i32_val),
265 Err(_) => MatcherResult::NoMatch,
266 },
267 None => MatcherResult::NoMatch,
268 },
269 _ => MatcherResult::NoMatch,
270 }
271 }
272 fn describe(&self, r: MatcherResult) -> Description {
273 self.inner.describe(r)
274 }
275 fn explain_match(&self, actual: &Value) -> Description {
276 match actual {
277 Value::Number(n) => match n.as_i64() {
278 Some(i) => match i32::try_from(i) {
279 Ok(i32_val) => self.inner.explain_match(i32_val),
280 Err(_) => Description::new().text(format!("number out of i32 range: {n}")),
281 },
282 None => Description::new().text(format!("number out of i64 range: {n}")),
283 },
284 _ => Description::new().text("which is not a JSON number"),
285 }
286 }
287 }
288
289 impl<M> IntoJsonMatcher<i32> for M
290 where
291 M: Matcher<i32> + 'static,
292 {
293 fn into_json_matcher(self) -> Box<dyn for<'a> Matcher<&'a Value>> {
294 Box::new(JsonPrimitiveMatcher::<M, i32>::new(self))
295 }
296 }
297}