expect_json/
json_integer.rs

1use serde::Deserialize;
2use serde::Serialize;
3use std::fmt::Display;
4use std::fmt::Formatter;
5use std::fmt::Result as FmtResult;
6
7/// Json integers can be i64 or u64, which cover different ranges.
8/// This is a type representing those numbers.
9#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
10#[serde(untagged)]
11pub enum JsonInteger {
12    Positive(u64),
13    Negative(i64),
14}
15
16impl JsonInteger {
17    pub(crate) fn gt<O>(self, other: O) -> bool
18    where
19        O: Into<JsonInteger>,
20    {
21        let other_json = other.into();
22        match (self, other_json) {
23            (Self::Positive(l), Self::Positive(r)) => l > r,
24            (Self::Positive(l), Self::Negative(r)) => {
25                if r < 0 {
26                    return true;
27                }
28
29                l > (r as u64)
30            }
31            (Self::Negative(l), Self::Negative(r)) => l > r,
32            (Self::Negative(l), Self::Positive(r)) => {
33                if l < 0 {
34                    return false;
35                }
36
37                (l as u64) > r
38            }
39        }
40    }
41
42    pub(crate) fn ge<O>(self, other: O) -> bool
43    where
44        O: Into<JsonInteger>,
45    {
46        let other_json = other.into();
47        match (self, other_json) {
48            (Self::Positive(l), Self::Positive(r)) => l >= r,
49            (Self::Positive(l), Self::Negative(r)) => {
50                if r < 0 {
51                    return true;
52                }
53
54                l >= (r as u64)
55            }
56            (Self::Negative(l), Self::Negative(r)) => l >= r,
57            (Self::Negative(l), Self::Positive(r)) => {
58                if l < 0 {
59                    return false;
60                }
61
62                (l as u64) >= r
63            }
64        }
65    }
66
67    pub(crate) fn lt<O>(self, other: O) -> bool
68    where
69        O: Into<JsonInteger>,
70    {
71        let other_json = other.into();
72        match (self, other_json) {
73            (Self::Positive(l), Self::Positive(r)) => l < r,
74            (Self::Positive(l), Self::Negative(r)) => {
75                if r < 0 {
76                    return false;
77                }
78
79                l < (r as u64)
80            }
81            (Self::Negative(l), Self::Negative(r)) => l < r,
82            (Self::Negative(l), Self::Positive(r)) => {
83                if l < 0 {
84                    return true;
85                }
86
87                (l as u64) < r
88            }
89        }
90    }
91
92    pub(crate) fn le<O>(self, other: O) -> bool
93    where
94        O: Into<JsonInteger>,
95    {
96        let other_json = other.into();
97        match (self, other_json) {
98            (Self::Positive(l), Self::Positive(r)) => l <= r,
99            (Self::Positive(l), Self::Negative(r)) => {
100                if r < 0 {
101                    return false;
102                }
103
104                l <= (r as u64)
105            }
106            (Self::Negative(l), Self::Negative(r)) => l <= r,
107            (Self::Negative(l), Self::Positive(r)) => {
108                if l < 0 {
109                    return true;
110                }
111
112                (l as u64) <= r
113            }
114        }
115    }
116}
117
118impl Display for JsonInteger {
119    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
120        match *self {
121            Self::Positive(n) => write!(f, "{n}"),
122            Self::Negative(n) => write!(f, "{n}"),
123        }
124    }
125}
126
127impl From<u8> for JsonInteger {
128    fn from(n: u8) -> Self {
129        Self::Positive(n as u64)
130    }
131}
132
133impl From<i8> for JsonInteger {
134    fn from(n: i8) -> Self {
135        Self::Negative(n as i64)
136    }
137}
138
139impl From<u16> for JsonInteger {
140    fn from(n: u16) -> Self {
141        Self::Positive(n as u64)
142    }
143}
144
145impl From<i16> for JsonInteger {
146    fn from(n: i16) -> Self {
147        Self::Negative(n as i64)
148    }
149}
150
151impl From<u32> for JsonInteger {
152    fn from(n: u32) -> Self {
153        Self::Positive(n as u64)
154    }
155}
156
157impl From<i32> for JsonInteger {
158    fn from(n: i32) -> Self {
159        Self::Negative(n as i64)
160    }
161}
162
163impl From<u64> for JsonInteger {
164    fn from(n: u64) -> Self {
165        Self::Positive(n)
166    }
167}
168
169impl From<i64> for JsonInteger {
170    fn from(n: i64) -> Self {
171        Self::Negative(n)
172    }
173}
174
175impl From<usize> for JsonInteger {
176    fn from(n: usize) -> Self {
177        Self::Positive(n as u64)
178    }
179}
180
181impl From<isize> for JsonInteger {
182    fn from(n: isize) -> Self {
183        Self::Negative(n as i64)
184    }
185}
186
187#[cfg(test)]
188mod test_from {
189    use super::*;
190    use pretty_assertions::assert_eq;
191
192    #[test]
193    fn it_should_contain_value_from_i8() {
194        let output = JsonInteger::from(-123_i8);
195        assert_eq!(output, JsonInteger::Negative(-123));
196    }
197
198    #[test]
199    fn it_should_contain_value_from_u8() {
200        let output = JsonInteger::from(123_u8);
201        assert_eq!(output, JsonInteger::Positive(123));
202    }
203
204    #[test]
205    fn it_should_contain_value_from_i16() {
206        let output = JsonInteger::from(-123_i16);
207        assert_eq!(output, JsonInteger::Negative(-123));
208    }
209
210    #[test]
211    fn it_should_contain_value_from_u16() {
212        let output = JsonInteger::from(123_u16);
213        assert_eq!(output, JsonInteger::Positive(123));
214    }
215
216    #[test]
217    fn it_should_contain_value_from_i32() {
218        let output = JsonInteger::from(-123_i32);
219        assert_eq!(output, JsonInteger::Negative(-123));
220    }
221
222    #[test]
223    fn it_should_contain_value_from_u32() {
224        let output = JsonInteger::from(123_u32);
225        assert_eq!(output, JsonInteger::Positive(123));
226    }
227
228    #[test]
229    fn it_should_contain_value_from_i64() {
230        let output = JsonInteger::from(-123_i64);
231        assert_eq!(output, JsonInteger::Negative(-123));
232    }
233
234    #[test]
235    fn it_should_contain_value_from_u64() {
236        let output = JsonInteger::from(123_u64);
237        assert_eq!(output, JsonInteger::Positive(123));
238    }
239
240    #[test]
241    fn it_should_contain_value_from_isize() {
242        let output = JsonInteger::from(-123_isize);
243        assert_eq!(output, JsonInteger::Negative(-123));
244    }
245
246    #[test]
247    fn it_should_contain_value_from_usize() {
248        let output = JsonInteger::from(123_usize);
249        assert_eq!(output, JsonInteger::Positive(123));
250    }
251}
252
253#[cfg(test)]
254mod test_fmt {
255    use super::*;
256
257    #[test]
258    fn it_should_print_positive_numbers_as_themselves() {
259        let num = JsonInteger::Positive(123);
260        let output = num.to_string();
261
262        assert_eq!(output, "123")
263    }
264
265    #[test]
266    fn it_should_print_negative_numbers_as_themselves() {
267        let num = JsonInteger::Negative(-123);
268        let output = num.to_string();
269
270        assert_eq!(output, "-123")
271    }
272}
273
274#[cfg(test)]
275mod test_lt {
276    use super::*;
277    use rstest::rstest;
278
279    #[rstest]
280    #[case(101, 100, false)]
281    #[case(100, 100, false)]
282    #[case(99, 100, true)]
283    fn it_should_handle_u64_to_u64_correctly(
284        #[case] l_num: u64,
285        #[case] r_num: u64,
286        #[case] expected: bool,
287    ) {
288        let l = JsonInteger::from(l_num);
289        let r = JsonInteger::from(r_num);
290        assert_eq!(
291            l.lt(r),
292            expected,
293            "{l_num} < {r_num} was expected to be {expected}"
294        );
295    }
296
297    #[rstest]
298    #[case(101, 100, false)]
299    #[case(100, 100, false)]
300    #[case(99, 100, true)]
301    #[case(-101, -100, true)]
302    #[case(-100, -100, false)]
303    #[case(-99, -100, false)]
304    fn it_should_handle_i64_to_i64_correctly(
305        #[case] l_num: i64,
306        #[case] r_num: i64,
307        #[case] expected: bool,
308    ) {
309        let l = JsonInteger::from(l_num);
310        let r = JsonInteger::from(r_num);
311        assert_eq!(
312            l.lt(r),
313            expected,
314            "{l_num} < {r_num} was expected to be {expected}"
315        );
316    }
317
318    #[rstest]
319    #[case(101, 100, false)]
320    #[case(100, 100, false)]
321    #[case(99, 100, true)]
322    #[case(0, 0, false)]
323    #[case(-0, 0, false)]
324    #[case(-1, 0, true)]
325    fn it_should_handle_i64_to_u64_correctly(
326        #[case] l_num: i64,
327        #[case] r_num: u64,
328        #[case] expected: bool,
329    ) {
330        let l = JsonInteger::from(l_num);
331        let r = JsonInteger::from(r_num);
332        assert_eq!(
333            l.lt(r),
334            expected,
335            "{l_num} < {r_num} was expected to be {expected}"
336        );
337    }
338
339    #[rstest]
340    #[case(101, 100, false)]
341    #[case(100, 100, false)]
342    #[case(99, 100, true)]
343    #[case(0, 0, false)]
344    #[case(0, -0, false)]
345    #[case(0, -1, false)]
346    fn it_should_handle_u64_to_i64_correctly(
347        #[case] l_num: u64,
348        #[case] r_num: i64,
349        #[case] expected: bool,
350    ) {
351        let l = JsonInteger::from(l_num);
352        let r = JsonInteger::from(r_num);
353        assert_eq!(
354            l.lt(r),
355            expected,
356            "{l_num} < {r_num} was expected to be {expected}"
357        );
358    }
359}
360
361#[cfg(test)]
362mod test_le {
363    use super::*;
364    use rstest::rstest;
365
366    #[rstest]
367    #[case(101, 100, false)]
368    #[case(100, 100, true)]
369    #[case(99, 100, true)]
370    fn it_should_handle_u64_to_u64_correctly(
371        #[case] l_num: u64,
372        #[case] r_num: u64,
373        #[case] expected: bool,
374    ) {
375        let l = JsonInteger::from(l_num);
376        let r = JsonInteger::from(r_num);
377        assert_eq!(
378            l.le(r),
379            expected,
380            "{l_num} <= {r_num} was expected to be {expected}"
381        );
382    }
383
384    #[rstest]
385    #[case(101, 100, false)]
386    #[case(100, 100, true)]
387    #[case(99, 100, true)]
388    #[case(-101, -100, true)]
389    #[case(-100, -100, true)]
390    #[case(-99, -100, false)]
391    fn it_should_handle_i64_to_i64_correctly(
392        #[case] l_num: i64,
393        #[case] r_num: i64,
394        #[case] expected: bool,
395    ) {
396        let l = JsonInteger::from(l_num);
397        let r = JsonInteger::from(r_num);
398        assert_eq!(
399            l.le(r),
400            expected,
401            "{l_num} <= {r_num} was expected to be {expected}"
402        );
403    }
404
405    #[rstest]
406    #[case(101, 100, false)]
407    #[case(100, 100, true)]
408    #[case(99, 100, true)]
409    #[case(0, 0, true)]
410    #[case(-0, 0, true)]
411    #[case(-1, 0, true)]
412    fn it_should_handle_i64_to_u64_correctly(
413        #[case] l_num: i64,
414        #[case] r_num: u64,
415        #[case] expected: bool,
416    ) {
417        let l = JsonInteger::from(l_num);
418        let r = JsonInteger::from(r_num);
419        assert_eq!(
420            l.le(r),
421            expected,
422            "{l_num} <= {r_num} was expected to be {expected}"
423        );
424    }
425
426    #[rstest]
427    #[case(101, 100, false)]
428    #[case(100, 100, true)]
429    #[case(99, 100, true)]
430    #[case(0, 0, true)]
431    #[case(0, -0, true)]
432    #[case(0, -1, false)]
433    fn it_should_handle_u64_to_i64_correctly(
434        #[case] l_num: u64,
435        #[case] r_num: i64,
436        #[case] expected: bool,
437    ) {
438        let l = JsonInteger::from(l_num);
439        let r = JsonInteger::from(r_num);
440        assert_eq!(
441            l.le(r),
442            expected,
443            "{l_num} <= {r_num} was expected to be {expected}"
444        );
445    }
446}
447
448#[cfg(test)]
449mod test_gt {
450    use super::*;
451    use rstest::rstest;
452
453    #[rstest]
454    #[case(101, 100, true)]
455    #[case(100, 100, false)]
456    #[case(99, 100, false)]
457    fn it_should_handle_u64_to_u64_correctly(
458        #[case] l_num: u64,
459        #[case] r_num: u64,
460        #[case] expected: bool,
461    ) {
462        let l = JsonInteger::from(l_num);
463        let r = JsonInteger::from(r_num);
464        assert_eq!(
465            l.gt(r),
466            expected,
467            "{l_num} > {r_num} was expected to be {expected}"
468        );
469    }
470
471    #[rstest]
472    #[case(101, 100, true)]
473    #[case(100, 100, false)]
474    #[case(99, 100, false)]
475    #[case(-101, -100, false)]
476    #[case(-100, -100, false)]
477    #[case(-99, -100, true)]
478    fn it_should_handle_i64_to_i64_correctly(
479        #[case] l_num: i64,
480        #[case] r_num: i64,
481        #[case] expected: bool,
482    ) {
483        let l = JsonInteger::from(l_num);
484        let r = JsonInteger::from(r_num);
485        assert_eq!(
486            l.gt(r),
487            expected,
488            "{l_num} > {r_num} was expected to be {expected}"
489        );
490    }
491
492    #[rstest]
493    #[case(101, 100, true)]
494    #[case(100, 100, false)]
495    #[case(99, 100, false)]
496    #[case(0, 0, false)]
497    #[case(-0, 0, false)]
498    #[case(-1, 0, false)]
499    fn it_should_handle_i64_to_u64_correctly(
500        #[case] l_num: i64,
501        #[case] r_num: u64,
502        #[case] expected: bool,
503    ) {
504        let l = JsonInteger::from(l_num);
505        let r = JsonInteger::from(r_num);
506        assert_eq!(
507            l.gt(r),
508            expected,
509            "{l_num} > {r_num} was expected to be {expected}"
510        );
511    }
512
513    #[rstest]
514    #[case(101, 100, true)]
515    #[case(100, 100, false)]
516    #[case(99, 100, false)]
517    #[case(0, 0, false)]
518    #[case(0, -0, false)]
519    #[case(0, -1, true)]
520    fn it_should_handle_u64_to_i64_correctly(
521        #[case] l_num: u64,
522        #[case] r_num: i64,
523        #[case] expected: bool,
524    ) {
525        let l = JsonInteger::from(l_num);
526        let r = JsonInteger::from(r_num);
527        assert_eq!(
528            l.gt(r),
529            expected,
530            "{l_num} > {r_num} was expected to be {expected}"
531        );
532    }
533}
534
535#[cfg(test)]
536mod test_ge {
537    use super::*;
538    use rstest::rstest;
539
540    #[rstest]
541    #[case(101, 100, true)]
542    #[case(100, 100, true)]
543    #[case(99, 100, false)]
544    fn it_should_handle_u64_to_u64_correctly(
545        #[case] l_num: u64,
546        #[case] r_num: u64,
547        #[case] expected: bool,
548    ) {
549        let l = JsonInteger::from(l_num);
550        let r = JsonInteger::from(r_num);
551        assert_eq!(
552            l.ge(r),
553            expected,
554            "{l_num} >= {r_num} was expected to be {expected}"
555        );
556    }
557
558    #[rstest]
559    #[case(101, 100, true)]
560    #[case(100, 100, true)]
561    #[case(99, 100, false)]
562    #[case(-101, -100, false)]
563    #[case(-100, -100, true)]
564    #[case(-99, -100, true)]
565    fn it_should_handle_i64_to_i64_correctly(
566        #[case] l_num: i64,
567        #[case] r_num: i64,
568        #[case] expected: bool,
569    ) {
570        let l = JsonInteger::from(l_num);
571        let r = JsonInteger::from(r_num);
572        assert_eq!(
573            l.ge(r),
574            expected,
575            "{l_num} >= {r_num} was expected to be {expected}"
576        );
577    }
578
579    #[rstest]
580    #[case(101, 100, true)]
581    #[case(100, 100, true)]
582    #[case(99, 100, false)]
583    #[case(0, 0, true)]
584    #[case(-0, 0, true)]
585    #[case(-1, 0, false)]
586    fn it_should_handle_i64_to_u64_correctly(
587        #[case] l_num: i64,
588        #[case] r_num: u64,
589        #[case] expected: bool,
590    ) {
591        let l = JsonInteger::from(l_num);
592        let r = JsonInteger::from(r_num);
593        assert_eq!(
594            l.ge(r),
595            expected,
596            "{l_num} >= {r_num} was expected to be {expected}"
597        );
598    }
599
600    #[rstest]
601    #[case(101, 100, true)]
602    #[case(100, 100, true)]
603    #[case(99, 100, false)]
604    #[case(0, 0, true)]
605    #[case(0, -0, true)]
606    #[case(0, -1, true)]
607    fn it_should_handle_u64_to_i64_correctly(
608        #[case] l_num: u64,
609        #[case] r_num: i64,
610        #[case] expected: bool,
611    ) {
612        let l = JsonInteger::from(l_num);
613        let r = JsonInteger::from(r_num);
614        assert_eq!(
615            l.ge(r),
616            expected,
617            "{l_num} >= {r_num} was expected to be {expected}"
618        );
619    }
620}