1use crate::{JsonMatcher, JsonMatcherError};
2
3pub struct U16Matcher {
4 allow_strings: bool,
5}
6
7impl Default for U16Matcher {
8 fn default() -> Self {
9 Self::new()
10 }
11}
12
13impl U16Matcher {
14 pub fn new() -> Self {
15 Self {
16 allow_strings: false,
17 }
18 }
19
20 pub fn new_allow_strings() -> Self {
21 Self {
22 allow_strings: true,
23 }
24 }
25}
26
27impl JsonMatcher for U16Matcher {
28 fn json_matches(&self, value: &serde_json::Value) -> Vec<JsonMatcherError> {
29 match self.allow_strings {
30 true => match value.as_str() {
31 Some(s) if s.parse::<u16>().is_ok() => vec![],
32 Some(_) => vec![JsonMatcherError::at_root("Expected number fitting u16")],
33 None => vec![JsonMatcherError::at_root("Expected string fitting u16")],
34 },
35 false => match value.as_i64() {
36 Some(s) if (0..=65535).contains(&s) => vec![],
37 Some(_) => vec![JsonMatcherError::at_root("Integer out of bounds for u16")],
38 None => vec![JsonMatcherError::at_root("Expected number fitting u16")],
39 },
40 }
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use crate::assert_jm;
47 use serde_json::Value;
48
49 use super::*;
50
51 #[test]
52 fn test_u16_matcher_valid_values() {
53 let get_matcher = || U16Matcher::new();
54
55 assert_jm!(Value::Number(0.into()), get_matcher());
57 assert_jm!(Value::Number(1.into()), get_matcher());
58 assert_jm!(Value::Number(65535.into()), get_matcher());
59 assert_jm!(Value::Number(32768.into()), get_matcher());
60 assert_jm!(Value::Number(100.into()), get_matcher());
61 }
62
63 #[test]
64 fn test_u16_matcher_out_of_bounds() {
65 let get_matcher = || U16Matcher::new();
66
67 assert_eq!(
69 *std::panic::catch_unwind(|| { assert_jm!(Value::Number((-1).into()), get_matcher()) })
70 .err()
71 .unwrap()
72 .downcast::<String>()
73 .unwrap(),
74 r#"
75Json matcher failed:
76 - $: Integer out of bounds for u16
77
78Actual:
79-1"#
80 );
81
82 assert_eq!(
84 *std::panic::catch_unwind(|| {
85 assert_jm!(Value::Number(65536.into()), get_matcher())
86 })
87 .err()
88 .unwrap()
89 .downcast::<String>()
90 .unwrap(),
91 r#"
92Json matcher failed:
93 - $: Integer out of bounds for u16
94
95Actual:
9665536"#
97 );
98
99 assert_eq!(
100 *std::panic::catch_unwind(|| {
101 assert_jm!(Value::Number(100000.into()), get_matcher())
102 })
103 .err()
104 .unwrap()
105 .downcast::<String>()
106 .unwrap(),
107 r#"
108Json matcher failed:
109 - $: Integer out of bounds for u16
110
111Actual:
112100000"#
113 );
114 }
115
116 #[test]
117 fn test_u16_matcher_non_numeric_values() {
118 let get_matcher = || U16Matcher::new();
119
120 assert_eq!(
122 *std::panic::catch_unwind(|| {
123 assert_jm!(Value::String("42".to_string()), get_matcher())
124 })
125 .err()
126 .unwrap()
127 .downcast::<String>()
128 .unwrap(),
129 r#"
130Json matcher failed:
131 - $: Expected number fitting u16
132
133Actual:
134"42""#
135 );
136
137 assert_eq!(
139 *std::panic::catch_unwind(|| { assert_jm!(Value::Bool(true), get_matcher()) })
140 .err()
141 .unwrap()
142 .downcast::<String>()
143 .unwrap(),
144 r#"
145Json matcher failed:
146 - $: Expected number fitting u16
147
148Actual:
149true"#
150 );
151
152 assert_eq!(
154 *std::panic::catch_unwind(|| { assert_jm!(Value::Null, get_matcher()) })
155 .err()
156 .unwrap()
157 .downcast::<String>()
158 .unwrap(),
159 r#"
160Json matcher failed:
161 - $: Expected number fitting u16
162
163Actual:
164null"#
165 );
166
167 assert_eq!(
169 *std::panic::catch_unwind(|| {
170 assert_jm!(Value::Array(vec![Value::Number(42.into())]), get_matcher())
171 })
172 .err()
173 .unwrap()
174 .downcast::<String>()
175 .unwrap(),
176 r#"
177Json matcher failed:
178 - $: Expected number fitting u16
179
180Actual:
181[
182 42
183]"#
184 );
185
186 assert_eq!(
188 *std::panic::catch_unwind(|| {
189 assert_jm!(Value::Object(serde_json::Map::new()), get_matcher())
190 })
191 .err()
192 .unwrap()
193 .downcast::<String>()
194 .unwrap(),
195 r#"
196Json matcher failed:
197 - $: Expected number fitting u16
198
199Actual:
200{}"#
201 );
202 }
203
204 #[test]
205 fn test_u16_matcher_floating_point_numbers() {
206 let get_matcher = || U16Matcher::new();
207
208 assert_eq!(
210 *std::panic::catch_unwind(|| {
211 assert_jm!(
212 Value::Number(serde_json::Number::from_f64(42.5).unwrap()),
213 get_matcher()
214 )
215 })
216 .err()
217 .unwrap()
218 .downcast::<String>()
219 .unwrap(),
220 r#"
221Json matcher failed:
222 - $: Expected number fitting u16
223
224Actual:
22542.5"#
226 );
227
228 assert_eq!(
229 *std::panic::catch_unwind(|| {
230 assert_jm!(
231 Value::Number(serde_json::Number::from_f64(0.0).unwrap()),
232 get_matcher()
233 )
234 })
235 .err()
236 .unwrap()
237 .downcast::<String>()
238 .unwrap(),
239 r#"
240Json matcher failed:
241 - $: Expected number fitting u16
242
243Actual:
2440.0"#
245 );
246 }
247
248 #[test]
249 fn test_u16_matcher_edge_cases() {
250 let get_matcher = || U16Matcher::new();
251
252 assert_jm!(Value::Number(0.into()), get_matcher());
254 assert_jm!(Value::Number(65535.into()), get_matcher());
255
256 assert_eq!(
258 *std::panic::catch_unwind(|| { assert_jm!(Value::Number((-1).into()), get_matcher()) })
259 .err()
260 .unwrap()
261 .downcast::<String>()
262 .unwrap(),
263 r#"
264Json matcher failed:
265 - $: Integer out of bounds for u16
266
267Actual:
268-1"#
269 );
270
271 assert_eq!(
272 *std::panic::catch_unwind(|| {
273 assert_jm!(Value::Number(65536.into()), get_matcher())
274 })
275 .err()
276 .unwrap()
277 .downcast::<String>()
278 .unwrap(),
279 r#"
280Json matcher failed:
281 - $: Integer out of bounds for u16
282
283Actual:
28465536"#
285 );
286 }
287
288 #[test]
289 fn test_raw_json_matches_method() {
290 let matcher = U16Matcher::new();
291
292 assert_eq!(matcher.json_matches(&Value::Number(42.into())), vec![]);
294
295 let errors = matcher.json_matches(&Value::Number((-1).into()));
297 assert_eq!(errors.len(), 1);
298 assert_eq!(errors[0].to_string(), "$: Integer out of bounds for u16");
299
300 let errors = matcher.json_matches(&Value::String("test".to_string()));
302 assert_eq!(errors.len(), 1);
303 assert_eq!(errors[0].to_string(), "$: Expected number fitting u16");
304 }
305
306 #[test]
308 fn test_u16_matcher_allow_strings_valid_values() {
309 let get_matcher = || U16Matcher::new_allow_strings();
310
311 assert_jm!(Value::String("0".to_string()), get_matcher());
313 assert_jm!(Value::String("1".to_string()), get_matcher());
314 assert_jm!(Value::String("65535".to_string()), get_matcher());
315 assert_jm!(Value::String("32768".to_string()), get_matcher());
316 assert_jm!(Value::String("100".to_string()), get_matcher());
317 assert_jm!(Value::String("42".to_string()), get_matcher());
318 }
319
320 #[test]
321 fn test_u16_matcher_allow_strings_invalid_string_values() {
322 let get_matcher = || U16Matcher::new_allow_strings();
323
324 assert_eq!(
326 *std::panic::catch_unwind(|| { assert_jm!(Value::String("-1".to_string()), get_matcher()) })
327 .err()
328 .unwrap()
329 .downcast::<String>()
330 .unwrap(),
331 r#"
332Json matcher failed:
333 - $: Expected number fitting u16
334
335Actual:
336"-1""#
337 );
338
339 assert_eq!(
341 *std::panic::catch_unwind(|| { assert_jm!(Value::String("65536".to_string()), get_matcher()) })
342 .err()
343 .unwrap()
344 .downcast::<String>()
345 .unwrap(),
346 r#"
347Json matcher failed:
348 - $: Expected number fitting u16
349
350Actual:
351"65536""#
352 );
353
354 assert_eq!(
355 *std::panic::catch_unwind(|| { assert_jm!(Value::String("100000".to_string()), get_matcher()) })
356 .err()
357 .unwrap()
358 .downcast::<String>()
359 .unwrap(),
360 r#"
361Json matcher failed:
362 - $: Expected number fitting u16
363
364Actual:
365"100000""#
366 );
367
368 assert_eq!(
370 *std::panic::catch_unwind(|| { assert_jm!(Value::String("hello".to_string()), get_matcher()) })
371 .err()
372 .unwrap()
373 .downcast::<String>()
374 .unwrap(),
375 r#"
376Json matcher failed:
377 - $: Expected number fitting u16
378
379Actual:
380"hello""#
381 );
382
383 assert_eq!(
384 *std::panic::catch_unwind(|| { assert_jm!(Value::String("".to_string()), get_matcher()) })
385 .err()
386 .unwrap()
387 .downcast::<String>()
388 .unwrap(),
389 r#"
390Json matcher failed:
391 - $: Expected number fitting u16
392
393Actual:
394"""#
395 );
396
397 assert_eq!(
399 *std::panic::catch_unwind(|| { assert_jm!(Value::String("42.5".to_string()), get_matcher()) })
400 .err()
401 .unwrap()
402 .downcast::<String>()
403 .unwrap(),
404 r#"
405Json matcher failed:
406 - $: Expected number fitting u16
407
408Actual:
409"42.5""#
410 );
411
412 assert_eq!(
414 *std::panic::catch_unwind(|| { assert_jm!(Value::String(" 42 ".to_string()), get_matcher()) })
415 .err()
416 .unwrap()
417 .downcast::<String>()
418 .unwrap(),
419 r#"
420Json matcher failed:
421 - $: Expected number fitting u16
422
423Actual:
424" 42 ""#
425 );
426
427 assert_jm!(Value::String("0042".to_string()), get_matcher());
429 assert_jm!(Value::String("00000".to_string()), get_matcher());
430 }
431
432 #[test]
433 fn test_u16_matcher_allow_strings_non_string_values() {
434 let get_matcher = || U16Matcher::new_allow_strings();
435
436 assert_eq!(
438 *std::panic::catch_unwind(|| { assert_jm!(Value::Number(42.into()), get_matcher()) })
439 .err()
440 .unwrap()
441 .downcast::<String>()
442 .unwrap(),
443 r#"
444Json matcher failed:
445 - $: Expected string fitting u16
446
447Actual:
44842"#
449 );
450
451 assert_eq!(
453 *std::panic::catch_unwind(|| { assert_jm!(Value::Bool(true), get_matcher()) })
454 .err()
455 .unwrap()
456 .downcast::<String>()
457 .unwrap(),
458 r#"
459Json matcher failed:
460 - $: Expected string fitting u16
461
462Actual:
463true"#
464 );
465
466 assert_eq!(
468 *std::panic::catch_unwind(|| { assert_jm!(Value::Null, get_matcher()) })
469 .err()
470 .unwrap()
471 .downcast::<String>()
472 .unwrap(),
473 r#"
474Json matcher failed:
475 - $: Expected string fitting u16
476
477Actual:
478null"#
479 );
480
481 assert_eq!(
483 *std::panic::catch_unwind(|| { assert_jm!(Value::Array(vec![Value::String("42".to_string())]), get_matcher()) })
484 .err()
485 .unwrap()
486 .downcast::<String>()
487 .unwrap(),
488 r#"
489Json matcher failed:
490 - $: Expected string fitting u16
491
492Actual:
493[
494 "42"
495]"#
496 );
497
498 assert_eq!(
500 *std::panic::catch_unwind(|| {
501 assert_jm!(Value::Object(serde_json::Map::new()), get_matcher())
502 })
503 .err()
504 .unwrap()
505 .downcast::<String>()
506 .unwrap(),
507 r#"
508Json matcher failed:
509 - $: Expected string fitting u16
510
511Actual:
512{}"#
513 );
514 }
515
516 #[test]
517 fn test_u16_matcher_allow_strings_edge_cases() {
518 let get_matcher = || U16Matcher::new_allow_strings();
519
520 assert_jm!(Value::String("0".to_string()), get_matcher());
522 assert_jm!(Value::String("65535".to_string()), get_matcher());
523
524 assert_eq!(
526 *std::panic::catch_unwind(|| { assert_jm!(Value::String("-1".to_string()), get_matcher()) })
527 .err()
528 .unwrap()
529 .downcast::<String>()
530 .unwrap(),
531 r#"
532Json matcher failed:
533 - $: Expected number fitting u16
534
535Actual:
536"-1""#
537 );
538
539 assert_eq!(
540 *std::panic::catch_unwind(|| { assert_jm!(Value::String("65536".to_string()), get_matcher()) })
541 .err()
542 .unwrap()
543 .downcast::<String>()
544 .unwrap(),
545 r#"
546Json matcher failed:
547 - $: Expected number fitting u16
548
549Actual:
550"65536""#
551 );
552 }
553
554 #[test]
555 fn test_u16_matcher_allow_strings_raw_method() {
556 let matcher = U16Matcher::new_allow_strings();
557
558 assert_eq!(
560 matcher.json_matches(&Value::String("42".to_string())),
561 vec![]
562 );
563
564 let errors = matcher.json_matches(&Value::String("invalid".to_string()));
566 assert_eq!(errors.len(), 1);
567 assert_eq!(errors[0].to_string(), "$: Expected number fitting u16");
568
569 let errors = matcher.json_matches(&Value::Number(42.into()));
571 assert_eq!(errors.len(), 1);
572 assert_eq!(errors[0].to_string(), "$: Expected string fitting u16");
573 }
574
575 #[test]
576 fn test_u16_matcher_modes_comparison() {
577 let number_matcher = U16Matcher::new();
578 let string_matcher = U16Matcher::new_allow_strings();
579
580 assert_eq!(number_matcher.json_matches(&Value::Number(42.into())), vec![]);
582 assert_eq!(string_matcher.json_matches(&Value::Number(42.into())).len(), 1);
583
584 assert_eq!(string_matcher.json_matches(&Value::String("42".to_string())), vec![]);
586 assert_eq!(number_matcher.json_matches(&Value::String("42".to_string())).len(), 1);
587
588 assert_eq!(number_matcher.json_matches(&Value::String("invalid".to_string())).len(), 1);
590 assert_eq!(string_matcher.json_matches(&Value::String("invalid".to_string())).len(), 1);
591 assert_eq!(number_matcher.json_matches(&Value::Number((-1).into())).len(), 1);
592 assert_eq!(string_matcher.json_matches(&Value::String("-1".to_string())).len(), 1);
593 }
594}