LCOV - code coverage report
Current view: top level - proxy/src - url.rs (source / functions) Coverage Total Hit
Test: 49aa928ec5b4b510172d8b5c6d154da28e70a46c.info Lines: 83.3 % 36 30
Test Date: 2024-11-13 18:23:39 Functions: 71.4 % 7 5

            Line data    Source code
       1              : use anyhow::bail;
       2              : 
       3              : /// A [url](url::Url) type with additional guarantees.
       4              : #[repr(transparent)]
       5              : #[derive(Debug, Clone, PartialEq, Eq)]
       6              : pub struct ApiUrl(url::Url);
       7              : 
       8              : impl ApiUrl {
       9              :     /// Consume the wrapper and return inner [url](url::Url).
      10            3 :     pub(crate) fn into_inner(self) -> url::Url {
      11            3 :         self.0
      12            3 :     }
      13              : 
      14              :     /// See [`url::Url::path_segments_mut`].
      15            3 :     pub(crate) fn path_segments_mut(&mut self) -> url::PathSegmentsMut<'_> {
      16            3 :         // We've already verified that it works during construction.
      17            3 :         self.0.path_segments_mut().expect("bad API url")
      18            3 :     }
      19              : }
      20              : 
      21              : /// This instance imposes additional requirements on the url.
      22              : impl std::str::FromStr for ApiUrl {
      23              :     type Err = anyhow::Error;
      24              : 
      25            4 :     fn from_str(s: &str) -> anyhow::Result<Self> {
      26            4 :         let mut url: url::Url = s.parse()?;
      27              : 
      28              :         // Make sure that we can build upon this URL.
      29            4 :         if url.path_segments_mut().is_err() {
      30            1 :             bail!("bad API url provided");
      31            3 :         }
      32            3 : 
      33            3 :         Ok(Self(url))
      34            4 :     }
      35              : }
      36              : 
      37              : /// This instance is safe because it doesn't allow us to modify the object.
      38              : impl std::ops::Deref for ApiUrl {
      39              :     type Target = url::Url;
      40              : 
      41            0 :     fn deref(&self) -> &Self::Target {
      42            0 :         &self.0
      43            0 :     }
      44              : }
      45              : 
      46              : impl std::fmt::Display for ApiUrl {
      47            0 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      48            0 :         self.0.fmt(f)
      49            0 :     }
      50              : }
      51              : 
      52              : #[cfg(test)]
      53              : mod tests {
      54              :     use super::*;
      55              : 
      56              :     #[test]
      57            1 :     fn bad_url() {
      58            1 :         let url = "test:foobar";
      59            1 :         url.parse::<url::Url>().expect("unexpected parsing failure");
      60            1 :         url.parse::<ApiUrl>().expect_err("should not parse");
      61            1 :     }
      62              : 
      63              :     #[test]
      64            1 :     fn good_url() {
      65            1 :         let url = "test://foobar";
      66            1 :         let mut a = url.parse::<url::Url>().expect("unexpected parsing failure");
      67            1 :         let mut b = url.parse::<ApiUrl>().expect("unexpected parsing failure");
      68            1 : 
      69            1 :         a.path_segments_mut().unwrap().push("method");
      70            1 :         b.path_segments_mut().push("method");
      71            1 : 
      72            1 :         assert_eq!(a, b.into_inner());
      73            1 :     }
      74              : }
        

Generated by: LCOV version 2.1-beta