Skip to main content

near_gas/trait_impls/
from_str.rs

1use crate::{NearGas, NearGasError, ONE_GIGA_GAS, ONE_PETA_GAS, ONE_TERA_GAS};
2
3impl std::str::FromStr for NearGas {
4    type Err = NearGasError;
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(|| NearGasError::IncorrectUnit(s.to_owned()))?,
10        );
11        let unit_precision = match unit {
12            "PGAS" | "PETAGAS" => ONE_PETA_GAS,
13            "TGAS" | "TERAGAS" => ONE_TERA_GAS,
14            "GIGAGAS" | "GGAS" => ONE_GIGA_GAS,
15            _ => return Err(NearGasError::IncorrectUnit(s.to_owned())),
16        };
17        Ok(NearGas::from_gas(
18            crate::utils::parse_decimal_number(value.trim(), unit_precision)
19                .map_err(NearGasError::IncorrectNumber)?,
20        ))
21    }
22}
23
24#[cfg(test)]
25mod test {
26    use std::str::FromStr;
27
28    use crate::{DecimalNumberParsingError, NearGas, NearGasError};
29
30    #[test]
31    fn doubledot() {
32        let data = "1.1.1 TeraGas";
33        let gas: Result<NearGas, NearGasError> = FromStr::from_str(data);
34        assert_eq!(
35            gas,
36            Err(NearGasError::IncorrectNumber(
37                DecimalNumberParsingError::InvalidNumber("1.1.1".to_owned())
38            ))
39        )
40    }
41
42    #[test]
43    fn space_after_dot() {
44        let data = "1. 0 TeraGas";
45        let gas: Result<NearGas, NearGasError> = FromStr::from_str(data);
46        assert_eq!(
47            gas,
48            Err(NearGasError::IncorrectNumber(
49                DecimalNumberParsingError::InvalidNumber("1. 0".to_owned())
50            ))
51        )
52    }
53
54    #[test]
55    fn decimal_tgas() {
56        let data = "0.5 TGas";
57        let gas: Result<NearGas, NearGasError> = FromStr::from_str(data);
58        assert_eq!(gas, Ok(NearGas::from_ggas(500)))
59    }
60
61    #[test]
62    fn incorect_currency() {
63        let data = "0 pas";
64        let gas: Result<NearGas, NearGasError> = FromStr::from_str(data);
65        assert_eq!(gas, Err(NearGasError::IncorrectUnit(data.to_owned())))
66    }
67
68    #[test]
69    fn without_currency() {
70        let data = "0";
71        let gas: Result<NearGas, NearGasError> = FromStr::from_str(data);
72        assert_eq!(gas, Err(NearGasError::IncorrectUnit("0".to_owned())))
73    }
74
75    #[test]
76    fn invalid_whole() {
77        let data = "-1 TeraGas";
78        let gas: Result<NearGas, NearGasError> = FromStr::from_str(data);
79        assert_eq!(
80            gas,
81            Err(NearGasError::IncorrectNumber(
82                DecimalNumberParsingError::InvalidNumber("-1".to_owned())
83            ))
84        )
85    }
86
87    #[test]
88    fn test_from_str_f64_gas_without_int() {
89        let near_gas = NearGas::from_str(".055ggas").unwrap_err();
90        assert_eq!(
91            near_gas,
92            NearGasError::IncorrectNumber(DecimalNumberParsingError::InvalidNumber(
93                ".055".to_string()
94            ))
95        );
96    }
97
98    #[test]
99    fn test_from_str_without_unit() {
100        let near_gas = NearGas::from_str("100").unwrap_err();
101        assert_eq!(near_gas, NearGasError::IncorrectUnit("100".to_string()));
102    }
103
104    #[test]
105    fn test_from_str_incorrect_unit() {
106        let near_gas = NearGas::from_str("100 UAH").unwrap_err();
107        assert_eq!(near_gas, NearGasError::IncorrectUnit("100 UAH".to_string()));
108    }
109
110    #[test]
111    fn test_from_str_invalid_double_dot() {
112        let near_gas = NearGas::from_str("100.55.").unwrap_err();
113        assert_eq!(near_gas, NearGasError::IncorrectUnit("100.55.".to_string()));
114    }
115
116    #[test]
117    fn test_from_str_large_fractional_part() {
118        let near_gas = NearGas::from_str("100.1111122222333 ggas").unwrap_err(); // 13 digits after "."
119        assert_eq!(
120            near_gas,
121            NearGasError::IncorrectNumber(DecimalNumberParsingError::LongFractional(
122                "1111122222333".to_string()
123            ))
124        );
125    }
126
127    #[test]
128    fn test_from_str_large_int_part() {
129        let near_gas = NearGas::from_str("200123456789123.0 tgas").unwrap_err();
130        assert_eq!(
131            near_gas,
132            NearGasError::IncorrectNumber(DecimalNumberParsingError::LongWhole(
133                "200123456789123".to_string()
134            ))
135        );
136    }
137
138    #[test]
139    fn test_from_str_negative_value() {
140        let near_gas = NearGas::from_str("-100 ggas").unwrap_err();
141        assert_eq!(
142            near_gas,
143            NearGasError::IncorrectNumber(DecimalNumberParsingError::InvalidNumber(
144                "-100".to_string()
145            ))
146        );
147    }
148
149    #[test]
150    fn near_gas_from_str_currency_pgas() {
151        assert_eq!(
152            NearGas::from_str("10 pgas").unwrap(),
153            NearGas::from_gas(10_000_000_000_000_000) // 17 digits
154        );
155        assert_eq!(
156            NearGas::from_str("10.055PETAGAS").unwrap(),
157            NearGas::from_gas(10_055_000_000_000_000) // 17 digits
158        )
159    }
160    #[test]
161    fn near_gas_from_str_currency_tgas() {
162        assert_eq!(
163            NearGas::from_str("10 tgas").unwrap(),
164            NearGas::from_gas(10_000_000_000_000) // 14 digits
165        );
166        assert_eq!(
167            NearGas::from_str("10.055TERAGAS").unwrap(),
168            NearGas::from_gas(10_055_000_000_000) // 14 digits
169        );
170    }
171
172    #[test]
173    fn near_gas_from_str_currency_gigagas() {
174        assert_eq!(
175            NearGas::from_str("10 gigagas").unwrap(),
176            NearGas::from_gas(10_000_000_000) // 11 digits
177        );
178        assert_eq!(
179            NearGas::from_str("10GGAS ").unwrap(),
180            NearGas::from_gas(10_000_000_000) // 11 digits
181        );
182    }
183
184    #[test]
185    fn near_gas_from_str_f64_pgas() {
186        assert_eq!(
187            NearGas::from_str("0.000001 pgas").unwrap(),
188            NearGas::from_gas(1_000_000_000) // 10 digits
189        )
190    }
191    #[test]
192    fn near_gas_from_str_f64_tgas() {
193        assert_eq!(
194            NearGas::from_str("0.000001 tgas").unwrap(),
195            NearGas::from_gas(1_000_000) // 7 digits
196        );
197    }
198}