unc_token/trait_impls/
from_str.rs

1use crate::{UncToken, UncTokenError, ONE_UNC};
2
3impl std::str::FromStr for UncToken {
4    type Err = UncTokenError;
5    fn from_str(s: &str) -> Result<Self, Self::Err> {
6        let uppercase_s = s.trim().to_ascii_uppercase();
7        let (value, unit) = uppercase_s.split_at(
8            s.find(|c: char| c.is_ascii_alphabetic())
9                .ok_or_else(|| UncTokenError::InvalidTokenUnit(s.to_owned()))?,
10        );
11        let unit_precision = match unit {
12            "AN" | "AUNC" | "ATTOUNC" => 1,
13            "UNC" | "N" => ONE_UNC,
14            _ => return Err(UncTokenError::InvalidTokenUnit(s.to_owned())),
15        };
16        Ok(UncToken::from_attounc(
17            crate::utils::parse_decimal_number(value.trim(), unit_precision)
18                .map_err(UncTokenError::InvalidTokensAmount)?,
19        ))
20    }
21}
22
23#[cfg(test)]
24mod test {
25    use std::str::FromStr;
26
27    use crate::{DecimalNumberParsingError, UncToken, UncTokenError};
28
29    #[test]
30    fn parse_decimal_number() {
31        let data = "0.123456 unc";
32        let gas: Result<UncToken, UncTokenError> = FromStr::from_str(data);
33        assert_eq!(
34            gas.unwrap(),
35            UncToken::from_attounc(123456000000000000000000)
36        );
37    }
38    #[test]
39    fn parse_number_with_decimal_part() {
40        let data = "11.123456 unc";
41        let gas: Result<UncToken, UncTokenError> = FromStr::from_str(data);
42        assert_eq!(
43            gas.unwrap(),
44            UncToken::from_attounc(11123456000000000000000000)
45        );
46    }
47
48    #[test]
49    fn parse_atto_number() {
50        let data = "123456 AN";
51        let gas: Result<UncToken, UncTokenError> = FromStr::from_str(data);
52        assert_eq!(gas.unwrap(), UncToken::from_attounc(123456));
53    }
54
55    #[test]
56    fn doubledot() {
57        let data = "1.1.1 UNC";
58        let gas: Result<UncToken, UncTokenError> = FromStr::from_str(data);
59        assert_eq!(
60            gas,
61            Err(UncTokenError::InvalidTokensAmount(
62                DecimalNumberParsingError::InvalidNumber("1.1.1".to_owned())
63            ))
64        )
65    }
66
67    #[test]
68    fn space_after_dot() {
69        let data = "1. 0 unc";
70        let gas: Result<UncToken, UncTokenError> = FromStr::from_str(data);
71        assert_eq!(
72            gas,
73            Err(UncTokenError::InvalidTokensAmount(
74                DecimalNumberParsingError::InvalidNumber("1. 0".to_owned())
75            ))
76        )
77    }
78
79    #[test]
80    fn incorect_currency() {
81        let data = "0 pas";
82        let gas: Result<UncToken, UncTokenError> = FromStr::from_str(data);
83        assert_eq!(gas, Err(UncTokenError::InvalidTokenUnit(data.to_owned())))
84    }
85
86    #[test]
87    fn without_currency() {
88        let data = "0";
89        let gas: Result<UncToken, UncTokenError> = FromStr::from_str(data);
90        assert_eq!(gas, Err(UncTokenError::InvalidTokenUnit("0".to_owned())))
91    }
92
93    #[test]
94    fn invalid_whole() {
95        let data = "-1 UNC";
96        let gas: Result<UncToken, UncTokenError> = FromStr::from_str(data);
97        assert_eq!(
98            gas,
99            Err(UncTokenError::InvalidTokensAmount(
100                DecimalNumberParsingError::InvalidNumber("-1".to_owned())
101            ))
102        )
103    }
104
105    #[test]
106    fn test_from_str_f64_gas_without_int() {
107        let unc_gas = UncToken::from_str(".055 yunc").unwrap_err();
108        assert_eq!(
109            unc_gas,
110            UncTokenError::InvalidTokensAmount(DecimalNumberParsingError::InvalidNumber(
111                ".055".to_string()
112            ))
113        );
114    }
115
116    #[test]
117    fn test_from_str_without_unit() {
118        let unc_gas = UncToken::from_str("100").unwrap_err();
119        assert_eq!(
120            unc_gas,
121            UncTokenError::InvalidTokenUnit("100".to_string())
122        );
123    }
124
125    #[test]
126    fn test_from_str_incorrect_unit() {
127        let unc_gas = UncToken::from_str("100 UAH").unwrap_err();
128        assert_eq!(
129            unc_gas,
130            UncTokenError::InvalidTokenUnit("100 UAH".to_string())
131        );
132    }
133
134    #[test]
135    fn test_from_str_invalid_double_dot() {
136        let unc_gas = UncToken::from_str("100.55.").unwrap_err();
137        assert_eq!(
138            unc_gas,
139            UncTokenError::InvalidTokenUnit("100.55.".to_string())
140        );
141    }
142
143    #[test]
144    fn test_from_str_large_fractional_part() {
145        let unc_gas = UncToken::from_str("100.1111122222333 aunc").unwrap_err(); // 13 digits after "."
146        assert_eq!(
147            unc_gas,
148            UncTokenError::InvalidTokensAmount(DecimalNumberParsingError::LongFractional(
149                "1111122222333".to_string()
150            ))
151        );
152    }
153}