LCOV - code coverage report
Current view: top level - libs/utils/src - serde_percent.rs (source / functions) Coverage Total Hit
Test: 6df3fc19ec669bcfbbf9aba41d1338898d24eaa0.info Lines: 100.0 % 55 55
Test Date: 2025-03-12 18:28:53 Functions: 36.1 % 36 13

            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            2 : #[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          285 :     pub const fn new(pct: u8) -> Option<Self> {
      15          285 :         if pct <= 100 { Some(Percent(pct)) } else { None }
      16          285 :     }
      17              : 
      18        25867 :     pub fn get(&self) -> u8 {
      19        25867 :         self.0
      20        25867 :     }
      21              : }
      22              : 
      23            7 : fn deserialize_pct_0_to_100<'de, D>(deserializer: D) -> Result<u8, D::Error>
      24            7 : where
      25            7 :     D: serde::de::Deserializer<'de>,
      26            7 : {
      27            7 :     let v: u8 = serde::de::Deserialize::deserialize(deserializer)?;
      28            3 :     if v > 100 {
      29            1 :         return Err(serde::de::Error::custom(
      30            1 :             "must be an integer between 0 and 100",
      31            1 :         ));
      32            2 :     }
      33            2 :     Ok(v)
      34            7 : }
      35              : 
      36              : #[cfg(test)]
      37              : mod tests {
      38              :     use super::Percent;
      39              : 
      40            7 :     #[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq, Eq)]
      41              :     struct Foo {
      42              :         bar: Percent,
      43              :     }
      44              : 
      45              :     #[test]
      46            1 :     fn basics() {
      47            1 :         let input = r#"{ "bar": 50 }"#;
      48            1 :         let foo: Foo = serde_json::from_str(input).unwrap();
      49            1 :         assert_eq!(foo.bar.get(), 50);
      50            1 :     }
      51              :     #[test]
      52            1 :     fn null_handling() {
      53            1 :         let input = r#"{ "bar": null }"#;
      54            1 :         let res: Result<Foo, _> = serde_json::from_str(input);
      55            1 :         assert!(res.is_err());
      56            1 :     }
      57              :     #[test]
      58            1 :     fn zero() {
      59            1 :         let input = r#"{ "bar": 0 }"#;
      60            1 :         let foo: Foo = serde_json::from_str(input).unwrap();
      61            1 :         assert_eq!(foo.bar.get(), 0);
      62            1 :     }
      63              :     #[test]
      64            1 :     fn out_of_range_above() {
      65            1 :         let input = r#"{ "bar": 101 }"#;
      66            1 :         let res: Result<Foo, _> = serde_json::from_str(input);
      67            1 :         assert!(res.is_err());
      68            1 :     }
      69              :     #[test]
      70            1 :     fn out_of_range_below() {
      71            1 :         let input = r#"{ "bar": -1 }"#;
      72            1 :         let res: Result<Foo, _> = serde_json::from_str(input);
      73            1 :         assert!(res.is_err());
      74            1 :     }
      75              :     #[test]
      76            1 :     fn float() {
      77            1 :         let input = r#"{ "bar": 50.5 }"#;
      78            1 :         let res: Result<Foo, _> = serde_json::from_str(input);
      79            1 :         assert!(res.is_err());
      80            1 :     }
      81              :     #[test]
      82            1 :     fn string() {
      83            1 :         let input = r#"{ "bar": "50 %" }"#;
      84            1 :         let res: Result<Foo, _> = serde_json::from_str(input);
      85            1 :         assert!(res.is_err());
      86            1 :     }
      87              : }
        

Generated by: LCOV version 2.1-beta