LCOV - code coverage report
Current view: top level - libs/utils/src - serde_percent.rs (source / functions) Coverage Total Hit
Test: 050dd70dd490b28fffe527eae9fb8a1222b5c59c.info Lines: 98.2 % 57 56
Test Date: 2024-06-25 21:28:46 Functions: 51.6 % 31 16

            Line data    Source code
       1              : //! A serde::Deserialize type for percentages.
       2              : //!
       3              : //! See [`Percent`] for details.
       4              : 
       5              : use serde::{Deserialize, Serialize};
       6              : 
       7              : /// If the value is not an integer between 0 and 100,
       8              : /// deserialization fails with a descriptive error.
       9            6 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
      10              : #[serde(transparent)]
      11              : pub struct Percent(#[serde(deserialize_with = "deserialize_pct_0_to_100")] u8);
      12              : 
      13              : impl Percent {
      14            4 :     pub const fn new(pct: u8) -> Option<Self> {
      15            4 :         if pct <= 100 {
      16            4 :             Some(Percent(pct))
      17              :         } else {
      18            0 :             None
      19              :         }
      20            4 :     }
      21              : 
      22           18 :     pub fn get(&self) -> u8 {
      23           18 :         self.0
      24           18 :     }
      25              : }
      26              : 
      27           16 : fn deserialize_pct_0_to_100<'de, D>(deserializer: D) -> Result<u8, D::Error>
      28           16 : where
      29           16 :     D: serde::de::Deserializer<'de>,
      30           16 : {
      31           16 :     let v: u8 = serde::de::Deserialize::deserialize(deserializer)?;
      32            8 :     if v > 100 {
      33            2 :         return Err(serde::de::Error::custom(
      34            2 :             "must be an integer between 0 and 100",
      35            2 :         ));
      36            6 :     }
      37            6 :     Ok(v)
      38           16 : }
      39              : 
      40              : #[cfg(test)]
      41              : mod tests {
      42              :     use super::Percent;
      43              : 
      44           38 :     #[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq, Eq)]
      45              :     struct Foo {
      46              :         bar: Percent,
      47              :     }
      48              : 
      49              :     #[test]
      50            2 :     fn basics() {
      51            2 :         let input = r#"{ "bar": 50 }"#;
      52            2 :         let foo: Foo = serde_json::from_str(input).unwrap();
      53            2 :         assert_eq!(foo.bar.get(), 50);
      54            2 :     }
      55              :     #[test]
      56            2 :     fn null_handling() {
      57            2 :         let input = r#"{ "bar": null }"#;
      58            2 :         let res: Result<Foo, _> = serde_json::from_str(input);
      59            2 :         assert!(res.is_err());
      60            2 :     }
      61              :     #[test]
      62            2 :     fn zero() {
      63            2 :         let input = r#"{ "bar": 0 }"#;
      64            2 :         let foo: Foo = serde_json::from_str(input).unwrap();
      65            2 :         assert_eq!(foo.bar.get(), 0);
      66            2 :     }
      67              :     #[test]
      68            2 :     fn out_of_range_above() {
      69            2 :         let input = r#"{ "bar": 101 }"#;
      70            2 :         let res: Result<Foo, _> = serde_json::from_str(input);
      71            2 :         assert!(res.is_err());
      72            2 :     }
      73              :     #[test]
      74            2 :     fn out_of_range_below() {
      75            2 :         let input = r#"{ "bar": -1 }"#;
      76            2 :         let res: Result<Foo, _> = serde_json::from_str(input);
      77            2 :         assert!(res.is_err());
      78            2 :     }
      79              :     #[test]
      80            2 :     fn float() {
      81            2 :         let input = r#"{ "bar": 50.5 }"#;
      82            2 :         let res: Result<Foo, _> = serde_json::from_str(input);
      83            2 :         assert!(res.is_err());
      84            2 :     }
      85              :     #[test]
      86            2 :     fn string() {
      87            2 :         let input = r#"{ "bar": "50 %" }"#;
      88            2 :         let res: Result<Foo, _> = serde_json::from_str(input);
      89            2 :         assert!(res.is_err());
      90            2 :     }
      91              : }
        

Generated by: LCOV version 2.1-beta