Skip to main content

transip/authentication/
token_expiration.rs

1use std::{fmt::Display, str::FromStr};
2
3use crate::Error;
4
5#[allow(dead_code)]
6#[derive(PartialEq, Debug, Clone)]
7pub enum TokenExpiration {
8    Seconds(u8),
9    Minutes(u8),
10    Hours(u8),
11}
12
13impl Default for TokenExpiration {
14    fn default() -> Self {
15        Self::Minutes(5)
16    }
17}
18
19fn fmt(count: &u8, unit: &'static str) -> String {
20    format!("{} {}", count, unit) + if count <= &1 { "" } else { "s" }
21}
22
23impl Display for TokenExpiration {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        write!(
26            f,
27            "{}",
28            match self {
29                TokenExpiration::Seconds(seconds) => fmt(seconds, "second"),
30                TokenExpiration::Minutes(minutes) => fmt(minutes, "minute"),
31                TokenExpiration::Hours(hours) => fmt(hours, "hour"),
32            }
33        )
34    }
35}
36
37impl FromStr for TokenExpiration {
38    type Err = Error;
39
40    fn from_str(s: &str) -> Result<Self, Self::Err> {
41        let splitted = s.split(' ').collect::<Vec<_>>();
42        if splitted.len() != 2 {
43            return Err(Error::ParseExpiration("String should contain 2 words"));
44        };
45        let first_word = splitted[0].trim().parse::<u8>()?;
46        let second_word = splitted[1].trim();
47
48        const IS_SECONDS: [&str; 2] = ["second", "seconds"];
49        if IS_SECONDS.contains(&second_word.to_lowercase().as_str()) {
50            return Ok(TokenExpiration::Seconds(first_word));
51        }
52
53        const IS_MINUTES: [&str; 2] = ["minute", "minutes"];
54        if IS_MINUTES.contains(&second_word.to_lowercase().as_str()) {
55            return Ok(TokenExpiration::Minutes(first_word));
56        }
57
58        const IS_HOURS: [&str; 2] = ["hour", "hours"];
59        if IS_HOURS.contains(&second_word.to_lowercase().as_str()) {
60            return Ok(TokenExpiration::Hours(first_word));
61        }
62
63        Err(Error::ParseExpiration("Invalid"))
64    }
65}
66
67#[cfg(test)]
68mod test {
69    use super::TokenExpiration;
70
71    #[test]
72    fn seconds_ok() {
73        let s = "5 seconds";
74        let expiration = s.parse::<TokenExpiration>().unwrap();
75        assert_eq!(expiration, TokenExpiration::Seconds(5));
76    }
77
78    #[test]
79    fn seconds_error() {
80        assert!("10 secconds".parse::<TokenExpiration>().is_err());
81        assert!("five seconds".parse::<TokenExpiration>().is_err());
82    }
83
84    #[test]
85    fn minutes_ok() {
86        assert_eq!(
87            "10 minutes".parse::<TokenExpiration>().unwrap(),
88            TokenExpiration::Minutes(10),
89        );
90    }
91
92    #[test]
93    fn minutes_err() {
94        assert!("10 minuttes".parse::<TokenExpiration>().is_err());
95        assert!("ten minutes".parse::<TokenExpiration>().is_err());
96    }
97
98    #[test]
99    fn hours_ok() {
100        assert_eq!(
101            "60 hours".parse::<TokenExpiration>().unwrap(),
102            TokenExpiration::Hours(60),
103        );
104        assert_eq!(
105            "60 HOUR".parse::<TokenExpiration>().unwrap(),
106            TokenExpiration::Hours(60),
107        );
108    }
109
110    #[test]
111    fn hours_err() {
112        assert!("10 uur".parse::<TokenExpiration>().is_err());
113        assert!("ten hours".parse::<TokenExpiration>().is_err());
114    }
115}